ds2.10/bin/
ds2.10/extra/
ds2.10/extra/crat/
ds2.10/extra/creremote/
ds2.10/extra/mingw/
ds2.10/extra/wolfpaw/
ds2.10/fluffos-2.16-ds05/
ds2.10/fluffos-2.16-ds05/Win32/
ds2.10/fluffos-2.16-ds05/compat/
ds2.10/fluffos-2.16-ds05/compat/simuls/
ds2.10/fluffos-2.16-ds05/include/
ds2.10/fluffos-2.16-ds05/testsuite/
ds2.10/fluffos-2.16-ds05/testsuite/clone/
ds2.10/fluffos-2.16-ds05/testsuite/command/
ds2.10/fluffos-2.16-ds05/testsuite/data/
ds2.10/fluffos-2.16-ds05/testsuite/etc/
ds2.10/fluffos-2.16-ds05/testsuite/include/
ds2.10/fluffos-2.16-ds05/testsuite/inherit/
ds2.10/fluffos-2.16-ds05/testsuite/inherit/master/
ds2.10/fluffos-2.16-ds05/testsuite/log/
ds2.10/fluffos-2.16-ds05/testsuite/single/
ds2.10/fluffos-2.16-ds05/testsuite/single/tests/compiler/
ds2.10/fluffos-2.16-ds05/testsuite/single/tests/efuns/
ds2.10/fluffos-2.16-ds05/testsuite/single/tests/operators/
ds2.10/fluffos-2.16-ds05/testsuite/u/
ds2.10/lib/cmds/admins/
ds2.10/lib/cmds/common/
ds2.10/lib/cmds/creators/include/
ds2.10/lib/daemon/services/
ds2.10/lib/daemon/tmp/
ds2.10/lib/doc/
ds2.10/lib/doc/bguide/
ds2.10/lib/doc/efun/all/
ds2.10/lib/doc/efun/arrays/
ds2.10/lib/doc/efun/buffers/
ds2.10/lib/doc/efun/compile/
ds2.10/lib/doc/efun/floats/
ds2.10/lib/doc/efun/functions/
ds2.10/lib/doc/efun/general/
ds2.10/lib/doc/efun/mixed/
ds2.10/lib/doc/efun/numbers/
ds2.10/lib/doc/efun/parsing/
ds2.10/lib/doc/help/classes/
ds2.10/lib/doc/help/races/
ds2.10/lib/doc/lfun/
ds2.10/lib/doc/lfun/all/
ds2.10/lib/doc/lfun/lib/abilities/
ds2.10/lib/doc/lfun/lib/armor/
ds2.10/lib/doc/lfun/lib/bank/
ds2.10/lib/doc/lfun/lib/bot/
ds2.10/lib/doc/lfun/lib/clay/
ds2.10/lib/doc/lfun/lib/clean/
ds2.10/lib/doc/lfun/lib/clerk/
ds2.10/lib/doc/lfun/lib/client/
ds2.10/lib/doc/lfun/lib/combat/
ds2.10/lib/doc/lfun/lib/connect/
ds2.10/lib/doc/lfun/lib/container/
ds2.10/lib/doc/lfun/lib/corpse/
ds2.10/lib/doc/lfun/lib/creator/
ds2.10/lib/doc/lfun/lib/daemon/
ds2.10/lib/doc/lfun/lib/damage/
ds2.10/lib/doc/lfun/lib/deterioration/
ds2.10/lib/doc/lfun/lib/donate/
ds2.10/lib/doc/lfun/lib/door/
ds2.10/lib/doc/lfun/lib/equip/
ds2.10/lib/doc/lfun/lib/file/
ds2.10/lib/doc/lfun/lib/fish/
ds2.10/lib/doc/lfun/lib/fishing/
ds2.10/lib/doc/lfun/lib/flashlight/
ds2.10/lib/doc/lfun/lib/follow/
ds2.10/lib/doc/lfun/lib/ftp_client/
ds2.10/lib/doc/lfun/lib/ftp_data_connection/
ds2.10/lib/doc/lfun/lib/fuel/
ds2.10/lib/doc/lfun/lib/furnace/
ds2.10/lib/doc/lfun/lib/genetics/
ds2.10/lib/doc/lfun/lib/holder/
ds2.10/lib/doc/lfun/lib/id/
ds2.10/lib/doc/lfun/lib/interactive/
ds2.10/lib/doc/lfun/lib/lamp/
ds2.10/lib/doc/lfun/lib/leader/
ds2.10/lib/doc/lfun/lib/light/
ds2.10/lib/doc/lfun/lib/limb/
ds2.10/lib/doc/lfun/lib/living/
ds2.10/lib/doc/lfun/lib/load/
ds2.10/lib/doc/lfun/lib/look/
ds2.10/lib/doc/lfun/lib/manipulate/
ds2.10/lib/doc/lfun/lib/meal/
ds2.10/lib/doc/lfun/lib/messages/
ds2.10/lib/doc/lfun/lib/player/
ds2.10/lib/doc/lfun/lib/poison/
ds2.10/lib/doc/lfun/lib/position/
ds2.10/lib/doc/lfun/lib/post_office/
ds2.10/lib/doc/lfun/lib/potion/
ds2.10/lib/doc/lfun/lib/room/
ds2.10/lib/doc/lfun/lib/server/
ds2.10/lib/doc/lfun/lib/spell/
ds2.10/lib/doc/lfun/lib/torch/
ds2.10/lib/doc/lfun/lib/vendor/
ds2.10/lib/doc/lfun/lib/virt_sky/
ds2.10/lib/doc/lfun/lib/weapon/
ds2.10/lib/doc/lfun/lib/worn_storage/
ds2.10/lib/doc/lpc/constructs/
ds2.10/lib/doc/lpc/etc/
ds2.10/lib/doc/lpc/intermediate/
ds2.10/lib/doc/lpc/types/
ds2.10/lib/doc/misc/
ds2.10/lib/doc/old/
ds2.10/lib/doc/phints/
ds2.10/lib/domains/
ds2.10/lib/domains/Praxis/adm/
ds2.10/lib/domains/Praxis/attic/
ds2.10/lib/domains/Praxis/cemetery/mon/
ds2.10/lib/domains/Praxis/data/
ds2.10/lib/domains/Praxis/death/
ds2.10/lib/domains/Praxis/mountains/
ds2.10/lib/domains/Praxis/obj/armour/
ds2.10/lib/domains/Praxis/obj/magic/
ds2.10/lib/domains/Praxis/obj/weapon/
ds2.10/lib/domains/Praxis/orc_valley/
ds2.10/lib/domains/Ylsrim/
ds2.10/lib/domains/Ylsrim/adm/
ds2.10/lib/domains/Ylsrim/armor/
ds2.10/lib/domains/Ylsrim/broken/
ds2.10/lib/domains/Ylsrim/fish/
ds2.10/lib/domains/Ylsrim/meal/
ds2.10/lib/domains/Ylsrim/npc/
ds2.10/lib/domains/Ylsrim/obj/
ds2.10/lib/domains/Ylsrim/virtual/
ds2.10/lib/domains/Ylsrim/weapon/
ds2.10/lib/domains/alpha/room/
ds2.10/lib/domains/alpha/virtual/
ds2.10/lib/domains/campus/adm/
ds2.10/lib/domains/campus/etc/
ds2.10/lib/domains/campus/meals/
ds2.10/lib/domains/campus/txt/ai/charles/
ds2.10/lib/domains/campus/txt/ai/charles/bak2/
ds2.10/lib/domains/campus/txt/ai/charles/bak2/bak1/
ds2.10/lib/domains/campus/txt/ai/charly/
ds2.10/lib/domains/campus/txt/ai/charly/bak/
ds2.10/lib/domains/campus/txt/jenny/
ds2.10/lib/domains/cave/doors/
ds2.10/lib/domains/cave/etc/
ds2.10/lib/domains/cave/meals/
ds2.10/lib/domains/cave/weap/
ds2.10/lib/domains/default/chamber/
ds2.10/lib/domains/default/creator/
ds2.10/lib/domains/default/doors/
ds2.10/lib/domains/default/etc/
ds2.10/lib/domains/default/vehicle/
ds2.10/lib/domains/default/virtual/
ds2.10/lib/domains/town/save/
ds2.10/lib/domains/town/txt/shame/
ds2.10/lib/domains/town/virtual/
ds2.10/lib/domains/town/virtual/bottom/
ds2.10/lib/domains/town/virtual/space/
ds2.10/lib/estates/
ds2.10/lib/ftp/
ds2.10/lib/lib/comp/
ds2.10/lib/lib/daemons/
ds2.10/lib/lib/daemons/include/
ds2.10/lib/lib/lvs/
ds2.10/lib/lib/user/
ds2.10/lib/lib/virtual/
ds2.10/lib/log/
ds2.10/lib/log/adm/
ds2.10/lib/log/archive/
ds2.10/lib/log/chan/
ds2.10/lib/log/errors/
ds2.10/lib/log/law/adm/
ds2.10/lib/log/law/email/
ds2.10/lib/log/law/names/
ds2.10/lib/log/law/sites-misc/
ds2.10/lib/log/law/sites-register/
ds2.10/lib/log/law/sites-tempban/
ds2.10/lib/log/law/sites-watch/
ds2.10/lib/log/open/
ds2.10/lib/log/reports/
ds2.10/lib/log/router/
ds2.10/lib/log/secure/
ds2.10/lib/log/watch/
ds2.10/lib/obj/book_source/
ds2.10/lib/obj/include/
ds2.10/lib/powers/prayers/
ds2.10/lib/powers/spells/
ds2.10/lib/realms/template/
ds2.10/lib/realms/template/adm/
ds2.10/lib/realms/template/area/
ds2.10/lib/realms/template/area/armor/
ds2.10/lib/realms/template/area/npc/
ds2.10/lib/realms/template/area/obj/
ds2.10/lib/realms/template/area/room/
ds2.10/lib/realms/template/area/weap/
ds2.10/lib/realms/template/bak/
ds2.10/lib/realms/template/cmds/
ds2.10/lib/save/kills/o/
ds2.10/lib/secure/cfg/classes/
ds2.10/lib/secure/cmds/builders/
ds2.10/lib/secure/cmds/creators/include/
ds2.10/lib/secure/cmds/players/include/
ds2.10/lib/secure/daemon/imc2server/
ds2.10/lib/secure/daemon/include/
ds2.10/lib/secure/lib/
ds2.10/lib/secure/lib/include/
ds2.10/lib/secure/lib/net/include/
ds2.10/lib/secure/lib/std/
ds2.10/lib/secure/log/adm/
ds2.10/lib/secure/log/bak/
ds2.10/lib/secure/log/intermud/
ds2.10/lib/secure/log/network/
ds2.10/lib/secure/modules/
ds2.10/lib/secure/npc/
ds2.10/lib/secure/obj/include/
ds2.10/lib/secure/room/
ds2.10/lib/secure/save/
ds2.10/lib/secure/save/backup/
ds2.10/lib/secure/save/boards/
ds2.10/lib/secure/save/players/g/
ds2.10/lib/secure/tmp/
ds2.10/lib/secure/upgrades/files/
ds2.10/lib/secure/verbs/creators/
ds2.10/lib/std/board/
ds2.10/lib/std/lib/
ds2.10/lib/verbs/admins/include/
ds2.10/lib/verbs/builders/
ds2.10/lib/verbs/common/
ds2.10/lib/verbs/common/include/
ds2.10/lib/verbs/creators/
ds2.10/lib/verbs/creators/include/
ds2.10/lib/verbs/rooms/
ds2.10/lib/verbs/rooms/include/
ds2.10/lib/www/client/
ds2.10/lib/www/errors/
ds2.10/lib/www/images/
ds2.10/win32/
#define SUPPRESS_COMPILER_INLINES
#include "std.h"
#include "generate.h"
#include "compiler.h"

