/* ---------------------------------------------------------------------- */ /* Copyright (C) 1991 by Natuerlich! */ /* 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 OSBIND #include "code.h" #define _EXPR_ 1 #include "exprfast.h" #include "op.h" #include "ldebug.h" #if VERSION ref huge *rp; expr huge *ep; lexpr huge *lp; #endif #if DEBUG # define xreturn \ LEAVE(); \ return #else # define xreturn return #endif exp_m huge *ex_h; #if ! LINKER unsigned branch_line; #endif #if ! DORECLAIM # define expr_tryfree( x) #endif /* ---------------------------------------------------------- */ /* Entrefern von den der referenz list. Ist mal ein Label */ /* mit ner value versehen worden, kann die ref abgehakt */ /* werden. Danach brauch dieses label nie wieder 'ne ref */ /* ---------------------------------------------------------- */ void entrefer( p) label huge *p; { ref huge *q; register expr huge *r; POINTER_CHECK( p); ENTER("entrefer"); for( q = p->refs; q ; q = q->next) { POINTER_CHECK( q); (r = q->ref)->val = p->val; /* init expression */ POINTER_CHECK( r); r->label = 0; #if DEBUG dump_expr( r); #endif #if ! LINKER branch_line = q->line; #else INTEGRITY_CHECK(); #endif if( r) recalc( r); } p->refs = 0; LEAVE(); } #if ! LINKER # define xe_pcrel( x) ! runnable && e_pcrel( x) extern int runnable; static char fwd_loss[] = "label already known as PC-relative"; #else # define xe_pcrel e_pcrel #endif /* ---------------------------------------------------------- */ /* Jaja, mal wat in deutsch. Falls ein Label endlich einen */ /* Wert bekommen hat und inner ref ein entry auf eine expr */ /* pointed, dann wird versucht von da aus soviel wie m”glich */ /* von unten nach oben auszuwerten. Hat alles geklappt, dann */ /* kann man endlich die s-expr dahin schreiben, wo sie eigen- */ /* lich l„ngst sein sollte (Backpatching). */ /* Da wir brigens fr jeden Scheiž einen eigenen Mallocer */ /* haben ist es eigentlich kein Problem in NASM65 einen */ /* GarbageCollector einzubauen. Das w„rs noch!! */ /* For our befuddled english-speaking readers. The various */ /* MESS messages are gibberish. */ /* ---------------------------------------------------------- */ void recalc( p) register expr huge *p; { register fix huge *f; register byte huge *q; ENTER("recalc"); for(;;) { #if DEBUG dump_expr( p); #endif if( ! p->fix) goto nofix; f = p->zonk.fixp; POINTER_CHECK( f); switch( p->fix) /* Mmmh sind wir schon so weit ?? */ { case FIX_NOTHING: LEAVE(); return; case FIX_WCODE : MESS("Preferring the (1) wonderful"); q = __program + f->poof.block->index + f->index; POINTER_CHECK( q); adpoke( q, p->val); /* pack den Wert rein */ LEAVE(); return; case FIX_DCODE : MESS("Preferring the wonderful"); q = __program + f->poof.block->index + f->index; POINTER_CHECK( q); adbyte( q, p->val); /* pack den Wert rein */ LEAVE(); return; case FIX_BRANCH : { register sword i; MESS("The worx"); i = p->val - p->aux; #if ! LINKER if( i < -128 || i > 127) nberror("Branch too long", branch_line); #else if( i < -128 || i > 127) nerror("Branch too long"); #endif q = __program + f->poof.block->index + f->index; POINTER_CHECK( q); apoke( q, i); /* pack den Wert rein */ LEAVE(); return; } case FIX_ZCODE : case FIX_SZCODE : MESS("Admiring very small wonders"); q = __program + f->poof.block->index + f->index; POINTER_CHECK( q); if( xe_pcrel( p)) cure_patch( f->imm, p->aux); if( p->fix == FIX_ZCODE) { MESS("+"); apoke( q, p->val); /* pack den Wert rein */ } else { extern byte scrtab[]; MESS("*"); apoke( q, scrtab[ p->val]); /* pack'n Wert rein */ } MESS("-"); LEAVE(); return; case FIX_LABEL : { register label huge *q = f->poof.label; MESS("Doing the strange first"); IMESS("p->t @$%lX", (lword) p->zonk.t, 4); q->val = p->val; /* ok mach's dem */ #if ! LINKER if( ! runnable && (q->type & L_EQU)) { nserror( fwd_loss, q->name); goto skip; } #endif entrefer( q); skip: LEAVE(); return; } default : nierror("Invalid fix request"); nofix: case 0 : MESS("doing gods work 'ere, yessir!"); p = p->zonk.t; { register expr huge *l = p->l, huge *r = p->r; if( unvalued( l) || (r && unvalued( r))) /* if L or R */ { LEAVE(); return; /* USED TO BE A BREAK */ } do_calc( l, r, p->op & O_BITS); p->val = l->val; if( is_lsbmsb( p->op)) p->aux = l->aux; p->op = l->op; p->l = p->r = 0; /* leave kids to the garbage man */ } } } } /* ---------------------------------------------------------- */ /* Do the expression calculation that needs to be done for */ /* statements like LDA #>FOO&[$FF+NMIEN]/2 */ /* (never mind the sense...) */ /* ---------------------------------------------------------- */ void do_calc( l, r, op) register expr huge *l, huge *r; int op; { #if ! LINKER extern int runnable; #endif static char err[] = "Can't use arithemtic w/relocatable address", div_zero[] = "You can't / or \\ with zero"; ENTER("do_calc"); POINTER_CHECK( l); POINTER_CHECK( r); #if ! LINKER if( runnable) if( r) switch( op) { case O_ADD : l->val += r->val; xreturn; case O_SUB : l->val -= r->val; xreturn; case O_MUL : l->val *= r->val; xreturn; case O_DIV : if( ! r->val) nerror( div_zero); else l->val /= r->val; xreturn; case O_MOD : if( ! r->val) nerror( div_zero); else l->val %= r->val; xreturn; case O_AND : l->val &= r->val; xreturn; case O_EOR : l->val ^= r->val; xreturn; case O_OR : l->val |= r->val; xreturn; case O_EQ : l->val = l->val == r->val; xreturn; case O_BAND: l->val = l->val && r->val; xreturn; case O_BOR : l->val = l->val || r->val; xreturn; case O_NEQ : l->val = l->val != r->val; xreturn; case O_GEQ : l->val = l->val >= r->val; xreturn; case O_LEQ : l->val = l->val <= r->val; xreturn; case O_GT : l->val = l->val > r->val; xreturn; case O_LT : l->val = l->val < r->val; xreturn; } else switch( op) { case O_INC : l->val++; xreturn; case O_DEC : l->val--; xreturn; case O_BNOT: l->val = ! l->val; xreturn; case O_MIN : l->val = - l->val; xreturn; case O_LSB : l->aux = l->val; /* stands for LSB O_LT */ l->val &= 0xFF; xreturn; case O_MSB : l->aux = l->val; /* stands for MSB O_GT */ { byte huge *p = (byte huge *) &l->val; #if ! BIGENDIAN p[1] = *p; *p = 0; #else *p = p[1]; p[1] = 0; #endif xreturn; } } #endif if( r) switch( (e_pcrel( l) << 1) | e_pcrel( r)) { case 0 : /* value op value -> value */ MESS("val op val"); switch( op) { case O_ADD : l->val += r->val; goto iszerop; case O_SUB : l->val -= r->val; if( r->val & O_ZEROP) goto isvalue; goto issame; case O_MUL : l->val *= r->val; goto isvalue; case O_DIV : if( ! r->val) nerror( div_zero); else l->val /= r->val; goto isvalue; case O_MOD : if( ! r->val) nerror( div_zero); else l->val %= r->val; goto isvalue; case O_AND : l->val &= r->val; goto isvalue; case O_EOR : l->val ^= r->val; goto isvalue; case O_OR : l->val |= r->val; goto isvalue; case O_EQ : l->val = l->val == r->val; goto isvalue; case O_BAND: l->val = l->val && r->val; goto isvalue; case O_BOR : l->val = l->val || r->val; goto isvalue; case O_NEQ : l->val = l->val != r->val; goto isvalue; case O_GEQ : l->val = l->val >= r->val; goto isvalue; case O_LEQ : l->val = l->val <= r->val; goto isvalue; case O_GT : l->val = l->val > r->val; goto isvalue; case O_LT : l->val = l->val < r->val; goto isvalue; } case 1 : /* value op reladr -> ??? */ MESS("val op reladr"); switch( op) { case O_ADD : l->val += r->val; goto ispcrel; case O_SUB : case O_MUL : case O_DIV : case O_MOD : case O_AND : case O_EOR : case O_OR : nerror( err); l->val = 0; goto isvalue; case O_EQ : l->val = l->val == r->val; goto isvalue; case O_BAND: l->val = l->val && r->val; goto isvalue; case O_BOR : l->val = l->val || r->val; goto isvalue; case O_NEQ : l->val = l->val != r->val; goto isvalue; case O_GEQ : l->val = l->val >= r->val; goto isvalue; case O_LEQ : l->val = l->val <= r->val; goto isvalue; case O_GT : l->val = l->val > r->val; goto isvalue; case O_LT : l->val = l->val < r->val; goto isvalue; } case 2 : /* reladr op value -> ??? */ MESS("reladr op val"); switch( op) { case O_ADD : l->val += r->val; goto ispcrel; case O_SUB : l->val -= r->val; goto ispcrel; case O_MUL : case O_DIV : case O_MOD : case O_AND : case O_EOR : case O_OR : nerror( err); l->val = 0; goto isvalue; case O_EQ : l->val = l->val == r->val; goto isvalue; case O_BAND: l->val = l->val && r->val; goto isvalue; case O_BOR : l->val = l->val || r->val; goto isvalue; case O_NEQ : l->val = l->val != r->val; goto isvalue; case O_GEQ : l->val = l->val >= r->val; goto isvalue; case O_LEQ : l->val = l->val <= r->val; goto isvalue; case O_GT : l->val = l->val > r->val; goto isvalue; case O_LT : l->val = l->val < r->val; goto isvalue; } case 3 : MESS("reladr op reladr"); switch( op) { case O_SUB : l->val -= r->val; goto isvalue; case O_ADD : case O_MUL : case O_DIV : case O_MOD : case O_AND : case O_EOR : case O_OR : nerror( err); l->val = 0; goto isvalue; case O_EQ : l->val = l->val == r->val; goto isvalue; case O_BAND: l->val = l->val && r->val; goto isvalue; case O_BOR : l->val = l->val || r->val; goto isvalue; case O_NEQ : l->val = l->val != r->val; goto isvalue; case O_GEQ : l->val = l->val >= r->val; goto isvalue; case O_LEQ : l->val = l->val <= r->val; goto isvalue; case O_GT : l->val = l->val > r->val; goto isvalue; case O_LT : l->val = l->val < r->val; goto isvalue; } default: nierror("Algorithmic fuck up!"); } else if( e_pcrel( l)) switch( op) { case O_INC : l->val++; goto ispcrel; case O_DEC : l->val--; goto ispcrel; case O_BNOT: case O_MIN : l->val = 0; nerror( err); goto isvalue; case O_LSB : l->aux = l->val; l->val &= 0xFF; goto ispcrel; case O_MSB : l->aux = l->val; { byte huge *p = (byte huge *) &l->val; #if ! BIGENDIAN p[1] = *p; *p = 0; #else *p = p[1]; p[1] = 0; #endif goto ispcrel; } } else switch( op) { case O_INC : l->val++; goto issame; case O_DEC : l->val--; goto issame; case O_BNOT : l->val = ! l->val; goto isvalue; case O_MIN : nerror( err); l->val = 0; goto isvalue; case O_LSB : l->val &= 0xFF; goto issame; case O_MSB : { byte huge *p = (byte huge *) &l->val; #if ! BIGENDIAN p[1] = *p; *p = 0; #else *p = p[1]; p[1] = 0; #endif } goto isvalue; } ispcrel: l->op = O_PCREL | op; xreturn; iszerop: l->op |= r->op & O_ZEROP; issame: l->op = (l->op & O_BITS) | op; xreturn; isvalue: l->op = op; xreturn; } /* ---------------------------------------------------------- */ /* Mallocer for the reflist */ /* */ /* (Keeping the fingers crossed that this is faster than a) */ /* (simple malloc) */ /* For added speed put the first "if" into a #define */ /* ---------------------------------------------------------- */ make_mallocer( ref, REFMAX, ref_alloc); /* ---------------------------------------------------------- */ /* Mallocer for expressions */ /* */ /* (Keeping the fingers crossed that this is faster than a) */ /* (simple malloc) */ /* ---------------------------------------------------------- */ expr *sexp_alloc() { register exp_m huge *p; extern word _a_expr, _m_expr; extern lword _s_expr; #if STATISTICS _a_expr++; #endif if( (p = ex_h) && p->free--) return( p->tab++); #if STATISTICS _m_expr++; _s_expr = sizeof(exp_m) + EXPMAX * sizeof( expr); #endif p = (exp_m huge *) nmalloc( (long) sizeof(exp_m) + EXPMAX * sizeof( expr)); p->free = (int) EXPMAX - 1; p->tab = (expr huge *) ((char huge *) p + sizeof( exp_m)); bzero( p->tab, (long) EXPMAX * sizeof( expr)); /* Clear memory */ p->before = (exp_m huge *) ex_h; ex_h = p; return( p->tab++); } /* ---------------------------------------------------------- */ /* Try to free the expression. This will work easily in cases */ /* like LDA #2 or STA WSYNC (where WSYNC is already known */ /* Unless we are going to use GC we have to do this 'cause I */ /* expect approx. 2 expr/line (makes 60 bytes per line) */ /* We clear it so that it can be properly reused again */ /* ---------------------------------------------------------- */ #if DORECLAIM void expr_tryfree( e) register expr huge *e; { extern word _efrees, _erfrees; #if STATISTICS _efrees++; #endif if( e == (ex_h->tab - 1)) { register lword huge *q = (lword huge *) e; #if LINKER # if EXPRSIZE != 26 bzero( q, (long) sizeof( expr)); # else # if ! LATEPLUSPLUS /* like the good book says/be quick or dead [DLR] */ *(word huge *)q = (word) (*q++ = *q++ = *q++ = *q++ = *q++ = *q++ = 0); # else { register lword zero = 0; *q++ = zero; *q++ = zero; *q++ = zero; *q++ = zero; *q++ = zero; *q++ = zero; *(word huge *)q = 0; } # endif # endif #else # if EXPRSIZE != 24 || LATEPLUSPLUS bzero( q, (long) sizeof( expr)); # else # if ! LATEPLUSPLUS *q = *q++ = *q++ = *q++ = *q++ = *q++ = 0; # else { register lword zero = 0; *q++ = zero; *q++ = zero; *q++ = zero; *q++ = zero; *q++ = zero; *q++ = zero; } # endif # endif #endif --ex_h->tab; ++ex_h->free; #if STATISTICS _erfrees++; #endif if( e->l) { if( e->r) expr_tryfree( e->r); expr_tryfree( e->l); } } } #endif #if DEBUG #include dump_expr( p) expr huge *p; { if( p) { fprintf( ESTREAM, "\t\tEXPR @$%8.8lX\n", p); fprintf( ESTREAM, "\t\tOp='%c' Val=$%4.4X Label=$%8.8X ", p->op, p->val, p->label); fprintf( ESTREAM, "Aux=$%4.4X Fixtype=%d\n", p->aux, p->fix); fprintf( ESTREAM, "\t\tTop/Left/Rite [ $%8.8lX | $%8.8lX | $%8.8lX ]\n\n", p->zonk.t, p->l, p->r); if( ! p->fix) dump_expr( p->zonk.t); } } #endif /* [EOF][EOF][EOF][EOF][EOF][EOF][EOF][EOF][EOF][EOF][EOF][EOF][EOF][EOF] -- Kleiner Diskurs Deutschland heute (1/1990): "Ich _weiž_ nicht ob 2+2 4 oder 5 ist Ich _will_ es auch gar nicht wissen Aus dieser Art der Fragestellung dringt doch schon wieder diese rationale Einstellung zur Umwelt auf, von der wir doch wissen wo sie uns hin fhrt. Es ist doch jetzt einmal an der Zeit zu begreifen, daž wichtige Ver„nderungen durchgefhrt werden mssen. Und wenn die Herren Politiker sich mal wieder nicht dazu entschliežen k”nnen, die Probleme der heutigen Zeit konkret anzufassen, dann muss eben der Druck von der Strasse kommen" APPLAUS!! */