skylib_mudos_v1/
skylib_mudos_v1/bin/
skylib_mudos_v1/bin/db/
skylib_mudos_v1/mudlib/banish/a/
skylib_mudos_v1/mudlib/banish/b/
skylib_mudos_v1/mudlib/banish/c/
skylib_mudos_v1/mudlib/banish/d/
skylib_mudos_v1/mudlib/banish/e/
skylib_mudos_v1/mudlib/banish/f/
skylib_mudos_v1/mudlib/banish/g/
skylib_mudos_v1/mudlib/banish/h/
skylib_mudos_v1/mudlib/banish/j/
skylib_mudos_v1/mudlib/banish/l/
skylib_mudos_v1/mudlib/banish/m/
skylib_mudos_v1/mudlib/banish/n/
skylib_mudos_v1/mudlib/banish/o/
skylib_mudos_v1/mudlib/banish/p/
skylib_mudos_v1/mudlib/banish/r/
skylib_mudos_v1/mudlib/banish/s/
skylib_mudos_v1/mudlib/banish/t/
skylib_mudos_v1/mudlib/banish/u/
skylib_mudos_v1/mudlib/banish/w/
skylib_mudos_v1/mudlib/cmds/
skylib_mudos_v1/mudlib/cmds/admin/
skylib_mudos_v1/mudlib/cmds/guild-race/
skylib_mudos_v1/mudlib/cmds/guild-race/crafts/
skylib_mudos_v1/mudlib/cmds/guild-race/magic/
skylib_mudos_v1/mudlib/cmds/guild-race/other/
skylib_mudos_v1/mudlib/cmds/living/broken/
skylib_mudos_v1/mudlib/cmds/player/group_cmds/
skylib_mudos_v1/mudlib/d/admin/
skylib_mudos_v1/mudlib/d/admin/room/
skylib_mudos_v1/mudlib/d/admin/room/we_care/
skylib_mudos_v1/mudlib/d/admin/save/
skylib_mudos_v1/mudlib/d/admin/text/
skylib_mudos_v1/mudlib/d/learning/TinyTown/buildings/
skylib_mudos_v1/mudlib/d/learning/TinyTown/map/
skylib_mudos_v1/mudlib/d/learning/TinyTown/roads/
skylib_mudos_v1/mudlib/d/learning/chars/
skylib_mudos_v1/mudlib/d/learning/functions/
skylib_mudos_v1/mudlib/d/learning/handlers/
skylib_mudos_v1/mudlib/d/learning/help_topics/
skylib_mudos_v1/mudlib/d/learning/help_topics/npcs/
skylib_mudos_v1/mudlib/d/learning/help_topics/objects/
skylib_mudos_v1/mudlib/d/learning/help_topics/rcs_demo/
skylib_mudos_v1/mudlib/d/learning/help_topics/rcs_demo/RCS/
skylib_mudos_v1/mudlib/d/learning/help_topics/rooms/
skylib_mudos_v1/mudlib/d/learning/help_topics/rooms/crowd/
skylib_mudos_v1/mudlib/d/learning/help_topics/rooms/situations/
skylib_mudos_v1/mudlib/d/learning/save/
skylib_mudos_v1/mudlib/d/learning/school/
skylib_mudos_v1/mudlib/d/learning/school/add_sc/
skylib_mudos_v1/mudlib/d/learning/school/characters/
skylib_mudos_v1/mudlib/d/learning/school/general/
skylib_mudos_v1/mudlib/d/learning/school/getting-started/
skylib_mudos_v1/mudlib/d/learning/school/getting-started/basic_commands/
skylib_mudos_v1/mudlib/d/learning/school/getting-started/edtutor/
skylib_mudos_v1/mudlib/d/learning/school/getting-started/unix_tutor/
skylib_mudos_v1/mudlib/d/learning/school/items/
skylib_mudos_v1/mudlib/d/learning/school/npc_school/
skylib_mudos_v1/mudlib/d/learning/school/room_school/
skylib_mudos_v1/mudlib/d/learning/school/room_school/room_basic/
skylib_mudos_v1/mudlib/d/learning/school/room_school/situations/
skylib_mudos_v1/mudlib/d/learning/school/room_school/terrain_tutor/
skylib_mudos_v1/mudlib/d/learning/text/
skylib_mudos_v1/mudlib/d/liaison/
skylib_mudos_v1/mudlib/d/mudlib/
skylib_mudos_v1/mudlib/d/mudlib/changes/
skylib_mudos_v1/mudlib/d/playtesters/
skylib_mudos_v1/mudlib/d/playtesters/effects/
skylib_mudos_v1/mudlib/d/playtesters/handlers/
skylib_mudos_v1/mudlib/d/playtesters/items/
skylib_mudos_v1/mudlib/d/sage/
skylib_mudos_v1/mudlib/doc/
skylib_mudos_v1/mudlib/doc/creator/
skylib_mudos_v1/mudlib/doc/driver/
skylib_mudos_v1/mudlib/doc/driver/efuns/arrays/
skylib_mudos_v1/mudlib/doc/driver/efuns/buffers/
skylib_mudos_v1/mudlib/doc/driver/efuns/compile/
skylib_mudos_v1/mudlib/doc/driver/efuns/filesystem/
skylib_mudos_v1/mudlib/doc/driver/efuns/floats/
skylib_mudos_v1/mudlib/doc/driver/efuns/functions/
skylib_mudos_v1/mudlib/doc/driver/efuns/general/
skylib_mudos_v1/mudlib/doc/driver/efuns/mappings/
skylib_mudos_v1/mudlib/doc/driver/efuns/mixed/
skylib_mudos_v1/mudlib/doc/driver/efuns/mudlib/
skylib_mudos_v1/mudlib/doc/driver/efuns/numbers/
skylib_mudos_v1/mudlib/doc/driver/efuns/parsing/
skylib_mudos_v1/mudlib/doc/known_command/
skylib_mudos_v1/mudlib/doc/login/
skylib_mudos_v1/mudlib/doc/lpc/basic_manual/
skylib_mudos_v1/mudlib/doc/lpc/intermediate/
skylib_mudos_v1/mudlib/doc/new/add_command/
skylib_mudos_v1/mudlib/doc/new/events/
skylib_mudos_v1/mudlib/doc/new/handlers/
skylib_mudos_v1/mudlib/doc/new/living/race/
skylib_mudos_v1/mudlib/doc/new/living/spells/
skylib_mudos_v1/mudlib/doc/new/object/
skylib_mudos_v1/mudlib/doc/new/player/
skylib_mudos_v1/mudlib/doc/new/room/guild/
skylib_mudos_v1/mudlib/doc/new/room/outside/
skylib_mudos_v1/mudlib/doc/new/room/storeroom/
skylib_mudos_v1/mudlib/doc/object/
skylib_mudos_v1/mudlib/doc/playtesters/
skylib_mudos_v1/mudlib/doc/policy/
skylib_mudos_v1/mudlib/doc/weapons/
skylib_mudos_v1/mudlib/global/
skylib_mudos_v1/mudlib/global/creator/
skylib_mudos_v1/mudlib/global/handlers/
skylib_mudos_v1/mudlib/global/virtual/setup_compiler/
skylib_mudos_v1/mudlib/include/cmds/
skylib_mudos_v1/mudlib/include/effects/
skylib_mudos_v1/mudlib/include/npc/
skylib_mudos_v1/mudlib/include/room/
skylib_mudos_v1/mudlib/include/shops/
skylib_mudos_v1/mudlib/net/daemon/
skylib_mudos_v1/mudlib/net/daemon/chars/
skylib_mudos_v1/mudlib/net/inherit/
skylib_mudos_v1/mudlib/net/obj/
skylib_mudos_v1/mudlib/obj/amulets/
skylib_mudos_v1/mudlib/obj/b_day/
skylib_mudos_v1/mudlib/obj/clothes/
skylib_mudos_v1/mudlib/obj/dwarmours/plate/
skylib_mudos_v1/mudlib/obj/dwclothes/transport/horse/
skylib_mudos_v1/mudlib/obj/dwscabbards/
skylib_mudos_v1/mudlib/obj/dwweapons/axes/
skylib_mudos_v1/mudlib/obj/dwweapons/chains/
skylib_mudos_v1/mudlib/obj/faith/symbols/
skylib_mudos_v1/mudlib/obj/fungi/
skylib_mudos_v1/mudlib/obj/gatherables/
skylib_mudos_v1/mudlib/obj/instruments/
skylib_mudos_v1/mudlib/obj/magic/
skylib_mudos_v1/mudlib/obj/media/
skylib_mudos_v1/mudlib/obj/misc/player_shop/
skylib_mudos_v1/mudlib/obj/monster/godmother/
skylib_mudos_v1/mudlib/obj/monster/transport/
skylib_mudos_v1/mudlib/obj/rings/
skylib_mudos_v1/mudlib/obj/spells/
skylib_mudos_v1/mudlib/obj/stationery/
skylib_mudos_v1/mudlib/obj/stationery/envelopes/
skylib_mudos_v1/mudlib/obj/stationery/papers/
skylib_mudos_v1/mudlib/obj/toys/
skylib_mudos_v1/mudlib/obj/vessels/
skylib_mudos_v1/mudlib/obj/weapons/swords/
skylib_mudos_v1/mudlib/save/autodoc/
skylib_mudos_v1/mudlib/save/leaflets/
skylib_mudos_v1/mudlib/save/mail/
skylib_mudos_v1/mudlib/save/new_soul/data/
skylib_mudos_v1/mudlib/save/parcels/
skylib_mudos_v1/mudlib/save/playerinfo/
skylib_mudos_v1/mudlib/save/players/d/
skylib_mudos_v1/mudlib/save/random_names/
skylib_mudos_v1/mudlib/save/random_names/data/
skylib_mudos_v1/mudlib/save/terrains/
skylib_mudos_v1/mudlib/save/terrains/tutorial_desert/
skylib_mudos_v1/mudlib/save/terrains/tutorial_grassy_field/
skylib_mudos_v1/mudlib/save/terrains/tutorial_mountain/
skylib_mudos_v1/mudlib/save/todo_lists/
skylib_mudos_v1/mudlib/secure/
skylib_mudos_v1/mudlib/secure/cmds/admin/
skylib_mudos_v1/mudlib/secure/cmds/lord/
skylib_mudos_v1/mudlib/secure/config/
skylib_mudos_v1/mudlib/secure/handlers/autodoc/
skylib_mudos_v1/mudlib/secure/handlers/intermud/
skylib_mudos_v1/mudlib/secure/include/global/
skylib_mudos_v1/mudlib/secure/save/
skylib_mudos_v1/mudlib/secure/save/handlers/
skylib_mudos_v1/mudlib/secure/std/classes/
skylib_mudos_v1/mudlib/secure/std/modules/
skylib_mudos_v1/mudlib/std/commands/
skylib_mudos_v1/mudlib/std/commands/shadows/
skylib_mudos_v1/mudlib/std/creator/
skylib_mudos_v1/mudlib/std/dom/
skylib_mudos_v1/mudlib/std/effects/
skylib_mudos_v1/mudlib/std/effects/external/
skylib_mudos_v1/mudlib/std/effects/fighting/
skylib_mudos_v1/mudlib/std/effects/priest/
skylib_mudos_v1/mudlib/std/effects/room/
skylib_mudos_v1/mudlib/std/environ/
skylib_mudos_v1/mudlib/std/guilds/
skylib_mudos_v1/mudlib/std/guilds/old/
skylib_mudos_v1/mudlib/std/languages/
skylib_mudos_v1/mudlib/std/languages/BACKUPS/
skylib_mudos_v1/mudlib/std/liquids/
skylib_mudos_v1/mudlib/std/npc/
skylib_mudos_v1/mudlib/std/npc/goals/
skylib_mudos_v1/mudlib/std/npc/goals/basic/
skylib_mudos_v1/mudlib/std/npc/goals/misc/
skylib_mudos_v1/mudlib/std/npc/plans/
skylib_mudos_v1/mudlib/std/npc/plans/basic/
skylib_mudos_v1/mudlib/std/npc/types/
skylib_mudos_v1/mudlib/std/npc/types/helper/
skylib_mudos_v1/mudlib/std/npcs/
skylib_mudos_v1/mudlib/std/outsides/
skylib_mudos_v1/mudlib/std/races/shadows/
skylib_mudos_v1/mudlib/std/room/basic/topography/
skylib_mudos_v1/mudlib/std/room/controller/
skylib_mudos_v1/mudlib/std/room/inherit/topography/
skylib_mudos_v1/mudlib/std/room/topography/area/
skylib_mudos_v1/mudlib/std/room/topography/iroom/
skylib_mudos_v1/mudlib/std/room/topography/milestone/
skylib_mudos_v1/mudlib/std/shadows/curses/
skylib_mudos_v1/mudlib/std/shadows/disease/
skylib_mudos_v1/mudlib/std/shadows/fighting/
skylib_mudos_v1/mudlib/std/shadows/healing/
skylib_mudos_v1/mudlib/std/shadows/magic/
skylib_mudos_v1/mudlib/std/shadows/poison/
skylib_mudos_v1/mudlib/std/shadows/rituals/
skylib_mudos_v1/mudlib/std/shadows/room/
skylib_mudos_v1/mudlib/std/shops/controllers/
skylib_mudos_v1/mudlib/std/shops/objs/
skylib_mudos_v1/mudlib/std/shops/player_shop/
skylib_mudos_v1/mudlib/std/socket/
skylib_mudos_v1/mudlib/std/soul/
skylib_mudos_v1/mudlib/std/soul/d/
skylib_mudos_v1/mudlib/std/soul/e/
skylib_mudos_v1/mudlib/std/soul/i/
skylib_mudos_v1/mudlib/std/soul/j/
skylib_mudos_v1/mudlib/std/soul/k/
skylib_mudos_v1/mudlib/std/soul/l/
skylib_mudos_v1/mudlib/std/soul/n/
skylib_mudos_v1/mudlib/std/soul/o/
skylib_mudos_v1/mudlib/std/soul/q/
skylib_mudos_v1/mudlib/std/soul/u/
skylib_mudos_v1/mudlib/std/soul/v/
skylib_mudos_v1/mudlib/std/soul/y/
skylib_mudos_v1/mudlib/std/soul/z/
skylib_mudos_v1/mudlib/std/stationery/
skylib_mudos_v1/mudlib/w/
skylib_mudos_v1/mudlib/w/default/
skylib_mudos_v1/mudlib/w/default/armour/
skylib_mudos_v1/mudlib/w/default/clothes/
skylib_mudos_v1/mudlib/w/default/item/
skylib_mudos_v1/mudlib/w/default/npc/
skylib_mudos_v1/mudlib/w/default/room/
skylib_mudos_v1/mudlib/w/default/weapon/
skylib_mudos_v1/mudlib/www/
skylib_mudos_v1/mudlib/www/download/
skylib_mudos_v1/mudlib/www/java/
skylib_mudos_v1/mudlib/www/secure/
skylib_mudos_v1/mudlib/www/secure/lpc/advanced/
skylib_mudos_v1/mudlib/www/secure/lpc/intermediate/
skylib_mudos_v1/v22.2b14-DSv10/
skylib_mudos_v1/v22.2b14-DSv10/ChangeLog.old/
skylib_mudos_v1/v22.2b14-DSv10/Win32/
skylib_mudos_v1/v22.2b14-DSv10/compat/
skylib_mudos_v1/v22.2b14-DSv10/compat/simuls/
skylib_mudos_v1/v22.2b14-DSv10/include/
skylib_mudos_v1/v22.2b14-DSv10/mudlib/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/clone/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/command/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/data/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/etc/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/include/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/inherit/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/inherit/master/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/log/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/single/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/single/tests/compiler/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/single/tests/efuns/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/single/tests/operators/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/u/
skylib_mudos_v1/v22.2b14-DSv10/tmp/
skylib_mudos_v1/v22.2b14-DSv10/windows/
/*
 * Support for parse trees for the compiler.
 *
 * Added by Beek (Tim Hollebeek) 9/29/94.  Only converting expression parsing
 *    to parse trees at this point; the rest of code generation will likely
 *    follow later.
 *
 * Note: it did.  See ChangeLogs.
 *
 */

