#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 MAXOPSTACK 64 #define MAXNUMSTACK 64 #define CALL_STACK_SZ 64 #define VARMAP_SIZE 256 #define VARFORMAT "%lld" #define VARNAME_MAX 24 #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 vid_write(const char *str) { write_instr(WRITE_STR); while(*str) { write_byte(*str++); } write_byte('\0'); } static void __attribute__((format(printf,1,2))) vid_logf(const char *fmt, ...) { char fmtbuf[256]; va_list ap; va_start(ap, fmt); vsnprintf(fmtbuf, sizeof(fmtbuf), fmt, ap); printf("%s\n", fmtbuf); va_end(ap); } static void __attribute__((noreturn,format(printf,1,2))) error(const char *fmt, ...) { char fmtbuf[256]; va_list ap; va_start(ap, fmt); vsnprintf(fmtbuf, sizeof(fmtbuf), fmt, ap); if(current_line) vid_logf("Line %d: ", current_line); vid_logf("ERROR: %s\n", fmtbuf); va_end(ap); exit(EXIT_FAILURE); } static void __attribute__((format(printf,1,2))) warning(const char *fmt, ...) { char fmtbuf[256]; va_list ap; va_start(ap, fmt); vsnprintf(fmtbuf, sizeof(fmtbuf), fmt, ap); vid_logf("Line %d: WARNING: %s\n", current_line, fmtbuf); va_end(ap); } /* grabs a line from a file, -1 on error, returns # bytes read otherwise */ static int read_line(int fd, char *buf, size_t sz) { unsigned i = 0; int bytes_read = 0; int status = 1; while(i < sz) { char c; status = read(fd, &c, 1); if(status != 1) break; ++bytes_read; if(c == '\r') continue; if(c == '\n' || c == EOF) { break; } buf[i++] = c; } buf[MIN(i, sz - 1)] = '\0'; return (status <= 0)?-1:bytes_read; } /* depends on index_lines, indexes labels in the file */ static 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); vid_logf("found label %s val %d", tok, i); if(tok && isValidVariable(tok)) { setVariable(tok, i); setConst(tok, true); } } } lseek(fd, 0, SEEK_SET); } /* index_lines() precalculates the offset of each line for faster jumping */ /* the line data is only used by index_labels */ static off_t *index_lines(int fd, unsigned *numlines) { size_t sz = sizeof(off_t); off_t *data = malloc(sz); /* this uses 1-indexed line numbers, so the first indice is wasted */ unsigned idx = 1; while(1) { sz += sizeof(off_t); data = realloc(data, sz); data[idx] = lseek(fd, 0, SEEK_CUR); char buf[MAX_LINE_LEN]; if(read_line(fd, buf, sizeof(buf)) < 0) break; ++idx; } lseek(fd, 0, SEEK_SET); *numlines = idx - 1; return data; } 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; } static void sub_call(int fd, unsigned where) { if(stack_frame < ARRAYLEN(call_stack)) { call_stack[stack_frame] = current_line + 1; ++stack_frame; jump_line(fd, where); } else error("call stack overflow"); } static void sub_return(int fd) { if(stack_frame > 0) { --stack_frame; jump_line(fd, call_stack[stack_frame]); } } /** 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); vid_write(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; vid_logf("REM, skipping line"); return BREAK; } static int quit_handler(char **save) { (void) save; write_instr(QUIT); return OK; } static int newline_handler(char **save) { (void) save; vid_write("\n"); 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; } #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 { "ALT", alt_handler }, { "APP", menu_handler }, { "BACKSPACE", bksp_handler }, { "BKSP", bksp_handler }, { "BREAK", pause_handler }, { "CAPS", cpslck_handler }, { "CAPSLOCK", cpslck_handler }, { "CAPS_LOCK", cpslck_handler }, { "CONTROL", ctrl_handler }, { "CTRL", ctrl_handler }, { "DEFAULT_DELAY", dfldel_handler }, { "DEL", del_handler }, { "DELETE", del_handler }, { "DOWN", down_handler }, { "DOWNARROW", down_handler }, { "ENTER", enter_handler }, { "ESC", esc_handler }, { "ESCAPE", esc_handler }, { "F1", f1_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 }, { "F10", f10_handler }, { "F11", f11_handler }, { "F12", f12_handler }, { "GUI", gui_handler }, { "HOME", home_handler }, { "INS", ins_handler }, { "INSERT", ins_handler }, { "LEFT", left_handler }, { "LEFTARROW", left_handler }, { "LOGCHAR", logchar_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 }, { "RALT", ralt_handler }, { "RCONTROL", rctrl_handler }, { "RCTRL", rctrl_handler }, { "REMTA", ralt_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 }, #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, }, #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 */ /* sacrifices memory for SPEED! */ /* * d=3 * n=87 * m=70 * c=1.23 * maxlen=13 * minklen=2 * maxklen=13 * minchar=48 * maxchar=95 * loop=0 * numiter=64 * seed= */ static int g[] = { 13, 53, 0, 0, 50, 4, 0, 40, -1, -1, 24, 27, 16, 26, 57, 1, 0, 27, 48, -1, 36, 32, 39, 12, 45, 0, 23, 37, 54, 37, 29, 47, 37, 28, 0, 5, 27, 0, 59, 10, 20, 0, 16, 68, 64, 45, -1, -1, 45, 29, 21, 49, 20, 56, 29, 8, 13, 38, 0, 8, 20, 17, 0, 58, 56, 56, 8, 6, 5, 53, 33, 29, 0, 0, 34, 20, 42, -1, 7, 23, 49, 0, 51, 51, 29, 12, 24, }; static int T0[] = { 0x08, 0x49, 0x24, 0x38, 0x28, 0x43, 0x0d, 0x20, 0x28, 0x15, 0x54, 0x00, 0x3e, 0x2f, 0x53, 0x22, 0x52, 0x4a, 0x15, 0x2f, 0x1c, 0x3e, 0x4e, 0x1b, 0x2d, 0x49, 0x4c, 0x25, 0x1c, 0x4a, 0x13, 0x25, 0x3c, 0x37, 0x55, 0x0d, 0x23, 0x0b, 0x26, 0x43, 0x18, 0x1b, 0x44, 0x56, 0x4a, 0x40, 0x22, 0x46, 0x10, 0x19, 0x00, 0x27, 0x49, 0x50, 0x07, 0x20, 0x3a, 0x05, 0x0a, 0x15, 0x19, 0x47, 0x43, 0x3d, 0x0f, 0x53, 0x09, 0x2c, 0x02, 0x27, 0x2f, 0x29, 0x49, 0x10, 0x37, 0x39, 0x31, 0x31, 0x56, 0x41, 0x4a, 0x56, 0x09, 0x34, 0x47, 0x10, 0x55, 0x2a, 0x15, 0x00, 0x3f, 0x26, 0x47, 0x2b, 0x0d, 0x00, 0x35, 0x53, 0x1a, 0x07, 0x45, 0x38, 0x4b, 0x1b, 0x40, 0x25, 0x27, 0x4c, 0x0c, 0x52, 0x00, 0x07, 0x0e, 0x05, 0x0c, 0x40, 0x1c, 0x2b, 0x36, 0x38, 0x46, 0x16, 0x18, 0x0c, 0x44, 0x1e, 0x08, 0x23, 0x1a, 0x22, 0x2a, 0x00, 0x03, 0x16, 0x14, 0x3b, 0x3b, 0x3b, 0x28, 0x47, 0x2e, 0x20, 0x47, 0x3c, 0x36, 0x37, 0x31, 0x31, 0x43, 0x27, 0x49, 0x14, 0x26, 0x26, 0x29, 0x1d, 0x11, 0x0e, 0x02, 0x15, 0x0a, 0x3e, 0x41, 0x2d, 0x47, 0x10, 0x2c, 0x52, 0x04, 0x29, 0x30, 0x3e, 0x18, 0x48, 0x2b, 0x4e, 0x20, 0x54, 0x20, 0x0d, 0x24, 0x0a, 0x19, 0x42, 0x30, 0x42, 0x09, 0x3a, 0x48, 0x03, 0x4f, 0x4b, 0x41, 0x05, 0x48, 0x15, 0x18, 0x3b, 0x29, 0x52, 0x29, 0x24, 0x3b, 0x18, 0x0e, 0x2f, 0x36, 0x2d, 0x44, 0x53, 0x32, 0x15, 0x46, 0x42, 0x1b, 0x4e, 0x39, 0x34, 0x2d, 0x49, 0x16, 0x17, 0x00, 0x4f, 0x14, 0x40, 0x06, 0x24, 0x1c, 0x2f, 0x1f, 0x45, 0x4b, 0x03, 0x56, 0x51, 0x2b, 0x35, 0x27, 0x18, 0x2d, 0x28, 0x1f, 0x55, 0x53, 0x35, 0x31, 0x2f, 0x13, 0x55, 0x2c, 0x21, 0x00, 0x1e, 0x3c, 0x35, 0x43, 0x10, 0x07, 0x39, 0x3d, 0x4a, 0x2f, 0x14, 0x0f, 0x3d, 0x34, 0x33, 0x25, 0x23, 0x30, 0x4a, 0x4b, 0x4f, 0x41, 0x48, 0x2e, 0x1b, 0x20, 0x39, 0x11, 0x44, 0x52, 0x11, 0x0b, 0x30, 0x3e, 0x4e, 0x36, 0x51, 0x44, 0x19, 0x44, 0x2b, 0x22, 0x17, 0x02, 0x56, 0x44, 0x0a, 0x00, 0x12, 0x38, 0x0d, 0x49, 0x3b, 0x27, 0x19, 0x34, 0x0e, 0x4b, 0x29, 0x47, 0x03, 0x51, 0x27, 0x04, 0x51, 0x51, 0x3a, 0x4b, 0x3f, 0x4b, 0x38, 0x0b, 0x0e, 0x4f, 0x06, 0x0d, 0x35, 0x10, 0x0e, 0x47, 0x48, 0x13, 0x32, 0x17, 0x51, 0x12, 0x27, 0x4d, 0x37, 0x0a, 0x18, 0x0f, 0x19, 0x53, 0x18, 0x3e, 0x43, 0x16, 0x16, 0x28, 0x1f, 0x37, 0x4e, 0x2d, 0x30, 0x4b, 0x44, 0x02, 0x2b, 0x51, 0x36, 0x4c, 0x17, 0x3a, 0x0c, 0x09, 0x44, 0x2c, 0x56, 0x25, 0x36, 0x17, 0x2c, 0x47, 0x0c, 0x3c, 0x27, 0x47, 0x4a, 0x35, 0x18, 0x1e, 0x39, 0x3d, 0x2e, 0x01, 0x47, 0x4d, 0x07, 0x0f, 0x4f, 0x53, 0x1d, 0x37, 0x10, 0x17, 0x4b, 0x1b, 0x36, 0x0b, 0x1d, 0x2e, 0x52, 0x43, 0x10, 0x2c, 0x2c, 0x35, 0x17, 0x3f, 0x2a, 0x31, 0x06, 0x0d, 0x0f, 0x2d, 0x06, 0x56, 0x23, 0x0d, 0x07, 0x13, 0x02, 0x24, 0x42, 0x0a, 0x3b, 0x37, 0x25, 0x15, 0x42, 0x4c, 0x52, 0x25, 0x1c, 0x4e, 0x26, 0x49, 0x39, 0x4d, 0x50, 0x32, 0x22, 0x0e, 0x4d, 0x42, 0x2b, 0x3c, 0x35, 0x0c, 0x1f, 0x08, 0x23, 0x3b, 0x07, 0x3c, 0x2e, 0x51, 0x0b, 0x13, 0x07, 0x4d, 0x09, 0x52, 0x14, 0x1d, 0x49, 0x3a, 0x07, 0x23, 0x31, 0x00, 0x4d, 0x4b, 0x07, 0x3b, 0x2e, 0x19, 0x0c, 0x08, 0x16, 0x0f, 0x03, 0x36, 0x0a, 0x25, 0x3d, 0x05, 0x44, 0x01, 0x22, 0x56, 0x3c, 0x47, 0x36, 0x37, 0x02, 0x40, 0x45, 0x07, 0x40, 0x27, 0x08, 0x36, 0x4f, 0x4c, 0x11, 0x53, 0x0f, 0x1d, 0x53, 0x25, 0x24, 0x56, 0x04, 0x2e, 0x1c, 0x3a, 0x34, 0x0a, 0x3b, 0x4e, 0x01, 0x18, 0x3e, 0x4a, 0x09, 0x47, 0x23, 0x47, 0x14, 0x15, 0x48, 0x4f, 0x2e, 0x46, 0x0a, 0x3d, 0x44, 0x23, 0x49, 0x08, 0x3a, 0x3b, 0x42, 0x36, 0x49, 0x06, 0x52, 0x34, 0x46, 0x33, 0x2e, 0x14, 0x32, 0x23, 0x00, 0x3b, 0x13, 0x23, 0x2b, 0x28, 0x31, 0x14, 0x20, 0x00, 0x04, 0x2a, 0x3e, 0x40, 0x45, 0x28, 0x48, 0x36, 0x12, 0x0f, 0x2c, 0x14, 0x36, 0x16, 0x0b, 0x42, 0x4b, 0x33, 0x22, 0x52, 0x07, 0x42, 0x3a, 0x1a, 0x3c, 0x49, 0x19, 0x4e, 0x45, 0x3c, 0x05, 0x05, 0x54, 0x53, 0x30, 0x1b, 0x51, 0x0b, 0x51, 0x0c, 0x1a, 0x26, 0x20, 0x49, 0x3d, 0x24, 0x34, 0x29, 0x00, 0x4e, 0x25, 0x08, 0x32, 0x08, 0x1a, }; static int T1[] = { 0x52, 0x34, 0x35, 0x46, 0x2e, 0x4c, 0x50, 0x13, 0x54, 0x44, 0x20, 0x31, 0x20, 0x04, 0x3f, 0x11, 0x13, 0x2d, 0x4a, 0x14, 0x52, 0x0a, 0x3b, 0x33, 0x44, 0x15, 0x30, 0x3c, 0x29, 0x28, 0x18, 0x1c, 0x05, 0x4e, 0x03, 0x2c, 0x3b, 0x54, 0x3f, 0x38, 0x39, 0x00, 0x0a, 0x03, 0x04, 0x49, 0x14, 0x17, 0x1a, 0x47, 0x0c, 0x40, 0x13, 0x2a, 0x04, 0x00, 0x37, 0x4c, 0x30, 0x54, 0x2a, 0x11, 0x23, 0x11, 0x17, 0x54, 0x3b, 0x45, 0x35, 0x41, 0x27, 0x0f, 0x14, 0x4d, 0x3c, 0x00, 0x34, 0x55, 0x3e, 0x4e, 0x3d, 0x42, 0x37, 0x48, 0x0d, 0x3b, 0x49, 0x44, 0x29, 0x1a, 0x3a, 0x4b, 0x2b, 0x06, 0x05, 0x42, 0x53, 0x45, 0x45, 0x55, 0x36, 0x44, 0x0b, 0x31, 0x40, 0x3a, 0x0a, 0x2f, 0x39, 0x04, 0x56, 0x1b, 0x34, 0x1d, 0x09, 0x19, 0x48, 0x19, 0x29, 0x1f, 0x17, 0x4a, 0x31, 0x3c, 0x00, 0x3d, 0x2a, 0x4b, 0x23, 0x18, 0x41, 0x02, 0x54, 0x4c, 0x2b, 0x3d, 0x28, 0x36, 0x0d, 0x0a, 0x32, 0x0c, 0x1d, 0x10, 0x1e, 0x1a, 0x4b, 0x1e, 0x2f, 0x36, 0x24, 0x44, 0x20, 0x1f, 0x34, 0x25, 0x43, 0x21, 0x4f, 0x51, 0x47, 0x19, 0x20, 0x25, 0x0e, 0x11, 0x49, 0x2f, 0x2d, 0x29, 0x2a, 0x35, 0x32, 0x49, 0x24, 0x48, 0x0c, 0x19, 0x10, 0x3c, 0x4f, 0x2c, 0x21, 0x19, 0x4b, 0x55, 0x36, 0x2f, 0x20, 0x26, 0x29, 0x08, 0x00, 0x14, 0x41, 0x15, 0x18, 0x4c, 0x0e, 0x4a, 0x46, 0x0d, 0x10, 0x33, 0x19, 0x0a, 0x0c, 0x16, 0x22, 0x07, 0x00, 0x1f, 0x05, 0x22, 0x3b, 0x40, 0x51, 0x48, 0x45, 0x09, 0x16, 0x2a, 0x48, 0x16, 0x3f, 0x2a, 0x2b, 0x4f, 0x1f, 0x31, 0x43, 0x06, 0x3f, 0x4b, 0x3a, 0x50, 0x56, 0x46, 0x10, 0x21, 0x4a, 0x4a, 0x14, 0x22, 0x28, 0x41, 0x4b, 0x42, 0x00, 0x51, 0x33, 0x4e, 0x19, 0x56, 0x22, 0x21, 0x08, 0x16, 0x04, 0x3d, 0x38, 0x3e, 0x0a, 0x3d, 0x0c, 0x55, 0x14, 0x47, 0x22, 0x36, 0x31, 0x15, 0x21, 0x3d, 0x2f, 0x49, 0x1f, 0x23, 0x2c, 0x20, 0x15, 0x01, 0x0f, 0x2f, 0x00, 0x31, 0x48, 0x01, 0x30, 0x0c, 0x34, 0x43, 0x31, 0x51, 0x35, 0x4e, 0x10, 0x09, 0x3d, 0x23, 0x1c, 0x15, 0x15, 0x4f, 0x02, 0x0c, 0x4a, 0x48, 0x27, 0x4b, 0x22, 0x04, 0x01, 0x0f, 0x2e, 0x25, 0x43, 0x4e, 0x0b, 0x1c, 0x03, 0x38, 0x08, 0x2c, 0x32, 0x3d, 0x24, 0x3b, 0x3e, 0x02, 0x07, 0x03, 0x17, 0x14, 0x52, 0x12, 0x11, 0x2e, 0x32, 0x1a, 0x49, 0x1a, 0x2e, 0x13, 0x55, 0x4b, 0x4b, 0x29, 0x44, 0x18, 0x01, 0x38, 0x4c, 0x14, 0x30, 0x16, 0x4e, 0x44, 0x4b, 0x33, 0x4d, 0x31, 0x4b, 0x38, 0x46, 0x43, 0x50, 0x4f, 0x1a, 0x2b, 0x0a, 0x04, 0x3e, 0x30, 0x18, 0x34, 0x24, 0x04, 0x06, 0x0a, 0x14, 0x00, 0x42, 0x09, 0x1b, 0x4a, 0x2b, 0x36, 0x3f, 0x4c, 0x1a, 0x0e, 0x54, 0x3d, 0x0a, 0x01, 0x06, 0x27, 0x53, 0x41, 0x51, 0x51, 0x25, 0x07, 0x10, 0x3b, 0x33, 0x2d, 0x0c, 0x33, 0x48, 0x1d, 0x41, 0x51, 0x0c, 0x05, 0x44, 0x2f, 0x33, 0x24, 0x1c, 0x4d, 0x32, 0x11, 0x33, 0x34, 0x0b, 0x32, 0x05, 0x07, 0x1c, 0x56, 0x1d, 0x17, 0x1b, 0x2f, 0x0a, 0x51, 0x47, 0x3d, 0x03, 0x23, 0x28, 0x18, 0x35, 0x1f, 0x33, 0x52, 0x26, 0x35, 0x0c, 0x23, 0x31, 0x30, 0x03, 0x03, 0x3d, 0x33, 0x4f, 0x3a, 0x52, 0x05, 0x44, 0x19, 0x1c, 0x08, 0x48, 0x1e, 0x52, 0x30, 0x53, 0x55, 0x53, 0x24, 0x0e, 0x29, 0x43, 0x39, 0x24, 0x0b, 0x4b, 0x01, 0x10, 0x47, 0x3d, 0x1e, 0x18, 0x01, 0x32, 0x4e, 0x42, 0x41, 0x2f, 0x0a, 0x2d, 0x28, 0x38, 0x54, 0x29, 0x20, 0x11, 0x37, 0x21, 0x1a, 0x32, 0x45, 0x18, 0x2e, 0x18, 0x48, 0x18, 0x04, 0x49, 0x28, 0x4b, 0x27, 0x46, 0x0c, 0x28, 0x22, 0x52, 0x0b, 0x04, 0x2a, 0x0d, 0x32, 0x52, 0x46, 0x53, 0x26, 0x4f, 0x34, 0x11, 0x08, 0x2d, 0x46, 0x31, 0x33, 0x3b, 0x0e, 0x19, 0x0f, 0x4c, 0x0b, 0x49, 0x2c, 0x3f, 0x06, 0x46, 0x4a, 0x26, 0x25, 0x33, 0x3a, 0x35, 0x07, 0x42, 0x42, 0x2b, 0x36, 0x09, 0x1c, 0x13, 0x1b, 0x24, 0x38, 0x02, 0x4d, 0x0c, 0x3d, 0x04, 0x1e, 0x44, 0x51, 0x29, 0x36, 0x43, 0x37, 0x47, 0x23, 0x0f, 0x38, 0x3c, 0x3d, 0x06, 0x30, 0x08, 0x3d, 0x27, 0x07, 0x0b, 0x09, 0x3c, 0x0a, 0x14, 0x49, 0x43, 0x35, 0x2b, 0x34, 0x38, 0x1e, 0x0d, 0x50, 0x01, 0x12, 0x09, 0x44, 0x41, 0x50, 0x08, 0x48, 0x29, 0x3d, 0x2f, 0x2f, 0x0e, 0x37, 0x0e, 0x35, 0x36, 0x11, 0x3e, 0x1b, }; static int T2[] = { 0x00, 0x46, 0x2f, 0x0e, 0x0b, 0x0c, 0x19, 0x2b, 0x28, 0x17, 0x4c, 0x38, 0x30, 0x1f, 0x12, 0x55, 0x09, 0x42, 0x39, 0x2c, 0x30, 0x14, 0x2d, 0x51, 0x26, 0x38, 0x49, 0x4e, 0x39, 0x06, 0x48, 0x31, 0x44, 0x18, 0x40, 0x50, 0x24, 0x51, 0x1c, 0x4d, 0x11, 0x11, 0x2e, 0x41, 0x30, 0x40, 0x37, 0x31, 0x37, 0x1e, 0x18, 0x1d, 0x4b, 0x16, 0x22, 0x2f, 0x1a, 0x0d, 0x51, 0x2c, 0x4d, 0x55, 0x1a, 0x19, 0x06, 0x13, 0x4d, 0x0b, 0x38, 0x44, 0x24, 0x17, 0x32, 0x0a, 0x3f, 0x30, 0x1f, 0x28, 0x1b, 0x56, 0x47, 0x2b, 0x1c, 0x33, 0x42, 0x36, 0x0b, 0x05, 0x3c, 0x06, 0x29, 0x2a, 0x53, 0x43, 0x43, 0x51, 0x56, 0x0a, 0x0c, 0x28, 0x42, 0x20, 0x15, 0x1c, 0x4b, 0x36, 0x3a, 0x11, 0x36, 0x3d, 0x10, 0x07, 0x05, 0x0f, 0x01, 0x12, 0x1a, 0x02, 0x34, 0x27, 0x4a, 0x04, 0x0a, 0x46, 0x0d, 0x0a, 0x05, 0x0d, 0x15, 0x12, 0x2d, 0x4f, 0x2a, 0x42, 0x14, 0x1e, 0x19, 0x46, 0x27, 0x48, 0x2c, 0x2f, 0x4f, 0x2a, 0x2d, 0x54, 0x19, 0x2a, 0x29, 0x2e, 0x4d, 0x40, 0x30, 0x2b, 0x1a, 0x01, 0x16, 0x17, 0x28, 0x50, 0x03, 0x1c, 0x4f, 0x35, 0x4c, 0x39, 0x17, 0x1b, 0x0d, 0x50, 0x17, 0x34, 0x4c, 0x43, 0x10, 0x22, 0x38, 0x22, 0x44, 0x02, 0x50, 0x32, 0x3a, 0x22, 0x07, 0x54, 0x23, 0x15, 0x0c, 0x43, 0x0e, 0x07, 0x56, 0x47, 0x12, 0x4e, 0x0e, 0x56, 0x34, 0x43, 0x36, 0x27, 0x1c, 0x01, 0x55, 0x02, 0x1d, 0x01, 0x4d, 0x44, 0x30, 0x3b, 0x2d, 0x3c, 0x37, 0x27, 0x2a, 0x54, 0x1b, 0x21, 0x46, 0x28, 0x3f, 0x45, 0x18, 0x52, 0x34, 0x1f, 0x51, 0x12, 0x0b, 0x28, 0x31, 0x28, 0x21, 0x2f, 0x2a, 0x37, 0x28, 0x18, 0x4b, 0x49, 0x04, 0x50, 0x10, 0x31, 0x56, 0x53, 0x02, 0x4f, 0x11, 0x32, 0x51, 0x29, 0x1e, 0x45, 0x34, 0x4b, 0x10, 0x09, 0x41, 0x35, 0x26, 0x54, 0x45, 0x25, 0x47, 0x51, 0x4d, 0x16, 0x46, 0x39, 0x09, 0x43, 0x32, 0x19, 0x15, 0x29, 0x0d, 0x17, 0x21, 0x16, 0x41, 0x1b, 0x40, 0x09, 0x09, 0x15, 0x05, 0x1f, 0x34, 0x2d, 0x4c, 0x11, 0x4a, 0x0d, 0x45, 0x06, 0x20, 0x34, 0x3f, 0x25, 0x12, 0x3e, 0x53, 0x17, 0x1e, 0x29, 0x36, 0x4f, 0x29, 0x4c, 0x12, 0x17, 0x3f, 0x56, 0x3d, 0x15, 0x30, 0x42, 0x34, 0x0d, 0x10, 0x21, 0x17, 0x52, 0x27, 0x54, 0x01, 0x47, 0x31, 0x38, 0x15, 0x3c, 0x20, 0x11, 0x55, 0x29, 0x28, 0x03, 0x43, 0x16, 0x3a, 0x19, 0x40, 0x36, 0x01, 0x33, 0x4a, 0x0e, 0x56, 0x0e, 0x06, 0x3c, 0x11, 0x10, 0x1f, 0x51, 0x4b, 0x11, 0x01, 0x50, 0x25, 0x3c, 0x3f, 0x54, 0x05, 0x3d, 0x1e, 0x26, 0x41, 0x0a, 0x3c, 0x1c, 0x1b, 0x1e, 0x52, 0x15, 0x49, 0x3d, 0x23, 0x48, 0x4c, 0x22, 0x3b, 0x2e, 0x09, 0x4d, 0x4c, 0x3e, 0x42, 0x41, 0x0e, 0x14, 0x03, 0x1c, 0x4c, 0x40, 0x35, 0x48, 0x26, 0x04, 0x15, 0x1b, 0x35, 0x24, 0x31, 0x14, 0x29, 0x02, 0x2f, 0x0a, 0x19, 0x11, 0x39, 0x4c, 0x3f, 0x3b, 0x42, 0x2d, 0x1a, 0x2d, 0x17, 0x20, 0x41, 0x12, 0x3c, 0x2e, 0x52, 0x12, 0x1f, 0x1a, 0x17, 0x21, 0x23, 0x07, 0x4e, 0x26, 0x15, 0x1f, 0x1d, 0x16, 0x1b, 0x19, 0x48, 0x14, 0x4c, 0x1b, 0x13, 0x46, 0x3c, 0x37, 0x3d, 0x49, 0x0b, 0x32, 0x26, 0x3c, 0x2c, 0x1f, 0x07, 0x08, 0x0b, 0x1e, 0x29, 0x2e, 0x1d, 0x21, 0x4c, 0x32, 0x38, 0x0b, 0x40, 0x53, 0x1c, 0x31, 0x10, 0x11, 0x44, 0x1c, 0x42, 0x2a, 0x49, 0x29, 0x50, 0x21, 0x1a, 0x16, 0x16, 0x56, 0x03, 0x23, 0x4f, 0x2a, 0x04, 0x28, 0x49, 0x3b, 0x11, 0x39, 0x0d, 0x0b, 0x40, 0x2e, 0x07, 0x05, 0x10, 0x30, 0x19, 0x36, 0x4a, 0x05, 0x09, 0x3c, 0x26, 0x02, 0x55, 0x40, 0x10, 0x14, 0x3f, 0x0c, 0x2f, 0x2f, 0x36, 0x2b, 0x4f, 0x20, 0x35, 0x0d, 0x2f, 0x1c, 0x02, 0x15, 0x18, 0x2d, 0x3d, 0x41, 0x51, 0x3e, 0x1c, 0x0e, 0x3b, 0x29, 0x0a, 0x39, 0x55, 0x0c, 0x3e, 0x00, 0x27, 0x14, 0x4d, 0x16, 0x11, 0x50, 0x49, 0x00, 0x00, 0x1f, 0x05, 0x27, 0x33, 0x08, 0x34, 0x43, 0x2d, 0x1b, 0x2d, 0x20, 0x51, 0x41, 0x26, 0x2d, 0x0c, 0x30, 0x10, 0x1f, 0x32, 0x0c, 0x18, 0x3f, 0x34, 0x07, 0x30, 0x0b, 0x28, 0x3d, 0x0b, 0x00, 0x0a, 0x13, 0x1e, 0x49, 0x0c, 0x3e, 0x09, 0x41, 0x01, 0x19, 0x1a, 0x4e, 0x41, 0x4e, 0x35, 0x01, 0x0e, 0x3d, 0x18, 0x40, 0x41, 0x31, 0x28, 0x1e, 0x30, 0x50, 0x22, 0x50, 0x37, 0x2d, 0x49, 0x39, 0x41, 0x10, }; #define uchar unsigned char int tok_hash(const uchar *key) { int i; unsigned f0, f1, f2; const uchar *kp = key; for (i=-48, f0=f1=f2=0; *kp; ++kp) { if (*kp < 48 || *kp > 95) return -1; if (kp-key > 12) return -1; f0 += T0[i + *kp]; f1 += T1[i + *kp]; f2 += T2[i + *kp]; i += 48; } if (kp-key < 2) return -1; f0 %= 87; f1 %= 87; f2 %= 87; return (g[f0] + g[f1] + g[f2]) % 70; } #else /* auto-generated with mph-1.2 */ /* * d=3 * n=28 * m=22 * c=1.23 * maxlen=7 * minklen=2 * maxklen=7 * minchar=47 * maxchar=89 * loop=0 * numiter=200 * seed= */ static int g[] = { 19, 12, -1, 15, 17, 1, 4, 4, 0, 13, 10, 19, 18, -1, 14, 19, 19, 21, 19, 0, 7, 0, 15, 18, 4, 0, 4, 3, }; static int T0[] = { 0x15, 0x0c, 0x1a, 0x17, 0x16, 0x02, 0x16, 0x07, 0x17, 0x09, 0x0f, 0x0f, 0x0f, 0x17, 0x07, 0x0c, 0x1a, 0x08, 0x17, 0x04, 0x14, 0x07, 0x06, 0x07, 0x10, 0x0e, 0x0e, 0x18, 0x01, 0x08, 0x1b, 0x17, 0x14, 0x19, 0x12, 0x1a, 0x0b, 0x0c, 0x12, 0x07, 0x05, 0x05, 0x06, 0x13, 0x06, 0x19, 0x07, 0x0d, 0x01, 0x0c, 0x1a, 0x09, 0x15, 0x1b, 0x16, 0x03, 0x15, 0x19, 0x12, 0x07, 0x1b, 0x05, 0x08, 0x0a, 0x15, 0x05, 0x16, 0x0b, 0x0a, 0x00, 0x0e, 0x0d, 0x08, 0x0a, 0x04, 0x1b, 0x07, 0x17, 0x0c, 0x15, 0x07, 0x0a, 0x02, 0x0c, 0x15, 0x08, 0x0d, 0x12, 0x10, 0x00, 0x07, 0x13, 0x15, 0x10, 0x17, 0x0a, 0x0e, 0x01, 0x14, 0x14, 0x1a, 0x06, 0x15, 0x05, 0x0a, 0x14, 0x03, 0x12, 0x04, 0x0c, 0x11, 0x1b, 0x0e, 0x1b, 0x17, 0x03, 0x08, 0x09, 0x15, 0x08, 0x15, 0x0c, 0x1b, 0x0e, 0x00, 0x16, 0x08, 0x1b, 0x08, 0x10, 0x0a, 0x00, 0x09, 0x01, 0x00, 0x09, 0x13, 0x03, 0x19, 0x03, 0x05, 0x15, 0x10, 0x06, 0x13, 0x02, 0x19, 0x15, 0x13, 0x12, 0x18, 0x16, 0x02, 0x0b, 0x0a, 0x1b, 0x0a, 0x15, 0x08, 0x06, 0x09, 0x12, 0x06, 0x12, 0x14, 0x12, 0x0c, 0x17, 0x15, 0x09, 0x1a, 0x0b, 0x05, 0x00, 0x1b, 0x0c, 0x10, 0x09, 0x02, 0x17, 0x11, 0x0a, 0x15, 0x11, 0x18, 0x12, 0x16, 0x00, 0x0e, 0x10, 0x18, 0x11, 0x0b, 0x07, 0x0b, 0x1a, 0x1b, 0x07, 0x07, 0x15, 0x0a, 0x16, 0x1a, 0x0f, 0x06, 0x19, 0x0c, 0x17, 0x06, 0x0e, 0x12, 0x08, 0x18, 0x17, 0x09, 0x0c, 0x03, 0x1b, 0x15, 0x0e, 0x06, 0x01, 0x11, 0x0e, 0x04, 0x08, 0x05, 0x1b, 0x05, 0x03, 0x15, 0x04, 0x17, 0x10, 0x0e, 0x07, 0x0e, 0x14, 0x13, 0x17, 0x14, 0x1b, 0x0a, 0x07, 0x18, 0x04, 0x03, 0x00, 0x10, 0x19, 0x1a, 0x16, 0x0a, 0x0f, 0x14, 0x1a, 0x18, 0x19, 0x0c, 0x1b, 0x06, 0x0a, 0x03, 0x0b, 0x0e, 0x1b, 0x1b, 0x0d, 0x03, 0x0d, 0x19, 0x0a, 0x0f, 0x14, 0x14, 0x06, 0x00, 0x01, 0x10, 0x0d, 0x19, 0x18, 0x09, 0x1b, 0x17, 0x16, 0x14, 0x15, 0x0b, 0x10, 0x14, 0x02, 0x1b, 0x08, 0x0d, 0x0d, 0x13, 0x0c, 0x0a, 0x16, 0x09, }; static int T1[] = { 0x13, 0x0e, 0x17, 0x12, 0x13, 0x12, 0x08, 0x19, 0x05, 0x0d, 0x0b, 0x07, 0x06, 0x05, 0x0b, 0x0f, 0x06, 0x07, 0x12, 0x06, 0x11, 0x0d, 0x08, 0x10, 0x18, 0x1b, 0x18, 0x12, 0x03, 0x00, 0x00, 0x16, 0x1a, 0x07, 0x18, 0x11, 0x19, 0x10, 0x1a, 0x0e, 0x0e, 0x16, 0x16, 0x02, 0x10, 0x0d, 0x11, 0x0a, 0x02, 0x14, 0x00, 0x0c, 0x1a, 0x1a, 0x08, 0x02, 0x01, 0x06, 0x0b, 0x0b, 0x06, 0x02, 0x13, 0x15, 0x0f, 0x11, 0x0d, 0x01, 0x04, 0x0c, 0x0b, 0x13, 0x02, 0x11, 0x06, 0x12, 0x0e, 0x07, 0x01, 0x10, 0x1b, 0x01, 0x01, 0x0a, 0x0b, 0x09, 0x0c, 0x13, 0x11, 0x0a, 0x03, 0x11, 0x02, 0x13, 0x01, 0x08, 0x0c, 0x0a, 0x06, 0x0e, 0x00, 0x13, 0x1b, 0x03, 0x12, 0x01, 0x01, 0x0e, 0x0d, 0x09, 0x11, 0x1b, 0x08, 0x05, 0x0b, 0x0c, 0x02, 0x08, 0x10, 0x13, 0x02, 0x13, 0x14, 0x04, 0x16, 0x15, 0x18, 0x06, 0x10, 0x13, 0x1a, 0x01, 0x03, 0x16, 0x17, 0x12, 0x1b, 0x10, 0x0f, 0x0f, 0x06, 0x0f, 0x0f, 0x1a, 0x10, 0x17, 0x18, 0x09, 0x06, 0x10, 0x01, 0x03, 0x06, 0x0d, 0x03, 0x0d, 0x0d, 0x0f, 0x16, 0x09, 0x13, 0x14, 0x0b, 0x16, 0x1a, 0x12, 0x0d, 0x1a, 0x06, 0x00, 0x19, 0x18, 0x17, 0x18, 0x1b, 0x10, 0x0d, 0x14, 0x17, 0x16, 0x0a, 0x04, 0x0e, 0x03, 0x10, 0x1a, 0x01, 0x10, 0x19, 0x04, 0x09, 0x0f, 0x08, 0x0b, 0x1a, 0x0f, 0x0f, 0x09, 0x09, 0x1b, 0x18, 0x08, 0x16, 0x03, 0x10, 0x05, 0x14, 0x02, 0x19, 0x0f, 0x18, 0x13, 0x03, 0x16, 0x06, 0x1b, 0x01, 0x0f, 0x19, 0x0d, 0x00, 0x0a, 0x11, 0x0f, 0x0d, 0x0e, 0x08, 0x10, 0x1b, 0x0c, 0x1b, 0x19, 0x08, 0x17, 0x0c, 0x1b, 0x0a, 0x12, 0x0d, 0x0f, 0x0a, 0x14, 0x04, 0x0f, 0x0b, 0x05, 0x0f, 0x18, 0x04, 0x18, 0x09, 0x05, 0x06, 0x1b, 0x04, 0x13, 0x19, 0x0c, 0x1b, 0x0c, 0x18, 0x19, 0x08, 0x0e, 0x11, 0x0b, 0x03, 0x16, 0x1b, 0x15, 0x11, 0x14, 0x09, 0x09, 0x17, 0x0e, 0x12, 0x1a, 0x14, 0x12, 0x19, 0x08, 0x16, 0x07, 0x12, 0x0a, 0x17, 0x14, 0x13, 0x06, 0x10, 0x0f, 0x03, 0x18, 0x0d, 0x04, 0x13, 0x10, 0x1b, 0x03, 0x09, }; static int T2[] = { 0x16, 0x04, 0x18, 0x10, 0x13, 0x0f, 0x08, 0x19, 0x19, 0x17, 0x13, 0x0b, 0x0b, 0x08, 0x0a, 0x08, 0x01, 0x05, 0x15, 0x1a, 0x11, 0x02, 0x16, 0x0f, 0x0d, 0x09, 0x16, 0x13, 0x17, 0x0d, 0x05, 0x11, 0x11, 0x0d, 0x05, 0x14, 0x01, 0x19, 0x12, 0x0a, 0x15, 0x15, 0x15, 0x17, 0x13, 0x15, 0x0e, 0x18, 0x11, 0x0f, 0x03, 0x04, 0x03, 0x09, 0x1a, 0x13, 0x04, 0x08, 0x09, 0x07, 0x15, 0x16, 0x05, 0x11, 0x02, 0x00, 0x15, 0x10, 0x1b, 0x0d, 0x14, 0x18, 0x10, 0x0f, 0x13, 0x13, 0x14, 0x11, 0x10, 0x0a, 0x05, 0x03, 0x1a, 0x14, 0x0d, 0x19, 0x05, 0x1a, 0x1a, 0x00, 0x06, 0x0c, 0x07, 0x11, 0x01, 0x18, 0x12, 0x06, 0x02, 0x06, 0x1a, 0x17, 0x03, 0x0d, 0x09, 0x02, 0x09, 0x19, 0x03, 0x01, 0x16, 0x0d, 0x17, 0x10, 0x01, 0x06, 0x18, 0x06, 0x10, 0x16, 0x07, 0x06, 0x12, 0x1a, 0x17, 0x04, 0x16, 0x19, 0x0a, 0x1b, 0x15, 0x16, 0x13, 0x11, 0x09, 0x1b, 0x02, 0x05, 0x12, 0x0c, 0x10, 0x11, 0x08, 0x0f, 0x0c, 0x05, 0x0d, 0x0f, 0x19, 0x01, 0x1b, 0x17, 0x03, 0x08, 0x00, 0x1a, 0x0d, 0x0c, 0x07, 0x19, 0x17, 0x01, 0x03, 0x0e, 0x02, 0x18, 0x19, 0x10, 0x02, 0x00, 0x0c, 0x02, 0x0a, 0x0b, 0x1a, 0x11, 0x19, 0x01, 0x16, 0x02, 0x09, 0x01, 0x10, 0x1a, 0x0c, 0x0c, 0x12, 0x10, 0x18, 0x1b, 0x14, 0x17, 0x17, 0x12, 0x1b, 0x08, 0x0d, 0x0c, 0x07, 0x1a, 0x04, 0x03, 0x0b, 0x0e, 0x1b, 0x16, 0x10, 0x08, 0x17, 0x16, 0x16, 0x10, 0x17, 0x0a, 0x1a, 0x0c, 0x17, 0x0f, 0x0a, 0x19, 0x00, 0x0c, 0x08, 0x11, 0x17, 0x09, 0x17, 0x0f, 0x00, 0x05, 0x17, 0x05, 0x05, 0x17, 0x17, 0x15, 0x0f, 0x00, 0x00, 0x19, 0x0c, 0x19, 0x0f, 0x11, 0x08, 0x18, 0x01, 0x10, 0x17, 0x17, 0x0d, 0x18, 0x13, 0x15, 0x0d, 0x0e, 0x0e, 0x09, 0x05, 0x17, 0x14, 0x17, 0x16, 0x16, 0x1b, 0x10, 0x10, 0x0c, 0x06, 0x02, 0x17, 0x12, 0x05, 0x08, 0x12, 0x00, 0x0b, 0x17, 0x07, 0x12, 0x08, 0x01, 0x18, 0x0a, 0x19, 0x16, 0x01, 0x0b, 0x12, 0x12, 0x06, 0x0a, 0x0e, 0x0c, 0x10, 0x0d, 0x00, 0x04, 0x19, 0x12, 0x06, }; #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 %= 28; f1 %= 28; f2 %= 28; return (g[f0] + g[f1] + g[f2]) % 22; } #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; stack_frame = 0; current_line = 0; bytes_written = 0; } void ducky_compile(int fd, bool verbose, int out) { 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); 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("Compiling..."); } /* initialize some other constants */ makeConstantVariable(".", 0); makeConstantVariable("true", 1); makeConstantVariable("false", 0); /* 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"); } 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: /* 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; }