/* ---------------------------------------------------------------------- */ /* Copyright (C) 1991 by NatŠrlich! */ /* This file is copyrighted! */ /* Refer to the documentation for details. */ /* ---------------------------------------------------------------------- */ #define DEBUG 0 #define LOCALDEBUG DEBUG #include <stdio.h> #include "defines.h" #include "nasm.h" #include "y_tab.h" #include "labels.h" #include "debug.h" #include <setjmp.h> #include "buffer.h" #if VERSION #include "inputfst.h" #include "exprfast.h" #endif #include OSBIND #include NMALLOC_H #include "code.h" #define MB_SIZE (sizeof( buffer) + sizeof( macro)) #define NIL ((char *) 0) #if __NSTDC__ && TURBO static void mac_done( buffer huge *), lxsyntax( char *); static int mac_get( void), *more_space( void); extern int (*gettoken)(void); #else static void mac_done(), lxsyntax(); static int mac_get( void); extern int (*gettoken)(); #endif static macro huge *header[SEP], huge *tailer[SEP], huge *rover; extern char is_where[], ovf_loss[]; int freshflag = 1, _call_macro; extern char c; extern jmp_buf syn_panic; #if DEBUG #if LOCALDEBUG int syndebug; #else extern int syndebug; #endif #endif extern int _in_if, show_expansion, show_mload; extern lword yylval, l_hash; extern buffer huge *bp, huge *hp; int used, _in_macro; /* ---------------------------------------------------------- */ /* This is a rather wasteful, but nevertheless _fast_ way of */ /* Sucking in macros. Only once, when the boundary has been */ /* crossed, there is a need to copy over stuff. */ /* ---------------------------------------------------------- */ typedef struct mac_m_ { int huge *s; struct mac_m_ huge *before; } mac_m; static mac_m huge *c_h; word tok_remain; static int huge *start; /* points to the beginning of macro */ static int *more_space() { register mac_m huge *p; register lword rem; #if STATISTICS extern word _m_macro; extern lword _s_macro; _m_macro++; _s_macro = MACSPACE + sizeof( mac_m); #endif ENTER("more_space"); p = (mac_m huge *) nmalloc( MACSPACE + sizeof( mac_m)); p->s = (int *) ((char huge *) p + sizeof( mac_m)); if( ! (p->before = (mac_m huge *) c_h)) /* First time ?? */ { c_h = p; tok_remain = MACTOKMAX; LEAVE(); return( start = p->s); } #if ! VERSION if( (size_t) ((char huge *) c_h->s + MACSPACE - (char huge *) start) != (lword) ((char huge *) c_h->s + MACSPACE - (char huge *) start)) nierror("Conversion did indeed lose some bytes in MACRO.C:more_space"); #endif if( start == c_h->s) nferror("ONE macro can't possibly be THAT long!"); bcopy( start, p->s, rem = (lword) ((char huge *) c_h->s + MACSPACE - (char huge *) start)); tok_remain = (word) ((MACSPACE - rem) / (sizeof( int) + sizeof( lword))); c_h = p; LEAVE(); return( (int *) ((char huge *) (start = p->s) + rem)); } /* ---------------------------------------------------------- */ /* Functions to suck in a macro and store it. */ /* HIDE your register variables, if a LONGJMP is about to */ /* happen. Therefore no and remain are static outside. */ /* ---------------------------------------------------------- */ static unsigned no = 0; /* bc/o LONGJMPs */ void load_macro( name) char *name; { register int tok; register int huge *s = start; ENTER("load_macro"); no = 0; freshflag = 1; /* new yylex caller */ if( find_macro( name)) { nerror("This old assembler can't handle macro redefinitions, so you better choose another name"); while( (tok = yylex()) && tok != T_ENDM); if( ! tok) nferror("Reached end of file while skipping to .ENDM"); return; } if( (tok = yylex()) != T_EOL) { nwarning("Garbage after .macro <name> definition!"); while( (tok = yylex()) != T_EOL); } inc_line(); if( show_mload) printf("Loading macro definition \"%s\"\n", name); for(;;) { switch( tok = yylex()) { case 0 : MESS("Case 0"); nferror("Reached end of file before an .ENDM"); case T_MACRO : MESS("Case T_MACRO"); nerror("U can't define a macro in a macro, ignoring until .ENDM"); while( (tok = yylex()) && tok != T_ENDM); if( ! tok) nferror("...unfortunately that doesn't exist"); break; case T_ENDM : MESS("Case T_ENDM"); { register buffer huge *p; register macro huge *q; p = (buffer huge *) nmalloc( (long) MB_SIZE); q = (macro huge *) ((char huge *) p + sizeof( buffer)); p->buflist = p->p = (byte *) start; p->name = name; p->remain = p->oremain = no; p->type = BUF_ALLOC | BUF_TOKEN | BUF_MACRO; p->multi.fill= (void (*)(buffer *)) dummy; /* **-PORT #1-**/ p->done = mac_done; p->get = (int (*)()) mac_get; /* **-PORT #1-**/ MESS("Filling q"); q->name = p->name = name; q->hash = l_hash; q->buf = p; q->inuse = p->line = 0; MESS("Linking in..."); einlinker( header, tailer, rover, used, q); start = (int huge *) s; freshflag = 1; /* a new yylex caller will appear */ LEAVE(); return; } case T_INCLUDE : MESS("T_INCLUDE"); if( ! (tok = yylex())) nferror("Unexpected EOF in the middle of a macro definition"); if( tok != T_FILE) nerror("Valid file specifier expected after .INCLUDE"); include( (char *) yylval, ".s65"); if( (tok = yylex()) != T_EOL) { nwarning("Garbage after .include <file> definition!"); while( (tok = yylex()) != T_EOL); } break; default : while( ! tok_remain--) s = more_space(); if( (*s++ = tok) == T_EOL) bp->line++; *(lword huge *)s = yylval; s += sizeof( lword) / sizeof( int); no++; } } } #if DEBUG #define fdreturn( val) \ { \ int foo = (val); \ \ prtname( foo); \ LEAVE(); \ return( foo); \ } #else #define fdreturn return #endif static int mac_get() { static int tok; register buffer huge *P = bp; ENTER("mac_get"); if( freshflag) /* Have we set syn_panic already ?? */ { freshflag = 0; /* No clr flag */ #if DEBUG SAVESTATE( &syndebug); #endif if( setjmp( syn_panic)) /* Do the setjmp ONCE */ { int foo; #if DEBUG SETBACK(syndebug); #endif MESS("\007\t\tsyntax panic occurred"); while( P->remain--) /* Something left ? */ { foo = *(int huge *)P->p; P->p += sizeof( int) + sizeof( lword); if( foo) break; } } } if( P->remain--) /* Something left ? */ { #if ! PHILOSOPHICAL_PROBLEM tok = *((int huge *) P->p)++; yylval = *((lword huge *) P->p)++; #else tok = *(int huge *) P->p; P->p = (void huge *) ((int *) P->p + 1); yylval = *(lword huge *) P->p; P->p = (void huge *) ((lword huge *) P->p + 1); #endif if( tok < HIGHEST || _in_if) /* not a parameter ?? */ fdreturn( tok); /* then return that */ { register lexpr huge *l; if( tok >= T_MLPARA) { register label huge *q; MESS("Using the label indirection"); if( ! (q = find_label( (char huge *) yylval)) || q->refs) lxsyntax("Foward references of macro indices. Tsk Tsk"); yylval = (lword) q->val; } if( yylval > P->parms.list->expr->val) lxsyntax("Missing macro parameter error"); l = lex_get( P->parms.list, (word) yylval); if( _call_macro) { yylval = (lword) l; return( T_PARA); } if( (tok & 1) == (T_MSPARA & 1)) /* OPTIMIZE */ { yylval = (lword) l->string; IMESS("Supplying $%lx as string value", yylval, 4); fdreturn( T_STRING); } l = (lexpr huge *) l->expr; yylval = (lword) copyexpr( (expr *) l); /* ((expr *)yylval)->fix = 0; */ /* That true ? */ IMESS("Supplying $%lx for an expression", yylval, 4); fdreturn( T_EXPR); } } #if DEBUG dump_buffer( bp); #endif MESS("Killing buffer"); kill_buffer( hp); /* Install new buffer */ #if DEBUG dump_buffer( bp); #endif fdreturn( T_EOL); } macro *find_macro( s) register char *s; { register macro huge *p; register lword hash; register int res; ENTER("find_macro"); IMESS("Looking for \"%s\"", (lword) s, 4); l_hash = hash = calc_hash( s + 1); p = header[ used = is_where[*s]]; while( p && (p->hash < hash || (p->hash == hash && (res = strcmp( p->name, s)) < 0))) p = p->next; rover = p; if( ! found( p, hash) || res) /* if not found or at end of table */ { LEAVE(); return( 0); } LEAVE(); return( p); } void do_macro( name, lex) char *name; lexpr huge *lex; { register macro huge *q; register buffer huge *p; int flag = __p - __program >= MAXMODULE; ENTER("do_macro"); IMESS("Executing macro \"%s\"", (lword) name, 4); if( q = find_macro( name)) { lex->string = make_string( name); /* ARGH! make that better */ if( ! q->buf->oremain) { LEAVE(); return; } if( q->inuse) { MESS("q seems to be in use"); if( q->inuse == 1) nwarning("Macro recursion (allowed but maybe unwanted)"); if( flag) nferror("Probably a macro recursion caused the code buffer\ overflow"); p = (buffer huge *) nmalloc( (long) sizeof( buffer)); bcopy((char *) q->buf, (char *) p, (long) sizeof( buffer)); p->buflist = p->p = q->buf->buflist; p->remain = p->oremain; p->name = q->name; p->type = BUF_MACRO | BUF_TOKEN | BUF_FREE | BUF_ALLOC; } else p = q->buf; if( flag) nferror( ovf_loss); q->inuse++; IMESS("p->remain = %ld", p->remain, 4); if( (p->before = bp)) { bp->next = p; /* if( ! (bp->type & BUF_TOKEN)) bp->_aux2 = c; */ } p->multi.dad = q; p->parms.list = lex; p->line = 0; p->next = 0; p->get = (int (*)()) (gettoken = mac_get); /* **-PORT #1-**/ p->done = mac_done; bp = p; MESS("MACRO has been linked into buffer list"); #if DEBUG dump_buffer( bp); #endif freshflag = 1; _in_macro++; if( show_expansion) { int i = 1; tabout(); printf( "line %4.4d, expanding macro: \"%s\"\n", p->before->line, name); tab(); printf( "\t#parameters : %d\n", lex->expr->val); while( lex = lex->next) { tab(); printf("\t%%%d : %c $%04X %%$%d : \"%s\"\n", i, valued( lex->expr) ? ' ' : 'F', lex->expr->val, i, lex->string + 2); i++; } } } else nserror( "Macro is undefined", name); LEAVE(); } void call_macro( s) char *s; { nwarning("unimplemented directive"); /* if( bp->type & BUF_MACRO) do_macro( s, slex_ch( lex_pl( NIL, bp->parms.list->expr), bp->parms.list->next)); else nerror("You can use .CALL only in macro definitions"); */ } void rept_macro( ex, name, lex) expr huge *ex; char *name; lexpr huge *lex; { if( unvalued( ex)) nerror("No foward references for repeat factor allowed"); else { word i; for( i = ex->val; i; i--) do_macro( name, lex); } } static void mac_done( p) register buffer huge *p; { ENTER("mac_done"); p->line = 0; p->p = p->buflist; p->remain = p->oremain; p->multi.dad->inuse--; /* incomplete */ _in_macro--; /* (later: ;) */ if( show_expansion) { tabin(); printf( "Done with macro: \"%s\"\n", p->name); } LEAVE(); } static void lxsyntax( err) char *err; { nerror( err); longjmp( syn_panic, 1); } /* ; Huh? What? Why?? Tell me more... I don't see the problem */