/* c4.c - C in four functions */ /* char, int, structs, and pointer types */ /* if, while, do, return, switch and expression statements */ /* just enough features to allow self-compilation and a bit more */ /* Written by Robert Swierczek */ #if !defined(__FREESTANDING__) #include #include #include #include #include #include #endif /* #define int long long */ char *p, *lp, /* current position in source code */ *startp, /* start of the source code (for free) */ *data, /* data/bss pointer */ *sdata; /* start of data/bss pointer (for free) */ int *e, *le, /* current position in emitted code */ *se, /* start of emited code (for free) */ *cas, /* case statement patch-up pointer */ *brak, /* break statement patch-up pointer */ *def, /* default statement patch-up pointer */ *tsize, /* array (indexed by type) of type sizes */ tnew, /* next available type */ tk, /* current token */ ival, /* current token value */ ty, /* current expression type */ loc, /* local variable offset */ line, /* current line number */ src, /* print source and assembly flag */ debug; /* print executed instructions */ /* identifier */ struct ident_s { int tk; int hash; char *name; int class; int type; int val; int stype; int hclass; int htype; int hval; } *id, /* currently parsed identifier */ *sym; /* symbol table (simple list of identifiers) */ struct member_s { struct ident_s *id; int offset; int type; struct member_s *next; } **members; /* array (indexed by type) of struct member lists */ /* tokens and classes (operators last and in precedence order) */ enum { Num = 128, Fun, Sys, Glo, Loc, Id, Break, Case, Char, Default, Else, Enum, If, Int, Return, Sizeof, Do, Struct, Switch, While, Assign, Cond, Lor, Lan, Or, Xor, And, Eq, Ne, Lt, Gt, Le, Ge, Shl, Shr, Add, Sub, Mul, Div, Mod, Inc, Dec, Dot, Arrow, Brak }; /* opcodes */ enum { LEA ,IMM ,JMP ,JSR ,BZ ,BNZ ,ENT ,ADJ ,LEV ,LI ,LC ,SI ,SC ,PSH , OR ,XOR ,AND ,EQ ,NE ,LT ,GT ,LE ,GE ,SHL ,SHR ,ADD ,SUB ,MUL ,DIV ,MOD , MALC,FREE,MCPY,MSET,MCMP,GETC,PUTS,PUTN,PUTC,PUTI,ISPC,IDGT,IANU,IALP,SCMP,SDUP,EXIT }; /* types */ enum { CHAR, INT, PTR = 256, PTR2 = 512 }; void error(char *msg) { putint(line); putstring(": "); putstring(msg); putnl(); exit(-1); } void error1int(char *msg, int i) { putint(line); putstring(": "); putstring(msg); putint(i); putnl(); exit(-1); } void next() { char *pp; char *buf; while ((tk = *p) != 0) { ++p; switch (tk) { case '\n': if (src) { putint(line); putstring(": "); buf = (char *)malloc(512); memcpy(buf, lp, p - lp); buf[p-lp] = 0; putstring(buf); lp = p; while (le < e) { le++; memcpy(buf, &"LEA ,IMM ,JMP ,JSR ,BZ ,BNZ ,ENT ,ADJ ,LEV ,LI ,LC ,SI ,SC ,PSH ," "OR ,XOR ,AND ,EQ ,NE ,LT ,GT ,LE ,GE ,SHL ,SHR ,ADD ,SUB ,MUL ,DIV ,MOD ," "MALC,FREE,MCPY,MSET,MCMP,GETC,PUTS,PUTN,PUTC,PUTI,ISPC,IDGT,IANU.IALP,SCMP,SDUP,EXIT,"[*le * 5], 4); buf[4] = 0; putstring(" "); putstring(buf); if (*le <= ADJ) { le++; putchar(' '); putint(*le); } putnl(); } free(buf); } ++line; break; case '#': while (*p != 0 && *p != '\n') ++p; break; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '_': pp = p - 1; while ((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z') || (*p >= '0' && *p <= '9') || *p == '_') tk = tk * 147 + *p++; tk = (tk << 6) + (p - pp); id = sym; while (id->tk) { if (tk == id->hash && !memcmp(id->name, pp, p - pp)) { tk = id->tk; return; } id = id + 1; } id->name = pp; id->hash = tk; tk = id->tk = Id; return; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if ((ival = tk - '0') != 0) { while (*p >= '0' && *p <= '9') ival = ival * 10 + *p++ - '0'; } else if (*p == 'x' || *p == 'X') { while ((tk = *++p) && ((tk >= '0' && tk <= '9') || (tk >= 'a' && tk <= 'f') || (tk >= 'A' && tk <= 'F'))) ival = ival * 16 + (tk & 15) + (tk >= 'A' ? 9 : 0); } else { while (*p >= '0' && *p <= '7') ival = ival * 8 + *p++ - '0'; } tk = Num; return; case ' ': case '\t': break; case '/': if (*p == '/') { ++p; while (*p != 0 && *p != '\n') ++p; } else if (*p != 0 && *p == '*') { do { while (*p != 0 && *p != '*') { ++p; } ++p; } while (*p != '/'); ++p; } else { tk = Div; return; } break; case '\'': case '"': pp = data; while (*p != 0 && *p != tk) { if ((ival = *p++) == '\\') { switch (ival = *p++) { case 'n': ival = '\n'; break; case 't': ival = '\t'; break; } } if (tk == '"') *data++ = ival; } ++p; if (tk == '"') ival = (int)pp; else tk = Num; return; case '=': if (*p == '=') { ++p; tk = Eq; } else tk = Assign; return; case '+': if (*p == '+') { ++p; tk = Inc; } else tk = Add; return; case '-': if (*p == '-') { ++p; tk = Dec; } else if (*p == '>') { ++p; tk = Arrow; } else tk = Sub; return; case '!': if (*p == '=') { ++p; tk = Ne; } return; case '<': if (*p == '=') { ++p; tk = Le; } else if (*p == '<') { ++p; tk = Shl; } else tk = Lt; return; case '>': if (*p == '=') { ++p; tk = Ge; } else if (*p == '>') { ++p; tk = Shr; } else tk = Gt; return; case '|': if (*p == '|') { ++p; tk = Lor; } else tk = Or; return; case '&': if (*p == '&') { ++p; tk = Lan; } else tk = And; return; case '^': tk = Xor; return; case '%': tk = Mod; return; case '*': tk = Mul; return; case '[': tk = Brak; return; case '?': tk = Cond; return; case '.': tk = Dot; return; case '~': case ';': case '{': case '}': case '(': case ')': case ']': case ',': case ':': return; } } } void expr(int lev) { int t, *b, sz; struct ident_s *d; struct member_s *m; switch (tk) { case 0: error("unexpected eof in expression"); case Num: *++e = IMM; *++e = ival; next(); ty = INT; break; case '"': *++e = IMM; *++e = ival; next(); while (tk == '"') next(); data = (char *)(((int)data + sizeof(int)) & -sizeof(int)); ty = PTR; break; case Sizeof: next(); if (tk == '(') next(); else { error("open paren expected in sizeof"); } ty = INT; if (tk == Int) next(); else if (tk == Char) { next(); ty = CHAR; } else if (tk == Struct) { next(); if (tk != Id) { error("bad struct type"); } ty = id->stype; next(); } while (tk == Mul) { next(); ty = ty + PTR; } if (tk == ')') next(); else { error("close paren expected in sizeof"); } *++e = IMM; *++e = ty >= PTR ? sizeof(int) : tsize[ty]; ty = INT; break; case Id: d = id; next(); if (tk == '(') { next(); t = 0; while (tk != ')') { expr(Assign); *++e = PSH; ++t; if (tk == ',') next(); } next(); if (d->class == Sys) *++e = d->val; else if (d->class == Fun) { *++e = JSR; *++e = d->val; } else { error("bad function call"); } if (t) { *++e = ADJ; *++e = t; } ty = d->type; } else if (d->class == Num) { *++e = IMM; *++e = d->val; ty = INT; } else { if (d->class == Loc) { *++e = LEA; *++e = loc - d->val; } else if (d->class == Glo) { *++e = IMM; *++e = d->val; } else { error("undefined variable"); } if ((ty = d->type) <= INT || ty >= PTR) *++e = (ty == CHAR) ? LC : LI; } break; case '(': next(); if (tk == Int || tk == Char || tk == Struct) { if (tk == Int) { next(); t = INT; } else if (tk == Char) { next(); t = CHAR; } else { next(); if (tk != Id) { error("bad struct type"); } t = id->stype; next(); } while (tk == Mul) { next(); t = t + PTR; } if (tk == ')') next(); else { error("bad cast"); } expr(Inc); ty = t; } else { expr(Assign); if (tk == ')') next(); else { error("close paren expected"); } } break; case Mul: next(); expr(Inc); if (ty > INT) ty = ty - PTR; else { error("bad dereference"); } if (ty <= INT || ty >= PTR) *++e = (ty == CHAR) ? LC : LI; break; case And: next(); expr(Inc); if (*e == LC || *e == LI) --e; else { error("bad address-of"); } ty = ty + PTR; break; case '!': next(); expr(Inc); *++e = PSH; *++e = IMM; *++e = 0; *++e = EQ; ty = INT; break; case '~': next(); expr(Inc); *++e = PSH; *++e = IMM; *++e = -1; *++e = XOR; ty = INT; break; case Add: next(); expr(Inc); ty = INT; break; case Sub: next(); *++e = IMM; if (tk == Num) { *++e = -ival; next(); } else { *++e = -1; *++e = PSH; expr(Inc); *++e = MUL; } ty = INT; break; case Inc: case Dec: t = tk; next(); expr(Inc); if (*e == LC) { *e = PSH; *++e = LC; } else if (*e == LI) { *e = PSH; *++e = LI; } else { error("bad lvalue in pre-increment"); } *++e = PSH; *++e = IMM; *++e = ty >= PTR2 ? sizeof(int) : (ty >= PTR) ? tsize[ty - PTR] : 1; *++e = (t == Inc) ? ADD : SUB; *++e = (ty == CHAR) ? SC : SI; break; default: error("bad expression"); } while (tk >= lev) { /* "precedence climbing" or "Top Down Operator Precedence" method */ t = ty; switch (tk) { case Assign: next(); if (*e == LC || *e == LI) *e = PSH; else { error("bad lvalue in assignment"); } expr(Assign); *++e = ((ty = t) == CHAR) ? SC : SI; break; case Cond: next(); *++e = BZ; b = ++e; expr(Assign); if (tk == ':') next(); else { error("conditional missing colon"); } *b = (int)(e + 3); *++e = JMP; b = ++e; expr(Cond); *b = (int)(e + 1); break; case Lor: next(); *++e = BNZ; b = ++e; expr(Lan); *b = (int)(e + 1); ty = INT; break; case Lan: next(); *++e = BZ; b = ++e; expr(Or); *b = (int)(e + 1); ty = INT; break; case Or: next(); *++e = PSH; expr(Xor); *++e = OR; ty = INT; break; case Xor: next(); *++e = PSH; expr(And); *++e = XOR; ty = INT; break; case And: next(); *++e = PSH; expr(Eq); *++e = AND; ty = INT; break; case Eq: next(); *++e = PSH; expr(Lt); *++e = EQ; ty = INT; break; case Ne: next(); *++e = PSH; expr(Lt); *++e = NE; ty = INT; break; case Lt: next(); *++e = PSH; expr(Shl); *++e = LT; ty = INT; break; case Gt: next(); *++e = PSH; expr(Shl); *++e = GT; ty = INT; break; case Le: next(); *++e = PSH; expr(Shl); *++e = LE; ty = INT; break; case Ge: next(); *++e = PSH; expr(Shl); *++e = GE; ty = INT; break; case Shl: next(); *++e = PSH; expr(Add); *++e = SHL; ty = INT; break; case Shr: next(); *++e = PSH; expr(Add); *++e = SHR; ty = INT; break; case Add: next(); *++e = PSH; expr(Mul); sz = (ty = t) >= PTR2 ? sizeof(int) : ty >= PTR ? tsize[ty - PTR] : 1; if (sz > 1) { *++e = PSH; *++e = IMM; *++e = sz; *++e = MUL; } *++e = ADD; break; case Sub: next(); *++e = PSH; expr(Mul); sz = t >= PTR2 ? sizeof(int) : t >= PTR ? tsize[t - PTR] : 1; if (t == ty && sz > 1) { *++e = SUB; *++e = PSH; *++e = IMM; *++e = sz; *++e = DIV; ty = INT; } else if (sz > 1) { *++e = PSH; *++e = IMM; *++e = sz; *++e = MUL; *++e = SUB; } else *++e = SUB; ty = t; break; case Mul: next(); *++e = PSH; expr(Inc); *++e = MUL; ty = INT; break; case Div: next(); *++e = PSH; expr(Inc); *++e = DIV; ty = INT; break; case Mod: next(); *++e = PSH; expr(Inc); *++e = MOD; ty = INT; break; case Inc: case Dec: if (*e == LC) { *e = PSH; *++e = LC; } else if (*e == LI) { *e = PSH; *++e = LI; } else { error("bad lvalue in post-increment"); } sz = ty >= PTR2 ? sizeof(int) : ty >= PTR ? tsize[ty - PTR] : 1; *++e = PSH; *++e = IMM; *++e = sz; *++e = (tk == Inc) ? ADD : SUB; *++e = (ty == CHAR) ? SC : SI; *++e = PSH; *++e = IMM; *++e = sz; *++e = (tk == Inc) ? SUB : ADD; next(); break; case Dot: ty = ty + PTR; case Arrow: if (ty <= PTR+INT || ty >= PTR2) { error("structure expected"); } next(); if (tk != Id) { error("structure member expected"); } m = members[ty - PTR]; while (m && m->id != id) m = m->next; if (!m) { error("structure member not found"); } if (m->offset) { *++e = PSH; *++e = IMM; *++e = m->offset; *++e = ADD; } ty = m->type; if (ty <= INT || ty >= PTR) *++e = (ty == CHAR) ? LC : LI; next(); break; case Brak: next(); *++e = PSH; expr(Assign); if (tk == ']') next(); else { error("close bracket expected"); } if (t < PTR) { error("pointer type expected"); } sz = (t = t - PTR) >= PTR ? sizeof(int) : tsize[t]; if (sz > 1) { *++e = PSH; *++e = IMM; *++e = sz; *++e = MUL; } *++e = ADD; if ((ty = t) <= INT || ty >= PTR) *++e = (ty == CHAR) ? LC : LI; break; default: error1int("compiler error tk=", tk); } } } void stmt() { int *a, *b, *d, i; switch (tk) { case If: next(); if (tk == '(') next(); else { error("open paren expected"); } expr(Assign); if (tk == ')') next(); else { error("close paren expected\n"); } *++e = BZ; b = ++e; stmt(); if (tk == Else) { *b = (int)(e + 3); *++e = JMP; b = ++e; next(); stmt(); } *b = (int)(e + 1); return; case Do: next(); a = e + 1; stmt(); if (tk != While) { error("while expected to terminate do loop"); } next(); if (tk == '(') next(); else { error("open paren expected"); } expr(Assign); if (tk == ')') next(); else { error("close paren expected"); } *++e = BZ; b = ++e; *++e = JMP; *++e = (int)a; *b = (int)(e + 1); return; case While: next(); a = e + 1; if (tk == '(') next(); else { error("open paren expected"); } expr(Assign); if (tk == ')') next(); else { error("close paren expected"); } *++e = BZ; b = ++e; stmt(); *++e = JMP; *++e = (int)a; *b = (int)(e + 1); return; case Switch: next(); if (tk == '(') next(); else { error("open paren expected"); } expr(Assign); if (tk == ')') next(); else { error("close paren expected"); } a = cas; *++e = JMP; cas = ++e; b = brak; d = def; brak = def = 0; stmt(); *cas = def ? (int)def : (int)(e + 1); cas = a; while (brak) { a = (int *)*brak; *brak = (int)(e + 1); brak = a; } brak = b; def = d; return; case Case: *++e = JMP; ++e; *e = (int)(e + 7); *++e = PSH; i = *cas; *cas = (int)e; next(); expr(Or); if (e[-1] != IMM) { error("bad case immediate"); } *e = *e - i; *++e = SUB; *++e = BNZ; cas = ++e; *e = i + e[-3]; if (tk == ':') next(); else { error("colon expected"); } stmt(); return; case Break: next(); if (tk == ';') next(); else { error("semicolon expected"); } *++e = JMP; *++e = (int)brak; brak = e; return; case Default: next(); if (tk == ':') next(); else { error("colon expected"); } def = e + 1; stmt(); return; case Return: next(); if (tk != ';') expr(Assign); *++e = LEV; if (tk == ';') next(); else { error("semicolon expected"); } return; case '{': next(); while (tk != '}') stmt(); next(); return; case ';': next(); return; default: expr(Assign); if (tk == ';') next(); else { error("semicolon expected"); } } } int main(int argc, char **argv) { int bt, mbt, ty, poolsz; struct ident_s *idmain; struct member_s *m, *mtmp; int *pc, *sp, *bp, a, cycle; /* vm registers */ int i, *t, neg; /* temps */ int rt, run, n; int *ssp; char *buf; --argc; ++argv; if (argc > 0 && **argv == '-' && (*argv)[1] == 's') { src = 1; --argc; ++argv; } if (argc > 0 && **argv == '-' && (*argv)[1] == 'd') { debug = 1; --argc; ++argv; } poolsz = 256*1024; /* arbitrary size */ if (!(sym = (struct ident_s *)malloc(poolsz))) { error("could not malloc symbol area"); } if (!(se = le = e = (int *)malloc(poolsz))) { error("could not malloc text area"); } if (!(sdata = data = malloc(poolsz))) { error("could not malloc data area"); } if (!(ssp = sp = (int *)malloc(poolsz))) { error("could not malloc stack area"); } if (!(tsize = (int *)malloc(PTR * sizeof(int)))) { error("could not malloc tsize area"); } if (!(members = (struct member_s **)malloc(PTR * sizeof(struct member_s *)))) { error("could not malloc members area"); } memset((char *)sym, 0, poolsz); memset((char *)e, 0, poolsz); memset((char *)data, 0, poolsz); memset((char *)tsize, 0, PTR * sizeof(int)); memset((char *)members, 0, PTR * sizeof(struct member_s *)); p = "break case char default else enum if int return sizeof do struct switch while " "EOF EXIT_SUCCESS EXIT_FAILURE NULL " "malloc free memcpy memset memcmp getchar putstring putnl putchar putint isspace isdigit isalnum isalpha strcmp strdup exit void main"; i = Break; while (i <= While) { next(); id->tk = i++; } /* add keywords to symbol table */ /* add library constants */ next(); id->class = Num; id->type = INT; id->val = -1; next(); id->class = Num; id->type = INT; id->val = 0; next(); id->class = Num; id->type = INT; id->val = 1; next(); id->class = Num; id->type = INT; id->val = (int)NULL; i = MALC; while (i <= EXIT) { next(); id->class = Sys; id->type = INT; id->val = i++; } /* add library to symbol table */ next(); id->tk = Char; /* handle void type */ next(); idmain = id; /* keep track of main */ if (!(startp = lp = p = malloc(poolsz))) { error("could not malloc source area"); } i = 0; p[i] = getchar(); while (p[i]!=28 /* FS file separator */ && p[i]!=EOF) { i++; p[i] = getchar(); if (i>=poolsz-1) { error("too small read buffer"); } } p[i] = 0; /* add primitive types */ tsize[tnew++] = sizeof(char); tsize[tnew++] = sizeof(int); /* parse declarations */ line = 1; next(); while (tk) { bt = INT; /* basetype */ if (tk == Int) next(); else if (tk == Char) { next(); bt = CHAR; } else if (tk == Enum) { next(); if (tk != '{') next(); if (tk == '{') { next(); i = 0; while (tk != '}') { if (tk != Id) { error("bad enum identifier"); } next(); if (tk == Assign) { next(); neg = 0; if (tk == Sub) { next(); neg =1; } if (tk != Num) { error("bad enum initializer"); } i = ival; if (neg) { i = -ival; } next(); } id->class = Num; id->type = INT; id->val = i++; if (tk == ',') next(); } next(); } } else if (tk == Struct) { next(); if (tk == Id) { if (!id->stype) id->stype = tnew++; bt = id->stype; next(); } else { bt = tnew++; } if (tk == '{') { next(); if (members[bt]) { error("duplicate structure definition"); } i = 0; while (tk != '}') { mbt = INT; if (tk == Int) next(); else if (tk == Char) { next(); mbt = CHAR; } else if (tk == Struct) { next(); if (tk != Id) { error("bad struct declaration\n"); } mbt = id->stype; next(); } while (tk != ';') { ty = mbt; while (tk == Mul) { next(); ty = ty + PTR; } if (tk != Id) { error("bad struct member definition"); } m = (struct member_s *)malloc(sizeof(struct member_s)); m->id = id; m->offset = i; m->type = ty; m->next = members[bt]; members[bt] = m; i = i + (ty >= PTR ? sizeof(int) : tsize[ty]); i = (i + 3) & -4; next(); if (tk == ',') next(); } next(); } next(); tsize[bt] = i; } } while (tk != ';' && tk != '}') { ty = bt; while (tk == Mul) { next(); ty = ty + PTR; } if (tk != Id) { error("bad global declaration"); } if (id->class) { error("duplicate global definition"); } next(); id->type = ty; if (tk == '(') { /* function */ id->class = Fun; id->val = (int)(e + 1); next(); i = 0; while (tk != ')') { ty = INT; if (tk == Int) next(); else if (tk == Char) { next(); ty = CHAR; } else if (tk == Struct) { next(); if (tk != Id) { error("bad struct declaration"); } ty = id->stype; next(); } while (tk == Mul) { next(); ty = ty + PTR; } if (tk != Id) { error("bad parameter declaration"); } if (id->class == Loc) { error("duplicate parameter definition"); } id->hclass = id->class; id->class = Loc; id->htype = id->type; id->type = ty; id->hval = id->val; id->val = i++; next(); if (tk == ',') next(); } next(); if (tk != '{') { error("bad function definition"); } loc = ++i; next(); while (tk == Int || tk == Char || tk == Struct) { if (tk == Int) bt = INT; else if (tk == Char) bt = CHAR; else { next(); if (tk != Id) { error("bad struct declaration"); } bt = id->stype; } next(); while (tk != ';') { ty = bt; while (tk == Mul) { next(); ty = ty + PTR; } if (tk != Id) { error("bad local declaration"); } if (id->class == Loc) { error("duplicate local definition"); } id->hclass = id->class; id->class = Loc; id->htype = id->type; id->type = ty; id->hval = id->val; id->val = ++i; next(); if (tk == ',') next(); } next(); } *++e = ENT; *++e = i - loc; while (tk != '}') stmt(); *++e = LEV; id = sym; /* unwind symbol table locals */ while (id->tk) { if (id->class == Loc) { id->class = id->hclass; id->type = id->htype; id->val = id->hval; } id = id + 1; } } else { id->class = Glo; id->val = (int)data; data = data + sizeof(int); } if (tk == ',') next(); } next(); } if (!(pc = (int *)idmain->val)) { error("main() not defined\n"); } rt = 0; if (!src) { /* setup stack */ bp = sp = (int *)((int)sp + poolsz); *--sp = EXIT; /* call exit if main returns */ *--sp = PSH; t = sp; *--sp = argc; *--sp = (int)argv; *--sp = (int)t; /* run... */ cycle = 0; a = 0; run = 1; while (run) { i = *pc++; ++cycle; if (debug) { putint(cycle); putstring("> "); buf = (char *)malloc( 5 ); memcpy(buf, &"LEA ,IMM ,JMP ,JSR ,BZ ,BNZ ,ENT ,ADJ ,LEV ,LI ,LC ,SI ,SC ,PSH ," "OR ,XOR ,AND ,EQ ,NE ,LT ,GT ,LE ,GE ,SHL ,SHR ,ADD ,SUB ,MUL ,DIV ,MOD ," "MALC,FREE,MCPY,MSET,MCMP,GETC,PUTS,PUTN,PUTC,PUTI,ISPC,IDGT,IANU.IALP,SCMP,SDUP,EXIT,"[i * 5],4); buf[4] = 0; putstring(buf); free(buf); if (i <= ADJ) { putchar(' '); putint(*pc); } putnl(); } switch (i) { case LEA: a = (int)(bp + *pc++); break; /* load local address */ case IMM: a = *pc++; break; /* load global address or immediate */ case JMP: pc = (int *)*pc; break; /* jump */ case JSR: *--sp = (int)(pc + 1); pc = (int *)*pc; break; /* jump to subroutine */ case BZ: pc = a ? pc + 1 : (int *)*pc; break; /* branch if zero */ case BNZ: pc = a ? (int *)*pc : pc + 1; break; /* branch if not zero */ case ENT: *--sp = (int)bp; bp = sp; sp = sp - *pc++; break; /* enter subroutine */ case ADJ: sp = sp + *pc++; break; /* stack adjust */ case LEV: sp = bp; bp = (int *)*sp++; pc = (int *)*sp++; break; /* leave subroutine */ case LI: a = *(int *)a; break; /* load int */ case LC: a = *(char *)a; break; /* load char */ case SI: *(int *)*sp++ = a; break; /* store int */ case SC: a = *(char *)*sp++ = a; break; /* store char */ case PSH: *--sp = a; break; /* push */ case OR: a = *sp++ | a; break; case XOR: a = *sp++ ^ a; break; case AND: a = *sp++ & a; break; case EQ: a = *sp++ == a; break; case NE: a = *sp++ != a; break; case LT: a = *sp++ < a; break; case GT: a = *sp++ > a; break; case LE: a = *sp++ <= a; break; case GE: a = *sp++ >= a; break; case SHL: a = *sp++ << a; break; case SHR: a = *sp++ >> a; break; case ADD: a = *sp++ + a; break; case SUB: a = *sp++ - a; break; case MUL: a = *sp++ * a; break; case DIV: a = *sp++ / a; break; case MOD: a = *sp++ % a; break; case MALC: a = (int)malloc(*sp); break; case FREE: free((void *)*sp); break; case MCPY: a = (int)memcpy((char *)sp[2], (char *)sp[1], *sp); break; case MSET: a = (int)memset((char *)sp[2], sp[1], *sp); break; case MCMP: a = memcmp((char *)sp[2], (char *)sp[1], *sp); break; case GETC: a = getchar(); break; case PUTS: t = sp + pc[1]; a = putstring((char *)t[-1]); break; case PUTN: a = putnl(); break; case PUTC: a = putchar(*sp); break; case PUTI: t = sp + pc[1]; a = putint((int)t[-1]); break; case ISPC: t = sp + pc[1]; a = isspace( (int)t[-1]); break; case IDGT: t = sp + pc[1]; a = isdigit( (int)t[-1]); break; case IANU: t = sp + pc[1]; a = isalnum( (int)t[-1]); break; case IALP: t = sp + pc[1]; a = isalpha( (int)t[-1]); break; case SCMP: t = sp + pc[1]; a = strcmp((char *)t[-1], (char *)t[-2]); break; case SDUP: t = sp + pc[1]; a = (int)strdup((char *)t[-1]); break; case EXIT: /* putstring("exit("); putint(*sp); putstring(") cycle = "); putint(cycle); putnl(); */ rt = *sp; run = 0; break; default: putstring("unknown instruction = "); putint(i); putstring("! cycle = "); putint(cycle); putnl(); rt = -1; run = 0; break; } } } free((char *)startp); n = 0; while (nnext; free((char *)mtmp); } } n++; } free((char *)members); free((char *)tsize); free((char *)ssp); free((char *)sdata); free((char *)se); free((char *)sym); exit(rt); return rt; }