static void generate_expr_list (parse_node_t * expr) { parse_node_t *pn; int n, flag; if (!expr) return; pn = expr; flag = n = 0; do { if (pn->type & 1) flag = 1; i_generate_node(pn->v.expr); n++; } while ((pn = pn->r.expr)); if (flag) { pn = expr; do { n--; if (pn->type & 1) { end_pushes(); ins_byte(F_EXPAND_VARARGS); ins_byte(n); } } while ((pn = pn->r.expr)); } }
void i_generate_inherited_init_call P2(int, index, short, f) { ins_f_byte(F_CALL_INHERITED); ins_byte(index); ins_short(f); ins_byte(0); ins_f_byte(F_POP_VALUE); }
static int try_to_push (int kind, int value) { if (push_state) { if (value <= PUSH_MASK) { if (push_state == 1) initialize_push(); push_state++; ins_byte(kind | value); if (push_state == 255) end_pushes(); return 1; } else end_pushes(); } else if (value <= PUSH_MASK) { push_start = CURRENT_PROGRAM_SIZE; push_state = 1; switch (kind) { case PUSH_STRING: ins_byte(F_SHORT_STRING); break; case PUSH_LOCAL: ins_byte(F_LOCAL); break; case PUSH_GLOBAL: ins_byte(F_GLOBAL); break; case PUSH_NUMBER: if (value == 0) { ins_byte(F_CONST0); return 1; } else if (value == 1) { ins_byte(F_CONST1); return 1; } ins_byte(F_BYTE); } ins_byte(value); return 1; } return 0; }
static void initialize_push (void) { int what = mem_block[A_PROGRAM].block[push_start]; int arg = 0; // This is only valid if it is not a one byte const target. if (what != F_CONST0 && what != F_CONST1) { arg = mem_block[A_PROGRAM].block[push_start + 1]; } prog_code = mem_block[A_PROGRAM].block + push_start; ins_byte(F_PUSH); push_start++; /* now points to the zero here */ ins_byte(0); switch (what) { case F_CONST0: ins_byte(PUSH_NUMBER | 0); break; case F_CONST1: ins_byte(PUSH_NUMBER | 1); break; case F_BYTE: ins_byte(PUSH_NUMBER | arg); break; case F_SHORT_STRING: ins_byte(PUSH_STRING | arg); break; case F_LOCAL: ins_byte(PUSH_LOCAL | arg); break; case F_GLOBAL: ins_byte(PUSH_GLOBAL | arg); break; } }
INLINE static void ins_f_byte P1(unsigned int, b) { #ifdef NEEDS_CALL_EXTRA if (b >= 0xff) { ins_byte((char)F_CALL_EXTRA); ins_byte((char)(b - 0xff)); } else { #endif ins_byte((char)b); #ifdef NEEDS_CALL_EXTRA } #endif }
static void generate_lvalue_list (parse_node_t * expr) { while ((expr = expr->r.expr)) { i_generate_node(expr->l.expr); end_pushes(); ins_byte(F_VOID_ASSIGN); } }
/* * Generate the code to push a number on the stack. * This varies since there are several opcodes (for * optimizing speed and/or size). */ static void write_number P1(int, val) { if (val == 0) { ins_f_byte(F_CONST0); } else if (val == 1) { ins_f_byte(F_CONST1); } else if (val > 0 && val < 256) { ins_f_byte(F_BYTE); ins_byte(val); } else if (val < 0 && val > -256) { ins_f_byte(F_NBYTE); ins_byte(-val); } else { ins_f_byte(F_NUMBER); ins_int(val); } }
void i_generate_continue() { if (switches) { ins_f_byte(F_POP_BREAK); ins_byte(switches); } /* form a linked list of the continue addresses */ ins_f_byte(F_BRANCH); ins_short(cont_ptr->line); cont_ptr = cont_ptr->v.expr; }
static void write_number (long val) { if ((val & ~0xff) == 0) write_small_number(val); else { end_pushes(); if (val < 0 && val > -256) { ins_byte(F_NBYTE); ins_byte(-val); } else if (val >= -32768 && val <= 32767) { ins_byte(F_SHORT_INT); ins_short(val); } else { ins_byte(F_NUMBER); #if SIZEOF_LONG == 4 ins_int(val); #else ins_long(val); #endif } } }
void i_generate_node (parse_node_t * expr) { if (!expr) return; if (expr->line && expr->line != line_being_generated) switch_to_line(expr->line); switch (expr->kind) { case NODE_FUNCTION: { unsigned short num; /* In the following we know that this function wins all the */ /* rest - Sym */ num = FUNCTION_TEMP(expr->v.number)->u.index; FUNC(num)->address = generate_function(FUNC(num), expr->r.expr, expr->l.number); break; } case NODE_TERNARY_OP: i_generate_node(expr->l.expr); expr = expr->r.expr; case NODE_BINARY_OP: i_generate_node(expr->l.expr); /* fall through */ case NODE_UNARY_OP: i_generate_node(expr->r.expr); /* fall through */ case NODE_OPCODE: end_pushes(); ins_byte(expr->v.number); break; case NODE_TERNARY_OP_1: i_generate_node(expr->l.expr); expr = expr->r.expr; /* fall through */ case NODE_BINARY_OP_1: i_generate_node(expr->l.expr); i_generate_node(expr->r.expr); end_pushes(); ins_byte(expr->v.number); ins_byte(expr->type); break; case NODE_UNARY_OP_1: i_generate_node(expr->r.expr); /* fall through */ case NODE_OPCODE_1: if (expr->v.number == F_LOCAL) { if (try_to_push(PUSH_LOCAL, expr->l.number)) break; } else if (expr->v.number == F_GLOBAL) { if (try_to_push(PUSH_GLOBAL, expr->l.number)) break; } end_pushes(); ins_byte(expr->v.number); ins_byte(expr->l.number); break; case NODE_OPCODE_2: end_pushes(); ins_byte(expr->v.number); ins_byte(expr->l.number); if (expr->v.number == F_LOOP_COND_NUMBER) #if SIZEOF_LONG == 8 ins_long(expr->r.number); #else ins_int(expr->r.number); #endif else ins_byte(expr->r.number); break; case NODE_RETURN: { int n; n = foreach_depth; end_pushes(); while (n--) ins_byte(F_EXIT_FOREACH); if (expr->r.expr) { i_generate_node(expr->r.expr); end_pushes(); ins_byte(F_RETURN); } else ins_byte(F_RETURN_ZERO); break; } case NODE_STRING: if (try_to_push(PUSH_STRING, expr->v.number)) break; if (expr->v.number <= 0xff) { ins_byte(F_SHORT_STRING); ins_byte(expr->v.number); } else { ins_byte(F_STRING); ins_short(expr->v.number); } break; case NODE_REAL: end_pushes(); ins_byte(F_REAL); ins_real(expr->v.real); break; case NODE_NUMBER: write_number(expr->v.number); break; case NODE_LAND_LOR: i_generate_node(expr->l.expr); i_generate_forward_branch(expr->v.number); i_generate_node(expr->r.expr); if (expr->l.expr->kind == NODE_BRANCH_LINK) i_update_forward_branch_links(expr->v.number,expr->l.expr); else i_update_forward_branch("&& or ||"); break; case NODE_BRANCH_LINK: i_generate_node(expr->l.expr); end_pushes(); ins_byte(0); expr->v.number = CURRENT_PROGRAM_SIZE; ins_short(0); i_generate_node(expr->r.expr); break; case NODE_CALL_2: generate_expr_list(expr->r.expr); end_pushes(); ins_byte(expr->v.number); ins_byte(expr->l.number >> 16); ins_short(expr->l.number & 0xffff); ins_byte((expr->r.expr ? expr->r.expr->kind : 0)); break; case NODE_CALL_1: generate_expr_list(expr->r.expr); end_pushes(); if (expr->v.number == F_CALL_FUNCTION_BY_ADDRESS) { expr->l.number = comp_def_index_map[expr->l.number]; } ins_byte(expr->v.number); ins_short(expr->l.number); ins_byte((expr->r.expr ? expr->r.expr->kind : 0)); break; case NODE_CALL: generate_expr_list(expr->r.expr); end_pushes(); ins_byte(expr->v.number); ins_short(expr->l.number); break; case NODE_TWO_VALUES: i_generate_node(expr->l.expr); i_generate_node(expr->r.expr); break; case NODE_CONTROL_JUMP: { int kind = expr->v.number; end_pushes(); ins_byte(F_BRANCH); expr->v.expr = branch_list[kind]; expr->l.number = CURRENT_PROGRAM_SIZE; ins_short(0); branch_list[kind] = expr; break; } case NODE_PARAMETER: { int which = expr->v.number + current_num_values; if (try_to_push(PUSH_LOCAL, which)) break; ins_byte(F_LOCAL); ins_byte(which); break; } case NODE_PARAMETER_LVALUE: end_pushes(); ins_byte(F_LOCAL_LVALUE); ins_byte(expr->v.number + current_num_values); break; case NODE_IF: i_generate_if_branch(expr->v.expr, 0); i_generate_node(expr->l.expr); if (expr->r.expr) { i_generate_else(); i_generate_node(expr->r.expr); } i_update_forward_branch("if"); break; case NODE_LOOP: i_generate_loop(expr->type, expr->v.expr, expr->l.expr, expr->r.expr); break; case NODE_FOREACH: { int tmp = 0; i_generate_node(expr->v.expr); end_pushes(); ins_byte(F_FOREACH); if (expr->l.expr->v.number == F_GLOBAL_LVALUE) tmp |= FOREACH_RIGHT_GLOBAL; else if (expr->l.expr->v.number == F_REF_LVALUE) tmp |= FOREACH_REF; if (expr->r.expr) { if (tmp & FOREACH_RIGHT_GLOBAL) tmp = (tmp & ~FOREACH_RIGHT_GLOBAL) | FOREACH_LEFT_GLOBAL; tmp |= FOREACH_MAPPING; if (expr->r.expr->v.number == F_GLOBAL_LVALUE) tmp |= FOREACH_RIGHT_GLOBAL; else if (expr->r.expr->v.number == F_REF_LVALUE) tmp |= FOREACH_REF; } ins_byte(tmp); ins_byte(expr->l.expr->l.number); if (expr->r.expr) ins_byte(expr->r.expr->l.number); } break; case NODE_CASE_NUMBER: case NODE_CASE_STRING: if (expr->v.expr) { parse_node_t *other = expr->v.expr; expr->v.number = 1; other->l.expr = expr->l.expr; other->v.number = CURRENT_PROGRAM_SIZE; expr->l.expr = other; } else { expr->v.number = CURRENT_PROGRAM_SIZE; } end_pushes(); break; case NODE_DEFAULT: expr->v.number = CURRENT_PROGRAM_SIZE; end_pushes(); break; case NODE_SWITCH_STRINGS: case NODE_SWITCH_NUMBERS: case NODE_SWITCH_DIRECT: case NODE_SWITCH_RANGES: { long addr, last_break; parse_node_t *sub = expr->l.expr; parse_node_t *save_switch_breaks = branch_list[CJ_BREAK_SWITCH]; i_generate_node(sub); branch_list[CJ_BREAK_SWITCH] = 0; end_pushes(); ins_byte(F_SWITCH); addr = CURRENT_PROGRAM_SIZE; /* all these are addresses in here are relative to addr now, * which is also the value of pc in f_switch(). Note that * addr is one less than it was in older drivers. */ ins_byte(0xff); /* kind of table */ ins_short(0); /* address of table */ ins_short(0); /* end of table */ ins_short(0); /* default address */ i_generate_node(expr->r.expr); if (expr->v.expr && expr->v.expr->kind == NODE_DEFAULT) { upd_short(addr + 5, expr->v.expr->v.number - addr, "switch"); expr->v.expr = expr->v.expr->l.expr; } else { upd_short(addr + 5, CURRENT_PROGRAM_SIZE - addr, "switch"); } /* just in case the last case doesn't have a break */ end_pushes(); ins_byte(F_BRANCH); last_break = CURRENT_PROGRAM_SIZE; ins_short(0); /* build table */ upd_short(addr + 1, CURRENT_PROGRAM_SIZE - addr, "switch"); #ifdef BINARIES if (pragmas & PRAGMA_SAVE_BINARY) { if (expr->kind == NODE_SWITCH_STRINGS) { short sw; sw = addr - 1; add_to_mem_block(A_PATCH, (char *)&sw, sizeof sw); } } #endif if (expr->kind == NODE_SWITCH_DIRECT) { parse_node_t *pn = expr->v.expr; while (pn) { ins_rel_short(pn->v.number - addr); pn = pn->l.expr; } ins_int(expr->v.expr->r.number); mem_block[A_PROGRAM].block[addr] = (char)0xfe; } else { int table_size = 0; int power_of_two = 1; int i = 0; parse_node_t *pn = expr->v.expr; while (pn) { if (expr->kind == NODE_SWITCH_STRINGS) { if (pn->r.number) { INS_POINTER((POINTER_INT) PROG_STRING(pn->r.number)); } else INS_POINTER((POINTER_INT)0); } else INS_POINTER((POINTER_INT)pn->r.expr); if (pn->v.number == 1) ins_short(1); else ins_rel_short(pn->v.number - addr); pn = pn->l.expr; table_size += 1; } while ((power_of_two<<1) <= table_size) { power_of_two <<= 1; i++; } if (expr->kind != NODE_SWITCH_STRINGS) mem_block[A_PROGRAM].block[addr] = (char)(0xf0+i); else mem_block[A_PROGRAM].block[addr] = (char)(i*0x10+0x0f); } i_update_branch_list(branch_list[CJ_BREAK_SWITCH], "switch break"); branch_list[CJ_BREAK_SWITCH] = save_switch_breaks; upd_short(last_break, CURRENT_PROGRAM_SIZE - last_break, "switch break"); upd_short(addr+3, CURRENT_PROGRAM_SIZE - addr, "switch"); break; } case NODE_CATCH: { int addr; end_pushes(); ins_byte(F_CATCH); addr = CURRENT_PROGRAM_SIZE; ins_short(0); i_generate_node(expr->r.expr); ins_byte(F_END_CATCH); upd_short(addr, CURRENT_PROGRAM_SIZE - addr, "catch"); break; } case NODE_TIME_EXPRESSION: { end_pushes(); ins_byte(F_TIME_EXPRESSION); i_generate_node(expr->r.expr); ins_byte(F_END_TIME_EXPRESSION); break; } case NODE_LVALUE_EFUN: i_generate_node(expr->l.expr); generate_lvalue_list(expr->r.expr); break; case NODE_FUNCTION_CONSTRUCTOR: if (expr->r.expr) { generate_expr_list(expr->r.expr); end_pushes(); ins_byte(F_AGGREGATE); ins_short(expr->r.expr->kind); } else { end_pushes(); ins_byte(F_CONST0); } end_pushes(); ins_byte(F_FUNCTION_CONSTRUCTOR); ins_byte(expr->v.number & 0xff); switch (expr->v.number & 0xff) { case FP_SIMUL: ins_short(expr->v.number >> 8); break; case FP_LOCAL: ins_short(comp_def_index_map[expr->v.number >> 8]); break; case FP_EFUN: ins_short(predefs[expr->v.number >> 8].token); break; case FP_FUNCTIONAL: case FP_FUNCTIONAL | FP_NOT_BINDABLE: { int addr, save_current_num_values = current_num_values; ins_byte(expr->v.number >> 8); addr = CURRENT_PROGRAM_SIZE; ins_short(0); current_num_values = expr->r.expr ? expr->r.expr->kind : 0; i_generate_node(expr->l.expr); current_num_values = save_current_num_values; end_pushes(); ins_byte(F_RETURN); upd_short(addr, CURRENT_PROGRAM_SIZE - addr - 2, "function pointer"); break; } } break; case NODE_ANON_FUNC: { int addr; int save_fd = foreach_depth; foreach_depth = 0; end_pushes(); ins_byte(F_FUNCTION_CONSTRUCTOR); if (expr->v.number & 0x10000) ins_byte(FP_ANONYMOUS | FP_NOT_BINDABLE); else ins_byte(FP_ANONYMOUS); ins_byte(expr->v.number & 0xff); ins_byte(expr->l.number); addr = CURRENT_PROGRAM_SIZE; ins_short(0); i_generate_node(expr->r.expr); upd_short(addr, CURRENT_PROGRAM_SIZE - addr - 2, "function pointer"); foreach_depth = save_fd; break; } case NODE_EFUN: { int novalue_used = expr->v.number & NOVALUE_USED_FLAG; int f = expr->v.number & ~NOVALUE_USED_FLAG; generate_expr_list(expr->r.expr); end_pushes(); if (f < ONEARG_MAX) { ins_byte(f); } else { /* max_arg == -1 must use F_EFUNV so that varargs expansion works*/ if (expr->l.number < 4 && instrs[f].max_arg != -1) ins_byte(F_EFUN0 + expr->l.number); else { ins_byte(F_EFUNV); ins_byte(expr->l.number); } ins_byte(f - ONEARG_MAX); } if (novalue_used) { /* the value of a void efun was used. Put in a zero. */ ins_byte(F_CONST0); } break; } default: fatal("Unknown node %i in i_generate_node.\n", expr->kind); }
/* * Generate the code to push a number on the stack. * This varies since there are several opcodes (for * optimizing speed and/or size). */ static void write_small_number (int val) { if (try_to_push(PUSH_NUMBER, val)) return; ins_byte(F_BYTE); ins_byte(val); }
void i_generate_function_call P2(short, f, char, num) { ins_f_byte(F_CALL_FUNCTION_BY_ADDRESS); ins_short(f); ins_byte(0); }
void i_generate_node P1(struct parse_node *, expr) { if (!expr) return; if (expr->line && expr->line != line_being_generated) switch_to_line(expr->line); switch (expr->kind) { case F_OR: case F_XOR: case F_AND: case F_EQ: case F_NE: case F_GT: case F_GE: case F_LT: case F_LE: case F_LSH: case F_RSH: case F_ADD: case F_SUBTRACT: case F_MULTIPLY: case F_DIVIDE: case F_MOD: i_generate_node(expr->l.expr); /* fall through */ case F_RETURN: case F_POP_VALUE: case F_PRE_INC: case F_PRE_DEC: case F_INC: case F_DEC: case F_POST_INC: case F_POST_DEC: case F_NOT: case F_COMPL: case F_NEGATE: i_generate_node(expr->r.expr); /* fall through */ case F_CONST0: case F_CONST1: #ifdef DEBUG case F_BREAK_POINT: #endif case F_BREAK: ins_f_byte(expr->kind); break; case F_ASSIGN: /* note these are backwards */ case F_VOID_ASSIGN: case F_VOID_ADD_EQ: case F_ADD_EQ: case F_AND_EQ: case F_OR_EQ: case F_XOR_EQ: case F_LSH_EQ: case F_RSH_EQ: case F_SUB_EQ: case F_MULT_EQ: case F_MOD_EQ: case F_DIV_EQ: case F_INDEX_LVALUE: case F_INDEX: case F_RINDEX: case F_RINDEX_LVALUE: i_generate_node(expr->r.expr); i_generate_node(expr->l.expr); ins_f_byte(expr->kind); break; case F_NN_RANGE: case F_RN_RANGE: case F_RR_RANGE: case F_NR_RANGE: case F_NN_RANGE_LVALUE: case F_RN_RANGE_LVALUE: case F_NR_RANGE_LVALUE: case F_RR_RANGE_LVALUE: i_generate_node(expr->l.expr); i_generate_node(expr->r.expr); i_generate_node(expr->v.expr); ins_f_byte(expr->kind); break; case NODE_NE_RANGE_LVALUE: i_generate_node(expr->l.expr); ins_f_byte(F_CONST1); i_generate_node(expr->v.expr); ins_f_byte(F_NR_RANGE_LVALUE); break; case NODE_RE_RANGE_LVALUE: i_generate_node(expr->l.expr); ins_f_byte(F_CONST1); i_generate_node(expr->v.expr); ins_f_byte(F_RR_RANGE_LVALUE); break; case F_RE_RANGE: case F_NE_RANGE: i_generate_node(expr->l.expr); i_generate_node(expr->v.expr); ins_f_byte(expr->kind); break; case F_STRING: if (expr->v.number <= 0xff) { ins_f_byte(F_SHORT_STRING); ins_byte(expr->v.number); } else { ins_f_byte(F_STRING); ins_short(expr->v.number); } break; case F_REAL: ins_f_byte(F_REAL); ins_real(expr->v.real); break; case F_NBYTE: case F_BYTE: ins_f_byte(expr->kind); ins_byte(expr->v.number); break; case F_NUMBER: write_number(expr->v.number); break; case F_LOR: case F_LAND: i_generate_node(expr->l.expr); i_generate_forward_branch(expr->kind); i_generate_node(expr->r.expr); if (expr->l.expr->kind == NODE_BRANCH_LINK){ i_update_forward_branch_links(expr->kind,expr->l.expr); } else i_update_forward_branch(); break; case NODE_BRANCH_LINK: i_generate_node(expr->l.expr); ins_byte(0); expr->line = CURRENT_PROGRAM_SIZE; ins_short(0); i_generate_node(expr->r.expr); break; case F_AGGREGATE: case F_AGGREGATE_ASSOC: generate_expr_list(expr->r.expr); ins_f_byte(expr->kind); ins_short(expr->v.number); break; case NODE_COMMA: case NODE_ASSOC: i_generate_node(expr->l.expr); i_generate_node(expr->r.expr); break; case NODE_BREAK: ins_f_byte(F_BRANCH); expr->v.expr = break_ptr; expr->line = CURRENT_PROGRAM_SIZE; expr->type = 0; ins_short(0); break_ptr = expr; break; case NODE_CONTINUE: if (switches) { ins_f_byte(F_POP_BREAK); ins_byte(switches); } ins_f_byte(F_BRANCH); expr->v.expr = cont_ptr; expr->line = CURRENT_PROGRAM_SIZE; expr->type = 0; ins_short(0); cont_ptr = expr; break; case NODE_STATEMENTS: i_generate_node(expr->l.expr); i_generate_node(expr->r.expr); break; case NODE_PARAMETER: ins_f_byte(F_LOCAL); ins_byte(expr->v.number + current_num_values); break; case NODE_PARAMETER_LVALUE: ins_f_byte(F_LOCAL_LVALUE); ins_byte(expr->v.number + current_num_values); break; case NODE_VALUE: ins_f_byte(F_LOCAL); ins_byte(expr->v.number); break; case NODE_LVALUE: ins_f_byte(F_LOCAL_LVALUE); ins_byte(expr->v.number); break; case NODE_IF: if (expr->v.expr->kind == F_NOT) { i_generate_node(expr->v.expr->r.expr); i_generate_forward_branch(F_BRANCH_WHEN_NON_ZERO); } else { i_generate_node(expr->v.expr); i_generate_forward_branch(F_BRANCH_WHEN_ZERO); } i_generate_node(expr->l.expr); if (expr->r.expr) { i_generate_else(); i_generate_node(expr->r.expr); } i_update_forward_branch(); break; case NODE_FOR: { int forever = node_always_true(expr->l.expr->v.expr), pos; i_save_loop_info(); i_generate_node(expr->l.expr->l.expr); if (!forever) i_generate_forward_branch(F_BRANCH); pos = CURRENT_PROGRAM_SIZE; i_generate_node(expr->r.expr); i_update_continues(); i_generate_node(expr->l.expr->r.expr); if (!forever) i_update_forward_branch(); if (expr->l.expr->v.expr->kind == F_LOOP_COND){ i_generate_node(expr->l.expr->v.expr); ins_short(CURRENT_PROGRAM_SIZE - pos); } else i_branch_backwards(generate_conditional_branch(expr->l.expr->v.expr), pos); i_update_breaks(); i_restore_loop_info(); } break; case NODE_WHILE: { int forever = node_always_true(expr->l.expr), pos; i_save_loop_info(); if (!forever) i_generate_forward_branch(F_BRANCH); pos = CURRENT_PROGRAM_SIZE; i_generate_node(expr->r.expr); if (!forever) i_update_forward_branch(); i_update_continues(); if (expr->l.expr->kind == F_LOOP_COND){ i_generate_node(expr->l.expr); ins_short(CURRENT_PROGRAM_SIZE - pos); } else i_branch_backwards(generate_conditional_branch(expr->l.expr), pos); i_update_breaks(); i_restore_loop_info(); } break; case NODE_DO_WHILE: { int pos; i_save_loop_info(); pos = CURRENT_PROGRAM_SIZE; i_generate_node(expr->l.expr); i_update_continues(); i_branch_backwards(generate_conditional_branch(expr->r.expr), pos); i_update_breaks(); i_restore_loop_info(); } break; case NODE_CASE_NUMBER: case NODE_CASE_STRING: if (expr->v.expr) { struct parse_node *other = expr->v.expr; expr->v.number = 1; other->l.expr = expr->l.expr; other->v.number = CURRENT_PROGRAM_SIZE; expr->l.expr = other; } else { expr->v.number = CURRENT_PROGRAM_SIZE; } break; case NODE_DEFAULT: expr->v.number = CURRENT_PROGRAM_SIZE; break; case NODE_SWITCH_STRINGS: case NODE_SWITCH_NUMBERS: case NODE_SWITCH_DIRECT: { int addr; i_generate_node(expr->l.expr); switches++; ins_f_byte(F_SWITCH); ins_byte(0xff); /* kind of table */ addr = CURRENT_PROGRAM_SIZE; ins_short(0); /* address of table */ ins_short(0); /* break address to push, table is entered before */ ins_short(0); /* default address */ i_generate_node(expr->r.expr); if (expr->v.expr && expr->v.expr->kind == NODE_DEFAULT) { upd_short(addr + 4, expr->v.expr->v.number); expr->v.expr = expr->v.expr->l.expr; } else { upd_short(addr + 4, CURRENT_PROGRAM_SIZE); } /* just in case the last case doesn't have a break */ ins_f_byte(F_BREAK); /* build table */ upd_short(addr, CURRENT_PROGRAM_SIZE); #ifdef BINARIES if (expr->kind == NODE_SWITCH_STRINGS) { short sw; sw = addr - 2; add_to_mem_block(A_PATCH, (char *)&sw, sizeof sw); } #endif if (expr->kind == NODE_SWITCH_DIRECT) { struct parse_node *pn = expr->v.expr; while (pn) { ins_short((short)pn->v.number); pn = pn->l.expr; } ins_int(expr->v.expr->r.number); mem_block[current_block].block[addr-1] = (char)0xfe; } else { int table_size = 0; int power_of_two = 1; int i = 0; struct parse_node *pn = expr->v.expr; while (pn) { INS_POINTER((POINTER_INT)pn->r.expr); ins_short((short)pn->v.number); pn = pn->l.expr; table_size += 1; } while ((power_of_two<<1) <= table_size) { power_of_two <<= 1; i++; } if (expr->kind == NODE_SWITCH_NUMBERS) mem_block[current_block].block[addr-1] = (char)(0xf0+i); else mem_block[current_block].block[addr-1] = (char)(i*0x10+0x0f); } upd_short(addr + 2, CURRENT_PROGRAM_SIZE); break; } case NODE_CONDITIONAL: { int addr; i_generate_node(expr->l.expr); ins_f_byte(F_BRANCH_WHEN_ZERO); addr = CURRENT_PROGRAM_SIZE; ins_short(0); i_generate_node(expr->r.expr->l.expr); upd_short(addr, CURRENT_PROGRAM_SIZE - addr + 3); /*over the branch */ ins_f_byte(F_BRANCH); addr = CURRENT_PROGRAM_SIZE; ins_short(0); i_generate_node(expr->r.expr->r.expr); upd_short(addr, CURRENT_PROGRAM_SIZE - addr); } break; case F_CATCH: { int addr; ins_f_byte(F_CATCH); addr = CURRENT_PROGRAM_SIZE; ins_short(0); i_generate_node(expr->r.expr); ins_f_byte(F_END_CATCH); upd_short(addr, CURRENT_PROGRAM_SIZE - addr); break; } case F_SSCANF: i_generate_node(expr->l.expr->l.expr); i_generate_node(expr->l.expr->r.expr); ins_f_byte(F_SSCANF); ins_byte(expr->r.expr->v.number); generate_lvalue_list(expr->r.expr); break; case F_PARSE_COMMAND: i_generate_node(expr->l.expr->l.expr); i_generate_node(expr->l.expr->r.expr->l.expr); i_generate_node(expr->l.expr->r.expr->r.expr); ins_f_byte(F_PARSE_COMMAND); ins_byte(expr->r.expr->v.number); generate_lvalue_list(expr->r.expr); break; case F_TIME_EXPRESSION: ins_f_byte(F_TIME_EXPRESSION); i_generate_node(expr->r.expr); ins_f_byte(F_END_TIME_EXPRESSION); break; case F_TO_FLOAT: case F_TO_INT: generate_expr_list(expr->r.expr); ins_f_byte(expr->kind); break; case F_GLOBAL_LVALUE: case F_GLOBAL: case F_LOCAL_LVALUE: case F_LOCAL: case F_LOOP_INCR: case F_WHILE_DEC: ins_f_byte(expr->kind); ins_byte(expr->v.number); break; case F_LOOP_COND: { int i; ins_f_byte(F_LOOP_COND); ins_byte(expr->l.expr->v.number); /* expand this into a number so we can pull it fast at runtime */ if (expr->r.expr->kind == F_LOCAL) { i_generate_node(expr->r.expr); } else { ins_f_byte(F_NUMBER); switch (expr->r.expr->kind) { case F_CONST0: i = 0; break; case F_CONST1: i = 1; break; case F_NBYTE: i = - expr->r.expr->v.number; break; case F_BYTE: case F_NUMBER: i = expr->r.expr->v.number; break; default: fatal("Unknown node %i in F_LOOP_COND\n", expr->r.expr->kind); } ins_int(i); } break; } case F_SIMUL_EFUN: case F_CALL_FUNCTION_BY_ADDRESS: generate_expr_list(expr->r.expr); ins_f_byte(expr->kind); ins_short(expr->v.number); ins_byte((expr->r.expr ? expr->r.expr->kind : 0)); break; case F_CALL_INHERITED: generate_expr_list(expr->r.expr); ins_f_byte(F_CALL_INHERITED); ins_byte(expr->v.number & 0xff); ins_short(expr->v.number >> 8); ins_byte((expr->r.expr ? expr->r.expr->kind : 0)); break; case F_EVALUATE: #ifdef NEW_FUNCTIONS generate_expr_list(expr->r.expr); ins_f_byte(F_EVALUATE); #else i_generate_node(expr->l.expr); ins_f_byte(F_EVALUATE); generate_expr_list(expr->r.expr); ins_f_byte(F_CALL_OTHER); #endif ins_byte(expr->v.number); break; case F_FUNCTION_CONSTRUCTOR: #ifdef NEW_FUNCTIONS if ((expr->v.number & 0xff) == FP_CALL_OTHER) { i_generate_node(expr->l.expr); i_generate_node(expr->r.expr); ins_f_byte(F_FUNCTION_CONSTRUCTOR); ins_f_byte(FP_CALL_OTHER); break; } if (expr->r.expr) { generate_expr_list(expr->r.expr); ins_f_byte(F_AGGREGATE); ins_short(expr->r.expr->kind); } else ins_f_byte(F_CONST0); ins_f_byte(F_FUNCTION_CONSTRUCTOR); ins_byte(expr->v.number & 0xff); switch (expr->v.number & 0xff) { case FP_SIMUL: case FP_LOCAL: ins_short(expr->v.number >> 8); break; case FP_EFUN: ins_f_byte(predefs[expr->v.number >> 8].token); break; case FP_FUNCTIONAL: case FP_FUNCTIONAL | FP_NOT_BINDABLE: { int addr, save_current_num_values = current_num_values; ins_byte(expr->v.number >> 8); addr = CURRENT_PROGRAM_SIZE; ins_short(0); current_num_values = expr->r.expr ? expr->r.expr->kind : 0; i_generate_node(expr->l.expr); current_num_values = save_current_num_values; ins_f_byte(F_RETURN); upd_short(addr, CURRENT_PROGRAM_SIZE - addr - 2); break; } } #else if (expr->l.expr) i_generate_node(expr->l.expr); i_generate_node(expr->r.expr); ins_f_byte(F_FUNCTION_CONSTRUCTOR); ins_byte(expr->v.number); #endif break; #ifdef NEW_FUNCTIONS case NODE_ANON_FUNC: { int addr; ins_f_byte(F_FUNCTION_CONSTRUCTOR); ins_byte(FP_ANONYMOUS); ins_byte(expr->v.number); ins_byte(expr->l.number); addr = CURRENT_PROGRAM_SIZE; ins_short(0); i_generate_node(expr->r.expr); upd_short(addr, CURRENT_PROGRAM_SIZE - addr - 2); break; } #endif default: DEBUG_CHECK1(expr->kind < BASE, "Unknown eoperator %s in i_generate_node.\n", get_f_name(expr->kind)); generate_expr_list(expr->r.expr); ins_f_byte(expr->kind); if (expr->v.number != -1) ins_byte(expr->v.number); } }