예제 #1
0
파일: icode.c 프로젝트: Yuffster/fluffOS
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));
    }
}
예제 #2
0
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);
}
예제 #3
0
파일: icode.c 프로젝트: Yuffster/fluffOS
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;
}
예제 #4
0
파일: icode.c 프로젝트: Yuffster/fluffOS
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;
    }
}
예제 #5
0
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
}
예제 #6
0
파일: icode.c 프로젝트: Yuffster/fluffOS
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);
    }
}
예제 #7
0
/*
 * 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);
    }
}
예제 #8
0
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;
}
예제 #9
0
파일: icode.c 프로젝트: Yuffster/fluffOS
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
        }
    }
}
예제 #10
0
파일: icode.c 프로젝트: Yuffster/fluffOS
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);
    }
예제 #11
0
파일: icode.c 프로젝트: Yuffster/fluffOS
/*
 * 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);
}
예제 #12
0
void
i_generate_function_call P2(short, f, char, num) {
  ins_f_byte(F_CALL_FUNCTION_BY_ADDRESS);
  ins_short(f);
  ins_byte(0);
}
예제 #13
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);
   }
}