/* File: macro.c * * Contains: macro, getmac, maclook,mlocal * * This is the routine that EXPANDS a macro. */ #include "asm.h" #define LMACO (AFLOC | AFMLOC) static int mstart_count = 1; static MAC *insert_point; static MAC *start_mp = 0; static int maccnt = 0; static char loc; /* processed local */ int nmac; /* number of nested macros */ int nargs; MAC *mp_ptr = 0; MACTX *mxp = 0; char *dmacro_parm; /* macro definition parm list */ char *macro_parm; /* macro usage parm list */ /*. ************************************************************************* * * * macro * * ----- * * * * expand macro * * * * * * * ************************************************************************* */ void macro() { register MAC *mp; register char *fp; register unsigned char *lp; register int i; char old_nargs; MACTX *old_mxp; char *old_dmacro_parm, *old_macro_parm; char ex1[100]; #if DEBUG printf("macro\n"); #endif if (false_condit) return; if (nmac >= MAXMAC) { eror('O'); return; } mp = mp_ptr; #if DEBUG printf("macro:found *%s*\n",mp->mx_name); #endif if (passno == 2 && mp->mx_flag & MXDDEF) { /* * if error already noted, then just mark line */ if (mp->mx_flag & MXDDRD) errbuf[0] = 'D'; else { /* * macro doublely defined - error */ eror('D'); mp->mx_flag |= MXDDRD; } } proces(); lstln(); if (passno == 2 && objfile) putobj(); /* * evaluate all parameters to count the number of args */ i = 0; errbuf[0] = 'U'; lp = linpnt; fp = ex1; while (*lp && *lp != ';') { if (*lp == SQUOTE) { *fp++ = *lp++; while (*lp != SQUOTE) { if (*lp == 0) { lp--; break; } *fp++ = *lp++; } *fp++ = SQUOTE; lp++; } else if (*lp == ',') { i++; *fp++ = *lp++; } else *fp++ = *lp++; } *fp = 0; if (i) i++; old_nargs = nargs; nargs = i; nmac++; old_mxp = mxp; old_dmacro_parm = dmacro_parm; old_macro_parm = macro_parm; dmacro_parm = mp->mx_param; macro_parm = ex1; mxp = mp->mx_text; while(mxp) { get_mac_text(); doasm(0); } if (!(--nmac)) { if (loc && (is_on(LMACO) == LMACO)) { turn_off(AFMLOC); if (is_off(AFLOCL)) turn_off(AFLOC); loc = 0; ++mlocnum; } } lstoff &= MACON; errbuf[0] = ' '; initl(0); dont = 1; /* * restore previous macro pointers */ nargs = old_nargs; mxp = old_mxp; dmacro_parm = old_dmacro_parm; macro_parm = old_macro_parm; } /*. ************************************************************************* * * * get_mac_text * * ------------ * * * * load the next text line of the current macro into 'minbuf' * * * * get_mac_text() * * * * returns no value * * * ************************************************************************* */ void get_mac_text() { register unsigned char *fp, *lp; register int i; lp = minbuf; fp = mxp->mtx_text; /* * move stuff into the expansion buffer until we * encounter a carriage return or a pound sign. * If we hit a pound sign, expand it in line. */ while(*fp) { if (*fp == SQUOTE) { *lp++ = *fp++; while (*fp != SQUOTE) { if (*fp == 0) { fp--; break; } *lp++ = *fp++; } *lp++ = SQUOTE; fp++; } else if (*fp == MACRO) { /* * if we found a pound sign, substitute */ lp = (unsigned char *) getmac(*++fp, dmacro_parm, macro_parm, lp); fp++; if (lp[-1] == SQUOTE && *fp == SQUOTE) fp++; } else *lp++ = *fp++; } *lp = 0; #if DEBUG printf("get_mac_text:*%s*\n",minbuf); #endif fp = numbbb; for(i = 0; i < 5; i++) fp[i] = (i < nmac) ? '+' : SPACE; if (print_mac == 0) lstoff |= MACOFF; mxp = mxp->mtx_next; } /*. ************************************************************************* * * * getmac * * ------ * * * * * * * * * ************************************************************************* */ /* macro substitution. There are three entry parameters; c, pp, fp. * These are: * (c) ascii substitution number * (pp) pointer to definition parameters * (fp) pointer to substitution list * If we can't find the specified parameter, we'll return with a * pointer to 'zero', otherwise return with pointer to substitution. * * The idea behind the routine is to find the same number (c) in the * definition list (pp), counting the arguments as we are looking. * When we find a match, we move in (count) number of arguments in * the substitution list (fp). This argument gets moved to buff * (tx2) and a pointer to that buffer returned to the caller. */ char *getmac(c, pp, fp, lp) register char c, *pp, *fp, *lp; { #if DEBUG printf("getmac\n"); #endif #if DEBUG > 1 printf("getmac: c = *%c*\n",c); printf("getmac: pp *%s*\n",pp); printf("getmac: fp *%s*\n",fp); #endif /* find the number (c) in list (pp) */ for(;;) { if (!notend(pp)) { *lp++ = '0'; return(lp); } if (*pp == COMMA) { while (*fp != COMMA) { if (*fp == 0) { *lp++ = '0'; return(lp); } if (*fp++ == SQUOTE) while (*fp++ != SQUOTE) ; } fp++; } else if (pp[0] == MACRO && pp[1] == c) break; pp++; } if (*pp != MACRO || *fp == COMMA) { *lp++ = '0'; return(lp); } #if DEBUG > 1 printf("getmac: found pp *%s*\n",pp); printf("getmac: found fp *%s*\n",fp); #endif /* * move argument into lp */ while (*fp && *fp != COMMA) { if (*fp == SQUOTE) { if (lp[-1] != SQUOTE) *lp++ = *fp++; while((*lp++ = *fp++) != SQUOTE) ; } else *lp++ = *fp++; } while (lp[-1] == SPACE || lp[-1] == HT) lp--; *lp = 0; return(lp); } /*. ************************************************************************* * * * * * * * * * * ************************************************************************* */ /* look up a macro in the macro table */ MAC *maclook(buff) register char *buff; { register MAC *mp; register int low,high,ptr,retcode; /* #if DEBUG printf("maclook\n"); #endif */ if (*buff == 0) return(0); mp = start_mp; maccnt = mstart_count; low = 0; high = macnum + 1; while ((ptr = (high-low)/2 + low) != low && ptr != high) { retcode = maccnt; while (ptr > retcode) { mp = mp->mx_right; retcode++; } while (ptr < retcode) { mp = mp->mx_left; retcode--; } maccnt = retcode; #if DEBUG > 1 printf("maclook: low = %d\n",low); printf("maclook: high = %d\n",high); printf("maclook: ptr = %d\n",ptr); printf("maclook: maccnt = %d\n",maccnt); printf("maclook: buff = *%s*\n",buff); printf("maclook: mp->mx_name = *%s*\n",mp->mx_name); #endif if ((retcode = check(buff,mp->mx_name)) == TOO_HIGH) low = ptr; else if (retcode == TOO_LOW) high = ptr; else return(mp); } if (retcode == TOO_HIGH) { if (mp->mx_right) insert_point = mp->mx_right; else insert_point = 0; maccnt++; } else insert_point = mp; return(0); } /*. ************************************************************************* * * * mlocal * * ------ * * * * * * * * * ************************************************************************* */ void mlocal() { int x; unsigned char *lp; unsigned char buff[MAXLTH]; lp = skipsp(linpnt); while(notend(lp)) { if (*lp != MLOCAL) { eror('S'); return; } ++lp; lp = gsym(lp, labbuf); (void) sprintf(buff, "%x", mlocnum); if((x = slenth - len(buff)) > 0) labbuf[x] = 0; (void) strcat(labbuf, buff); labflg = 0; turn_on(LMACO | AFGLAB); (void) proc_symbol(DEFBTK,0); if (*lp == COMMA) ++lp; } turn_off(AFMLOC); if (is_off(AFLOCL)) turn_off(AFLOC); loc = 1; } /*. ************************************************************************* * * * gmacro * * ------ * * * * * * * * * ************************************************************************* * * This is the routine that DEFINES a macro. On pass 1 it will read * in each line, storing it in the macro table, until an ENDM is * found. One pass 2, the macro is just listed and ignorned. */ void gmacro() { register MAC *mp, *old_mp; register MACTX *mxpp, *old_mxp; register char *fp; register unsigned char *lp; int flag, i; #if DEBUG printf("gmacro\n"); #endif if (false_condit) return; if (ortkbf[1] == 2) { eror('S'); return; } flag = 1; /* * if duplicate macro name, error */ if (mp = maclook(labbuf)) { flag = 0; if (passno == 1) { eror('D'); mp->mx_flag |= MXDDEF; } } else { /* * move the new macro name into the table */ macnum++; if ((mp = (MAC *) xalloc(MSIZE)) == 0) { bad: printl("Can't allocate for macro\n"); xdone(1); } if ((mp->mx_name = xalloc(slenth+1)) == 0) goto bad; (void) strcpy(mp->mx_name, labbuf); /* * move any parameters into the macro */ lp = linpnt; if ((mp->mx_param = xalloc(30)) == 0) goto bad; fp = mp->mx_param; while(!term(lp)) { if (*lp == MACRO) { if (alpnum(lp+2)) { (void) strcpy(mp->mx_name, "+++++"); eror('S'); } } if (*lp == ' ' || *lp == HT) lp++; else *fp++ = *lp++; } *fp = 0; #if DEBUG printf("stored: %s\n", mp->mx_param); #endif mp->mx_flag = 0; mp->mx_text = 0; mp->mx_left = 0; mp->mx_right = 0; if (macbeg == 0) { macbeg = mp; macend = mp; start_mp = mp; mstart_count = maccnt; } else { old_mp = insert_point; if (old_mp == 0) { /* * insert macro at the end of the table */ old_mp = macend; old_mp->mx_right = mp; mp->mx_left = old_mp; macend = mp; } else { /* * insert macro somewhere inside the table */ mp->mx_left = old_mp->mx_left; old_mp->mx_left = mp; mp->mx_right = old_mp; if (old_mp == macbeg) macbeg = mp; else { old_mp = mp->mx_left; old_mp->mx_right = mp; } if (maccnt <= mstart_count) mstart_count++; i = macnum/2; if (abs(maccnt - i) < abs(mstart_count - i)) { start_mp = mp; mstart_count = maccnt; } } } } /* * now process each line till we see an endm */ for(;;) { lstln(); /* list PREVIOUS line */ initl(0); turn_on(DMACRO); if (getline() == EOF) break; if (rlist) printl("%s%s\n", numbbb, minbuf); (void) get_label(minbuf); getor(linpnt); #if DEBUG > 1 printf("gmacro: minbuf=*%s*\n",minbuf); printf("gmacro: errbuf=*%s*\n",errbuf[0]); #endif if (ortkbf[0] == MACROT && ortkbf[1] == 2) break; if (flag) { if ((mxpp = (MACTX *) xalloc(MTSIZE)) == 0) goto bad; mxpp->mtx_next = 0; mxpp->mtx_text = (unsigned char *) xalloc(len(minbuf)+1); (void) strcpy(mxpp->mtx_text, minbuf); if (mp->mx_text) old_mxp->mtx_next = mxpp; else mp->mx_text = mxpp; old_mxp = mxpp; } } turn_off(DMACRO); }