#define SUPPRESS_COMPILER_INLINES
#include "std.h"
#include "lpc_incl.h"
#include "compiler.h"
#include "opcodes.h"

/* our globals */
static parse_node_block_t *parse_block_list = 0;
static parse_node_block_t *free_block_list = 0;

static parse_node_t *next_node = 0;
static parse_node_t *last_node = 0;

static int last_prog_size = 1;

/* called by code generation when it is done with the tree */
void
free_tree() {
    parse_node_block_t *cur_block;

    if (!(cur_block = parse_block_list))
	return;

    while (cur_block->next) cur_block = cur_block->next;

    /* put all the blocks in the free list */
    cur_block->next = free_block_list;
    free_block_list = parse_block_list;
    parse_block_list = 0;
    next_node = 0;
    last_node = 0;
}

/* called when the parser cleans up */
void
release_tree() {
    parse_node_block_t *cur_block;
    parse_node_block_t *next_block;
    
    free_tree();
    next_block = free_block_list;
    while ((cur_block = next_block)) {
	next_block = cur_block->next;
	FREE(cur_block);
    }
    free_block_list = 0;
    last_prog_size = 1;
}

/* get a new node to add to the tree */
parse_node_t *
new_node() {
    parse_node_block_t *cur_block;

    /* fast case */
    if (next_node < last_node) {
	next_node->line = current_line_base + current_line;
	return next_node++;
    }

    /* no more nodes in the current block; do we have a free one? */
    if ((cur_block = free_block_list)) {
	free_block_list = cur_block->next;
    } else {
	cur_block = ALLOCATE(parse_node_block_t, TAG_COMPILER, "new_node");
    }
    /* add to block list */
    cur_block->next = parse_block_list;
    parse_block_list = cur_block;
    /* point the nodes correctly */
    next_node = &cur_block->nodes[0];
    last_node = &cur_block->nodes[NODES_PER_BLOCK];
    next_node->line = current_line_base + current_line;
    return next_node++;
}

