/* ---------------------------------------------------------------------- */ /* Copyright (C) 1991 by NatŠrlich! */ /* This file is copyrighted! */ /* Refer to the documentation for details. */ /* ---------------------------------------------------------------------- */ #include "defines.h" #include "nasm.h" #include "debug.h" #include "labels.h" #include NMALLOC_H #include "exprfast.h" #include OSBIND #include "code.h" #include "op.h" extern byte scrtab[]; extern int runnable; int _in_doteq; #if ! DORECLAIM #define expr_tryfree( p) #endif #if ! VERSION /* ---------------------------------------------------------- */ /* There is this unfortunate problems with labels. They might */ /* be defined anywhere and with nasm65 even unknown (linked */ /* from elsewhere). That leads to problems when generating */ /* code. REFER and DREFER (pronounce REEFER and DEEREEFER) */ /* "Don't fear the REFER" (Blue Oyster Cult (almost)) */ /* build up lists of places, where labels have been used and */ /* whether the label had a value then. */ /* drefer means define and refer */ /* ---------------------------------------------------------- */ /* I NEVER USE XREFs */ /* I NEVER LOOK AT THE SYMBOLTABLE AT THE END OF THE LISTING */ /* WHY SHOULD I WASTE MEMORY FOR FEATURES I DON'T WANT */ /* Therefore I don't need drefer just refer. That also means */ /* I can compress the "ref" to 8 bytes. Now if I could get */ /* rid of that one pointer. */ /* ---------------------------------------------------------- */ void refer( l, ex) label huge *l; expr huge *ex; { register ref huge *p = ref_alloc(); extern buffer huge *bp; ENTER("refer"); IMESS("label @$%lX", (lword) l, 4); p->ref = ex; /* Note expression that needs fixing */ p->line = bp->line; /* (*) */ p->next = l->refs; /* put it in the first slot... */ l->refs = p; l->type |= L_REF; LEAVE(); } #endif /* ---------------------------------------------------------- */ /* Recursively copy expression (deep copy or shallow copy ?) */ /* and if needed refer as of yet unkown labels. */ /* code looks very nice, but can conceivably use some optimi- */ /* zation. */ /* ---------------------------------------------------------- */ expr *copyexpr( p) register expr huge *p; { ENTER("copyexpr"); if( ! p) { LEAVE(); return( 0); } { register expr huge *q = exp_alloc(); #if EXPRSIZE != 24 || PHILOSOPHICAL_PROBLEM bcopy( p, q, (lword) sizeof( expr)); #else *((lword huge *) q)++ = *((lword huge *) p)++; /* label */ *((lword huge *) q)++ = *((lword huge *) p)++; /* no & val */ *((lword huge *) q) = *(lword huge *) p; /* aux & op & fix */ (char huge *) q -= 8; (char huge *) p -= 8; #endif if( q->label) /* Tell label that we need a */ refer( q->label, q); /* fix (if we need a fix) */ if( q->l = copyexpr( p->l)) q->l->zonk.t = q; if( q->r = copyexpr( p->r)) q->r->zonk.t = q; LEAVE(); return( q); } } #if ! VERSION /* ----------------------------------------------------------- */ /* Create an s_expression node by planting a value */ /* (could be a label as well) */ /* ----------------------------------------------------------- */ expr *ival_pl( value) word value; { expr huge *p = exp_alloc(); ENTER("ival_pl"); MESS("Wolf! Right here and now!"); p->val = value; LEAVE(); return( p); } #endif expr *lval_pl( name) char huge *name; { register expr huge *p = exp_alloc(); register label huge *q; ENTER("lval_pl"); MESS("Wolf! Right here and now!"); if( q = find_label( name)) { if( q->refs) { p->label = q; refer( q, p); } else p->val = q->val; IMESS("p->op %u", (lword) p->op, 2); p->op = ((q->type & L_PC) ? O_PCREL : 0) | ((q->type & L_ZERO) ? O_ZEROP : 0); } else if( runnable && _in_doteq) enter_elabel( name, ival_pl( __pc), L_NORMAL); else { p->label = enter_flabel( name, p); if( ! runnable) p->op = O_PCREL; /* cause fwd then is PC rel */ } LEAVE(); return( p); } /* ----------------------------------------------------------- */ /* Create an s_expression node by planting an operation */ /* There is still a bug in this as expressions like foo+2+3 */ /* are not simplified if foo is unvalued */ /* ----------------------------------------------------------- */ expr *op_pl( op, left, rite) register int op; register expr huge *left, huge *rite; { register int lop; int rop; ENTER("op_pl"); if( (lop = left->op) == (O_PCREL | (O_MSB & O_LSB)) || (rite && (rop = rite->op) == (O_PCREL | (O_MSB & O_LSB)))) { nerror("You can't calculate with a short PC relative expression"); return( left); } if( valued( left)) /* if left is value */ { if( ! rite || valued( rite)) { MESS("Just calcing it"); do_calc( left, rite, op); /* calc it */ expr_tryfree( rite); IMESS("After do_calc %ld", (lword) lop, 4); LEAVE(); return( left); } } else if( rite && valued( rite)) switch( lop) { case O_ADD : if( is_addsub( op)) { if( valued( left->l)) do_calc( left->l, rite, op); else if( valued( left->r)) do_calc( left->r, rite, op); else break; expr_tryfree( rite); return( left); } break; case O_SUB : if( op == O_ADD) { if( valued( left->l)) do_calc( left->l, rite, O_ADD); else if( valued( left->r)) do_calc( left->r, rite, O_SUB); else break; } else if( op == O_SUB) { if( valued( left->l)) do_calc( left->l, rite, O_SUB); else if( valued( left->r)) do_calc( left->r, rite, O_ADD); else break; } else break; expr_tryfree( rite); return( left); case O_MUL : if( op == O_MUL) { if( valued( left->l)) do_calc( left->l, rite, op); else if( valued( left->r)) do_calc( left->r, rite, op); else break; expr_tryfree( rite); return( left); } break; case O_DIV : if( op == O_DIV) { if( valued( left->l)) do_calc( left->l, rite, op); else if( valued( left->r)) do_calc( left->r, rite, O_MUL); else break; expr_tryfree( rite); return( left); } } MESS("Creating a node"); { register expr huge *p; if( rite && valued( rite) && rite->val == 1) { if( is_addsub( op)) { p = rite; rite = 0; op = op == O_ADD ? O_INC : O_DEC; goto asusual; } } p = exp_alloc(); asusual: lop &= O_PCREL; rop &= O_PCREL; switch( op) { case O_INC : case O_DEC : case O_MSB : case O_LSB : p->op = lop; break; case O_ADD : p->op = lop ^ rop; break; case O_SUB : { static char what[] = { 0, 0, 0x80, 0 }; p->op = what[ ((lop != 0) << 1) | (rop != 0) ]; } } if( (left->op | (rite ? rite->op : 0)) & O_ZEROP) switch( op) { case O_SUB : if( rite->op & O_ZEROP) break; case O_ADD : if( ! p->op) case O_INC : case O_DEC : case O_LSB : p->op |= O_ZEROP; } p->op |= op; p->l = left; left->fix = 0; /* for macros */ left->zonk.t = p; if( p->r = rite) rite->zonk.t = p; LEAVE(); return( p); } } #if ! VERSION lexpr *lex_pl( s, ex) expr huge *ex; char *s; { register lexpr *p = lex_alloc(); ENTER("lex_pl"); IMESS("planting string $%8.8lX", (lword) s, 4); IMESS(" with expr $%8.8lX", (lword) ex, 4); p->string = s; p->expr = ex; p->next = 0; LEAVE(); return( p); } #endif lexpr *slex_ch( l, r) register lexpr huge *l, huge *r; { ENTER("slex_ch"); IMESS("Chaining $%8.8lX", (lword) r, 4); IMESS(" to $%8.8lX", (lword) l, 4); l->next = r; LEAVE(); return( l); } int lex_cnt( l) register lexpr huge *l; { register int i = 0; ENTER("lex_cnt"); while( l) { i++; l = l->next; } LEAVE(); return( i); } /* ---------------------------------------------------------- */ /* Should be a macro */ /* Error checking elsewhere */ /* ---------------------------------------------------------- */ lexpr *lex_get( l, no) register lexpr huge *l; register word no; { ENTER("lex_get"); while( l && no--) l = l->next; IMESS("Returning L-expression @$%lx", (lword) l, 4); LEAVE(); return( l); } /* ---------------------------------------------------------- */ /* Mallocer for lexpressions */ /* make this mallocing scheme a macro sometime in the future..*/ /* */ /* (Keeping the fingers crossed that this is faster than a) */ /* (simple malloc) */ /* ---------------------------------------------------------- */ make_mallocer( lexpr, LEXPMAX, lex_alloc); /* (*) This isn't correct and fails when branches are made out of a buffer (like macro) or the buffer was changed. */