static parse_node_t *optimize (parse_node_t *);
static parse_node_t **last_local_refs = 0;
static int optimizer_num_locals;

/* Document optimizations here so we can make sure they don't interfere.
 *
 * Transfer of dying variables:
 * . If the last F_LOCAL was not in a loop, replace with transfer_local.
 * . Similarly, if an assign is done, change the last use to a transfer if safe
 * CAVEATS: we ignore while_dec, loop_cond, and loop_incr.  Justification is
 * that transfer_local doesn't clobber ints since it just sets type to T_NUMBER
 * This optimization also can't deal with code motion.  Since it assumes the
 * order optimized is the same as the order emitted.
 * It also can't detect that a variable dies along multiple branches, so:
 * if (y) { use(x); } else { use(x); } x = 1;
 * doesn't get optimized.
 */

static void
optimize_expr_list (parse_node_t * expr) {
    if (!expr) return;
    do {
        expr->v.expr = optimize(expr->v.expr);
    } while ((expr = expr->r.expr));
}

static void
optimize_lvalue_list (parse_node_t * expr) {
    while ((expr = expr->r.expr)) {
        expr->v.expr = optimize(expr->l.expr);
    }
}

#define OPT(x) x = optimize(x)
#define OPTIMIZER_IN_LOOP        1
#define OPTIMIZER_IN_COND	 2 /* switch or if or ?: */
static int optimizer_state = 0;