/* get a new node to add to the tree, but don't count it for line # purposes
 * This should be used for nodes that hold expressions together but don't
 * generate any code themselves (NODE_IF, etc)
 */
parse_node_t *
new_node_no_line() {
    parse_node_block_t *cur_block;

    /* fast case */
    if (next_node < last_node) {
      next_node->line = 0;
      return next_node++;
    }    
    /* no more nodes in the current block; do we have a free one? */
    if ((cur_block = free_block_list)) {
      free_block_list = cur_block->next;
    } else {
	cur_block = ALLOCATE(parse_node_block_t, TAG_COMPILER, "new_node");
    }
    /* add to block list */
    cur_block->next = parse_block_list;
    parse_block_list = cur_block;
    /* point the nodes correctly */
    next_node = &cur_block->nodes[0];
    last_node = &cur_block->nodes[NODES_PER_BLOCK];
    next_node->line = 0;
    return next_node++;
}

/* quick routine to make a generic branched node */
parse_node_t *
make_branched_node P4(short, kind, char, type, 
		      parse_node_t *, l, parse_node_t *, r) {
    parse_node_t *ret;

    ret = new_node();
    ret->kind = kind;
    ret->type = type;
    ret->l.expr = l;
    ret->r.expr = r;
    return ret;
}

/* create an optimized typical binary integer operator */
parse_node_t *
binary_int_op P4(parse_node_t *, l, parse_node_t *, r,
		 char, op, char *, name) {
    parse_node_t *ret;
    
    if (exact_types) {
	if (!IS_TYPE(l->type, TYPE_NUMBER)) {
	    char buf[256];
	    char *end = EndOf(buf);
	    char *p;
	    
	    p = strput(buf, end, "Bad left argument to '");
	    p = strput(p, end, name);
	    p = strput(p, end, "' : \"");
	    p = get_type_name(p, end, l->type);
	    p = strput(p, end, "\"");
	    yyerror(buf);
	}
	if (!IS_TYPE(r->type,TYPE_NUMBER)) {
	    char buf[256];
	    char *end = EndOf(buf);
	    char *p;
	    
	    p = strput(buf, end, "Bad right argument to '");
	    p = strput(p, end, name);
	    p = strput(p, end, "' : \"");
	    p = get_type_name(p, end, r->type);
	    p = strput(p, end, "\"");
	    yyerror(buf);
	}
    }
    if (l->kind == NODE_NUMBER) {
      if (r->kind == NODE_NUMBER) {
          switch (op) {
          case F_OR: l->v.number |= r->v.number; break;
          case F_XOR: l->v.number ^= r->v.number; break;
          case F_AND: l->v.number &= r->v.number; break;
          case F_LSH: l->v.number <<= r->v.number; break;
          case F_RSH: l->v.number >>= r->v.number; break;
          case F_MOD:
              if (r->v.number == 0) {
                  yyerror("Modulo by zero constant");
                  break;
              }
             l->v.number %= r->v.number; break;
          default: fatal("Unknown opcode in binary_int_op()\n");
          }
          return l;
      }
      switch (op) {
      case F_OR:
      case F_XOR:
      case F_AND:
	  CREATE_BINARY_OP(ret, op, TYPE_NUMBER, r, l);
	  return ret;
      }
    }
    CREATE_BINARY_OP(ret, op, TYPE_NUMBER, l, r);
    return ret;
}

