ds2.9a12/bin/
ds2.9a12/extra/
ds2.9a12/extra/crat/
ds2.9a12/extra/creremote/
ds2.9a12/extra/mingw/
ds2.9a12/extra/wolfpaw/
ds2.9a12/fluffos-2.14-ds13/
ds2.9a12/fluffos-2.14-ds13/Win32/
ds2.9a12/fluffos-2.14-ds13/compat/
ds2.9a12/fluffos-2.14-ds13/compat/simuls/
ds2.9a12/fluffos-2.14-ds13/include/
ds2.9a12/fluffos-2.14-ds13/testsuite/
ds2.9a12/fluffos-2.14-ds13/testsuite/clone/
ds2.9a12/fluffos-2.14-ds13/testsuite/command/
ds2.9a12/fluffos-2.14-ds13/testsuite/data/
ds2.9a12/fluffos-2.14-ds13/testsuite/etc/
ds2.9a12/fluffos-2.14-ds13/testsuite/include/
ds2.9a12/fluffos-2.14-ds13/testsuite/inherit/
ds2.9a12/fluffos-2.14-ds13/testsuite/inherit/master/
ds2.9a12/fluffos-2.14-ds13/testsuite/log/
ds2.9a12/fluffos-2.14-ds13/testsuite/single/
ds2.9a12/fluffos-2.14-ds13/testsuite/single/tests/compiler/
ds2.9a12/fluffos-2.14-ds13/testsuite/single/tests/efuns/
ds2.9a12/fluffos-2.14-ds13/testsuite/single/tests/operators/
ds2.9a12/fluffos-2.14-ds13/testsuite/u/
ds2.9a12/lib/cmds/admins/
ds2.9a12/lib/cmds/common/
ds2.9a12/lib/cmds/creators/include/
ds2.9a12/lib/daemon/services/
ds2.9a12/lib/daemon/tmp/
ds2.9a12/lib/doc/
ds2.9a12/lib/doc/bguide/
ds2.9a12/lib/doc/efun/all/
ds2.9a12/lib/doc/efun/arrays/
ds2.9a12/lib/doc/efun/buffers/
ds2.9a12/lib/doc/efun/compile/
ds2.9a12/lib/doc/efun/floats/
ds2.9a12/lib/doc/efun/functions/
ds2.9a12/lib/doc/efun/general/
ds2.9a12/lib/doc/efun/mixed/
ds2.9a12/lib/doc/efun/numbers/
ds2.9a12/lib/doc/efun/parsing/
ds2.9a12/lib/doc/hbook/
ds2.9a12/lib/doc/help/classes/
ds2.9a12/lib/doc/help/races/
ds2.9a12/lib/doc/lfun/
ds2.9a12/lib/doc/lfun/all/
ds2.9a12/lib/doc/lfun/lib/abilities/
ds2.9a12/lib/doc/lfun/lib/armor/
ds2.9a12/lib/doc/lfun/lib/bank/
ds2.9a12/lib/doc/lfun/lib/bot/
ds2.9a12/lib/doc/lfun/lib/clay/
ds2.9a12/lib/doc/lfun/lib/clean/
ds2.9a12/lib/doc/lfun/lib/clerk/
ds2.9a12/lib/doc/lfun/lib/client/
ds2.9a12/lib/doc/lfun/lib/combat/
ds2.9a12/lib/doc/lfun/lib/connect/
ds2.9a12/lib/doc/lfun/lib/container/
ds2.9a12/lib/doc/lfun/lib/corpse/
ds2.9a12/lib/doc/lfun/lib/creator/
ds2.9a12/lib/doc/lfun/lib/daemon/
ds2.9a12/lib/doc/lfun/lib/damage/
ds2.9a12/lib/doc/lfun/lib/deterioration/
ds2.9a12/lib/doc/lfun/lib/donate/
ds2.9a12/lib/doc/lfun/lib/door/
ds2.9a12/lib/doc/lfun/lib/equip/
ds2.9a12/lib/doc/lfun/lib/file/
ds2.9a12/lib/doc/lfun/lib/fish/
ds2.9a12/lib/doc/lfun/lib/fishing/
ds2.9a12/lib/doc/lfun/lib/flashlight/
ds2.9a12/lib/doc/lfun/lib/follow/
ds2.9a12/lib/doc/lfun/lib/ftp_client/
ds2.9a12/lib/doc/lfun/lib/ftp_data_connection/
ds2.9a12/lib/doc/lfun/lib/fuel/
ds2.9a12/lib/doc/lfun/lib/furnace/
ds2.9a12/lib/doc/lfun/lib/genetics/
ds2.9a12/lib/doc/lfun/lib/holder/
ds2.9a12/lib/doc/lfun/lib/id/
ds2.9a12/lib/doc/lfun/lib/interactive/
ds2.9a12/lib/doc/lfun/lib/lamp/
ds2.9a12/lib/doc/lfun/lib/leader/
ds2.9a12/lib/doc/lfun/lib/light/
ds2.9a12/lib/doc/lfun/lib/limb/
ds2.9a12/lib/doc/lfun/lib/living/
ds2.9a12/lib/doc/lfun/lib/load/
ds2.9a12/lib/doc/lfun/lib/look/
ds2.9a12/lib/doc/lfun/lib/manipulate/
ds2.9a12/lib/doc/lfun/lib/meal/
ds2.9a12/lib/doc/lfun/lib/messages/
ds2.9a12/lib/doc/lfun/lib/player/
ds2.9a12/lib/doc/lfun/lib/poison/
ds2.9a12/lib/doc/lfun/lib/position/
ds2.9a12/lib/doc/lfun/lib/post_office/
ds2.9a12/lib/doc/lfun/lib/potion/
ds2.9a12/lib/doc/lfun/lib/room/
ds2.9a12/lib/doc/lfun/lib/server/
ds2.9a12/lib/doc/lfun/lib/spell/
ds2.9a12/lib/doc/lfun/lib/torch/
ds2.9a12/lib/doc/lfun/lib/vendor/
ds2.9a12/lib/doc/lfun/lib/virt_sky/
ds2.9a12/lib/doc/lfun/lib/weapon/
ds2.9a12/lib/doc/lfun/lib/worn_storage/
ds2.9a12/lib/doc/lpc/basic/
ds2.9a12/lib/doc/lpc/concepts/
ds2.9a12/lib/doc/lpc/constructs/
ds2.9a12/lib/doc/lpc/etc/
ds2.9a12/lib/doc/lpc/intermediate/
ds2.9a12/lib/doc/lpc/types/
ds2.9a12/lib/doc/misc/
ds2.9a12/lib/doc/old/
ds2.9a12/lib/domains/
ds2.9a12/lib/domains/Praxis/adm/
ds2.9a12/lib/domains/Praxis/attic/
ds2.9a12/lib/domains/Praxis/cemetery/mon/
ds2.9a12/lib/domains/Praxis/data/
ds2.9a12/lib/domains/Praxis/death/
ds2.9a12/lib/domains/Praxis/mountains/
ds2.9a12/lib/domains/Praxis/obj/armour/
ds2.9a12/lib/domains/Praxis/obj/magic/
ds2.9a12/lib/domains/Praxis/obj/weapon/
ds2.9a12/lib/domains/Praxis/orc_valley/
ds2.9a12/lib/domains/Ylsrim/
ds2.9a12/lib/domains/Ylsrim/adm/
ds2.9a12/lib/domains/Ylsrim/armor/
ds2.9a12/lib/domains/Ylsrim/broken/
ds2.9a12/lib/domains/Ylsrim/fish/
ds2.9a12/lib/domains/Ylsrim/meal/
ds2.9a12/lib/domains/Ylsrim/npc/
ds2.9a12/lib/domains/Ylsrim/obj/
ds2.9a12/lib/domains/Ylsrim/virtual/
ds2.9a12/lib/domains/Ylsrim/weapon/
ds2.9a12/lib/domains/campus/adm/
ds2.9a12/lib/domains/campus/etc/
ds2.9a12/lib/domains/campus/meals/
ds2.9a12/lib/domains/campus/save/
ds2.9a12/lib/domains/campus/txt/ai/charles/
ds2.9a12/lib/domains/campus/txt/ai/charles/bak2/
ds2.9a12/lib/domains/campus/txt/ai/charles/bak2/bak1/
ds2.9a12/lib/domains/campus/txt/ai/charly/
ds2.9a12/lib/domains/campus/txt/ai/charly/bak/
ds2.9a12/lib/domains/campus/txt/jenny/
ds2.9a12/lib/domains/cave/doors/
ds2.9a12/lib/domains/cave/etc/
ds2.9a12/lib/domains/cave/meals/
ds2.9a12/lib/domains/cave/weap/
ds2.9a12/lib/domains/default/creator/
ds2.9a12/lib/domains/default/doors/
ds2.9a12/lib/domains/default/etc/
ds2.9a12/lib/domains/default/vehicles/
ds2.9a12/lib/domains/default/virtual/
ds2.9a12/lib/domains/default/weap/
ds2.9a12/lib/domains/town/txt/shame/
ds2.9a12/lib/domains/town/virtual/
ds2.9a12/lib/domains/town/virtual/bottom/
ds2.9a12/lib/domains/town/virtual/space/
ds2.9a12/lib/estates/
ds2.9a12/lib/ftp/
ds2.9a12/lib/lib/comp/
ds2.9a12/lib/lib/daemons/
ds2.9a12/lib/lib/daemons/include/
ds2.9a12/lib/lib/lvs/
ds2.9a12/lib/lib/user/
ds2.9a12/lib/lib/virtual/
ds2.9a12/lib/log/
ds2.9a12/lib/log/adm/
ds2.9a12/lib/log/archive/
ds2.9a12/lib/log/chan/
ds2.9a12/lib/log/errors/
ds2.9a12/lib/log/law/adm/
ds2.9a12/lib/log/law/email/
ds2.9a12/lib/log/law/names/
ds2.9a12/lib/log/law/sites-misc/
ds2.9a12/lib/log/law/sites-register/
ds2.9a12/lib/log/law/sites-tempban/
ds2.9a12/lib/log/law/sites-watch/
ds2.9a12/lib/log/open/
ds2.9a12/lib/log/reports/
ds2.9a12/lib/log/router/
ds2.9a12/lib/log/secure/
ds2.9a12/lib/log/watch/
ds2.9a12/lib/obj/book_source/
ds2.9a12/lib/obj/include/
ds2.9a12/lib/powers/prayers/
ds2.9a12/lib/powers/spells/
ds2.9a12/lib/realms/template/adm/
ds2.9a12/lib/realms/template/area/armor/
ds2.9a12/lib/realms/template/area/npc/
ds2.9a12/lib/realms/template/area/obj/
ds2.9a12/lib/realms/template/area/room/
ds2.9a12/lib/realms/template/area/weap/
ds2.9a12/lib/realms/template/bak/
ds2.9a12/lib/realms/template/cmds/
ds2.9a12/lib/save/kills/o/
ds2.9a12/lib/secure/cfg/classes/
ds2.9a12/lib/secure/cmds/builders/
ds2.9a12/lib/secure/cmds/creators/include/
ds2.9a12/lib/secure/cmds/players/
ds2.9a12/lib/secure/cmds/players/include/
ds2.9a12/lib/secure/daemon/imc2server/
ds2.9a12/lib/secure/daemon/include/
ds2.9a12/lib/secure/lib/
ds2.9a12/lib/secure/lib/include/
ds2.9a12/lib/secure/lib/net/include/
ds2.9a12/lib/secure/lib/std/
ds2.9a12/lib/secure/log/adm/
ds2.9a12/lib/secure/log/bak/
ds2.9a12/lib/secure/log/intermud/
ds2.9a12/lib/secure/log/network/
ds2.9a12/lib/secure/modules/
ds2.9a12/lib/secure/npc/
ds2.9a12/lib/secure/obj/include/
ds2.9a12/lib/secure/room/
ds2.9a12/lib/secure/save/
ds2.9a12/lib/secure/save/backup/
ds2.9a12/lib/secure/save/boards/
ds2.9a12/lib/secure/tmp/
ds2.9a12/lib/secure/upgrades/files/
ds2.9a12/lib/secure/verbs/creators/
ds2.9a12/lib/std/board/
ds2.9a12/lib/std/lib/
ds2.9a12/lib/tmp/
ds2.9a12/lib/verbs/admins/include/
ds2.9a12/lib/verbs/builders/
ds2.9a12/lib/verbs/common/
ds2.9a12/lib/verbs/common/include/
ds2.9a12/lib/verbs/creators/
ds2.9a12/lib/verbs/creators/include/
ds2.9a12/lib/verbs/rooms/
ds2.9a12/lib/verbs/rooms/include/
ds2.9a12/lib/www/client/
ds2.9a12/lib/www/errors/
ds2.9a12/lib/www/images/
ds2.9a12/lib/www/lpmuds/downloads_files/
ds2.9a12/lib/www/lpmuds/intermud_files/
ds2.9a12/lib/www/lpmuds/links_files/
ds2.9a12/win32/
/*
 * 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 (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 (parse_node_t * l, parse_node_t * r,
                 char op, const 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 (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 (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)) {
                long 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 (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 (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 (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)) {
        long lvar = pn->r.expr->l.number;
        CREATE_OPCODE_1(ret, F_WHILE_DEC, 0, lvar);
    } else
        ret = pn;
    
    return ret;
}