static parse_node_t *
optimize (parse_node_t * expr) {
    if (!expr) return 0;

    switch (expr->kind) {
        case NODE_TERNARY_OP:
            OPT(expr->l.expr);
            OPT(expr->r.expr->l.expr);
            OPT(expr->r.expr->r.expr);
            break;
        case NODE_BINARY_OP:
            OPT(expr->l.expr);
            if (expr->v.number == F_ASSIGN) {
                if (IS_NODE(expr->r.expr, NODE_OPCODE_1, F_LOCAL_LVALUE)) {
                    if (!optimizer_state) {
                        int x = expr->r.expr->l.number;

                        if (last_local_refs[x]) {
                            last_local_refs[x]->v.number = F_TRANSFER_LOCAL;
                            last_local_refs[x] = 0;
                        }
                    }
                }
            }
            OPT(expr->r.expr);
            break;
        case NODE_UNARY_OP:
            OPT(expr->r.expr);
            break;
        case NODE_OPCODE:
            break;
        case NODE_TERNARY_OP_1:
            OPT(expr->l.expr);
            OPT(expr->r.expr->l.expr);
            OPT(expr->r.expr->r.expr);
            break;
        case NODE_BINARY_OP_1:
            OPT(expr->l.expr);
            OPT(expr->r.expr);
            break;
        case NODE_UNARY_OP_1:
            OPT(expr->r.expr);
            if (expr->v.number == F_VOID_ASSIGN_LOCAL) {
                if (last_local_refs[expr->l.number] && !optimizer_state) {
                    last_local_refs[expr->l.number]->v.number = F_TRANSFER_LOCAL;
                    last_local_refs[expr->l.number] = 0;
                }
            }
            break;
        case NODE_OPCODE_1:
            if (expr->v.number == F_LOCAL || expr->v.number == F_LOCAL_LVALUE) {
                if (expr->v.number == F_LOCAL) {
                    if(!optimizer_state) {
                        last_local_refs[expr->l.number] = expr;
                        break;
                    }
                }
                last_local_refs[expr->l.number] = 0;
            }
            break;
        case NODE_OPCODE_2:
            break;
        case NODE_RETURN:
            OPT(expr->r.expr);
            break;
        case NODE_STRING:
        case NODE_REAL:
        case NODE_NUMBER:
            break;
        case NODE_LAND_LOR:
        case NODE_BRANCH_LINK:
            {
                int in_cond = (optimizer_state & OPTIMIZER_IN_COND);

                OPT(expr->l.expr);
                optimizer_state |= OPTIMIZER_IN_COND;
                OPT(expr->r.expr);
                optimizer_state &= ~OPTIMIZER_IN_COND;
                optimizer_state |= in_cond;
                break;
            }
        case NODE_CALL_2:
        case NODE_CALL_1:
        case NODE_CALL:
            optimize_expr_list(expr->r.expr);
            break;
        case NODE_TWO_VALUES:
            OPT(expr->l.expr);
            OPT(expr->r.expr);
            break;
        case NODE_CONTROL_JUMP:
        case NODE_PARAMETER:
        case NODE_PARAMETER_LVALUE:
            break;
        case NODE_IF:
            {
                int in_cond;
                OPT(expr->v.expr);
                in_cond = (optimizer_state & OPTIMIZER_IN_COND);
                optimizer_state |= OPTIMIZER_IN_COND;
                OPT(expr->l.expr);
                OPT(expr->r.expr);
                optimizer_state &= ~OPTIMIZER_IN_COND;
                optimizer_state |= in_cond;
                break;
            }
        case NODE_LOOP:
            {
                int in_loop = (optimizer_state & OPTIMIZER_IN_LOOP);
                optimizer_state |= OPTIMIZER_IN_LOOP;
                OPT(expr->v.expr);
                OPT(expr->l.expr);
                OPT(expr->r.expr);
                optimizer_state &= ~OPTIMIZER_IN_LOOP;
                optimizer_state |= in_loop;
                break;
            }
        case NODE_FOREACH:
            OPT(expr->l.expr);
            OPT(expr->r.expr);
            OPT(expr->v.expr);
            break;
        case NODE_CASE_NUMBER:
        case NODE_CASE_STRING:
        case NODE_DEFAULT:
            break;
        case NODE_SWITCH_STRINGS:
        case NODE_SWITCH_NUMBERS:
        case NODE_SWITCH_DIRECT:
        case NODE_SWITCH_RANGES:
            {
                int in_cond;
                OPT(expr->l.expr);
                in_cond = (optimizer_state & OPTIMIZER_IN_COND);
                optimizer_state |= OPTIMIZER_IN_COND;
                OPT(expr->r.expr);
                optimizer_state &= ~OPTIMIZER_IN_COND;
                optimizer_state |= in_cond;
                break;
            }
        case NODE_CATCH:
            OPT(expr->r.expr);
            break;
        case NODE_LVALUE_EFUN:
            OPT(expr->l.expr);
            optimize_lvalue_list(expr->r.expr);
            break;

        case NODE_FUNCTION_CONSTRUCTOR:
            /* Don't optimize inside of these; we'll get confused by local vars
             * since it's a separate frame, etc
             *
             * OPT(expr->r.expr);
             *
             * BUT make sure to optimize the things which AREN'T part of that
             * frame, namely, the arguments, otherwise we will screw up:
             *
             * use(local); return (: foo, local :);       // local evaluated at
             * use(local); return (: ... $(local) ... :); // construction time
             */
            if (expr->r.expr)
                optimize_expr_list(expr->r.expr); /* arguments */
            break;
        case NODE_ANON_FUNC:
            break;
        case NODE_EFUN:
            optimize_expr_list(expr->r.expr);
            break;
        default:
            break;
    }
    return expr;
}

