/* ** MAC.C -- Small-Mac Assembler -- Part 1: Mainline and Macro Functions ** ** Copyright 1985 J. E. Hendrix ** ** usage: MAC [-L] [-NM] [-P] [-S#] [object] source... ** ** -L Generate an assembly listing on the standard output file. ** ** -NM No macro processing. This speeds up the assembler somewhat. ** Macro processing is NOT needed for Small-C 2.1 output files. ** ** -P Pause on errors waiting for an operator response of CR. ** ** -S# Set symble table size to accept # symbols. ** ** object Name of the object file to be output. It must have a REL ** extension to be recognized as an output file. A drive ** specifier is allowed. If not specified, the object code ** will go into a file (on the default drive) bearing the same ** name as the first source file, but with a REL extension. ** source... Names of the source files to be assembled. The default, and ** only allowed, extension is MAC. A drive specifier is allowed. ** The named files will be assembled as one file concatenated ** in the order given. ** ** NOTE: The module name in the REL file will be taken from ** the first 6 characters of the object filename. */ #include #include "notice.h" #include "mac.h" #include "rel.h" #include "mit.h" #define NOCCARGC /* ** symbol table */ int stmax = STMAX, /* maximum symbols */ stn, /* number of symbols loades */ *stp; /* symbol table pointer array */ char *st, /* symble table buffer */ *stend, /* end of symbol tBLE */ *stptr, /* st entry pointer */ stsym[MAXLAB+1]; /* temporRY SYMBOL SPACE */ /* ** macro definition table */ char *mt, /* macro tBLE BUFFER */ *mtprev, /* previous mt entry */ *mtnext, /* next available mt byte */ *mtend, /* end of macro table */ *mtptr; /* mt entry pointer */ int pass = 1, /* which pass? */ badsym, /* bad symbol? */ gotep, /* have an entry point? */ gotxr, /* have an external reference? */ gotlabel, /* have a label? */ gotnam, /* have a name? */ eom, /* end of module? */ endv, /* END value? */ endt, /* END type? */ err, /* error? */ lerr, /* line error flages */ loc, /* location counter */ lin, /* line counter */ srcfd, /* source file fd */ list, /* generate alisting? */ lline, /* listing inene, force 1st page heading */ part1, /* part one of listing line printed? */ ccnt, /* count of code characters printed */ lpage, /* listing page */ pause, /* pause on errors? */ looks, /* number of looks to find instruction */ macros = YES, /* macro processing? */ mlnext, /* next macro label to assign */ mlnbr[10], /* macro label numbers */ mpptr[10], /* macro parameter pointers */ defmode, /* macro definition mode */ expmode; /* macro expansion mode */ char *ep, /* expression pointer */ *lp, /* line pointer */ line[MAXLINE], /* source line */ *prior, /* prior ext ref in chain */ srcfn[MAXFN+4], /* source filename */ objfn[MAXFN+4]; /* object filename */ main(argc, argv) int argc, *argv; { fputs("Small-Mac Assembler, ", stderr); fputs(VERSION, stderr); fputs(CRIGHT1, stderr); getsw(argc, argv); /* get command line options */ pass1(argc, argv); /* build symbol table */ pass2(argc, argv); /* generate object code */ if(err) abort(7); /* sound the alarm */ } /* ** pass one */ pass1(argc, argv) int argc, *argv; { int max; st = calloc(STBUFSZ, 1); /* allocate zeroed symbol table */ stp = calloc(stmax, INTSZ); stend = st + STBUFSZ; /* remember end of table */ max = avail(YES); /* how much available? */ max -= STACK + (MAXOPEN * OHDOPEN); /* calculate how much */ mt = mtnext = calloc(max, 1); /* allocate space */ mtend = mt + max - MAXLINE; /* note end of macro buffer */ dopass(argc, argv); /* do pass 1 */ } /* ** pass two */ pass2(argc, argv) int argc, *argv; { int i; outrel = open(objfn, "w"); /* open object file */ putname(); /* declare module name */ putent(); /* declare entry points */ putsz(); /* declare program size */ pass = 2; /* signal pass 2 */ dopass(argc, argv); /* do pass 2 */ putexs(); /* declare ep and xr symbols */ putend(); /* declare end of program */ if(ferror(outrel)) err = YES; close(outrel); /* close object file */ } /* ** process passes 1 and 2 */ dopass(argc, argv) int argc, *argv; { int mop; int i; mlnext = lpage = i = lin = loc = 0; /* reset everything */ lline = 100; /* force page heading */ while(getarg(++i, srcfn, MAXFN, argc, argv) != EOF) { if(srcfn[0] == '-') continue; if(extend(srcfn, SRCEXT, OBJEXT)) continue; srcfd = open(srcfn, "r"); /* open source file */ eom = NO; /* not end of module */ goto input; while(YES) { poll(YES); ++lin; lerr = 0; /* bump line counter & zero errors */ part1 = NO; /* part 1 of line not listed */ beglin(); /* begin a listing line */ if(macros == NO) { dolabel(); /* do label and find next field */ if(!domach()) doasm(); /* machine or assembler instr? */ } else { lp = line; lp = getsym(lp, NO); if(!(mop = macop()) && gotnam) { /* 2nd field a token? */ lp = skip(1, line); /* no, ttry fisrst */ mop = macop(); } if(defmode) { /* definition mode */ if(mop == ENDM) defmode = NO; if(pass == 1) putmac(); /* put line in macro table */ } else { /* copy or expansion mode */ if(mop == CALL) { /* enter expansion mode */ expmode = YES; putparm(); /* savew parameters */ dolabel(); /* process label */ } else if(mop == MACRO) { /* enter definition mode */ defmode = YES; if(pass == 1) newmac(); /* init new macro in table */ } else if(mop == ENDM) { /* leave expansion mode */ expmode = NO; } else { if(expmode) replace(); dolabel(); /* do label and find next field */ if(!domach()) doasm(); /* machine or assembler instr? */ } } } endline(); /* end a lising line */ if(pass == 2) gripe(); /* gripe about errors */ if(expmode) getmac(); /* fetch next macro line */ else { input: if(eom) break; if(!fgets(line, MAXLINE, srcfd)) error("- Missing END"); } } if(defmode) {err = YES; puts("- Missing ENDM");} close(srcfd); /* close source file */ } } /* ** can line take more? */ cantake(i, need) int i, need; { return (i < (MAXLINE - 3) - need); } /* ** get a line from the macro buffer */ getmac() { char *cp; cp = line; while(*cp++ = *mtptr++) ; } /* ** get switches from command line */ getsw(argc, argv) int argc, *argv; { char arg[MAXFN+4]; int i, j, len; i = 0; while(getarg(++i, arg, MAXFN, argc, argv) != EOF) { if(arg[0] == '-') { if(toupper(arg[1]) == 'L') list = YES; else if(toupper(arg[1]) == 'P') pause = YES; else if(toupper(arg[1]) == 'N' && toupper(arg[2]) == 'M') macros = NO; else if(toupper(arg[1]) == 'S') { len = utoi(arg + 2, &j); if(len > 0 && !arg[len + 2]) stmax = j; else usage(); } else usage(); } else { if(extend(arg, OBJEXT, OBJEXT) || !*objfn) { if(arg[1] == ':') j = 2; else j = 0; strcpy(objfn, arg + j); } } } } /* ** recognize macro operation */ macop() { if(fldcmp(lp, "ENDM" ) == 0) return (ENDM); if(fldcmp(lp, "MACRO") == 0) return (MACRO); if(!expmode && !defmode && mtfind()) return (CALL); return (NO); } /* ** test for macro buffer overflow */ macover(ptr) char *ptr; { if(ptr > mtend) error("- Macro Buffer Overflow"); } /* ** find stsym in macro table ** return true if found, else false ** leave mtptr pointing to body of desired macro */ mtfind() { if(atend(*lp) == 0) { mtptr = mt; do { if(fldcmp(lp, mtptr + MTNAM) == 0) { mtptr += MTNAM; mtptr += strlen(mtptr) +1; return (YES); } mtptr = getint(mtptr); } while(mtptr); } return (NO); } /* ** establish new macro */ newmac() { int i; i = 0; if(!gotnam || badsym) symerr(); else { macover(mtnext); if(mtprev) putint(mtprev, mtnext); mtprev = mtnext; putint(mtnext, 0); mtnext += INTSZ; while(*mtnext++ = stsym[i++]) ; } } /* ** put a line in the macro buffer */ putmac() { char *cp; cp = line; macover(mtnext); /* will buffer take it? */ while(*mtnext++ = *cp++) ; /* copy everything */ } /* ** save macro call parameters in macro buffer ** and reset labels */ putparm() { int i, dlm; char *cp; i = -1; cp = mtnext; lp = skip(2, lp); /* skip to parameters */ while(++i < 10) { mlnbr[i] = 0; /* null macro label nbr */ while(isspace(*lp)) ++lp; if(atend(*lp) || *lp == ',') mpptr[i] = 0; else { macover(cp); mpptr[i] = cp; while(!atend(*lp) && *lp != ',') { if(*lp == '\"' || *lp == '\'') { dlm = *lp; while(!atend(*++lp)) { if(*lp == dlm && *++lp != dlm) break; *cp++ = *lp; } } else *cp++ = *lp++; } *cp++ = NULL; } if(*lp == ',') ++lp; } if(!atend(*lp)) parerr(); } /* ** replace parameters */ replace () { char lin[MAXLINE]; int ndx; char *cp, *cp2; int i; strcpy(lin, line); cp = lin; i = 0; do { if(*cp == '?') { /* substitution marker? */ if(isdigit(*++cp)) { /* parameter substitution */ ndx = *cp++ - '0' - 1; /* which one? */ if(ndx < 0) ndx = 9; /* make 0 mean 10 */ if(cp2 = mpptr[ndx]) { /* got parameter? */ while(*cp2) /* yes, copy it */ if(cantake(i, 1)) line[i++] = *cp2++; } continue; } } if(*cp == '@') { /* label substitution? */ if(cantake(i, 1)) line[i++] = '@';/* insert label prefix */ if(isdigit(*++cp)) { /* which one? */ ndx = *cp++ - '0'; if(!mlnbr[ndx]) mlnbr[ndx] = ++mlnext; /* need new label number? */ if(cantake(i, 5)) { left(itou(mlnbr[ndx], line + i, 5)); /* insert label number */ while(line[i]) ++i; /* bypass label number */ } continue; } } if(cantake(i, 1)) line[i++] = *cp++; else { line[i++] = '\n'; break; } } while(*cp); line[i] = NULL; } /* ** abort with message */ usage() { error("Usage: MAC [-L] [-NM] [-P] [-S#] [object] source..."); }