/* ** MAC2.c -- Small-Mac Assembler -- Part 2: pass 1 and 2 Functions ** ** Copyright 1985 J. E. Hendrix */ #include #include "mac.h" #include "rel.h" #include "ext.h" #define NOCCARGC extern int iloc; /* instr location */ /* ** add a new symbol to the table */ addsym() { char *dest, *sour; if(*stptr) error("- Symbol Table Overflow"); stp[stn++] = stptr; /* set symbol pointer */ dest = stptr; sour = stsym; while(*dest++ = toupper(*sour++)); } /* ** determine if an assembler insrtruction */ aifind() { char *cp; cp = lp; while(isgraph(*lp)) ++lp; while(isspace(*lp)) ++lp; if(fldcmp(cp, "DW") == 0) return (DW); else if(fldcmp(cp, "DB") == 0) return (DB); else if(fldcmp(cp, "DS") == 0) return (DS); else if(fldcmp(cp, "EXT") == 0) return (EX); else if(fldcmp(cp, "SET") == 0) return (SET); else if(fldcmp(cp, "EQU") == 0) return (EQU); else if(fldcmp(cp, "ORG") == 0) return (ORG); else if(fldcmp(cp, "END") == 0) return (END); return (ERR); } /* ** begin a line in the listing */ begline() { char str[6]; if(pass == 2 && list) { if(begpage()) { puts("line loc ----object---- source"); puts(""); lline += 2; } itou(lin, str, 5); fputs(str, stdout); itox(loc, str, 6); fputs(str, stdout); putchar(' '); ccnt = 0; ++lline; } } /* ** begin a page? */ begpage() { char str[4]; if(lline >= 58) { lline = 2; ++lpage; if(lpage > 1) puts("\n\n\n\n\n\n\n"); fputs("file: ", stdout); fputs(srcfn, stdout); itou(lpage, str, 4); fputs(" page: ", stdout); puts(str); puts(""); return (YES); } return (NO); } /* ** detect assembler instruction and process it */ doasm() { int j; if(atend(*lp) && (!stsym[0] || gotlabel)) return; if((j = aifind()) == ERR) { /* lp -> 2nd field or end */ lp = skip(1, line); /* lp -> 1st field */ j = aifind(); stsym[0] = NULL; /* declare no symble */ } switch(j) { case EX: doext(); return; case DW: dodat(INTSZ); return; case DB: dodat(1); return; case DS: doloc(YES); return; case ORG: doloc(NO); return; case SET: doval(SETBIT); return; case EQU: doval(0); return; case END: doend(); return; } oprerr(); } /* ** define data (DB & DW) */ dodat(sz) int sz; { int dlm; while(!atend(*lp)) { if(isspace(*lp) || *lp == ',') ++lp; else if(*lp == '\"' || *lp == '\'') { /* string? */ dlm = *lp; while(!atend(*++lp)) { if(*lp == dlm && *++lp != dlm) break; if(pass == 2) {field = *lp; genabs(sz);} else loc += sz; } } else { ep = lp; /* expression? */ expr(&field, &type); lp = ep; if(pass == 2) { type &= RELBITS; if(type == ABS) genabs(sz); else { if(sz == 1) {relerr(); genabs(1);} /* 1-byte relocatable? */ else genrel(); /* output relocatable item */ } } else loc += sz; } } } /* ** process END instruction */ doend() { eom = YES; /* flag end of module */ onexpr(); if((type & RELBITS) == PREL) { endt = PREL; endv = field; } else if(field) relerr(); } /* ** define external reference (ECT) */ doext() { while(!atend(*lp)) { while(isspace(*lp) || *lp == ',') {++lp; continue;} lp = getsym(lp, NO); /* fetch the next symbol */ if(badsym) {symerr(); continue;} /* symbol error */ else if(stfind()) { /* already in table? */ if(stptr[STFLAG] & (LABBIT|EQUBIT|SETBIT)) {rederr(); continue;} } else addsym(); /* not yet defined */ if(pass == 1) stptr[STFLAG] |= XRBIT|ABS; /* 1st ext ref is ABS 0 */ } } /* ** detect label and stow it away */ dolabel() { lp = skip(1, line); /* locatefirst field */ lp = getsym(lp, NO); /* fetch a symble */ if(gotlabel) { /* got label */ if(badsym) {laberr(); return;} if(stfind()) { /* already in table */ if(pass == 1) { if(stptr[STFLAG] & (LABBIT|EQUBIT|SETBIT|XRBIT)) {rederr(); return;} } else if(stptr[STFLAG] & (LABBIT2|EQUBIT|SETBIT|XRBIT)) {rederr(); return;} else stptr[STFLAG] |= LABBIT2; } else addsym(); /* not defined, stow it */ if(pass == 1) { putint(stptr + STVALUE, loc); /* value */ if(gotep) /* flags */ stptr[STFLAG] = LABBIT|PREL|EPBIT; else stptr[STFLAG] = LABBIT|PREL; } } } /* ** set location counter (ORG, DS) */ doloc(bump) int bump; { if(onexpr()) { if(bump) field = loc += field; else if(loc <= field) loc = field; else bakerr(); if(pass == 2) {item = SETLC; type = PREL; putrel();} } } /* ** detect machine instruction and process it */ domach() { char *fmt, *cp; if(gotlabel) cp = lp; else cp = skip(1, line); /* backup if no label */ if(fmt = find(cp)) { /* machine instruction? */ fmt += INTSZ; /* locate format byte in mit */ if(pass == 2) domac2(fmt); /* do pass 2 processing */ else loc += (*fmt & 3) + 1; /* bump location counter */ return (YES); } return (NO); /* may be pseudo-op */ } /* ** detect machine instruction and generate object code */ domac2(ptr) char *ptr; { int format, len, ilen, pcr, t, v, opcode, holding; format = getint(ptr++); /* ptr is now 1 byte early */ len = ilen = (format & 7) + 1; format >>= 3; /* first code/expr bit */ iloc = loc; /* preserve istr loc for $ */ holding = NO; ep = expbuf; /* set up for expr() */ while(len-- > 0) { /* for each byte of code */ if(format & 1) { /* expression */ if(holding) { holding = NO; field = opcode + opadj; /* adjust last byte before expr */ opadj = 0; genabs(1); } expr(&v, &t); /* evaluate next expression */ format >>= 1; /* pc relative bit */ if(format & 1) { if((t & RELBITS) == PREL) { v -= ilen + iloc; /* calc offset from this instr */ t = (t & ~RELBITS) + ABS; /* now abs, may be 1 byte */ } else v -= ilen; /* adjust offset from this instr */ pcr = YES; /* remember it's pc relative */ } else pcr = NO; format >>= 1; /* size bit */ if(format & 1) { /* 2-byte expr */ if(t & XRBIT) { /* ext ref */ if(v) { /* must be offset from ext ref */ item = XPOFF; type = ABS; field = v; listcode(2, "+ "); /* list offset */ putrel(); /* write 2-byte offset */ } field = prior; /* will link to prior ref */ } else field = v; /* expr value */ if((t & RELBITS) == ABS) genabs(2); /* write 2 absolute bytes */ else genrel(); /* write 2 relocatable bytes */ --len; } else { /* 1-byte expr */ if((t & RELBITS) == PREL) relerr(); /* 1 byte can't be relocatable */ if(pcr && (v > 127 || v < -128)) rngerr(); /* range error */ field = v; /* expr value */ genabs(1); /* write 1 absolute byte */ } } else { /* code byte */ if(holding) { field = opcode; /* don't adjust, not last byte */ genabs(1); /* write prior code byte */ } opcode = *++ptr & 255; /* hold this one, may be more */ holding = YES; } format >>= 1; } if(holding) { field = opcode + opadj; genabs(1); /* write last code byte */ } } /* ** define a symbol value (SET, EQU) */ doval(set) int set; { char *ptr; int found; if(!stsym[0] || badsym || gotlabel) {symerr(); return;} if((found = stfind()) == 0) addsym();/* not defined */ ptr = stptr; /* preserve stptr */ onexpr(); /* evaluate expression */ if(pass == 1 || set) { if(found == 0 || ptr[STFLAG] & set) { putint(ptr + STVALUE, field); /* value */ ptr[STFLAG] = set|type; /* flags */ } else rederr(); } else if(ptr[STFLAG] & (LABBIT|EQUBIT|SETBIT|XRBIT)) rederr(); else ptr[STFLAG] |= EQUBIT; if(pass == 2) { /* list value */ if((ptr[STFLAG] & RELBITS) == PREL) listcode(2, "' ="); else listcode(2, " ="); } } /* ** end a line in the listing */ endline() { char *cp; int col; col = 0; if(pass == 2 && list) { if(part1) puts(""); else { part1 = YES; while(ccnt++ < 16) putchar(' '); cp = line; while(*cp) { if(*cp != '\t') {++col; putchar(*cp++);} else {do putchar(' '); while(++col % 8); ++cp;} } } } } /* ** generate an absolute value of sz bytes */ genabs(sz) int sz; { listcode(sz, " "); loc += sz; /* bump location counter */ item = ABS; while(sz--) {putrel(); field >>= 8;} } /* ** generate a relocatable item */ genrel() { listcode(2, "' "); loc += 2; /* bump location counter */ item = PREL; putrel(); /* write 2-byte relocatable item */ } /* ** gripe about errors in a line */ gripe() { if(lerr) { if(!list) outerr(line); if(lerr & 1) outerr("- Backward Movement\n"); if(lerr & 2) outerr("- Bad Number\n"); if(lerr & 4) outerr("- Bad Expression\n"); if(lerr & 8) outerr("- Bad Label\n"); if(lerr & 16) outerr("- Bad Operation\n"); if(lerr & 32) outerr("- Redundant Definition\n"); if(lerr & 64) outerr("- Bad Symbol\n"); if(lerr & 128) outerr("- Relocation Error\n"); if(lerr & 256) outerr("- Undefined Symbol\n"); if(lerr & 512) outerr("- Bad Parameter\n"); if(lerr & 1024) outerr("- Range Error\n"); if(pause) wait(); outerr("\n"); err = YES; } } bakerr() {lerr |= 1;} numerr() {lerr |= 2;} experr() {lerr |= 4;} laberr() {lerr |= 8;} oprerr() {lerr |= 16;} rederr() {lerr |= 32;} symerr() {lerr |= 64;} relerr() {lerr |= 128;} underr() {lerr |= 256;} parerr() {lerr |= 512;} rngerr() {lerr |= 1024;} /* ** list a code item */ listcode(sz, suff) int sz; char suff[]; { int i; char str[3]; if(list) { i = sz + sz + strlen(suff); if((ccnt + i) > 16) {endline(); begline();} while(sz--) { if(sz) itox((field >> 8) & 255, str, 3); else itox(field & 255, str, 3); if(*str == ' ') *str = '0'; fputs(str, stdout); } fputs(suff, stdout); ccnt += i; } } /* ** output an error line */ outerr(str) char *str; { begpage(); fputs(str, stdout); ++lline; } /* ** require one expression only */ onexpr() { ep = lp; expr(&field, &type); if(atend(*ep)) return (YES); experr(); return (NO); } /* ** output end of program and file */ putend() { item = EPROG; type = endt; field = endv; putrel(); item = EFILE; type = ABS; field = 0; putrel(); } /* ** output entry points */ putent() { char *cp; cp = st; while(cp < stend) { poll(YES); if(*cp) { if(cp[STFLAG] & EPBIT) { /* entry point **/ item = ENAME; strncpy(symbol, cp, MAXSYM + 1); putrel(); } } cp += STENTRY; } } /* ** output entry point or external reference */ putex(cp, i) char *cp; int i; { item = i; type = cp[STFLAG] & RELBITS; field = getint(cp + STVALUE); strncpy(symbol, cp, MAXSYM + 1); putrel(); } /* ** output ent pnt and ext ref symbols */ putexs() { int i; char *cp; ccnt = 0; /* init for show() */ shell(0, stn - 1); /* sort the symbols */ if(list && !begpage()) {++lline; puts("");} for(i = 0; i < stn; ++i) { poll(YES); cp = stp[i]; if(list) show(cp); if(cp[STFLAG] & XRBIT) putex(cp, XCHAIN); if(cp[STFLAG] & EPBIT) putex(cp, EPOINT); } puts(""); } /* ** output module name */ putname() { int i, j; item = PNAME; if(objfn[1] == ':') i = 2; else i = 0; j = 0; while(objfn[i] && objfn[i] != '.' && j < MAXSYM) symbol[j++] = objfn[i++]; symbol[j] = NULL; putrel(); } /* ** output program size */ putsz() { item = PSIZE; type = PREL; field = loc; putrel(); } /* ** shell sort the symbols */ shell(l, u) int l, u; { int gap, i, j, k, jg; gap = (u - l + 1) >> 1; while(gap > 0) { i = gap + l; while(i <= u) { j = i++ - gap; while(j >= l) { jg = j + gap; if(strcmp(stp[j], stp[jg]) <= 0) break; k = stp[jg]; stp[jg] = stp[j]; stp[j] = k; j -= gap; } } gap >>= 1; } } /* ** show a symbol */ show(cp) char *cp; { char str[5]; begpage(); itox(getint(cp + STVALUE), str, 5); fputs(str, stdout); if((cp[STFLAG] & RELBITS) == PREL) fputs("' ", stdout); else fputs(" ", stdout); fputs(cp, stdout); ccnt += 6 + strlen(cp); if(cp[STFLAG] & LABBIT) {putchar(':'); ++ccnt;} if(cp[STFLAG] & EPBIT) {putchar(":"); ++ccnt;} if(cp[STFLAG] & XRBIT) {fputs("##", stdout); ccnt += 2;} if(ccnt < 60) while(ccnt % 20) {putchar(' '); ++ccnt;} else {puts(""); ++lline; ccnt = 0;} } /* ** find stsym in symbol table ** leave stptr pointing to desired or null entry ** return true if found, else false */ stfind(){ char *start; stptr = start = st + hash(stsym, stmax) * STENTRY; while(*stptr) { if(strcmp(stsym, stptr) == 0) return (YES); if((stptr += STENTRY) >= stend) stptr = st; if(stptr == start) break; } return (NO); }