parse_node_t *make_range_node P4(int, code, parse_node_t *, expr,
                                      parse_node_t *, l,
                                      parse_node_t *, r) {
    parse_node_t *newnode;

    if (r) {
	CREATE_TERNARY_OP(newnode, code, 0, l, r, expr);
    } else {
	CREATE_BINARY_OP(newnode, code, 0, l, expr);
    }
    
    if (exact_types) {
        switch(expr->type) {
            case TYPE_ANY:
            case TYPE_STRING:
            case TYPE_BUFFER:
                newnode->type = expr->type;
                break;

            default:
                if (expr->type & TYPE_MOD_ARRAY) newnode->type = expr->type;
                else{
                    type_error("Bad type of argument used for range: ", expr->type);
                    newnode->type = TYPE_ANY;
                }
        }

        if (!IS_TYPE(l->type, TYPE_NUMBER))
            type_error("Bad type of left index to range operator", l->type);
        if (r && !IS_TYPE(r->type, TYPE_NUMBER))
            type_error("Bad type of right index to range operator", r->type);
    } else newnode->type = TYPE_ANY;
    return newnode;
}

parse_node_t *insert_pop_value P1(parse_node_t *, expr) {
    parse_node_t *replacement;

    if (!expr)
	return 0;
    if (expr->type == TYPE_NOVALUE) {
	expr->type = TYPE_VOID;
	return expr;
    }
    switch (expr->kind) {
    case NODE_EFUN:
	if (expr->v.number & NOVALUE_USED_FLAG) {
	    expr->v.number &= ~NOVALUE_USED_FLAG;
	    return expr;
	}
	break;
    case NODE_TWO_VALUES:
	/* (two-values expr1 expr2) where expr1 is already popped.
	 * 
	 * instead of: (pop (two-values expr1 expr2))
	 * generated:  (two-values expr (pop expr2))
	 *
	 * both of which generate the same code, but the second optimizes
	 * better in cases like: i++, j++
	 *
	 * we get: (two-values (inc i) (post-inc j))
	 * first: (pop (two-values (inc i) (post-inc j)))
	 * -> INC i; POST_INC j; POP
	 * second: (two-values (inc i) (inc j))
	 * -> INC i; INC j
	 */
	if ((expr->r.expr = insert_pop_value(expr->r.expr)))
	    return expr;
	return expr->l.expr;
    case NODE_IF:
	/* a NODE_IF that gets popped is a (x ? y : z);
	 * propagate the pop in order to produce the same code as
	 * if (x) y; else z;
	 */
	expr->l.expr = insert_pop_value(expr->l.expr);
	expr->r.expr = insert_pop_value(expr->r.expr);

	if (!expr->l.expr && !expr->r.expr) {
	    /* if both branches do nothing, don't bother with the test ... */
	    return insert_pop_value(expr->v.expr);
	}
	return expr;
    case NODE_TERNARY_OP:
	switch (expr->r.expr->v.number) {
	case F_NN_RANGE: case F_RN_RANGE: case F_RR_RANGE: case F_NR_RANGE:
	    expr->kind = NODE_TWO_VALUES;
	    expr->l.expr = insert_pop_value(expr->l.expr);
	    expr->r.expr->kind = NODE_TWO_VALUES;
	    expr->r.expr->l.expr = insert_pop_value(expr->r.expr->l.expr);
	    expr->r.expr->r.expr = insert_pop_value(expr->r.expr->r.expr);

	    if (!expr->l.expr) {
		expr = expr->r.expr;
		if (!expr->l.expr)
		    return expr->r.expr;
		if (!expr->r.expr)
		    return expr->l.expr;
	    } else {
		if (!expr->r.expr->l.expr) {
		    expr->r.expr = expr->r.expr->r.expr;
		    if (!expr->r.expr)
			return expr->l.expr;
		} else {
		    if (!expr->r.expr->r.expr)
			expr->r.expr = expr->r.expr->l.expr;
		}
	    }
	    return expr;
	}
	break;
    /* take advantage of the fact that opcodes don't clash */
    case NODE_CALL:
    case NODE_BINARY_OP:
    case NODE_UNARY_OP_1:
    case NODE_UNARY_OP:
    case NODE_OPCODE_1:
	switch (expr->v.number) {
	case F_AGGREGATE_ASSOC:
	    /* This has to be done specially b/c of the way mapping constants
	       are stored */
	    return throw_away_mapping(expr);
	case F_AGGREGATE:
	    return throw_away_call(expr);
	case F_PRE_INC: case F_POST_INC:
	    expr->v.number = F_INC;
	    return expr;
	case F_PRE_DEC: case F_POST_DEC: 
	    expr->v.number = F_DEC;
	    return expr;
	case F_NOT: case F_COMPL: case F_NEGATE:
	    expr = insert_pop_value(expr->r.expr);
	    return expr;
	case F_MEMBER:
	    expr = insert_pop_value(expr->r.expr);
	    return expr;
	case F_LOCAL: case F_GLOBAL: case F_REF:
	    return 0;
	case F_EQ: case F_NE: case F_GT: case F_GE: case F_LT: case F_LE:
	case F_OR: case F_XOR: case F_AND: case F_LSH: case F_RSH:
	case F_ADD: case F_SUBTRACT: case F_MULTIPLY: case F_DIVIDE:
	case F_MOD: case F_RE_RANGE: case F_NE_RANGE: case F_RINDEX:
	case F_INDEX:
	    if ((expr->l.expr = insert_pop_value(expr->l.expr))) {
		if ((expr->r.expr = insert_pop_value(expr->r.expr))) {
		    expr->kind = NODE_TWO_VALUES;
		    return expr;
		} else
		    return expr->l.expr;
	    } else 
		return insert_pop_value(expr->r.expr);
	    break;
	case F_ASSIGN:
	    if (IS_NODE(expr->r.expr, NODE_OPCODE_1, F_LOCAL_LVALUE)) {
		int tmp = expr->r.expr->l.number;
		expr->kind = NODE_UNARY_OP_1;
		expr->r.expr = expr->l.expr;
		expr->v.number = F_VOID_ASSIGN_LOCAL;
		expr->l.number = tmp;
	    } else expr->v.number = F_VOID_ASSIGN;
	    return expr;
	case F_ADD_EQ: 
	    expr->v.number = F_VOID_ADD_EQ;
	    return expr;
	}
	break;
    case NODE_PARAMETER:
    case NODE_ANON_FUNC: /* some dweeb threw away one? */
    case NODE_FUNCTION_CONSTRUCTOR:
	return 0;
    case NODE_NUMBER:
    case NODE_STRING:
    case NODE_REAL: 
	return 0;
    }
    CREATE_UNARY_OP(replacement, F_POP_VALUE, 0, expr);
    return replacement;
}