#ifdef DEBUG
char *lpc_tree_name[] = {
    "return", "two values", "opcode", "opcode_1", "opcode_2",
    "unary op", "unary op_1", "binary op", "binary op_1",
    "ternary op", "ternary op_1", "control jump", "loop", "call",
    "call_1", "call_2", "&& ||", "foreach", "lvalue_efun", "switch_range",
    "switch_string", "switch_direct", "switch_number", "case_number",
    "case_string", "default", "if", "branch link", "parameter",
    "parameter_lvalue", "efun", "anon func", "real", "number",
    "string", "function", "catch"
};

static void lpc_tree (parse_node_t * dest, int num) {
    parse_node_t *pn;

    dest->kind = NODE_CALL;
    dest->v.number = F_AGGREGATE;
    dest->type = TYPE_ANY | TYPE_MOD_ARRAY;
    dest->l.number = num;
    if (!num)
        dest->r.expr = 0;
    else {
        dest->r.expr = new_node_no_line();
        dest->r.expr->kind = num--;
        pn = dest->r.expr;
        while (num--) {
            pn->r.expr = new_node_no_line();
            pn->type = 0;
            pn = pn->r.expr;
        }
        pn->type = 0;
        pn->r.expr = 0;
        dest->r.expr->l.expr = pn;
    }	
}

