#include #include #include "opcodes.h" #ifdef DUCKY_ROCKBOX #include "hid_codes.h" #endif /******************************************************************************* * Bytecode format (all numbers are little-endian): * * +0x00: 'DucK' signature (4 bytes) * +0x04: number of lines (4 bytes) * +0x08: line offsets (4 * num lines) * + : compiler-generated init code * +(0x08): start of compiled code */ /*** Defines ***/ #define DEFAULT_DELAY 0 #define STRING_DELAY 0 #define TOKEN_IS(str) (strcmp(tok, str) == 0) #define MAX_LINE_LEN 512 #define ARRAYLEN(x) (sizeof(x)/sizeof(x[0])) #define MIN(x,y) ((x= 0) close(file_des); if(line_offset) free(line_offset); } static void write_str(const char *str) { write_instr(WRITE_STR); while(*str) { write_byte(*str++); } write_byte('\0'); } static void jump_line(int fd, unsigned where) { if(1 <= where && where <= num_lines) { lseek(fd, line_offset[where], SEEK_SET); } else ERROR("JUMP target out of range (%u)", where); current_line = where - 1; } /** Expression Parsing **/ /* based on http://en.literateprograms.org/Shunting_yard_algorithm_%28C%29 */ static void eval_uminus(void) { write_instr(NEG); } static void eval_exp(void) { write_instr(POW); } static void eval_mul(void) { write_instr(MULT); } static void eval_div(void) { write_instr(DIV); } static void eval_mod(void) { write_instr(MOD); } static void eval_add(void) { write_instr(ADD); } static void eval_sub(void) { write_instr(SUB); } static void eval_eq(void) { write_instr(EQ); } static void eval_neq(void) { write_instr(NEQ); } static void eval_leq(void) { write_instr(LEQ); } static void eval_geq(void) { write_instr(GEQ); } static void eval_lt(void) { write_instr(LT); } static void eval_gt(void) { write_instr(GT); } static void eval_log_neg(void) { write_instr(LOGNOT); } static void eval_log_and(void) { write_instr(LOGAND); } static void eval_log_or(void) { write_instr(LOGOR); } static void eval_bit_and(void) { write_instr(BITAND); } static void eval_bit_xor(void) { write_instr(BITXOR); } static void eval_bit_or(void) { write_instr(BITOR); } static void eval_bit_comp(void) { write_instr(BITCOMP); } static void eval_lsh(void) { write_instr(LSH); } static void eval_rsh(void) { write_instr(RSH); } static void eval_sqrt(void) { write_instr(SQRT); } enum {ASSOC_NONE=0, ASSOC_LEFT, ASSOC_RIGHT}; /* order matters in this table, because operators can share prefixes */ /* apart from that, they should be ordered by frequency of use */ /* operator precedence is based on that of C */ /* frequency is based off a crude analysis of the rockbox source tree: */ /* 99639 * */ /* 48282 - */ /* 46639 + */ /* 27678 & */ /* 24542 < */ /* 21862 / */ /* 20000 | */ /* 19138 == */ /* 12694 % */ /* 11619 > */ /* 11087 ! */ /* 8230 << */ /* 7339 && */ /* 7180 != */ /* 6010 >> */ /* 5575 || */ /* 3121 ~ */ /* 1311 ^ */ /* arrays are implemented as UNARY OPERATORS */ static struct op_s { const char *op; int prec; int assoc; int unary; void (*eval)(void); unsigned int len; } ops[] = { {"+", 20, ASSOC_LEFT, 0, eval_add, -1}, {"-", 20, ASSOC_LEFT, 0, eval_sub, -1}, {"**", 40, ASSOC_RIGHT, 0, eval_exp, -1}, {"*", 30, ASSOC_LEFT, 0, eval_mul, -1}, {"&&", 8, ASSOC_LEFT, 0, eval_log_and, -1}, {"&", 11, ASSOC_LEFT, 0, eval_bit_and, -1}, {"<<", 15, ASSOC_LEFT, 0, eval_lsh, -1}, {">>", 15, ASSOC_LEFT, 0, eval_rsh, -1}, {"<=", 14, ASSOC_LEFT, 0, eval_leq, -1}, {">=", 14, ASSOC_LEFT, 0, eval_geq, -1}, {"<", 14, ASSOC_LEFT, 0, eval_lt, -1}, {">", 14, ASSOC_LEFT, 0, eval_gt, -1}, {"/", 30, ASSOC_LEFT, 0, eval_div, -1}, {"||", 7, ASSOC_LEFT, 0, eval_log_or, -1}, {"|", 9, ASSOC_LEFT, 0, eval_bit_or, -1}, {"==", 12, ASSOC_LEFT, 0, eval_eq, -1}, {"!=", 12, ASSOC_LEFT, 0, eval_neq, -1}, {"%", 30, ASSOC_LEFT, 0, eval_mod, -1}, {"!", 50, ASSOC_LEFT, 1, eval_log_neg, -1}, {"~", 50, ASSOC_LEFT, 1, eval_bit_comp, -1}, {"^", 10, ASSOC_LEFT, 0, eval_bit_xor, -1}, {"(", 0, ASSOC_NONE, 0, NULL, -1}, {")", 0, ASSOC_NONE, 0, NULL, -1}, {"sqrt", 1, ASSOC_LEFT, 1, eval_sqrt, -1}, }; #define OPMAP_SIZE 25 static void op_hash_round(char c, uint32_t *hash) { *hash *= 70; *hash ^= c; } static uint32_t op_hash(const char *c) { uint32_t hash = 4412; while(1) { if(!*c) return hash; op_hash_round(*c, &hash); ++c; } } /* optimized hash map for fast lookup of operators */ static struct op_s op_map[OPMAP_SIZE]; static size_t longest_op = 0; static void opmap_insert(struct op_s *op) { if(op->len > longest_op) longest_op = op->len; uint32_t hash = op_hash(op->op) % OPMAP_SIZE; if(op_map[hash].op) ERROR("hash map collision %lu: %s VS %s", hash, op->op, op_map[hash].op); memcpy(op_map+hash, op, sizeof(*op)); } static void init_optable(void) { memset(op_map, 0, sizeof(op_map)); for(unsigned int i = 0; i < ARRAYLEN(ops); ++i) { ops[i].len = strlen(ops[i].op); opmap_insert(ops+i); } } static const struct op_s *getop(const char *ch, int *len) { unsigned int i = 0; uint32_t hash = 4412; const struct op_s *poss = NULL; do { op_hash_round(ch[i], &hash); uint32_t modhash = hash % OPMAP_SIZE; if(op_map[modhash].op && strncmp(ch, op_map[modhash].op, op_map[modhash].len) == 0) { *len = op_map[modhash].len; poss = op_map + modhash; } } while(ch[i++] && i < longest_op); return poss; } static const struct op_s *opstack[MAXOPSTACK]; static int nopstack; static void push_opstack(const struct op_s *op) { if(nopstack>MAXOPSTACK - 1) { ERROR("operator stack overflow"); } opstack[nopstack++] = op; } static const struct op_s *pop_opstack(void) { if(!nopstack) { ERROR("operator stack empty"); } return opstack[--nopstack]; } static bool isDigit(char c) { return '0' <= c && c <= '9'; } static bool isValidNumber(char *str) { //vid_logf("isValidNumber %s", str); if(str && (isDigit(*str) || *str == '-')) { while(1) { char c = *str++; if(!c) break; if(!isDigit(c)) return false; } return true; } return false; } static bool isSpace(char c) { //vid_logf("isSpace '%c'", c); return (c == ' ') || (c == '\t'); } static bool isValidVariable(const char *c) { //vid_logf("isValidVariable %s", c); if(!isDigit(*c) && !getop(c, NULL) && !isSpace(*c)) { return true; } return false; } static bool isValidNumberOrVariable(const char *c) { //vid_logf("isValidNumberOrVariable %s", c); if(isDigit(*c) || isValidVariable(c)) { return true; } return false; } static void shunt_op(const struct op_s *op) { const struct op_s *pop; vartype n1, n2; if(strcmp(op->op, "(") == 0) { push_opstack(op); return; } else if(strcmp(op->op, ")") == 0) { while(nopstack > 0 && strcmp(opstack[nopstack-1]->op, "(") != 0) { pop = pop_opstack(); pop->eval(); } if(!(pop = pop_opstack()) || strcmp(pop->op,"(") != 0) { ERROR("mismatched parentheses"); } return; } if(op->assoc == ASSOC_LEFT) { while(nopstack && op->prec <= opstack[nopstack - 1]->prec) { pop = pop_opstack(); pop->eval(); } } else { while(nopstack && op->precprec) { pop = pop_opstack(); pop->eval(); } } push_opstack(op); } static vartype eval_expr(char *str) { //vid_write("**************** EVAL EXPR ***************"); /* token start */ char *tstart = NULL; /* hard-code some operators that are for internal use only */ const struct op_s startop = {"startop_", 0, ASSOC_NONE, 0, NULL, strlen("startop_")}; const struct op_s unaryminus = {"-", 50, ASSOC_RIGHT, 1, eval_uminus, strlen("-")}; const struct op_s *op = NULL; vartype n1, n2; const struct op_s *lastop = &startop; int len; char *expr; for(expr = str; *expr; expr += len) { //vid_write("****** PARSING A CHARACTER ******"); len = 1; if(!tstart) { if((op = getop(expr, &len))) { if(lastop && (lastop == &startop || strcmp(lastop->op, ")") != 0)) { if(strcmp(op->op, "-") == 0) { op = &unaryminus; len = 1; } else if(strcmp(op->op, "(") != 0 && !op->unary) { ERROR("illegal use of binary operator (%s)", op->op); } } shunt_op(op); lastop = op; } else if(isValidNumberOrVariable(expr)) tstart = expr; else if(!isSpace(*expr)) { ERROR("syntax ERROR"); } } else { if(isSpace(*expr)) { //push_numstack(getValue(tstart, expr)); if(isValidVariable(tstart)) { write_instr(PUSHVAR); /* isolate the variable name into a buffer */ char varname[VARNAME_MAX + 1] = { 0 }; memcpy(varname, tstart, expr - tstart); write_varid(get_varid(varname)); } else { write_instr(PUSHIMM); write_imm(strtol(tstart, NULL, 0)); } tstart = NULL; lastop = NULL; } else if((op = getop(expr, &len))) { //push_numstack(getValue(tstart, expr)); if(isValidVariable(tstart)) { write_instr(PUSHVAR); /* isolate the variable name into a buffer */ char varname[VARNAME_MAX + 1] = { 0 }; memcpy(varname, tstart, expr - tstart); write_varid(get_varid(varname)); } else { write_instr(PUSHIMM); write_imm(strtol(tstart, NULL, 0)); } tstart = NULL; shunt_op(op); lastop = op; } else if(!isValidNumberOrVariable(expr)) { ERROR("syntax ERROR"); } } } if(tstart) { //push_numstack(getValue(tstart, expr)); if(isValidVariable(tstart)) { write_instr(PUSHVAR); /* isolate the variable name into a buffer */ char varname[VARNAME_MAX + 1] = { 0 }; memcpy(varname, tstart, expr - tstart); write_varid(get_varid(varname)); } else { write_instr(PUSHIMM); write_imm(strtol(tstart, NULL, 0)); } } while(nopstack) { op = pop_opstack(); op->eval(); } } #define OK 0 #define DONE 1 #define NEXT 2 #define BREAK 3 static int let_handler(char **save) { (void) save; char *varname = strtok_r(NULL, "= \t", save); if(varname && isValidVariable(varname)) { int varid = get_varid(varname); char *tok = strtok_r(NULL, "=;", save); if(tok) eval_expr(tok); else ERROR("exprected valid expression after LET"); write_instr(POP); write_varid(varid); } else { ERROR("invalid variable name for LET"); } return OK; } static int repeat_handler(char **save) { (void) save; char *tok = strtok_r(NULL, ";", save); if(tok) { eval_expr(tok); write_instr(PUSHIMM); write_imm(current_line - 1); write_instr(REPEAT); return OK; } else ERROR("expected valid expression after REPEAT"); } static int goto_handler(char **save) { (void) save; char *tok = strtok_r(NULL, ";", save); if(tok) { eval_expr(tok); write_instr(JUMP); return OK; } else ERROR("expected valid expression after GOTO"); } static int call_handler(char **save) { (void) save; char *tok = strtok_r(NULL, "", save); if(tok) { eval_expr(tok); write_instr(SUBCALL); //sub_call(file_des, eval_expr(tok)); return OK; } else ERROR("expected destination for CALL"); } static int ret_handler(char **save) { (void) save; write_instr(SUBRET); //sub_return(file_des); return NEXT; } static int inc_handler(char **save) { (void) save; char *tok = strtok_r(NULL, " \t", save); if(isValidVariable(tok)) incVar(tok); return OK; } static int dec_handler(char **save) { (void) save; char *tok = strtok_r(NULL, " \t", save); if(isValidVariable(tok)) decVar(tok); return OK; } static int if_handler(char **save) { (void) save; char *tok = strtok_r(NULL, ";", save); if(!tok) ERROR("expected conditional after IF"); eval_expr(tok); write_instr(PUSHIMM); write_imm(current_line + 1); write_instr(IF); return OK; } static int delay_handler(char **save) { (void) save; /* delay N 1000ths of a sec */ char *tok = strtok_r(NULL, ";", save); if(tok) { eval_expr(tok); write_instr(DELAY); } else ERROR("expected valid expression after DELAY"); return OK; } static int log_handler(char **save) { (void) save; char *tok = strtok_r(NULL, "", save); write_str(tok); return OK; } static int logvar_handler(char **save) { (void) save; char *tok = strtok_r(NULL, ";", save); if(tok) { eval_expr(tok); write_instr(LOGVAR); return OK; } else ERROR("expected expression after LOGVAR"); } static int rem_handler(char **save) { (void) save; return BREAK; } static int quit_handler(char **save) { (void) save; write_instr(QUIT); return OK; } static int newline_handler(char **save) { (void) save; write_instr(NEWLINE); return OK; } static int logchar_handler(char **save) { char *tok = strtok_r(NULL, ";", save); if(tok) { eval_expr(tok); write_instr(LOGASCII); } else ERROR("expected expression after LOGCHAR"); return OK; } static int input_handler(char **save) { (void) save; char *varname = strtok_r(NULL, "= \t", save); if(varname && isValidVariable(varname)) { int varid = get_varid(varname); write_instr(READ_VAR); write_varid(varid); } else { ERROR("invalid variable name for INPUT"); } return OK; } static int prompt_handler(char **save) { (void) save; char *varname = strtok_r(NULL, "= \t", save); if(varname && isValidVariable(varname)) { int varid = get_varid(varname); write_str(varname); write_str("? "); write_instr(READ_VAR); write_varid(varid); } else { ERROR("invalid variable name for PROMPT"); } return OK; } #ifdef DUCKY_ROCKBOX #define KEY_HANDLER(KEY, NAME) \ static int NAME ## _handler(char **save) \ { \ write_instr(PUSHIMM); \ write_imm(KEY); \ write_instr(SENDKEY); \ return OK; \ } KEY_HANDLER(HID_KEYBOARD_RETURN, enter); KEY_HANDLER(HID_KEYBOARD_DELETE, del); KEY_HANDLER(HID_KEYBOARD_TAB, tab); KEY_HANDLER(HID_KEYBOARD_ESCAPE, esc); KEY_HANDLER(HID_KEYBOARD_LEFT_GUI, gui); KEY_HANDLER(HID_KEYBOARD_RIGHT_GUI, rgui); KEY_HANDLER(HID_KEYBOARD_LEFT_CONTROL, ctrl); KEY_HANDLER(HID_KEYBOARD_RIGHT_CONTROL, rctrl); KEY_HANDLER(HID_KEYBOARD_LEFT_ALT, alt); KEY_HANDLER(HID_KEYBOARD_RIGHT_ALT, ralt); KEY_HANDLER(HID_KEYBOARD_LEFT_SHIFT, shift) KEY_HANDLER(HID_KEYBOARD_RIGHT_SHIFT, rshift); KEY_HANDLER(HID_KEYBOARD_MENU, menu); KEY_HANDLER(HID_KEYBOARD_PAUSE, pause); KEY_HANDLER(HID_KEYBOARD_PRINT_SCREEN, psn); KEY_HANDLER(HID_KEYPAD_NUM_LOCK_AND_CLEAR, numlck); KEY_HANDLER(HID_KEYBOARD_CAPS_LOCK, cpslck); KEY_HANDLER(HID_KEYBOARD_SCROLL_LOCK, scrllck); KEY_HANDLER(HID_KEYBOARD_SPACEBAR, space); KEY_HANDLER(HID_KEYBOARD_BACKSPACE, bksp); KEY_HANDLER(HID_KEYBOARD_UP_ARROW, up); KEY_HANDLER(HID_KEYBOARD_DOWN_ARROW, down); KEY_HANDLER(HID_KEYBOARD_LEFT_ARROW, left); KEY_HANDLER(HID_KEYBOARD_RIGHT_ARROW, right); KEY_HANDLER(HID_KEYBOARD_PAGE_UP, pgup); KEY_HANDLER(HID_KEYBOARD_PAGE_DOWN, pgdn); KEY_HANDLER(HID_KEYBOARD_INSERT, ins); KEY_HANDLER(HID_KEYBOARD_HOME, home); KEY_HANDLER(HID_KEYBOARD_F1, f1); KEY_HANDLER(HID_KEYBOARD_F2, f2); KEY_HANDLER(HID_KEYBOARD_F3, f3); KEY_HANDLER(HID_KEYBOARD_F4, f4); KEY_HANDLER(HID_KEYBOARD_F5, f5); KEY_HANDLER(HID_KEYBOARD_F6, f6); KEY_HANDLER(HID_KEYBOARD_F7, f7); KEY_HANDLER(HID_KEYBOARD_F8, f8); KEY_HANDLER(HID_KEYBOARD_F9, f9); KEY_HANDLER(HID_KEYBOARD_F10, f10); KEY_HANDLER(HID_KEYBOARD_F11, f11); KEY_HANDLER(HID_KEYBOARD_F12, f12); static int dfldel_handler(char **save) { char *tok = strtok_r(NULL, ";", save); if(tok) { eval_expr(tok); write_instr(DFL_DELAY); } else ERROR("expected expression for DEFAULT_DELAY"); return OK; } static int strdel_handler(char **save) { char *tok = strtok_r(NULL, ";", save); if(tok) { eval_expr(tok); write_instr(STR_DELAY); } else ERROR("expected expression for STRING_DELAY"); return OK; } static int out_handler(char **save) { char *tok = strtok_r(NULL, ";", save); if(tok) { eval_expr(tok); /* types the expression in decimal */ write_instr(TYPE_DEC); } else ERROR("expected expression for default delay"); return OK; } static int string_handler(char **save) { char *str = strtok_r(NULL, "", save); write_instr(TYPE_STR); while(*str) { write_byte(*str++); } write_byte('\0'); return OK; } #endif static struct token_t { const char *tok; int (*func)(char **save); } tokens[] = { #ifdef DUCKY_ROCKBOX { "//", rem_handler }, { "ALT", alt_handler }, { "APP", menu_handler }, { "BACKSPACE", bksp_handler }, { "BKSP", bksp_handler }, { "BREAK", pause_handler }, { "CALL", call_handler }, { "CAPS", cpslck_handler }, { "CAPSLOCK", cpslck_handler }, { "CAPS_LOCK", cpslck_handler }, { "CONTROL", ctrl_handler }, { "CTRL", ctrl_handler }, { "DEC", dec_handler }, { "DEFAULT_DELAY", dfldel_handler }, { "DEL", del_handler }, { "DELAY", delay_handler }, { "DELETE", del_handler }, { "DOWN", down_handler }, { "DOWNARROW", down_handler }, { "ENTER", enter_handler }, { "ESC", esc_handler }, { "ESCAPE", esc_handler }, { "EXIT", quit_handler }, { "F1", f1_handler }, { "F10", f10_handler }, { "F11", f11_handler }, { "F12", f12_handler }, { "F2", f2_handler }, { "F3", f3_handler }, { "F4", f4_handler }, { "F5", f5_handler }, { "F6", f6_handler }, { "F7", f7_handler }, { "F8", f8_handler }, { "F9", f9_handler }, { "GOSUB", call_handler }, { "GOTO", goto_handler }, { "GUI", gui_handler }, { "HOME", home_handler }, { "IF", if_handler }, { "INC", inc_handler }, { "INS", ins_handler }, { "INSERT", ins_handler }, { "JUMP", goto_handler }, { "LABEL", rem_handler }, { "LBL", rem_handler }, { "LEFT", left_handler }, { "LEFTARROW", left_handler }, { "LET", let_handler }, { "LOG", log_handler }, { "LOGCHAR", logchar_handler }, { "LOGVAR", logvar_handler }, { "MENU", menu_handler }, { "META", alt_handler }, { "NEWLINE", newline_handler }, { "NUMLOCK", numlck_handler }, { "NUM_LOCK", numlck_handler }, { "OUT", out_handler }, { "PAGEDOWN", pgdn_handler }, { "PAGEUP", pgup_handler }, { "PAUSE", pause_handler }, { "PGDOWN", pgdn_handler }, { "PGUP", pgup_handler }, { "PRINTSCREEN", psn_handler }, { "PRINT_SCREEN", psn_handler }, { "QUIT", quit_handler }, { "RALT", ralt_handler }, { "RCONTROL", rctrl_handler }, { "RCTRL", rctrl_handler }, { "REM", rem_handler }, { "REMTA", ralt_handler }, { "REPEAT", repeat_handler }, { "RET", ret_handler }, { "RETURN", ret_handler }, { "RGUI", rgui_handler }, { "RIGHT", right_handler }, { "RIGHTARROW", right_handler }, { "RSHIFT", rshift_handler }, { "SCROLL", scrllck_handler }, { "SCROLLLOCK", scrllck_handler }, { "SCROLL_LOCK", scrllck_handler }, { "SHIFT", shift_handler }, { "SPACE", space_handler }, { "SPACEBAR", space_handler }, { "STRING", string_handler }, { "STRING_DELAY", strdel_handler }, { "SYSRQ", psn_handler }, { "TAB", tab_handler }, { "UP", up_handler }, { "UPARROW", up_handler }, { "WIN", gui_handler }, { "WINDOWS", gui_handler }, { "INPUT", input_handler }, { "PROMPT", prompt_handler }, #else { "LET", let_handler, }, { "REPEAT", repeat_handler, }, { "JUMP", goto_handler, }, { "GOTO", goto_handler, }, { "CALL", call_handler, }, { "GOSUB", call_handler, }, { "RET", ret_handler, }, { "RETURN", ret_handler, }, { "INC", inc_handler, }, { "DEC", dec_handler, }, { "IF", if_handler, }, { "DELAY", delay_handler, }, { "LOG", log_handler, }, { "LOGVAR", logvar_handler, }, { "LOGCHAR", logchar_handler }, { "NEWLINE", newline_handler, }, { "REM", rem_handler, }, { "//", rem_handler, }, { "LABEL", rem_handler, }, { "LBL", rem_handler, }, { "QUIT", quit_handler, }, { "EXIT", quit_handler, }, { "INPUT", input_handler, }, { "PROMPT", prompt_handler, }, #endif }; /* once again, this lookup table is implemented with a perfect hash map */ #define TOKMAP_SIZE ARRAYLEN(tokens) static struct token_t tokmap[TOKMAP_SIZE]; #ifdef DUCKY_ROCKBOX /* generated with mph 1.2 */ /* * d=3 * n=116 * m=94 * c=1.23 * maxlen=13 * minklen=2 * maxklen=13 * minchar=47 * maxchar=95 * loop=0 * numiter=20 * seed= */ static int g[] = { 0, 63, 85, 0, 25, 0, 45, 91, 38, 21, 68, -1, 73, 17, 52, 45, 5, 28, 68, 71, -1, 83, 63, 3, 18, 93, 56, 48, 28, 32, 13, 0, 61, -1, 0, 19, 70, 43, 20, 29, 64, 73, -1, 71, 67, 0, 4, 74, 35, 77, 83, -1, 45, 52, -1, 46, 30, 23, 24, 78, 88, 27, 71, 13, 91, 71, 34, 76, 35, 14, 0, 30, 71, 48, 63, 47, 92, 8, 72, 0, 2, 0, 0, 53, 7, 69, -1, 78, 78, 0, 55, 93, 79, 77, 24, 0, 93, 83, -1, 47, 39, -1, 60, 89, 41, 54, 1, 77, 0, 68, 32, 22, 5, 0, 5, 54, }; static int T0[] = { 0x20, 0x1d, 0x53, 0x44, 0x6f, 0x13, 0x22, 0x3b, 0x1f, 0x0a, 0x1e, 0x3c, 0x71, 0x27, 0x5c, 0x34, 0x3f, 0x5a, 0x23, 0x0d, 0x54, 0x09, 0x19, 0x46, 0x21, 0x12, 0x09, 0x55, 0x37, 0x24, 0x67, 0x57, 0x42, 0x47, 0x27, 0x35, 0x5a, 0x41, 0x70, 0x71, 0x4b, 0x1b, 0x39, 0x48, 0x3a, 0x19, 0x08, 0x71, 0x73, 0x6d, 0x3c, 0x21, 0x18, 0x0c, 0x71, 0x49, 0x27, 0x50, 0x06, 0x2e, 0x51, 0x51, 0x57, 0x03, 0x37, 0x70, 0x57, 0x64, 0x71, 0x4f, 0x34, 0x4d, 0x6f, 0x17, 0x20, 0x3a, 0x0d, 0x3d, 0x2b, 0x13, 0x2f, 0x67, 0x34, 0x47, 0x6b, 0x2a, 0x14, 0x16, 0x06, 0x1a, 0x44, 0x57, 0x64, 0x28, 0x52, 0x1f, 0x1c, 0x36, 0x32, 0x3f, 0x5b, 0x24, 0x03, 0x20, 0x4e, 0x0e, 0x33, 0x0f, 0x57, 0x5b, 0x6d, 0x4d, 0x30, 0x6c, 0x39, 0x5d, 0x31, 0x68, 0x68, 0x47, 0x47, 0x51, 0x69, 0x59, 0x2f, 0x5f, 0x1b, 0x1f, 0x1a, 0x4e, 0x56, 0x6d, 0x72, 0x51, 0x11, 0x44, 0x60, 0x45, 0x53, 0x3b, 0x2c, 0x45, 0x14, 0x54, 0x35, 0x46, 0x3e, 0x2c, 0x0a, 0x16, 0x5b, 0x56, 0x28, 0x04, 0x29, 0x48, 0x63, 0x6b, 0x31, 0x3a, 0x19, 0x43, 0x63, 0x08, 0x42, 0x68, 0x71, 0x17, 0x57, 0x4d, 0x27, 0x2a, 0x11, 0x65, 0x21, 0x31, 0x15, 0x10, 0x5e, 0x18, 0x27, 0x3d, 0x6e, 0x4f, 0x41, 0x1b, 0x1b, 0x29, 0x0a, 0x44, 0x5b, 0x23, 0x13, 0x4b, 0x23, 0x4e, 0x63, 0x14, 0x4a, 0x2e, 0x42, 0x6c, 0x01, 0x3a, 0x3d, 0x59, 0x5f, 0x6c, 0x09, 0x3d, 0x24, 0x4d, 0x37, 0x45, 0x4f, 0x2d, 0x5e, 0x3e, 0x27, 0x13, 0x48, 0x65, 0x2c, 0x64, 0x20, 0x22, 0x07, 0x0f, 0x2e, 0x49, 0x36, 0x70, 0x39, 0x37, 0x2e, 0x03, 0x14, 0x1a, 0x6f, 0x1d, 0x4f, 0x1f, 0x63, 0x13, 0x5d, 0x1e, 0x3b, 0x4c, 0x32, 0x2d, 0x69, 0x13, 0x25, 0x54, 0x60, 0x40, 0x5e, 0x65, 0x4a, 0x5f, 0x26, 0x32, 0x53, 0x0f, 0x24, 0x49, 0x3e, 0x61, 0x35, 0x1e, 0x2d, 0x32, 0x1a, 0x5d, 0x2b, 0x64, 0x07, 0x5e, 0x3c, 0x31, 0x0f, 0x31, 0x45, 0x2c, 0x0a, 0x31, 0x65, 0x60, 0x22, 0x33, 0x44, 0x40, 0x66, 0x23, 0x5a, 0x16, 0x60, 0x0d, 0x06, 0x1e, 0x36, 0x59, 0x56, 0x40, 0x60, 0x66, 0x6c, 0x40, 0x15, 0x0e, 0x55, 0x49, 0x4c, 0x42, 0x64, 0x6a, 0x55, 0x1d, 0x32, 0x19, 0x4f, 0x54, 0x6d, 0x4f, 0x0e, 0x54, 0x65, 0x66, 0x59, 0x63, 0x08, 0x1b, 0x48, 0x5e, 0x53, 0x35, 0x48, 0x4c, 0x01, 0x5d, 0x52, 0x4e, 0x2a, 0x42, 0x31, 0x71, 0x72, 0x25, 0x18, 0x21, 0x44, 0x49, 0x1e, 0x0a, 0x3d, 0x44, 0x1b, 0x35, 0x5c, 0x2a, 0x0c, 0x66, 0x35, 0x3d, 0x01, 0x02, 0x03, 0x13, 0x14, 0x6c, 0x46, 0x44, 0x4b, 0x5b, 0x12, 0x08, 0x59, 0x08, 0x2d, 0x69, 0x29, 0x69, 0x37, 0x3f, 0x00, 0x00, 0x0f, 0x13, 0x35, 0x64, 0x36, 0x39, 0x24, 0x5b, 0x73, 0x20, 0x0c, 0x20, 0x04, 0x3b, 0x3e, 0x3e, 0x1c, 0x2d, 0x23, 0x1a, 0x19, 0x52, 0x6b, 0x65, 0x4d, 0x18, 0x01, 0x09, 0x17, 0x59, 0x65, 0x39, 0x07, 0x6b, 0x4a, 0x65, 0x31, 0x6f, 0x44, 0x31, 0x13, 0x48, 0x51, 0x0f, 0x0f, 0x14, 0x4d, 0x2b, 0x39, 0x68, 0x3d, 0x52, 0x46, 0x2d, 0x3b, 0x32, 0x6b, 0x23, 0x0d, 0x32, 0x62, 0x2a, 0x24, 0x52, 0x5d, 0x21, 0x6d, 0x18, 0x3b, 0x12, 0x3c, 0x1a, 0x2f, 0x24, 0x01, 0x0b, 0x71, 0x17, 0x51, 0x70, 0x59, 0x21, 0x21, 0x47, 0x23, 0x4a, 0x71, 0x13, 0x65, 0x02, 0x45, 0x53, 0x2c, 0x69, 0x29, 0x15, 0x0e, 0x23, 0x25, 0x49, 0x2d, 0x5a, 0x63, 0x5d, 0x5c, 0x58, 0x6e, 0x58, 0x06, 0x31, 0x3c, 0x1c, 0x06, 0x4e, 0x4a, 0x26, 0x32, 0x3d, 0x5f, 0x2f, 0x44, 0x18, 0x5b, 0x25, 0x3e, 0x12, 0x2d, 0x22, 0x4f, 0x44, 0x15, 0x43, 0x39, 0x72, 0x54, 0x19, 0x56, 0x46, 0x69, 0x54, 0x03, 0x2a, 0x70, 0x09, 0x04, 0x3f, 0x2f, 0x2e, 0x08, 0x13, 0x55, 0x44, 0x23, 0x07, 0x44, 0x5c, 0x13, 0x1e, 0x6e, 0x48, 0x08, 0x6c, 0x58, 0x58, 0x19, 0x0d, 0x73, 0x47, 0x17, 0x30, 0x4e, 0x31, 0x12, 0x10, 0x28, 0x30, 0x24, 0x0b, 0x25, 0x4a, 0x0a, 0x18, 0x5d, 0x2c, 0x1f, 0x25, 0x0c, 0x33, 0x43, 0x06, 0x73, 0x4b, 0x73, 0x50, 0x28, 0x10, 0x5d, 0x27, 0x50, 0x00, 0x50, 0x22, 0x1e, 0x2b, 0x4f, 0x1f, 0x0f, 0x1c, 0x65, 0x5d, 0x2e, 0x36, 0x22, 0x20, 0x32, 0x53, 0x63, 0x4c, 0x38, 0x3d, 0x5e, 0x48, 0x3c, 0x49, 0x5e, 0x0f, 0x19, 0x48, 0x64, 0x5d, 0x62, 0x4f, 0x51, 0x04, 0x73, 0x2c, 0x1b, 0x0e, 0x40, 0x0c, 0x63, 0x66, 0x43, 0x11, 0x12, 0x6d, 0x5d, 0x01, 0x3d, 0x19, 0x36, }; static int T1[] = { 0x3c, 0x14, 0x6e, 0x56, 0x1e, 0x3b, 0x13, 0x66, 0x13, 0x69, 0x5f, 0x73, 0x42, 0x1b, 0x55, 0x3d, 0x68, 0x42, 0x0d, 0x63, 0x04, 0x60, 0x64, 0x3c, 0x17, 0x29, 0x4c, 0x02, 0x13, 0x0c, 0x4a, 0x4f, 0x20, 0x44, 0x2a, 0x37, 0x0b, 0x35, 0x21, 0x17, 0x2a, 0x0c, 0x16, 0x64, 0x20, 0x63, 0x2e, 0x0c, 0x2a, 0x22, 0x39, 0x37, 0x47, 0x21, 0x23, 0x0c, 0x4d, 0x32, 0x6d, 0x64, 0x3f, 0x49, 0x27, 0x63, 0x51, 0x27, 0x0d, 0x1f, 0x24, 0x67, 0x66, 0x03, 0x6f, 0x24, 0x35, 0x2a, 0x3f, 0x60, 0x06, 0x59, 0x06, 0x37, 0x1d, 0x4e, 0x50, 0x38, 0x52, 0x2a, 0x6a, 0x44, 0x12, 0x35, 0x11, 0x39, 0x1c, 0x5a, 0x58, 0x29, 0x22, 0x21, 0x64, 0x30, 0x5c, 0x62, 0x0a, 0x26, 0x45, 0x6c, 0x14, 0x44, 0x02, 0x71, 0x25, 0x45, 0x72, 0x3a, 0x27, 0x46, 0x5e, 0x0c, 0x67, 0x1f, 0x38, 0x5c, 0x60, 0x05, 0x3b, 0x45, 0x3f, 0x55, 0x5f, 0x27, 0x12, 0x47, 0x15, 0x14, 0x65, 0x5a, 0x0c, 0x72, 0x23, 0x0f, 0x6f, 0x48, 0x4c, 0x6d, 0x07, 0x6c, 0x6b, 0x3e, 0x02, 0x6c, 0x26, 0x1c, 0x32, 0x10, 0x21, 0x5f, 0x50, 0x1a, 0x29, 0x2c, 0x55, 0x70, 0x17, 0x62, 0x0f, 0x65, 0x1d, 0x18, 0x0c, 0x33, 0x27, 0x1e, 0x33, 0x48, 0x02, 0x65, 0x38, 0x66, 0x27, 0x33, 0x56, 0x4e, 0x4f, 0x14, 0x5e, 0x70, 0x6b, 0x33, 0x0f, 0x19, 0x5f, 0x64, 0x15, 0x6e, 0x15, 0x50, 0x44, 0x5f, 0x0f, 0x1b, 0x36, 0x49, 0x5c, 0x45, 0x00, 0x04, 0x15, 0x31, 0x3b, 0x4e, 0x2e, 0x3f, 0x50, 0x2e, 0x02, 0x65, 0x1e, 0x4b, 0x65, 0x0c, 0x0a, 0x1d, 0x43, 0x32, 0x23, 0x50, 0x06, 0x67, 0x3b, 0x15, 0x06, 0x71, 0x5e, 0x5a, 0x3a, 0x5f, 0x5f, 0x50, 0x14, 0x26, 0x2a, 0x42, 0x5d, 0x65, 0x37, 0x10, 0x0a, 0x10, 0x6b, 0x02, 0x0e, 0x56, 0x00, 0x6c, 0x08, 0x17, 0x23, 0x10, 0x4d, 0x13, 0x40, 0x26, 0x56, 0x2d, 0x08, 0x5f, 0x48, 0x0e, 0x1c, 0x63, 0x18, 0x5a, 0x51, 0x12, 0x43, 0x14, 0x1a, 0x4e, 0x1d, 0x09, 0x48, 0x23, 0x5f, 0x40, 0x1b, 0x67, 0x58, 0x36, 0x03, 0x31, 0x49, 0x43, 0x68, 0x40, 0x1e, 0x00, 0x11, 0x54, 0x22, 0x6f, 0x52, 0x01, 0x2b, 0x31, 0x15, 0x59, 0x3f, 0x5e, 0x24, 0x70, 0x51, 0x2d, 0x01, 0x0a, 0x25, 0x22, 0x65, 0x1f, 0x12, 0x06, 0x4b, 0x30, 0x62, 0x37, 0x68, 0x0c, 0x2f, 0x71, 0x58, 0x51, 0x6d, 0x36, 0x4b, 0x24, 0x68, 0x60, 0x02, 0x2b, 0x43, 0x26, 0x1f, 0x58, 0x15, 0x2d, 0x2f, 0x35, 0x0c, 0x29, 0x22, 0x24, 0x0a, 0x1d, 0x1c, 0x61, 0x68, 0x5d, 0x17, 0x1c, 0x1b, 0x4f, 0x71, 0x50, 0x3e, 0x48, 0x0a, 0x1f, 0x54, 0x4f, 0x09, 0x2d, 0x31, 0x16, 0x11, 0x46, 0x43, 0x38, 0x00, 0x47, 0x61, 0x22, 0x64, 0x6b, 0x37, 0x0c, 0x59, 0x2c, 0x62, 0x68, 0x40, 0x09, 0x2b, 0x28, 0x1b, 0x67, 0x5e, 0x0b, 0x68, 0x00, 0x0c, 0x2d, 0x19, 0x09, 0x15, 0x2f, 0x3e, 0x12, 0x67, 0x57, 0x63, 0x14, 0x2f, 0x02, 0x72, 0x44, 0x03, 0x6a, 0x0b, 0x21, 0x50, 0x62, 0x3b, 0x73, 0x0e, 0x57, 0x5e, 0x6d, 0x62, 0x52, 0x6d, 0x66, 0x0b, 0x12, 0x6f, 0x18, 0x39, 0x31, 0x22, 0x25, 0x14, 0x18, 0x0e, 0x0f, 0x49, 0x2d, 0x2f, 0x55, 0x3b, 0x5b, 0x1c, 0x5c, 0x3f, 0x2d, 0x41, 0x37, 0x66, 0x4a, 0x1c, 0x25, 0x57, 0x2b, 0x4e, 0x44, 0x05, 0x65, 0x69, 0x21, 0x10, 0x3d, 0x49, 0x38, 0x56, 0x57, 0x3f, 0x2b, 0x10, 0x6e, 0x04, 0x43, 0x55, 0x19, 0x2c, 0x18, 0x46, 0x65, 0x4f, 0x31, 0x33, 0x6b, 0x26, 0x3f, 0x16, 0x6c, 0x34, 0x6e, 0x30, 0x3a, 0x3f, 0x71, 0x23, 0x2d, 0x41, 0x6e, 0x10, 0x70, 0x58, 0x02, 0x3e, 0x5b, 0x29, 0x0e, 0x23, 0x5a, 0x2b, 0x46, 0x1c, 0x5b, 0x1f, 0x69, 0x00, 0x45, 0x2d, 0x16, 0x3d, 0x61, 0x10, 0x66, 0x1f, 0x47, 0x63, 0x42, 0x6c, 0x28, 0x35, 0x09, 0x1c, 0x11, 0x03, 0x73, 0x5c, 0x6c, 0x20, 0x5c, 0x51, 0x68, 0x33, 0x61, 0x07, 0x1b, 0x42, 0x62, 0x17, 0x2d, 0x27, 0x4e, 0x23, 0x06, 0x5e, 0x25, 0x32, 0x5b, 0x62, 0x06, 0x5e, 0x12, 0x1f, 0x60, 0x69, 0x27, 0x5f, 0x51, 0x20, 0x04, 0x31, 0x71, 0x6c, 0x5d, 0x57, 0x6b, 0x70, 0x1d, 0x5a, 0x13, 0x4b, 0x0d, 0x59, 0x66, 0x3a, 0x34, 0x19, 0x60, 0x02, 0x63, 0x1f, 0x69, 0x52, 0x28, 0x4b, 0x67, 0x0b, 0x14, 0x1c, 0x3d, 0x5f, 0x1b, 0x36, 0x6e, 0x4e, 0x07, 0x16, 0x1a, 0x65, 0x2e, 0x5f, 0x23, 0x6b, 0x41, 0x56, 0x29, 0x01, 0x6f, 0x0e, 0x70, 0x5e, 0x2d, 0x5d, 0x34, 0x55, 0x35, 0x1f, 0x58, 0x41, 0x3b, 0x21, 0x2c, 0x4f, }; static int T2[] = { 0x54, 0x73, 0x23, 0x34, 0x4a, 0x67, 0x3e, 0x1c, 0x4a, 0x2f, 0x50, 0x70, 0x6e, 0x18, 0x30, 0x2e, 0x4c, 0x6f, 0x3c, 0x68, 0x73, 0x6d, 0x0f, 0x6b, 0x0d, 0x16, 0x66, 0x5c, 0x6d, 0x4b, 0x21, 0x4d, 0x43, 0x3c, 0x0e, 0x19, 0x30, 0x44, 0x35, 0x72, 0x6b, 0x09, 0x6f, 0x65, 0x22, 0x23, 0x18, 0x66, 0x16, 0x61, 0x46, 0x13, 0x3e, 0x3d, 0x54, 0x05, 0x1b, 0x5b, 0x00, 0x29, 0x5d, 0x6d, 0x57, 0x02, 0x2d, 0x24, 0x3f, 0x2a, 0x03, 0x28, 0x4e, 0x48, 0x65, 0x01, 0x55, 0x69, 0x2d, 0x47, 0x01, 0x02, 0x34, 0x40, 0x0e, 0x6a, 0x01, 0x62, 0x68, 0x1c, 0x42, 0x68, 0x46, 0x23, 0x62, 0x21, 0x26, 0x13, 0x45, 0x5d, 0x56, 0x00, 0x3c, 0x1b, 0x38, 0x42, 0x5a, 0x52, 0x6c, 0x68, 0x1c, 0x44, 0x26, 0x20, 0x59, 0x5a, 0x13, 0x5e, 0x3a, 0x64, 0x03, 0x5b, 0x62, 0x6e, 0x12, 0x06, 0x18, 0x64, 0x41, 0x0e, 0x23, 0x1c, 0x0e, 0x57, 0x2f, 0x3e, 0x26, 0x16, 0x14, 0x16, 0x02, 0x30, 0x52, 0x29, 0x50, 0x37, 0x07, 0x5c, 0x1a, 0x4c, 0x5b, 0x71, 0x19, 0x1c, 0x03, 0x30, 0x69, 0x56, 0x3e, 0x40, 0x55, 0x12, 0x15, 0x5a, 0x56, 0x2a, 0x28, 0x11, 0x5e, 0x67, 0x68, 0x15, 0x05, 0x6b, 0x62, 0x24, 0x3b, 0x55, 0x6c, 0x3a, 0x25, 0x4b, 0x38, 0x3e, 0x68, 0x33, 0x6e, 0x55, 0x15, 0x31, 0x19, 0x62, 0x43, 0x2e, 0x48, 0x1d, 0x58, 0x68, 0x1d, 0x25, 0x6a, 0x64, 0x0a, 0x14, 0x27, 0x17, 0x53, 0x22, 0x01, 0x0c, 0x0b, 0x56, 0x3e, 0x61, 0x55, 0x24, 0x23, 0x5b, 0x32, 0x69, 0x5e, 0x0c, 0x01, 0x34, 0x71, 0x0f, 0x41, 0x3f, 0x0d, 0x5e, 0x5c, 0x03, 0x46, 0x5e, 0x10, 0x6d, 0x01, 0x5b, 0x13, 0x6e, 0x67, 0x1f, 0x50, 0x2a, 0x04, 0x31, 0x4e, 0x00, 0x0c, 0x45, 0x24, 0x4b, 0x25, 0x57, 0x6c, 0x04, 0x31, 0x42, 0x1e, 0x21, 0x5f, 0x5b, 0x46, 0x44, 0x12, 0x41, 0x2c, 0x67, 0x52, 0x09, 0x30, 0x04, 0x3c, 0x64, 0x04, 0x4c, 0x1f, 0x6f, 0x44, 0x2b, 0x40, 0x61, 0x6e, 0x5e, 0x44, 0x67, 0x62, 0x6e, 0x35, 0x0c, 0x1b, 0x19, 0x60, 0x62, 0x55, 0x6a, 0x0d, 0x24, 0x67, 0x16, 0x62, 0x02, 0x45, 0x58, 0x54, 0x4a, 0x27, 0x13, 0x2d, 0x53, 0x3a, 0x68, 0x12, 0x57, 0x26, 0x2b, 0x4e, 0x04, 0x37, 0x4b, 0x30, 0x29, 0x31, 0x20, 0x0c, 0x3c, 0x32, 0x11, 0x60, 0x1d, 0x27, 0x46, 0x18, 0x6c, 0x2b, 0x64, 0x3a, 0x4a, 0x03, 0x67, 0x29, 0x3d, 0x53, 0x33, 0x20, 0x42, 0x55, 0x2e, 0x67, 0x72, 0x29, 0x1c, 0x5f, 0x3d, 0x1e, 0x32, 0x2b, 0x50, 0x2a, 0x4a, 0x47, 0x57, 0x13, 0x6c, 0x37, 0x52, 0x61, 0x3c, 0x0c, 0x0c, 0x63, 0x0a, 0x46, 0x0c, 0x25, 0x20, 0x4f, 0x06, 0x46, 0x3a, 0x70, 0x67, 0x56, 0x5c, 0x31, 0x00, 0x12, 0x5c, 0x50, 0x3d, 0x2a, 0x23, 0x18, 0x3d, 0x08, 0x46, 0x27, 0x5f, 0x2f, 0x45, 0x52, 0x05, 0x62, 0x31, 0x45, 0x34, 0x37, 0x0f, 0x63, 0x50, 0x70, 0x4f, 0x4e, 0x54, 0x30, 0x20, 0x09, 0x22, 0x06, 0x09, 0x01, 0x33, 0x4d, 0x00, 0x0b, 0x4d, 0x3e, 0x32, 0x31, 0x6d, 0x70, 0x07, 0x6b, 0x56, 0x38, 0x34, 0x0f, 0x67, 0x43, 0x6a, 0x43, 0x40, 0x3d, 0x48, 0x25, 0x23, 0x2b, 0x25, 0x1b, 0x27, 0x34, 0x44, 0x1f, 0x4a, 0x21, 0x4f, 0x01, 0x38, 0x5c, 0x35, 0x57, 0x5d, 0x4f, 0x4b, 0x67, 0x67, 0x49, 0x5e, 0x5d, 0x56, 0x65, 0x5a, 0x5d, 0x35, 0x2e, 0x06, 0x58, 0x51, 0x23, 0x73, 0x04, 0x57, 0x3b, 0x1c, 0x26, 0x54, 0x6b, 0x1f, 0x19, 0x53, 0x54, 0x70, 0x63, 0x28, 0x3d, 0x3b, 0x11, 0x60, 0x73, 0x70, 0x20, 0x3b, 0x16, 0x68, 0x5e, 0x12, 0x21, 0x00, 0x05, 0x36, 0x1b, 0x11, 0x33, 0x66, 0x44, 0x14, 0x00, 0x6c, 0x6c, 0x69, 0x44, 0x67, 0x24, 0x2b, 0x13, 0x59, 0x5e, 0x1c, 0x46, 0x5e, 0x18, 0x5e, 0x25, 0x26, 0x52, 0x07, 0x30, 0x6b, 0x00, 0x35, 0x26, 0x30, 0x5f, 0x07, 0x2e, 0x58, 0x70, 0x14, 0x5b, 0x07, 0x32, 0x4b, 0x07, 0x38, 0x47, 0x09, 0x53, 0x57, 0x54, 0x6a, 0x43, 0x5e, 0x08, 0x61, 0x6b, 0x2b, 0x50, 0x3e, 0x4c, 0x0d, 0x15, 0x61, 0x35, 0x01, 0x68, 0x64, 0x51, 0x5d, 0x04, 0x38, 0x5c, 0x2e, 0x10, 0x5c, 0x5f, 0x4f, 0x5d, 0x3e, 0x32, 0x3d, 0x4a, 0x1f, 0x3e, 0x43, 0x59, 0x53, 0x08, 0x27, 0x5b, 0x62, 0x3a, 0x5a, 0x4b, 0x26, 0x2d, 0x27, 0x1b, 0x67, 0x18, 0x41, 0x49, 0x1f, 0x0d, 0x47, 0x0e, 0x30, 0x4e, 0x65, 0x1e, 0x02, 0x4b, 0x60, 0x19, 0x15, 0x28, 0x6a, 0x61, 0x30, 0x1d, 0x48, 0x16, 0x4f, 0x2e, 0x61, 0x01, 0x53, 0x0c, 0x14, 0x47, }; #define uchar unsigned char static int tok_hash(const uchar *key) { int i; unsigned f0, f1, f2; const uchar *kp = key; for (i=-47, f0=f1=f2=0; *kp; ++kp) { if (*kp < 47 || *kp > 95) return -1; if (kp-key > 12) return -1; f0 += T0[i + *kp]; f1 += T1[i + *kp]; f2 += T2[i + *kp]; i += 49; } if (kp-key < 2) return -1; f0 %= 116; f1 %= 116; f2 %= 116; return (g[f0] + g[f1] + g[f2]) % 94; } #else /* auto-generated with mph-1.2 */ /* * d=3 * n=30 * m=24 * c=1.23 * maxlen=7 * minklen=2 * maxklen=7 * minchar=47 * maxchar=89 * loop=0 * numiter=6 * seed= */ static int g[] = { 16, 8, 8, 5, 13, 18, 0, -1, 21, 12, 0, 4, 13, 23, 7, 0, 4, 8, 19, 23, 20, 20, 0, 9, 19, 0, 16, 15, 0, 1, }; static int T0[] = { 0x11, 0x0a, 0x1c, 0x11, 0x00, 0x18, 0x04, 0x14, 0x01, 0x15, 0x05, 0x1a, 0x09, 0x06, 0x0e, 0x14, 0x04, 0x0b, 0x03, 0x08, 0x1c, 0x1c, 0x1a, 0x05, 0x08, 0x00, 0x1c, 0x18, 0x07, 0x06, 0x17, 0x19, 0x08, 0x15, 0x04, 0x09, 0x10, 0x00, 0x1d, 0x09, 0x15, 0x1a, 0x1b, 0x11, 0x11, 0x16, 0x1d, 0x02, 0x00, 0x16, 0x07, 0x07, 0x1d, 0x0f, 0x17, 0x09, 0x1b, 0x05, 0x13, 0x14, 0x07, 0x1b, 0x0c, 0x14, 0x17, 0x1c, 0x0c, 0x11, 0x18, 0x0c, 0x01, 0x00, 0x13, 0x01, 0x11, 0x1c, 0x18, 0x08, 0x17, 0x18, 0x17, 0x00, 0x17, 0x16, 0x0f, 0x08, 0x18, 0x1d, 0x0e, 0x11, 0x07, 0x01, 0x0d, 0x1a, 0x05, 0x14, 0x05, 0x0b, 0x0e, 0x0b, 0x07, 0x08, 0x17, 0x0c, 0x0b, 0x18, 0x0c, 0x12, 0x19, 0x0b, 0x12, 0x0e, 0x06, 0x0a, 0x13, 0x18, 0x09, 0x05, 0x0f, 0x17, 0x17, 0x16, 0x18, 0x1c, 0x0a, 0x15, 0x0a, 0x10, 0x03, 0x11, 0x05, 0x07, 0x00, 0x0b, 0x13, 0x08, 0x11, 0x0c, 0x06, 0x03, 0x16, 0x08, 0x1c, 0x0e, 0x09, 0x14, 0x01, 0x03, 0x1b, 0x02, 0x0e, 0x09, 0x0b, 0x18, 0x00, 0x18, 0x19, 0x0a, 0x04, 0x1d, 0x1c, 0x0a, 0x06, 0x14, 0x0d, 0x1a, 0x1c, 0x16, 0x00, 0x04, 0x11, 0x16, 0x0e, 0x0d, 0x10, 0x01, 0x13, 0x07, 0x06, 0x00, 0x13, 0x0e, 0x1c, 0x10, 0x14, 0x13, 0x00, 0x19, 0x00, 0x14, 0x12, 0x19, 0x19, 0x15, 0x09, 0x16, 0x10, 0x1c, 0x12, 0x02, 0x11, 0x04, 0x04, 0x18, 0x09, 0x14, 0x19, 0x1d, 0x14, 0x17, 0x1d, 0x09, 0x07, 0x1b, 0x11, 0x00, 0x16, 0x07, 0x0f, 0x08, 0x09, 0x02, 0x07, 0x01, 0x0f, 0x15, 0x19, 0x08, 0x01, 0x14, 0x04, 0x0c, 0x1c, 0x09, 0x00, 0x1a, 0x0f, 0x0b, 0x09, 0x19, 0x1b, 0x0e, 0x0d, 0x14, 0x00, 0x07, 0x15, 0x0e, 0x07, 0x1c, 0x16, 0x08, 0x01, 0x15, 0x02, 0x08, 0x05, 0x1b, 0x0f, 0x0f, 0x13, 0x15, 0x0d, 0x04, 0x00, 0x05, 0x19, 0x08, 0x05, 0x0b, 0x0f, 0x1b, 0x10, 0x10, 0x09, 0x0c, 0x01, 0x13, 0x15, 0x03, 0x0a, 0x1c, 0x14, 0x12, 0x08, 0x19, 0x01, 0x0e, 0x1d, 0x08, 0x1d, 0x13, 0x15, 0x04, 0x0f, 0x15, 0x01, 0x02, 0x1d, 0x07, 0x0d, }; static int T1[] = { 0x05, 0x04, 0x07, 0x13, 0x0f, 0x01, 0x1b, 0x15, 0x0d, 0x15, 0x17, 0x13, 0x05, 0x05, 0x04, 0x18, 0x05, 0x05, 0x0e, 0x16, 0x13, 0x13, 0x15, 0x1a, 0x06, 0x09, 0x14, 0x19, 0x13, 0x02, 0x13, 0x18, 0x06, 0x12, 0x06, 0x0d, 0x13, 0x03, 0x05, 0x19, 0x11, 0x14, 0x0e, 0x06, 0x00, 0x16, 0x0c, 0x10, 0x07, 0x0e, 0x05, 0x1d, 0x07, 0x0b, 0x12, 0x02, 0x0b, 0x18, 0x13, 0x13, 0x17, 0x0c, 0x12, 0x19, 0x13, 0x1d, 0x0f, 0x19, 0x16, 0x1d, 0x0c, 0x17, 0x14, 0x11, 0x15, 0x14, 0x09, 0x04, 0x1c, 0x10, 0x0a, 0x1a, 0x08, 0x11, 0x07, 0x12, 0x06, 0x10, 0x0d, 0x09, 0x07, 0x08, 0x01, 0x15, 0x19, 0x10, 0x1b, 0x0d, 0x1c, 0x0d, 0x15, 0x0f, 0x11, 0x06, 0x1c, 0x03, 0x08, 0x00, 0x04, 0x0e, 0x08, 0x0e, 0x10, 0x1a, 0x1a, 0x18, 0x01, 0x02, 0x03, 0x0f, 0x03, 0x0a, 0x0f, 0x1b, 0x01, 0x0a, 0x0d, 0x15, 0x0f, 0x09, 0x0d, 0x14, 0x0f, 0x0a, 0x1d, 0x02, 0x15, 0x00, 0x0d, 0x07, 0x18, 0x08, 0x0e, 0x0f, 0x0c, 0x02, 0x00, 0x00, 0x0a, 0x1c, 0x09, 0x16, 0x18, 0x0f, 0x0c, 0x1a, 0x02, 0x12, 0x14, 0x10, 0x13, 0x19, 0x1c, 0x04, 0x05, 0x1b, 0x1c, 0x1a, 0x1b, 0x04, 0x03, 0x0d, 0x0f, 0x04, 0x1d, 0x09, 0x0a, 0x12, 0x0f, 0x19, 0x14, 0x14, 0x00, 0x17, 0x08, 0x11, 0x04, 0x0d, 0x16, 0x06, 0x05, 0x0d, 0x1c, 0x11, 0x10, 0x09, 0x1d, 0x00, 0x02, 0x0a, 0x01, 0x06, 0x00, 0x10, 0x0a, 0x00, 0x11, 0x0d, 0x0a, 0x03, 0x00, 0x00, 0x0f, 0x00, 0x0f, 0x0e, 0x04, 0x01, 0x12, 0x13, 0x11, 0x16, 0x02, 0x14, 0x0b, 0x1d, 0x00, 0x1d, 0x09, 0x03, 0x08, 0x11, 0x02, 0x08, 0x06, 0x08, 0x0e, 0x01, 0x12, 0x11, 0x08, 0x12, 0x0b, 0x16, 0x0d, 0x1b, 0x1c, 0x11, 0x1d, 0x10, 0x1d, 0x08, 0x01, 0x17, 0x15, 0x0c, 0x16, 0x15, 0x12, 0x0a, 0x17, 0x04, 0x1c, 0x1c, 0x0a, 0x0f, 0x17, 0x0d, 0x06, 0x07, 0x12, 0x0a, 0x05, 0x03, 0x04, 0x03, 0x1d, 0x0b, 0x11, 0x14, 0x13, 0x1a, 0x1b, 0x05, 0x06, 0x1a, 0x0c, 0x15, 0x07, 0x01, 0x17, 0x17, 0x1b, 0x15, 0x15, 0x08, 0x1c, 0x0e, 0x15, 0x04, 0x0d, }; static int T2[] = { 0x0f, 0x0d, 0x08, 0x09, 0x04, 0x0d, 0x05, 0x1a, 0x0d, 0x0b, 0x1b, 0x1a, 0x18, 0x09, 0x06, 0x02, 0x15, 0x1b, 0x1a, 0x02, 0x08, 0x08, 0x1c, 0x07, 0x0c, 0x16, 0x18, 0x09, 0x07, 0x07, 0x1d, 0x16, 0x14, 0x1d, 0x17, 0x11, 0x0c, 0x14, 0x0d, 0x1a, 0x17, 0x02, 0x0e, 0x19, 0x01, 0x03, 0x07, 0x00, 0x08, 0x02, 0x05, 0x0e, 0x12, 0x08, 0x1a, 0x0e, 0x1b, 0x18, 0x1a, 0x1a, 0x0b, 0x19, 0x12, 0x0c, 0x05, 0x15, 0x02, 0x0d, 0x18, 0x1b, 0x0a, 0x18, 0x0c, 0x15, 0x13, 0x05, 0x18, 0x12, 0x05, 0x19, 0x0c, 0x0a, 0x09, 0x16, 0x13, 0x1c, 0x11, 0x03, 0x0b, 0x07, 0x10, 0x09, 0x08, 0x0e, 0x0f, 0x14, 0x1a, 0x12, 0x16, 0x01, 0x07, 0x02, 0x07, 0x16, 0x11, 0x03, 0x16, 0x0e, 0x05, 0x1a, 0x08, 0x06, 0x0f, 0x03, 0x0b, 0x12, 0x1a, 0x14, 0x15, 0x07, 0x13, 0x1d, 0x08, 0x1c, 0x0d, 0x0f, 0x0a, 0x02, 0x03, 0x1d, 0x18, 0x0d, 0x07, 0x13, 0x1c, 0x0c, 0x1b, 0x0b, 0x01, 0x10, 0x0c, 0x1b, 0x18, 0x0b, 0x05, 0x15, 0x11, 0x00, 0x0f, 0x16, 0x01, 0x04, 0x14, 0x16, 0x09, 0x1a, 0x05, 0x1c, 0x1b, 0x06, 0x13, 0x0e, 0x14, 0x1a, 0x19, 0x12, 0x00, 0x16, 0x16, 0x01, 0x00, 0x1a, 0x18, 0x06, 0x00, 0x1a, 0x0e, 0x0c, 0x17, 0x01, 0x04, 0x06, 0x13, 0x1b, 0x16, 0x08, 0x0b, 0x06, 0x0f, 0x1b, 0x07, 0x0c, 0x0f, 0x05, 0x0a, 0x0d, 0x0e, 0x19, 0x0c, 0x10, 0x19, 0x1a, 0x06, 0x0b, 0x02, 0x06, 0x07, 0x09, 0x0a, 0x16, 0x0a, 0x06, 0x1d, 0x1d, 0x04, 0x00, 0x0f, 0x18, 0x0e, 0x01, 0x0e, 0x09, 0x0e, 0x1d, 0x17, 0x1d, 0x06, 0x02, 0x18, 0x18, 0x1a, 0x06, 0x17, 0x02, 0x05, 0x0e, 0x12, 0x0f, 0x05, 0x0e, 0x01, 0x13, 0x10, 0x11, 0x0a, 0x1a, 0x11, 0x19, 0x0c, 0x17, 0x13, 0x1a, 0x03, 0x03, 0x1a, 0x12, 0x03, 0x18, 0x06, 0x0b, 0x04, 0x16, 0x09, 0x02, 0x1d, 0x07, 0x02, 0x09, 0x1d, 0x03, 0x0e, 0x1a, 0x05, 0x17, 0x0d, 0x0b, 0x09, 0x0a, 0x05, 0x0a, 0x18, 0x02, 0x00, 0x17, 0x09, 0x05, 0x0c, 0x04, 0x0e, 0x0b, 0x0f, 0x12, 0x03, 0x18, 0x14, 0x19, 0x01, 0x0e, 0x04, 0x16, 0x11, }; #define uchar unsigned char static int tok_hash(const uchar *key) { int i; unsigned f0, f1, f2; const uchar *kp = key; for (i=-47, f0=f1=f2=0; *kp; ++kp) { if (*kp < 47 || *kp > 89) return -1; if (kp-key > 6) return -1; f0 += T0[i + *kp]; f1 += T1[i + *kp]; f2 += T2[i + *kp]; i += 43; } if (kp-key < 2) return -1; f0 %= 30; f1 %= 30; f2 %= 30; return (g[f0] + g[f1] + g[f2]) % 24; } #endif static void tokmap_insert(struct token_t *tok) { uint32_t hash = tok_hash(tok->tok) % TOKMAP_SIZE; if(hash < 0 || tokmap[hash].tok) ERROR("FIXME: hash map collision %s %s", tok->tok, tokmap[hash].tok); memcpy(tokmap+hash, tok, sizeof(*tok)); } static void init_tokmap(void) { memset(tokmap, 0, sizeof(tokmap)); for(unsigned int i = 0; i < ARRAYLEN(tokens); ++i) { tokmap_insert(tokens+i); } } static void init_globals(void) { line_offset = NULL; file_des = -1; current_line = 0; bytes_written = 0; } /* depends on index_lines's output, indexes labels in the file */ void index_labels(int fd) { for(unsigned i = 1; i <= num_lines; ++i) { lseek(fd, line_offset[i], SEEK_SET); char buf[MAX_LINE_LEN]; int status = read_line(fd, buf, sizeof(buf)); /* exit early if failed or too short for a label */ if(status < strlen("LBL")) break; char *save = NULL; char *tok = strtok_r(buf, " \t", &save); if(tok && (strcmp(tok, "LABEL") == 0 || strcmp("LBL", tok) == 0)) { tok = strtok_r(NULL, " \t", &save); if(tok && isValidVariable(tok)) { setVariable(tok, i); setConst(tok, true); } } } lseek(fd, 0, SEEK_SET); } int ducky_compile(int fd, bool verbose, int out) { if(!setjmp(exit_point)) { init_globals(); if(verbose) { vid_logf("COMPILER INIT"); } file_des = fd; out_fd = out; atexit(exit_handler); if(file_des < 0) ERROR("invalid file"); init_optable(); init_tokmap(); line_offset = index_lines(file_des, &num_lines, false, isValidVariable, setConst, setVariable); write_imm(DUCKY_MAGIC); write_imm(num_lines); off_t linetab_off = bytes_written; for(unsigned i = 1; i <= num_lines; ++i) { write_imm(0); } if(verbose) { vid_logf("Indexing complete (%u lines).", num_lines); vid_logf("Byte-compiling..."); } /* initialize some other constants */ makeConstantVariable(".", 0); makeConstantVariable("true", 1); makeConstantVariable("false", 0); /* initialize the special variables */ setSpecial("NULL", SPECIAL_NULL); setSpecial("RAND", SPECIAL_RAND); setSpecial("TIME", SPECIAL_TIME); /* initialize labels (using output from index_lines) */ index_labels(file_des); int repeats_left = 0; off_t code_start = bytes_written; while(1) { char instr_buf[MAX_LINE_LEN]; memset(instr_buf, 0, sizeof(instr_buf)); if(read_line(file_des, instr_buf, sizeof(instr_buf)) <= 0) { if(verbose) vid_logf("end of file"); goto done; } char *tok = NULL, *save = NULL; ++current_line; write_instr(LINEMARK); char *buf = instr_buf; line_offset[current_line] = bytes_written; /* compile all the commands on this line/instruction */ do { tok = strtok_r(buf, " -\t", &save); buf = NULL; if(!tok) break; int hash = tok_hash(tok) % TOKMAP_SIZE; struct token_t *t = tokmap+hash; if(hash >= 0 && strcmp(t->tok, tok) == 0) switch(tokmap[hash].func(&save)) { case OK: break; case BREAK: goto break_out; case DONE: goto done; case NEXT: goto next_line; default: ERROR("FIXME: invalid return value"); } #ifdef DUCKY_ROCKBOX else if(strlen(tok) == 1) { write_instr(ADD_CHAR); write_byte(tok[0]); } #endif else if(tok[0] == '#') goto next_line; else { ERROR("unknown token `%s` on line %d %d", tok, current_line); goto done; } } while(tok); break_out: ; next_line: ; } done: if(verbose) vid_logf("Finishing compile..."); /* add a final instruction to flush the key buffer */ write_instr(LINEMARK); /* go back and fill in the offset table */ lseek(out_fd, linetab_off, SEEK_SET); for(unsigned i = 1; i <= num_lines; ++i) { write_imm(line_offset[i]); } return 0; } else return 1; }