parse_node_t *pop_value P1(parse_node_t *, pn) {
    if (pn) {
	parse_node_t *ret = insert_pop_value(pn);

	if (!ret) {
	    if (pn->kind == NODE_BINARY_OP && pn->v.number >= F_EQ &&
		pn->v.number <= F_GT)
		yywarn("Value of conditional expression is unused");
	    else
		yywarn("Expression has no side effects, and the value is unused");
	}
	return ret;
    }
    
    return 0;
}

int is_boolean P1(parse_node_t *, pn) {
    switch (pn->kind) {
    case NODE_UNARY_OP:
	if (pn->v.number == F_NOT)
	    return 1;
	return 0;
    case NODE_BINARY_OP:
	if (pn->v.number >= F_EQ && pn->v.number <= F_GT)
	    return 1;
	return 0;
    case NODE_LAND_LOR:
    case NODE_BRANCH_LINK:
	return 1;
    }
    return 0;
}

parse_node_t *optimize_loop_test P1(parse_node_t *, pn) {
    parse_node_t *ret;

    if (!pn) return 0;
    
    if (IS_NODE(pn, NODE_BINARY_OP, F_LT) &&
	IS_NODE(pn->l.expr, NODE_OPCODE_1, F_LOCAL)) {
	if (IS_NODE(pn->r.expr, NODE_OPCODE_1, F_LOCAL)) {
	    CREATE_OPCODE_2(ret, F_LOOP_COND_LOCAL, 0,
			    pn->l.expr->l.number,
			    pn->r.expr->l.number);
	} else if (pn->r.expr->kind == NODE_NUMBER) {
	    CREATE_OPCODE_2(ret, F_LOOP_COND_NUMBER, 0,
			    pn->l.expr->l.number,
			    pn->r.expr->v.number);
	} else
	    ret = pn;
    } else if (IS_NODE(pn, NODE_UNARY_OP, F_POST_DEC) &&
	       IS_NODE(pn->r.expr, NODE_OPCODE_1, F_LOCAL_LVALUE)) {
	int lvar = pn->r.expr->l.number;
	CREATE_OPCODE_1(ret, F_WHILE_DEC, 0, lvar);
    } else
	ret = pn;
    
    return ret;
}