static void lpc_tree_number (parse_node_t * dest, int num) {
    CREATE_NUMBER(dest->v.expr, num);
}

static void lpc_tree_real (parse_node_t * dest, float real) {
    CREATE_REAL(dest->v.expr, real);
}

static void lpc_tree_expr (parse_node_t * dest, parse_node_t * expr) {
    dest->v.expr = new_node_no_line();
    lpc_tree_form(expr, dest->v.expr);
}

static void lpc_tree_string (parse_node_t * dest, const char * str) {
    CREATE_STRING(dest->v.expr, str);
}

static void lpc_tree_list (parse_node_t * dest, parse_node_t * expr) {
    parse_node_t *pn;
    int num = 0;

    pn = expr;
    while (pn) {
        pn = pn->r.expr;
        num++;
    }

    dest->v.expr = new_node_no_line();
    lpc_tree(dest->v.expr, num);
    dest = dest->v.expr;
    while (expr) {
        dest = dest->r.expr;
        lpc_tree_expr(dest, expr->v.expr);
        expr = expr->r.expr;
    }
}

#define lpc_tree_opc(x, y) lpc_tree_string(x, query_instr_name(y & ~NOVALUE_USED_FLAG))

#define ARG_1 dest->r.expr
#define ARG_2 dest->r.expr->r.expr
#define ARG_3 dest->r.expr->r.expr->r.expr
#define ARG_4 dest->r.expr->r.expr->r.expr->r.expr
#define ARG_5 dest->r.expr->r.expr->r.expr->r.expr->r.expr

void 
lpc_tree_form (parse_node_t * expr, parse_node_t * dest) {
    if (!expr) {
        dest->kind = NODE_NUMBER;
        dest->type = TYPE_ANY;
        dest->v.number = 0;
        return;
    }

    switch (expr->kind) {
        case NODE_TERNARY_OP:
            lpc_tree(dest, 4);
            lpc_tree_opc(ARG_2, expr->r.expr->v.number);
            lpc_tree_expr(ARG_3, expr->l.expr);
            lpc_tree_expr(ARG_4, expr->r.expr);
            break;
        case NODE_TERNARY_OP_1:
            lpc_tree(dest, 5);
            lpc_tree_opc(ARG_2, expr->r.expr->v.number);
            lpc_tree_number(ARG_3, expr->type);
            lpc_tree_expr(ARG_4, expr->l.expr);
            lpc_tree_expr(ARG_5, expr->r.expr);
            break;
        case NODE_BINARY_OP:
        case NODE_LAND_LOR:
        case NODE_BRANCH_LINK:
            lpc_tree(dest, 4);
            lpc_tree_opc(ARG_2, expr->v.number);
            lpc_tree_expr(ARG_3, expr->l.expr);
            lpc_tree_expr(ARG_4, expr->r.expr);
            break;
        case NODE_TWO_VALUES:
            lpc_tree(dest, 3);
            lpc_tree_expr(ARG_2, expr->l.expr);
            lpc_tree_expr(ARG_3, expr->r.expr);
            break;
        case NODE_BINARY_OP_1:
            lpc_tree(dest, 5);
            lpc_tree_opc(ARG_2, expr->v.number);
            lpc_tree_number(ARG_3, expr->type);
            lpc_tree_expr(ARG_4, expr->l.expr);
            lpc_tree_expr(ARG_5, expr->r.expr);	
            break;
        case NODE_UNARY_OP:
            lpc_tree(dest, 3);
            lpc_tree_opc(ARG_2, expr->v.number);
            lpc_tree_expr(ARG_3, expr->r.expr);
            break;
        case NODE_UNARY_OP_1:
            lpc_tree(dest, 4);
            lpc_tree_opc(ARG_2, expr->v.number);
            lpc_tree_number(ARG_3, expr->l.number);
            lpc_tree_expr(ARG_4, expr->r.expr);
            break;
        case NODE_OPCODE:
            lpc_tree(dest, 2);
            lpc_tree_opc(ARG_2, expr->v.number);
            break;
        case NODE_CONTROL_JUMP:
        case NODE_PARAMETER:
        case NODE_PARAMETER_LVALUE:
            lpc_tree(dest, 2);
            lpc_tree_number(ARG_2, expr->v.number);
            break;
        case NODE_OPCODE_1:
            lpc_tree(dest, 3);
            lpc_tree_opc(ARG_2, expr->v.number);
            lpc_tree_number(ARG_3, expr->l.number);
            break;
        case NODE_OPCODE_2:
            lpc_tree(dest, 4);
            lpc_tree_opc(ARG_2, expr->v.number);
            lpc_tree_number(ARG_3, expr->l.number);
            lpc_tree_number(ARG_4, expr->r.number);
            break;
        case NODE_RETURN:
            lpc_tree(dest, 2);
            lpc_tree_expr(ARG_2, expr->r.expr);
            break;
        case NODE_STRING:
        case NODE_NUMBER:
            lpc_tree(dest, 2);
            lpc_tree_number(ARG_2, expr->v.number);
            break;
        case NODE_REAL:
            lpc_tree(dest, 2);
            lpc_tree_real(ARG_2, expr->v.real);
            break;
        case NODE_CALL_2:
        case NODE_CALL_1:
        case NODE_CALL:
            lpc_tree(dest, 4);
            lpc_tree_opc(ARG_2, expr->v.number);
            lpc_tree_list(ARG_3, expr->r.expr);
            lpc_tree_number(ARG_4, expr->l.number);
            break;
        case NODE_IF:
        case NODE_FOREACH:
            lpc_tree(dest, 4);
            lpc_tree_expr(ARG_2, expr->l.expr);
            lpc_tree_expr(ARG_3, expr->r.expr);
            lpc_tree_expr(ARG_4, expr->v.expr);
            break;
        case NODE_LOOP:
            lpc_tree(dest, 5);
            lpc_tree_number(ARG_2, expr->type);
            lpc_tree_expr(ARG_3, expr->v.expr);
            lpc_tree_expr(ARG_4, expr->r.expr);
            lpc_tree_expr(ARG_5, expr->l.expr);
            break;
        case NODE_CASE_NUMBER:
        case NODE_CASE_STRING:
        case NODE_DEFAULT:
            lpc_tree(dest, 1);
            break;
        case NODE_SWITCH_STRINGS:
        case NODE_SWITCH_NUMBERS:
        case NODE_SWITCH_DIRECT:
        case NODE_SWITCH_RANGES:
            lpc_tree(dest, 3);
            lpc_tree_expr(ARG_2, expr->l.expr);
            lpc_tree_expr(ARG_3, expr->r.expr);
            break;
        case NODE_CATCH:
            lpc_tree(dest, 2);
            lpc_tree_expr(ARG_2, expr->r.expr);
            break;
        case NODE_LVALUE_EFUN:
            lpc_tree(dest, 3);
            lpc_tree_expr(ARG_2, expr->l.expr);
            lpc_tree_list(ARG_3, expr->r.expr);
            break;
        case NODE_FUNCTION_CONSTRUCTOR:
        case NODE_EFUN:
            lpc_tree(dest, 3);
            lpc_tree_opc(ARG_2, expr->v.number);
            lpc_tree_list(ARG_3, expr->r.expr);
            break;
        default:
            lpc_tree(dest,1);
            lpc_tree_string(ARG_1, "!GARBAGE!");
            return;
    }
    lpc_tree_string(ARG_1, lpc_tree_name[expr->kind]);
}
#endif

