📄 moon.c
字号:
void next () { char *t = token.symval; short op; strcpy(oldval, token.symval); while (*bp == ' ' || *bp == '\t') bp++; token.pos = bp; if (isalpha(*bp)) { /* Read a register, op code, directive, or symbol */ while (issymchar(*bp)) *t++ = *bp++; *t = '\0';/* printf("<%s>\n", token.symval);*/ if (isreg(token.symval)) { token.kind = T_REG; return; } for (op = lw; op < last; op++) { if (!strcmp(token.symval, opnames[op])) { token.op = op; token.kind = T_OP; return; } } token.kind = T_SYM; return; } else if (*bp == '-' || *bp == '+' || isdigit(*bp)) { /* Read a signed decimal integer */ *t++ = *bp++; while (isdigit(*bp)) *t++ = *bp++; *t = '\0'; sscanf(token.symval, "%ld", &token.intval); token.kind = T_NUM; return; } else if (*bp == '"') { /* Read a character string enclosed in quotes */ bp++; while (1) { if (*bp == '"') { *t = '\0'; token.kind = T_STR; bp++; break; } if (*bp == '\0' || *bp == '\n') { syntaxerror("unterminated string"); token.kind = T_BAD; *t = '\0'; break; } *t++ = *bp++; } return; } else if (*bp == ',') { bp++; token.kind = T_COMMA; strcpy(token.symval, ","); return; } else if (*bp == '(') { bp++; token.kind = T_LP; strcpy(token.symval, "("); return; } else if (*bp == ')') { bp++; token.kind = T_RP; strcpy(token.symval, ")"); return; } else if (*bp == '%' || *bp == '\n' || *bp == '\0') { token.kind = T_NULL; strcpy(token.symval, " "); return; } else { token.kind = T_BAD; strcpy(token.symval, " "); } }/* Match a token */void match (enum tokentype kind) { if (token.kind == kind) { next(); return; } switch (kind) { case T_COMMA: syntaxerror("',' expected"); break; case T_LP: syntaxerror("'(' expected"); break; case T_RP: syntaxerror("')' expected"); break; default: syntaxerror("Syntax error"); break; } }/* Parse an opcode. The error should never occur, since this function * is called only when the token type is know. */short getop () { if (token.kind == T_OP) { short res = token.op; next(); return res; } syntaxerror("Opcode expected"); return 0; }/* Parse a register and return the register number */short getreg () { if (token.kind == T_REG) { short res = token.reg; next(); return res; } syntaxerror("Register expected"); return 0; }/* Parse a constant (number or symbol) and return value */long getlong (long addr) { if (token.kind == T_NUM) { long res = token.intval; next(); return res; } else if (token.kind == T_SYM) { usesymbol(token.symval, addr); next(); return 0; } syntaxerror("Constant expected"); return 0; }/* Similar to getlong(), but checks that its argument can be stored * in 16 bits. */int getint (long addr) { long val = getlong(addr); if (labs(val) <= 32767) return (int) val; syntaxerror("Value cannot be represented with 16 bits"); return 0; }char buffer [BUFLEN]; /* Input buffer */long addr = 0;int linenum = 0;/* Parse one line of source code from the buffer. */void readline () { wordtype word; word.data = 0; bp = buffer; strcpy(errmes, ""); strcpy(oldval, ""); next(); while (token.kind == T_SYM) { defsymbol(token.symval, addr); next(); } if (token.kind == T_OP) { switch (token.op) { /* Format A -- registers only */ /* Operands Ri, Rj, Rk */ case add: case sub: case mul: case divr: case mod: case and: case or: case ceq: case cne: case clt: case cle: case cgt: case cge: word.fmta.op = getop(); word.fmta.ri = getreg(); match(T_COMMA); word.fmta.rj = getreg(); match(T_COMMA); word.fmta.rk = getreg(); putmeminstr(addr, word, 'a'); addr += 4; break; /* Operands Ri, Rj */ case not: case jlr: word.fmta.op = getop(); word.fmta.ri = getreg(); match(T_COMMA); word.fmta.rj = getreg(); putmeminstr(addr, word, 'a'); addr += 4; break; /* No operands */ case nop: case hlt: word.fmta.op = getop(); putmeminstr(addr, word, 'a'); addr += 4; break; /* Format B - operands and constant fields */ /* Operands Ri, K(Rj) */ case lw: case lb: word.fmtb.op = getop(); word.fmtb.ri = getreg(); match(T_COMMA); word.fmtb.k = getint(addr); match(T_LP); word.fmtb.rj = getreg(); match(T_RP); putmeminstr(addr, word, 'b'); addr += 4; break; /* Operands K(Rj), Ri */ case sw: case sb: word.fmtb.op = getop(); word.fmtb.k = getint(addr); match(T_LP); word.fmtb.rj = getreg(); match(T_RP); match(T_COMMA); word.fmtb.ri = getreg(); putmeminstr(addr, word, 'b'); addr += 4; break; /* Operands Ri, Rj, K */ case addi: case subi: case muli: case divi: case modi: case andi: case ori: case ceqi: case cnei: case clti: case clei: case cgti: case cgei: word.fmtb.op = getop(); word.fmtb.ri = getreg(); match(T_COMMA); word.fmtb.rj = getreg(); match(T_COMMA); word.fmtb.k = getint(addr); putmeminstr(addr, word, 'b'); addr += 4; break; /* Operands Ri, K */ case sl: case sr: case bz: case bnz: case jl: word.fmtb.op = getop(); word.fmtb.ri = getreg(); match(T_COMMA); word.fmtb.k = getint(addr); putmeminstr(addr, word, 'b'); addr += 4; break; /* Operands Ri */ case gtc: case ptc: case jr: word.fmtb.op = getop(); word.fmtb.ri = getreg(); putmeminstr(addr, word, 'b'); addr += 4; break; /* Operands K */ case j: word.fmtb.op = getop(); word.fmtb.k = getint(addr); putmeminstr(addr, word, 'b'); addr += 4; break; /* Set the entry point of the program. */ case entry: next(); if (entrypoint < 0) { entrypoint = addr; break; } syntaxerror("More than one entry point"); break; /* Adjust the address to the next word boundary. */ case align: next(); if (addr & 3) addr = (addr & ~3) + 4; break; /* Set the address to the given value. */ case org: next(); addr = getlong(addr); break; /* Store words. */ case dw: next(); while (token.kind == T_NUM || token.kind == T_SYM) { word.data = getlong(addr); putmeminstr(addr, word, 'd'); addr += 4; if (token.kind == T_COMMA) next(); else break; } break; /* Store bytes */ case db: next(); while (1) { if (token.kind == T_NUM) { if (0 <= token.intval && token.intval <= 255) { putmemchar(addr, token.intval, 'd'); addr++; } else syntaxerror("Value cannot be represented with 8 bits"); next(); } else if (token.kind == T_STR) { char *t = token.symval; while (*t) { putmemchar(addr, *t++, 'd'); addr++; } next(); } if (token.kind == T_COMMA) next(); else if (token.kind == T_NULL) break; else { syntaxerror("Syntax error in byte list"); break; } } break; /* Reserve the given number of words. */ case res: next(); addr += getlong(addr); break; /* Should never get here. */ default: syntaxerror("Unrecognized statement"); break; } } if (token.kind != T_NULL && errorcount < 5) { printf("Warning: junk following `%s' on next line.\n", token.symval); printf("%4d %s\n", linenum, buffer); errorcount++; } }/* Load a source file. */void load (FILE *inp, FILE *out, short listing) { linenum = 0; while (fgets(buffer, BUFLEN - 1, inp)) { long oldaddr = addr; linenum++; readline(); if (listing) fprintf(out, "%5d %5ld %s", linenum, oldaddr, buffer); if (strcmp(errmes, "")) { printf("%5d %5ld %s", linenum, oldaddr, buffer); printf(" >>>>> %s\n", errmes); if (listing) fprintf(out, " >>>>> %s\n", errmes); } } }/*************************** USER INSTRUCTION *******************************/void showusage () { printf("Usage:\n"); printf(" moon { option | filename }\n"); printf("The command line may contain source file names and options in any order.\n"); printf("There should be at least one source file. Source files will be loaded\n"); printf("in the order in which they are given.\n"); printf("Options:\n"); printf(" +p print listing\n"); printf(" -p (default) do not print listing\n"); printf(" +s display symbol values\n"); printf(" -s (default) do not display symbol values\n"); printf(" +t start in trace mode\n"); printf(" -t (default) execute without tracing\n"); printf(" +x (default) execute the program\n"); printf(" -x do not execute the program\n"); printf("Input files:\n"); printf(" If an input file name does not contain `.', the suffix\n"); printf(" `.n' will be appended to it.\n"); printf("Listing files:\n"); printf(" Source files may be listed selectively. The command\n"); printf(" moon -p lib +p appl\n"); printf(" would create a listing for `appl.m' but not for `lib.m'.\n"); printf(" The list file is named `moon.prn' by default.\n"); printf(" Use +o or -o followed by a name to changes the list file name.\n"); }/*************************** MAIN PROGRAM ***********************************/int main (int argc, char *argv[]) { struct { char name [MAXNAMELEN]; short list; } filedescs [MAXINFILES]; int numfiles = 0; char outname [MAXNAMELEN] = ""; short dump = FALSE; /* D Dump memory */ short listing = FALSE; /* P Generate a listing of the source code */ short symbols = FALSE; /* S Display symbol values */ short tracing = FALSE; /* T Execute program in trace mode */ short execute = TRUE; /* X Execute the program after loading */ short listreq = FALSE; /* A listing is needed */ long addr; int arg, fil; FILE *inp, *out; regs[0] = 0; /* Register 0 is always 0. */ /* If there are no arguments, help the poor user. */ if (argc <= 1) { showusage(); exit(0); } /* Process command line arguments. * There should be at least one argument. Arguments that start with * + (-) turn flags on (off). Other arguments are input file names. * The listing switch (+-l) is processed in sequence so that files * may be listed selectively. */ for (arg = 1; arg < argc; arg++) { char *p = argv[arg]; if (*p == '+') { p++; switch (*p++) { case 'd': case 'D': dump = TRUE; break; case 'o': case 'O': strcpy(outname, p); break; case 'p': case 'P': listing = TRUE; break; case 's': case 'S': symbols = TRUE; break; case 't': case 'T': tracing = TRUE; break; case 'x': case 'X': execute = TRUE; break; default: printf("Illegal option: +%s\n", --p); exit(1); } } else if (*p == '-') { p++; switch (*p++) { case 'd': case 'D': dump = FALSE; break; case 'o': case 'O': strcpy(outname, p); break; case 'p': case 'P': listing = FALSE; break; case 's': case 'S': symbols = FALSE; break; case 't': case 'T': tracing = FALSE; break; case 'x': case 'X': execute = FALSE; break; default: printf("Illegal option: -%s\n", --p); exit(1); } } else { if (numfiles >= MAXINFILES) { printf("Too many input files!\n"); exit(1); } strcpy(filedescs[numfiles].name, p); filedescs[numfiles].list = listing; if (listing) listreq = TRUE; numfiles++; } } /* Nothing to do if there were no files on the command line. */ if (numfiles == 0) { printf("No input files!\n"); exit(1); } /* Attempt to open an output file if a listing is required. * If no output file was named, use a default name. */ if (listreq) { if (strlen(outname) == 0) strcpy(outname,"moon.prn"); if ((out = fopen(outname, "w")) == NULL) { printf("Unable to open listing file %s.\n", outname); exit(1); } printf("Writing listing to %s.\n", outname); } /* Process each input file. If no extension is given, assume .m. * If the file can be opened, load assembler code from it. */ initmem(); defsymbol("topaddr", 4 * MEMSIZE); for (fil = 0; fil < numfiles; fil++) { if (!strchr(filedescs[fil].name, '.')) strcat(filedescs[fil].name, ".m"); if ((inp = fopen(filedescs[fil].name, "r")) == NULL) { printf("Unable to open input file: %s.\n", filedescs[fil].name); exit(1); } else { short listing = filedescs[fil].list; printf("Loading %s.\n", filedescs[fil].name); if (listing) { fprintf(out, "MOON listing of %s.\n\n", filedescs[fil].name); load(inp, out, TRUE); fprintf(out, "\n"); } else load(inp, out, FALSE); fclose(inp); } } if (listreq) fclose(out); /* Check symbols and entry point. If there are errors, stop now. */ errorcount += checksymbols(); if (entrypoint < 0) { printf("There is no `entry' directive.\n"); errorcount++; } if (errorcount > 0) { printf("Loader errors -- no execution.\n"); exit(1); } /* Store values of symbols where they are used in the program. * Display them if requested. */ storesymbols(); if (symbols) showsymbols(); /* If a dump was requested, dump the memory. This option is not * advertised and therefore need not be supported. */ if (dump) { printf("Memory dump:\n"); for (addr = 0; addr < MEMSIZE; addr += 4) { if (mem[addr >> 2].cont != 'u') { showword(addr); printf("\n"); } } printf("\n"); } /* Execute the program in normal or trace mode. */ if (execute) { if (tracing) exectrace(); else exec(); } return 0; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -