final_realms_fluffos_v1/
final_realms_fluffos_v1/bin/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/ChangeLog.old/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/Win32/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/compat/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/compat/simuls/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/include/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/testsuite/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/testsuite/clone/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/testsuite/command/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/testsuite/data/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/testsuite/etc/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/testsuite/include/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/testsuite/inherit/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/testsuite/inherit/master/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/testsuite/log/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/testsuite/single/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/testsuite/single/tests/compiler/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/testsuite/single/tests/efuns/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/testsuite/single/tests/operators/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/testsuite/u/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/tmp/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/windows/
final_realms_fluffos_v1/lib/baseobs/guilds/
final_realms_fluffos_v1/lib/baseobs/misc/
final_realms_fluffos_v1/lib/baseobs/races/shadows/
final_realms_fluffos_v1/lib/cmds/god/
final_realms_fluffos_v1/lib/cmds/handlers/
final_realms_fluffos_v1/lib/cmds/handlers/cmds/
final_realms_fluffos_v1/lib/d/heaven/
final_realms_fluffos_v1/lib/d/heaven/heaven/ave/
final_realms_fluffos_v1/lib/d/mudlib/
final_realms_fluffos_v1/lib/d/newbie/
final_realms_fluffos_v1/lib/d/newbie/docs/
final_realms_fluffos_v1/lib/d/newbie/drow/armour/
final_realms_fluffos_v1/lib/d/newbie/drow/items/
final_realms_fluffos_v1/lib/d/newbie/drow/mobs/
final_realms_fluffos_v1/lib/d/newbie/drow/oldmobs/
final_realms_fluffos_v1/lib/d/newbie/drow/weapons/
final_realms_fluffos_v1/lib/d/newbie/duergar/weapons/
final_realms_fluffos_v1/lib/d/newbie/dwarf/weapons/
final_realms_fluffos_v1/lib/d/newbie/elf/cafe/
final_realms_fluffos_v1/lib/d/newbie/elf/chars/equip/
final_realms_fluffos_v1/lib/d/newbie/elf/items/armours/
final_realms_fluffos_v1/lib/d/newbie/elf/items/obj/
final_realms_fluffos_v1/lib/d/newbie/elf/items/weapons/
final_realms_fluffos_v1/lib/d/newbie/elf/quick_fix/
final_realms_fluffos_v1/lib/d/newbie/gnome/armour/
final_realms_fluffos_v1/lib/d/newbie/gnome/buildings/
final_realms_fluffos_v1/lib/d/newbie/gnome/items/
final_realms_fluffos_v1/lib/d/newbie/gnome/npcs/clones/
final_realms_fluffos_v1/lib/d/newbie/gnome/rooms/northrooms/
final_realms_fluffos_v1/lib/d/newbie/gnome/weapons/
final_realms_fluffos_v1/lib/d/newbie/goblin/armour/
final_realms_fluffos_v1/lib/d/newbie/goblin/items/
final_realms_fluffos_v1/lib/d/newbie/grads/log/
final_realms_fluffos_v1/lib/d/newbie/grads/npcs/
final_realms_fluffos_v1/lib/d/newbie/grads/rooms/
final_realms_fluffos_v1/lib/d/newbie/grads/rooms/cave1/
final_realms_fluffos_v1/lib/d/newbie/grads/temp/
final_realms_fluffos_v1/lib/d/newbie/guests/weapons/
final_realms_fluffos_v1/lib/d/newbie/half-elf/items/
final_realms_fluffos_v1/lib/d/newbie/half-elf/newroomss/
final_realms_fluffos_v1/lib/d/newbie/half-elf/rooms/
final_realms_fluffos_v1/lib/d/newbie/half-elf/rooms/castle/
final_realms_fluffos_v1/lib/d/newbie/half-elf/rooms/drows/
final_realms_fluffos_v1/lib/d/newbie/half-elf/rooms/savannah/
final_realms_fluffos_v1/lib/d/newbie/half-elf/rooms/secret/
final_realms_fluffos_v1/lib/d/newbie/half-elf/rooms/town/
final_realms_fluffos_v1/lib/d/newbie/halfling/
final_realms_fluffos_v1/lib/d/newbie/halfling/misc/
final_realms_fluffos_v1/lib/d/newbie/halfling/rooms/cave/
final_realms_fluffos_v1/lib/d/newbie/human/
final_realms_fluffos_v1/lib/d/newbie/human/armour/
final_realms_fluffos_v1/lib/d/newbie/human/monsters/
final_realms_fluffos_v1/lib/d/newbie/human/obj/
final_realms_fluffos_v1/lib/d/newbie/human/weapons/
final_realms_fluffos_v1/lib/d/newbie/lizard/armour/
final_realms_fluffos_v1/lib/d/newbie/lizard/items/
final_realms_fluffos_v1/lib/d/newbie/lizard/underwater/
final_realms_fluffos_v1/lib/d/newbie/lizard/weapons/
final_realms_fluffos_v1/lib/d/newbie/logs/
final_realms_fluffos_v1/lib/d/newbie/new_halfelf/
final_realms_fluffos_v1/lib/d/newbie/new_halfelf/npcs/
final_realms_fluffos_v1/lib/d/newbie/newdrow/npcs/
final_realms_fluffos_v1/lib/d/newbie/newdrow/rooms/
final_realms_fluffos_v1/lib/d/newbie/newelf/
final_realms_fluffos_v1/lib/d/newbie/newelf/chars/
final_realms_fluffos_v1/lib/d/newbie/newelf/npcs/
final_realms_fluffos_v1/lib/d/newbie/newelf/npcs/recopied/
final_realms_fluffos_v1/lib/d/newbie/newelf/obj/
final_realms_fluffos_v1/lib/d/newbie/newelf/quest_docs./
final_realms_fluffos_v1/lib/d/newbie/newken/
final_realms_fluffos_v1/lib/d/newbie/newken/chars/
final_realms_fluffos_v1/lib/d/newbie/newken/misc/
final_realms_fluffos_v1/lib/d/newbie/newken/npcs/
final_realms_fluffos_v1/lib/d/newbie/newken/obj/
final_realms_fluffos_v1/lib/d/newbie/newliz/
final_realms_fluffos_v1/lib/d/newbie/newliz/cave/
final_realms_fluffos_v1/lib/d/newbie/newliz/npcs/
final_realms_fluffos_v1/lib/d/newbie/orc/items/misc/
final_realms_fluffos_v1/lib/d/newbie/orc/items/weapons/
final_realms_fluffos_v1/lib/d/newbie/orc/tower/
final_realms_fluffos_v1/lib/d/vehicle/
final_realms_fluffos_v1/lib/doc/
final_realms_fluffos_v1/lib/doc/driver/
final_realms_fluffos_v1/lib/doc/driver/concepts/
final_realms_fluffos_v1/lib/doc/driver/driver/
final_realms_fluffos_v1/lib/doc/driver/efuns/arrays/
final_realms_fluffos_v1/lib/doc/driver/efuns/bitstrings/
final_realms_fluffos_v1/lib/doc/driver/efuns/communication/
final_realms_fluffos_v1/lib/doc/driver/efuns/core/
final_realms_fluffos_v1/lib/doc/driver/efuns/debugging/
final_realms_fluffos_v1/lib/doc/driver/efuns/filesystem/
final_realms_fluffos_v1/lib/doc/driver/efuns/interactive/
final_realms_fluffos_v1/lib/doc/driver/efuns/mappings/
final_realms_fluffos_v1/lib/doc/driver/efuns/objects/
final_realms_fluffos_v1/lib/doc/driver/efuns/security/
final_realms_fluffos_v1/lib/doc/driver/efuns/strings/
final_realms_fluffos_v1/lib/doc/driver/efuns/system/
final_realms_fluffos_v1/lib/doc/driver/efuns/types/
final_realms_fluffos_v1/lib/doc/driver/lpc/constructs/
final_realms_fluffos_v1/lib/doc/driver/lpc/types/
final_realms_fluffos_v1/lib/doc/driver/platforms/
final_realms_fluffos_v1/lib/doc/lpc/
final_realms_fluffos_v1/lib/doc/mail/
final_realms_fluffos_v1/lib/doc/man/
final_realms_fluffos_v1/lib/doc/man/html/
final_realms_fluffos_v1/lib/doc/man/html/applies/
final_realms_fluffos_v1/lib/doc/man/html/applies/parsing/
final_realms_fluffos_v1/lib/doc/man/html/driver/
final_realms_fluffos_v1/lib/doc/man/html/efuns/
final_realms_fluffos_v1/lib/doc/man/html/efuns/arrays/
final_realms_fluffos_v1/lib/doc/man/html/efuns/buffers/
final_realms_fluffos_v1/lib/doc/man/html/efuns/compile/
final_realms_fluffos_v1/lib/doc/man/html/efuns/floats/
final_realms_fluffos_v1/lib/doc/man/html/efuns/functions/
final_realms_fluffos_v1/lib/doc/man/html/efuns/general/
final_realms_fluffos_v1/lib/doc/man/html/efuns/numbers/
final_realms_fluffos_v1/lib/doc/man/html/efuns/parsing/
final_realms_fluffos_v1/lib/doc/man/local/
final_realms_fluffos_v1/lib/doc/man/local/applies/
final_realms_fluffos_v1/lib/doc/man/local/applies/interactive/
final_realms_fluffos_v1/lib/doc/man/local/applies/master/
final_realms_fluffos_v1/lib/doc/man/local/concepts/
final_realms_fluffos_v1/lib/doc/man/local/defines/
final_realms_fluffos_v1/lib/doc/man/local/driver/
final_realms_fluffos_v1/lib/doc/man/local/efuns/
final_realms_fluffos_v1/lib/doc/man/local/efuns/arrays/
final_realms_fluffos_v1/lib/doc/man/local/efuns/buffers/
final_realms_fluffos_v1/lib/doc/man/local/efuns/calls/
final_realms_fluffos_v1/lib/doc/man/local/efuns/compile/
final_realms_fluffos_v1/lib/doc/man/local/efuns/filesystem/
final_realms_fluffos_v1/lib/doc/man/local/efuns/floats/
final_realms_fluffos_v1/lib/doc/man/local/efuns/functions/
final_realms_fluffos_v1/lib/doc/man/local/efuns/general/
final_realms_fluffos_v1/lib/doc/man/local/efuns/interactive/
final_realms_fluffos_v1/lib/doc/man/local/efuns/internals/
final_realms_fluffos_v1/lib/doc/man/local/efuns/mappings/
final_realms_fluffos_v1/lib/doc/man/local/efuns/mudlib/
final_realms_fluffos_v1/lib/doc/man/local/efuns/numbers/
final_realms_fluffos_v1/lib/doc/man/local/efuns/objects/
final_realms_fluffos_v1/lib/doc/man/local/efuns/parsing/
final_realms_fluffos_v1/lib/doc/man/local/efuns/sockets/
final_realms_fluffos_v1/lib/doc/man/local/efuns/strings/
final_realms_fluffos_v1/lib/doc/man/local/efuns/system/
final_realms_fluffos_v1/lib/doc/man/local/historical/
final_realms_fluffos_v1/lib/doc/man/local/lfun/QC/
final_realms_fluffos_v1/lib/doc/man/local/lfun/events/
final_realms_fluffos_v1/lib/doc/man/local/lfun/monster/
final_realms_fluffos_v1/lib/doc/man/local/lfun/properties/
final_realms_fluffos_v1/lib/doc/man/local/lpc/
final_realms_fluffos_v1/lib/doc/man/local/lpc/constructs/
final_realms_fluffos_v1/lib/doc/man/local/lpc/types/
final_realms_fluffos_v1/lib/doc/man/local/standards/
final_realms_fluffos_v1/lib/doc/man/local/tutorials/
final_realms_fluffos_v1/lib/doc/man/local/tutorials/basic/
final_realms_fluffos_v1/lib/doc/man/local/tutorials/intermediate/
final_realms_fluffos_v1/lib/doc/man/mudos/applies/
final_realms_fluffos_v1/lib/doc/man/mudos/applies/interactive/
final_realms_fluffos_v1/lib/doc/man/mudos/applies/parsing/
final_realms_fluffos_v1/lib/doc/man/mudos/concepts/
final_realms_fluffos_v1/lib/doc/man/mudos/driver/
final_realms_fluffos_v1/lib/doc/man/mudos/efuns/arrays/
final_realms_fluffos_v1/lib/doc/man/mudos/efuns/buffers/
final_realms_fluffos_v1/lib/doc/man/mudos/efuns/calls/
final_realms_fluffos_v1/lib/doc/man/mudos/efuns/compile/
final_realms_fluffos_v1/lib/doc/man/mudos/efuns/filesystem/
final_realms_fluffos_v1/lib/doc/man/mudos/efuns/floats/
final_realms_fluffos_v1/lib/doc/man/mudos/efuns/functions/
final_realms_fluffos_v1/lib/doc/man/mudos/efuns/general/
final_realms_fluffos_v1/lib/doc/man/mudos/efuns/mappings/
final_realms_fluffos_v1/lib/doc/man/mudos/efuns/mixed/
final_realms_fluffos_v1/lib/doc/man/mudos/efuns/mudlib/
final_realms_fluffos_v1/lib/doc/man/mudos/efuns/numbers/
final_realms_fluffos_v1/lib/doc/man/mudos/efuns/parsing/
final_realms_fluffos_v1/lib/doc/man/mudos/lpc/constructs/
final_realms_fluffos_v1/lib/doc/man/mudos/lpc/types/
final_realms_fluffos_v1/lib/doc/races/
final_realms_fluffos_v1/lib/doc/races/old_race/
final_realms_fluffos_v1/lib/global/virtual/
final_realms_fluffos_v1/lib/global/wiz_backup/
final_realms_fluffos_v1/lib/net/config/
final_realms_fluffos_v1/lib/net/daemon/chars/
final_realms_fluffos_v1/lib/net/inherit/
final_realms_fluffos_v1/lib/net/intermud3/
final_realms_fluffos_v1/lib/net/intermud3/cmds/
final_realms_fluffos_v1/lib/net/intermud3/save/
final_realms_fluffos_v1/lib/net/intermud3/services/
final_realms_fluffos_v1/lib/net/obj/
final_realms_fluffos_v1/lib/net/old/
final_realms_fluffos_v1/lib/net/old/intermud/
final_realms_fluffos_v1/lib/net/old/intermud/adm/
final_realms_fluffos_v1/lib/net/old/intermud/services/
final_realms_fluffos_v1/lib/net/old/intermud/udp/
final_realms_fluffos_v1/lib/net/virtual/
final_realms_fluffos_v1/lib/obj/b_day/
final_realms_fluffos_v1/lib/obj/chars/
final_realms_fluffos_v1/lib/obj/handlers/lists/
final_realms_fluffos_v1/lib/obj/handlers/useless/
final_realms_fluffos_v1/lib/obj/monsters/
final_realms_fluffos_v1/lib/obj/roomgen/
final_realms_fluffos_v1/lib/obj/soul/
final_realms_fluffos_v1/lib/obj/vegetation/
final_realms_fluffos_v1/lib/obj/weapons/oldsys/
final_realms_fluffos_v1/lib/open/
final_realms_fluffos_v1/lib/players/g/
final_realms_fluffos_v1/lib/releasefiles/d/heaven/
final_realms_fluffos_v1/lib/releasefiles/d/mudlib/
final_realms_fluffos_v1/lib/releasefiles/d/newbie/
final_realms_fluffos_v1/lib/releasefiles/doc/
final_realms_fluffos_v1/lib/releasefiles/players/g/
final_realms_fluffos_v1/lib/releasefiles/save/
final_realms_fluffos_v1/lib/releasefiles/save/environ/
final_realms_fluffos_v1/lib/releasefiles/save/roomgen/
final_realms_fluffos_v1/lib/releasefiles/secure/
final_realms_fluffos_v1/lib/releasefiles/w/
final_realms_fluffos_v1/lib/releasefiles/w/god/
final_realms_fluffos_v1/lib/room/
final_realms_fluffos_v1/lib/save/
final_realms_fluffos_v1/lib/save/environ/
final_realms_fluffos_v1/lib/save/roomgen/
final_realms_fluffos_v1/lib/scripts/
final_realms_fluffos_v1/lib/secure/crerem/
final_realms_fluffos_v1/lib/secure/dom/
final_realms_fluffos_v1/lib/secure/log/
final_realms_fluffos_v1/lib/secure/misc/
final_realms_fluffos_v1/lib/std/adnd/
final_realms_fluffos_v1/lib/std/commands/shadows/
final_realms_fluffos_v1/lib/std/creator/
final_realms_fluffos_v1/lib/std/curses/
final_realms_fluffos_v1/lib/std/curses/old_sys/
final_realms_fluffos_v1/lib/std/curses/shadows/
final_realms_fluffos_v1/lib/std/dom/
final_realms_fluffos_v1/lib/std/effects/
final_realms_fluffos_v1/lib/std/effects/healing/
final_realms_fluffos_v1/lib/std/effects/other/
final_realms_fluffos_v1/lib/std/effects/poisons/
final_realms_fluffos_v1/lib/std/environ/
final_realms_fluffos_v1/lib/std/guilds/
final_realms_fluffos_v1/lib/std/guilds/priests/samples/
final_realms_fluffos_v1/lib/std/guilds/wizards/
final_realms_fluffos_v1/lib/std/living/baldy/
final_realms_fluffos_v1/lib/std/living/divstuff/
final_realms_fluffos_v1/lib/std/paran/
final_realms_fluffos_v1/lib/std/poisons/
final_realms_fluffos_v1/lib/std/poisons/shadows/
final_realms_fluffos_v1/lib/std/poisons/weapons/
final_realms_fluffos_v1/lib/std/race_groups/
final_realms_fluffos_v1/lib/std/room/
final_realms_fluffos_v1/lib/std/room/old/
final_realms_fluffos_v1/lib/std/rooms/
final_realms_fluffos_v1/lib/std/shadows/
final_realms_fluffos_v1/lib/std/shadows/test_shad/
final_realms_fluffos_v1/lib/std/socket/
final_realms_fluffos_v1/lib/std/spells/
final_realms_fluffos_v1/lib/std/vaults/
final_realms_fluffos_v1/lib/tmp/
final_realms_fluffos_v1/lib/w/
final_realms_fluffos_v1/lib/w/god/
final_realms_fluffos_v1/old/
final_realms_fluffos_v1/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