short
generate (parse_node_t * node) {
    short where = CURRENT_PROGRAM_SIZE;

    if (num_parse_error) return 0;
    {
        i_generate_node(node);
    }
    free_tree();

    return where;
}

static void optimizer_start_function (int n) {
    if (n) {
        last_local_refs = CALLOCATE(n, parse_node_t *, TAG_COMPILER, "c_start_function");
        optimizer_num_locals = n;
        while (n--) {
            last_local_refs[n] = 0;
        }
    } else last_local_refs = 0;
}

static void optimizer_end_function (void) {
    int i;
    if (last_local_refs) {
        for (i = 0; i < optimizer_num_locals; i++) 
            if (last_local_refs[i]) {
                last_local_refs[i]->v.number = F_TRANSFER_LOCAL;
            }
        FREE(last_local_refs);
        last_local_refs = 0;
    }
}

short generate_function (function_t * f, parse_node_t * node, int num) {
    short ret;
    if (pragmas & PRAGMA_OPTIMIZE) {
        optimizer_start_function(num);
        optimizer_state = 0;
        node = optimize(node);
        optimizer_end_function();
    }
    ret = generate(node);
    return ret;
}

int
node_always_true (parse_node_t * node) {
    if (!node) return 1;
    if (node->kind == NODE_NUMBER)
        return node->v.number;
    return 0;
}

int
generate_conditional_branch (parse_node_t * node) {
    int branch;

    if (!node)
        return F_BBRANCH;

    /* only have to handle while (x != 0) since while (x == 0) will be
     * handled by the x == 0 -> !x and !x optimizations.
     */
    if (IS_NODE(node, NODE_BINARY_OP, F_NE)) {
        if (IS_NODE(node->r.expr, NODE_NUMBER, 0))
            node = node->l.expr;
        else if (IS_NODE(node->l.expr, NODE_NUMBER, 0))
            node = node->r.expr;
    }
    if (IS_NODE(node, NODE_UNARY_OP, F_NOT)) {
        node = node->r.expr;
        branch = F_BBRANCH_WHEN_ZERO;
    } else {
        branch = F_BBRANCH_WHEN_NON_ZERO;
        if (node->kind == NODE_NUMBER) {
            if (node->v.number == 0)
                branch = 0;
            else 
                branch = F_BBRANCH;
            node = 0;
        }
        if (node) {
            if (IS_NODE(node, NODE_BINARY_OP, F_LT)) {
                generate(node->l.expr);
                generate(node->r.expr);
                return F_BBRANCH_LT;
            }
            if (IS_NODE(node, NODE_OPCODE_1, F_WHILE_DEC)) {
                generate(node);
                return F_WHILE_DEC;
            }
        }
    }
    generate(node);
    return branch;
}

