/* * Simple Minded Assembler Program */ #include #include /* * Error Numbers */ #define DD 1 /* doubly defined symbol */ #define LN 2 /* too long a name */ #define LO 3 /* too large an octal constant */ #define XP 4 /* cross page reference (pass2) */ #define SX 5 /* some obscure syntax error */ #define UNDEF 6 /* undefined symbol (pass2) */ /* * Symbol Types */ #define LABEL8 0 #define MRI 1 #define OPR 2 #define IOT 3 #define INDIR 4 /* * Input Tokens */ #define LABELS 0 #define COMMENT 1 #define OCTAL 2 #define ORIGIN 3 #define ENDING 4 #define IDENTIFIER 5 #define NIL 6 #define ERRORS 7 /* * Detailed Input Tokens (Pass2) */ #define XLAB8 0 #define XCOMMENT 1 #define XOCTAL 2 #define XORIGIN 3 #define XENDING 4 #define XNIL 5 #define XERRORS 6 #define XVARIABLE 7 #define XMRIOPCODE 8 #define XIOTOPCODE 9 #define XOPROPCODE 10 #define XINDIRECTBIT 11 /* * Lexical States */ #define START 0 #define IDENT 1 #define INOCT 2 #define DONE 3 /* * Symbol Table Entry */ typedef struct entry entry; struct entry { char name[8]; int stype; int value; }; /* * Global Variables */ int error; /* flag for fatal error */ int ended; /* flag for end of source file */ char line[128]; /* source input line */ int numchars; /* number of characters in line */ char *posn; /* where we are on line */ entry symtab[512]; /* symbol table */ int numsym; /* number of defined symbols */ int where; /* location counter */ FILE *source; /* source file */ FILE *object; /* object file */ FILE *symbols; /* standard symbol file */ char newsym[8]; /* most recent identifier */ int newval; /* most recent number */ int printval; int passno; /* pass number */ int listing; /* flag to say if want listing */ int argextra; /* count of command line args used as flags, rather than file names. */ int errpass = 0; /* pass on which error report (if any) last generated */ errs(errno, passno) int errno; int passno; { char *p; error++; if (errpass != passno) { errpass = passno; printf("\n\nAssembly error detected in Pass %d\n", passno); } printf("\n\nError occurred in or about the line:\n"); printf("%s\n", line); for (p = line; p < posn; p++) putchar(' '); printf("^\n"); for (p = line; p < posn; p++) putchar(' '); printf("|\n"); printf("\n\nError Type: "); switch (errno) { case XP: printf("Cross Page Reference\n"); break; case DD: printf("doubly defined symbol, %s\n", newsym); break; case LN: printf("too long a name, %s\n", newsym); break; case LO: printf("too large an octal constant\n"); break; case SX: printf("syntax error\n"); break; case UNDEF: printf("undefined symbol, %s\n", newsym); break; } skipline(); } andsymtab() { int i; entry *e; fprintf(object, "%d\n", numsym + 1); for (e = symtab, i = 0; i <= numsym; e++, i++) fprintf(object, "%-8s %d %04o\n", e -> name, e -> stype, e -> value); fprintf(object, "$\n"); } char *pxtyp[] = { "label", "mri", "opr", "iot", "indirect" }; printsymtab() { int i,j; entry *e; printf("\nSymbol Table:\n\n"); printf("%8s %10s %6s %8s %10s %6s\n\n", "Name", "Type", "Value", "Name", "Type", "Value"); j = 1; for (e = symtab, i = 0; i <= numsym; e++, i++) if(e -> stype == LABEL8) { printf("%8s ", e -> name); printf("%10s ", pxtyp[e -> stype]); printf(" %04o", e -> value); j++; if (j % 2) putchar('\n'); else printf(" "); } } tab(tabpos) int tabpos; { int i; for (i = 0; i < tabpos; i++) putchar(' '); } dumpline() { printf("%s\n", line); } skipline() { while (*posn) posn++; } getline() { int ch; int i; numchars = 0; posn = line; while ((ch = getc(source)) != '\n' && ch != EOF) { numchars++; *posn++ = (isupper(ch) ? tolower(ch) : ch); } if(ch==EOF) { fprintf(stderr,"unexpected end of file\n"); exit(1); } *posn++ = ' '; for (i = numchars; i < 127; i++) *posn++ = 0; posn = line; numchars += 2; } nextsym() { int state; int ch; int octdigit; int alphabetic; int numeric; int dollars; int comma; int star; int slash; int space; int endln; int readtype; int octval; int symlength; int errno; int i; char symbuf[8]; state = START; octval = 0; symlength = 0; for (i = 0; i < 8; i++) symbuf[i] = 0; while (state != DONE) { if (posn - line > numchars) getline(); ch = *posn++; alphabetic = isalpha(ch); numeric = isdigit(ch); octdigit = (ch >= '0' && ch <= '7'); dollars = (ch == '$'); star = (ch == '*'); slash = (ch == '/'); space = (ch == ' ' || ch == '\t'); endln = (ch == 0); comma = (ch == ','); switch (state) { case START: if (star) { readtype = ORIGIN; state = INOCT; } else if (slash) { readtype = COMMENT; state = DONE; } else if (dollars) { readtype = ENDING; state = DONE; } else if (alphabetic) { readtype = IDENTIFIER; state = IDENT; symbuf[symlength++] = ch; } else if (octdigit) { readtype = OCTAL; state = INOCT; octval = (ch - '0'); } else if (endln) { readtype = NIL; state = DONE; } else if (!space) { errno = SX; readtype = ERRORS; state = DONE; } continue; case INOCT: if (octdigit) { if (octval >= 512) { errno = LO; readtype = ERRORS; state = DONE; } else octval = (octval << 3) + (ch - '0'); } else if (space || endln) state = DONE; else { errno = SX; readtype = ERRORS; } continue; case IDENT: if (alphabetic || numeric) { if (symlength < 6) symbuf[symlength++] = ch; if (symlength > 6) { strcpy(newsym, symbuf); errno = LN; readtype = ERRORS; state = DONE; } } else if (space) state = DONE; else if (comma) { state = DONE; readtype = LABELS; } continue; } } if (readtype == ERRORS) errs(errno, passno); if (readtype == LABELS || readtype == IDENTIFIER) strcpy(newsym, symbuf); if (readtype == ORIGIN || readtype == OCTAL) newval = octval; return (readtype); } findposn() { int top; int bottom; int sposn; int found; top = numsym; bottom = 0; found = 0; while (!found) { sposn = (top - bottom) / 2 + bottom; if (strcmp(newsym, symtab[sposn].name) == 0) found++; else if (strcmp(newsym, symtab[sposn].name) > 0) bottom = ++sposn; else top = sposn - 1; found = (found || (bottom > top)); } return (sposn); } xnextsym() { int temp; int sympos; int xtemp; temp = nextsym(); switch (temp) { case LABELS: xtemp = XLAB8; break; case COMMENT: xtemp = XCOMMENT; break; case OCTAL: xtemp = XOCTAL; break; case ORIGIN: xtemp = XORIGIN; break; case ENDING: xtemp = XENDING; break; case NIL: xtemp = XNIL; break; case ERRORS: xtemp = XERRORS; break; case IDENTIFIER: sympos = findposn(); if (strcmp(symtab[sympos].name, newsym) != 0) { xtemp = XERRORS; errs(UNDEF, passno); } else { switch (symtab[sympos].stype) { case LABEL8: xtemp = XVARIABLE; break; case MRI: xtemp = XMRIOPCODE; break; case IOT: xtemp = XIOTOPCODE; break; case OPR: xtemp = XOPROPCODE; break; case INDIR: xtemp = XINDIRECTBIT; break; } newval = symtab[sympos].value; } break; } return (xtemp); } insertsymbol() { int sposn; int n; sposn = findposn(); if (strcmp(newsym, symtab[sposn].name) == 0) errs(DD, passno); else { n = numsym; while (n >= sposn) { symtab[n + 1] = symtab[n]; n--; } strcpy(symtab[sposn].name, newsym); symtab[sposn].stype = LABEL8; symtab[sposn].value = where; numsym++; } } pass1(argc, argv) int argc; char **argv; { if ((source = fopen(argv[1+argextra], "r")) == NULL) { fprintf(stderr, "assemble: Cannot open %s\n", argv[1+argextra]); exit(1); } where = 0; ended = 0; numchars = 0; passno = 1; posn = line; while (!ended) { switch (nextsym()) { case COMMENT: skipline(); break; case ORIGIN: where = newval; break; case LABELS: insertsymbol(); break; case ENDING: ended++; break; case OCTAL: case IDENTIFIER: where++; skipline(); break; } } if(listing) printf("\n\n"); if ( listing) { printf("SMAP Pass 1, Symbol table listing:\n\n"); printsymtab(); printf("\n\n"); } } writecode(cval, next) int cval; int next; { if(!error)fprintf(object, " %04o\n", cval); if(listing) { printf("%04o", where); tab(4); printf("%04o", cval); tab(8); dumpline(); } where++; if (!(next == XCOMMENT || next == XNIL)) errs(SX, passno); else skipline(); } iots() { int next; printval = newval; next = xnextsym(); while (next == XOCTAL) { printval |= newval; next = xnextsym(); } writecode(printval, next); } operate() { int next; printval = newval; next = xnextsym(); while (next == XOCTAL || next == XOPROPCODE) { printval |= newval; next = xnextsym(); } writecode(printval, next); } memrefs() { int next; int temp; int pcp; int dp; printval = newval; next = xnextsym(); if (next == XINDIRECTBIT) { printval |= newval; next = xnextsym(); } if (!(next == XOCTAL || next == XVARIABLE)) errs(SX, passno); else { if (newval < 128) { printval |= newval; writecode(printval, xnextsym()); } else { pcp = where & 07600; dp = newval & 07600; if (pcp != dp) errs(XP, passno); else { temp = newval & 0177; temp |= 128; printval |= temp; writecode(printval, xnextsym()); } } } } pass2(argc, argv) int argc; char **argv; { char *s; rewind(source); ended = 0; numchars = 0; posn = line; passno = 2; if (argc < (3+argextra)) s = "object"; else s = argv[2+argextra]; if ((object = fopen(s, "w")) == NULL) { fprintf(stderr, "assemble: Cannot create %s\n", s); exit(1); } if(listing) printf("\n\nSMAP Pass 2 Assembly Listing.\n\n\n"); while (!ended ) { printval = 0; switch (xnextsym()) { case XINDIRECTBIT: errs(SX,passno); continue; case XCOMMENT: if(listing) { tab(20); dumpline(); } skipline(); continue; case XORIGIN: if(!error)fprintf(object, "*%04o\n", newval); where = newval; if(listing) { tab(20); dumpline(); } if (xnextsym() != XNIL) errs(SX, passno); continue; case XOCTAL: case XVARIABLE: writecode(newval, xnextsym()); continue; case XMRIOPCODE: memrefs(); continue; case XIOTOPCODE: iots(); continue; case XOPROPCODE: operate(); continue; case XENDING: ended++; continue; } } if(!error)fprintf(object, "$\n"); if (error) unlink(s); else andsymtab(); } initialise() { int i; int j; error = 0; if ((symbols = fopen("/usr/pub/cs/211/source/symbols", "r")) == NULL) { fprintf(stderr, "assemble: Cannot open symbols file\n"); exit(1); } fgets(line, 128, symbols); sscanf(line, "%d", &numsym); for (i = 0; i < numsym; i++) fscanf(symbols, "%s %d %o", symtab[i].name, &symtab[i].stype, &symtab[i].value); numsym--; fclose(symbols); } main(argc, argv) int argc; char **argv; { if (argc < 2) { fprintf(stderr, "Usage: assemble [-l] source [object]\n"); exit(1); } listing = 0; argextra = 0; if (argv[1][0] == '-') { argextra = 1; if((argc>2) && (argv[1][1] == 'l')) listing = 1; else { fprintf(stderr,"illegal option given to assemble\n"); exit(1); } } initialise(); zeroline(); pass1(argc, argv); zeroline(); if (error) printf("\n\nAssembly errors in Pass 1\nError reports from Pass 2 may not be valid\n"); pass2(argc, argv); if (!error) printf("\n\n\tassembled ok\n\n"); } zeroline() { char *p; int i; for (p = line, i = 0; i < 128; i++) *p++ = 0; }