#ifdef DEBUG
void
dump_expr_list (parse_node_t * expr) {
    if (!expr) return;
    do {
        dump_tree(expr->v.expr);
    } while ((expr = expr->r.expr));
}

static void
dump_lvalue_list (parse_node_t * expr) {
    printf("(lvalue_list ");
            while ((expr = expr->r.expr))
            dump_tree(expr->l.expr);
            }

            void
            dump_tree (parse_node_t * expr) {
            if (!expr) return;

            switch (expr->kind) {
            case NODE_TERNARY_OP:
            printf("(%s ", instrs[expr->r.expr->v.number].name);
                dump_tree(expr->l.expr);
                expr = expr->r.expr;
                dump_tree(expr->l.expr);
                dump_tree(expr->r.expr);
                printf(")");
            break;
            case NODE_BINARY_OP:
            printf("(%s ", instrs[expr->v.number].name);
                dump_tree(expr->l.expr);
                dump_tree(expr->r.expr);
                printf(")");
                break;
            case NODE_UNARY_OP:
                printf("(%s ", instrs[expr->v.number].name);
                        dump_tree(expr->r.expr);
                        printf(")");
                        break;
            case NODE_OPCODE:
                        printf("(%s)", instrs[expr->v.number].name);
                        break;
            case NODE_TERNARY_OP_1:
                        {
                            int p = expr->type;
                            printf("(%s ", instrs[expr->r.expr->v.number].name);
                                    dump_tree(expr->l.expr);
                                    expr = expr->r.expr;
                                    dump_tree(expr->l.expr);
                                    dump_tree(expr->r.expr);
                                    printf(" %i)", p);
                                    break;
                        }
            case NODE_BINARY_OP_1:
                        printf("(%s ", instrs[expr->v.number].name);
                                dump_tree(expr->l.expr);
                                dump_tree(expr->r.expr);
                                printf(" %i)", expr->type);
                                break;
            case NODE_UNARY_OP_1:
                                printf("(%s ", instrs[expr->v.number].name);
                                        dump_tree(expr->r.expr);
                                        printf(" %i)", expr->l.number);
                                        break;
            case NODE_OPCODE_1:
                                        printf("(%s %i)", instrs[expr->v.number].name, expr->l.number);
                                        break;
            case NODE_OPCODE_2:
                                        printf("(%s %i %i)", instrs[expr->v.number].name, expr->l.number, expr->r.number);
                                        break;
            case NODE_RETURN:
                                        if (expr->r.expr) {
                                            printf("(return ");
                                                    dump_tree(expr->r.expr);
                                                    printf(")");
                                        } else {
                                            printf("(return_zero)");
                                        }
                                        break;
            case NODE_STRING:
                                        printf("(string %i)", expr->v.number);
                                        break;
            case NODE_REAL:
                                        printf("(real %f)", expr->v.real);
                                        break;
            case NODE_NUMBER:
                                        printf("(number %i)", expr->v.number);
                                        break;
            case NODE_LAND_LOR:
                                        if (expr->v.number == F_LAND)
                                            printf("(&& ");
                                                    else
                                                    printf("(|| ");
                                                        dump_tree(expr->l.expr);
                                                        dump_tree(expr->r.expr);
                                                        printf(")");
                                                    break;
                                                    case NODE_BRANCH_LINK:
                                                    printf("(branch_link ");
                                                        dump_tree(expr->l.expr);
                                                        dump_tree(expr->r.expr);
                                                        printf(")");
                                                    break;
                                                    case NODE_CALL_2:
                                                    printf("(%s %i %i %i ", instrs[expr->v.number].name, expr->l.number >> 16,
                                                expr->l.number & 0xffff, (expr->r.expr ? expr->r.expr->kind : 0));
                                                        dump_expr_list(expr->r.expr);
                                                        printf(")");
                                                    break;
                                                    case NODE_CALL_1:
                                                    printf("(%s %i %i ", instrs[expr->v.number].name, expr->l.number,
                                                        (expr->r.expr ? expr->r.expr->kind : 0));
                                                        dump_expr_list(expr->r.expr);
                                                        printf(")");
                                                        break;
                                                    case NODE_CALL:
                                                        printf("(%s %i ", instrs[expr->v.number].name, expr->l.number);
                                                                dump_expr_list(expr->r.expr);
                                                                printf(")");
                                                                break;
                                                    case NODE_TWO_VALUES:
                                                                dump_tree(expr->l.expr);
                                                                printf("\n");
                                                                dump_tree(expr->r.expr);
                                                                break;
                                                    case NODE_CONTROL_JUMP:
                                                                if (expr->v.number == CJ_BREAK_SWITCH) {
                                                                    printf("(break_switch)");
                                                                } else if (expr->v.number == CJ_BREAK) {
                                                                    printf("(break)");
                                                                } else if (expr->v.number == CJ_CONTINUE) {
                                                                    printf("(continue)");
                                                                } else {
                                                                    printf("(UNKNOWN CONTROL JUMP)");
                                                                }
                                                                break;
                                                    case NODE_PARAMETER:
                                                                printf("(parameter %i)", expr->v.number);
                                                                break;
                                                    case NODE_PARAMETER_LVALUE:
                                                                printf("(parameter_lvalue %i)", expr->v.number);
                                                                break;
                                                    case NODE_IF:
                                                                printf("(if ");
                                                                        dump_tree(expr->v.expr);
                                                                        printf("\n");
                                                                        dump_tree(expr->l.expr);
                                                                        if (expr->r.expr) {
                                                                        printf("\n");
                                                                        dump_tree(expr->r.expr);
                                                                        }
                                                                        printf(")\n");
                                                                        break;
                                                    case NODE_LOOP:
                                                                        printf("(loop %i\n", expr->type);
                                                                                dump_tree(expr->v.expr);
                                                                                printf("\n");
                                                                                dump_tree(expr->l.expr);
                                                                                printf("\n");
                                                                                dump_tree(expr->r.expr);
                                                                                printf(")\n");
                                                                                break;
                                                    case NODE_FOREACH:
                                                                                printf("(foreach ");
                                                                                        dump_tree(expr->l.expr);
                                                                                        dump_tree(expr->r.expr);
                                                                                        dump_tree(expr->v.expr);
                                                                                        printf(")\n");
                                                                                        break;
                                                    case NODE_CASE_NUMBER:
                                                    case NODE_CASE_STRING:
                                                                                        printf("(case)");
                                                                                        break;
                                                    case NODE_DEFAULT:
                                                                                        printf("(default)");
                                                                                        break;
                                                    case NODE_SWITCH_STRINGS:
                                                    case NODE_SWITCH_NUMBERS:
                                                    case NODE_SWITCH_DIRECT:
                                                    case NODE_SWITCH_RANGES:
                                                                                        printf("(switch ");
                                                                                                dump_tree(expr->l.expr);
                                                                                                dump_tree(expr->r.expr);
                                                                                                printf(")");
                                                                                                break;
                                                    case NODE_CATCH:
                                                                                                printf("(catch ");
                                                                                                        dump_tree(expr->r.expr);
                                                                                                        printf(")");
                                                                                                        break;
                                                    case NODE_LVALUE_EFUN:
                                                                                                        printf("(lvalue_efun ");
                                                                                                                dump_tree(expr->l.expr);
                                                                                                                dump_lvalue_list(expr->r.expr);
                                                                                                                printf(")");
                                                                                                                break;
                                                    case NODE_FUNCTION_CONSTRUCTOR:
                                                                                                                printf("(function %i ", expr->v.number & 0xff);
                                                                                                                        if (expr->r.expr) {
                                                                                                                        printf("(array ");
                                                                                                                            dump_expr_list(expr->r.expr);
                                                                                                                            printf(")");
                                                                                                                        } else {
                                                                                                                        printf("(number 0)");
                                                                                                                        }
                                                                                                                        switch (expr->v.number & 0xff) {
                                                                                                                        case FP_SIMUL:
                                                                                                                        printf("(fp-simul %i)", expr->v.number >> 8);
                                                                                                                        break;
                                                                                                                        case FP_LOCAL:
                                                                                                                        printf("(fp-local %i)", expr->v.number >> 8);
                                                                                                                        break;
                                                                                                                        case FP_EFUN:
                                                                                                                        printf("(fp-efun %s)", instrs[expr->v.number >> 8].name);
                                                                                                                        break;
                                                                                                                        case FP_FUNCTIONAL:
                                                                                                                        case FP_FUNCTIONAL | FP_NOT_BINDABLE:
                                                                                                                        printf("(fp-functional %i ", expr->v.number >> 8);
                                                                                                                            dump_tree(expr->l.expr);
                                                                                                                            printf(")");
                                                                                                                            break;
                                                                                                                        }
                                                                                                                        printf(" %i)", expr->v.number >> 8);
                                                                                                                        break;
                                                    case NODE_ANON_FUNC:
                                                                                                                        printf("(anon-func %i %i ", expr->v.number, expr->l.number);
                                                                                                                                dump_tree(expr->r.expr);
                                                                                                                                printf(")");
                                                                                                                                break;
                                                    case NODE_EFUN:
                                                                                                                                printf("(%s ", instrs[expr->v.number & ~NOVALUE_USED_FLAG].name);
                                                                                                                                        dump_expr_list(expr->r.expr);
                                                                                                                                        printf(")");
                                                                                                                                        break;
                                                    default:
                                                                                                                                        printf("(unknown)");
                                                                                                                                        break;
            }
            fflush(stdout);
            }
#endif