compiler

Unnamed Compiled Systems Language Project
git clone http://frotz.net/git/compiler.git
Log | Files | Refs

commit 1086c2aa1133ed44b462b9a360f180ef9f0a851e
parent 4d17328fe53b8db469fc1a1e776c053ee6027208
Author: Brian Swetland <swetland@frotz.net>
Date:   Mon,  9 Mar 2020 22:53:19 -0700

compiler: make "ctx" global

- passing it around like an explicit "this" pointer adds
  clutter and reduces readability
- as far as codegen goes, accessing a global is going to be
  less overhead than accessing a pointer, until we start making
  better use of long-lived register variables:
  ldw rdst, [gp, off] vs ldw rptr, [sp, off] ; ldw dst, [rptr, off]
- I'm keeping the struct to make it easier to change my mind again
  later and to avoid collisions between local vars and global
  compiler state

Diffstat:
Msrc/compiler.c | 1104++++++++++++++++++++++++++++++++++++++++---------------------------------------
1 file changed, 553 insertions(+), 551 deletions(-)

diff --git a/src/compiler.c b/src/compiler.c @@ -244,52 +244,55 @@ struct CtxRec { #define cfVisibleEOL 1 #define cfAbortOnError 2 +CtxRec ctx; + + // generate function prologue and epilogue -void gen_prologue(Ctx ctx, Object fn); -void gen_epilogue(Ctx ctx, Object fn); +void gen_prologue(Object fn); +void gen_epilogue(Object fn); // return from function, consumes x -void gen_return(Ctx ctx, Item x); +void gen_return(Item x); // generate a binary op, consumes y, transforms x -void gen_add_op(Ctx ctx, u32 op, Item x, Item y); -void gen_mul_op(Ctx ctx, u32 op, Item x, Item y); -void gen_rel_op(Ctx ctx, u32 op, Item x, Item y); +void gen_add_op(u32 op, Item x, Item y); +void gen_mul_op(u32 op, Item x, Item y); +void gen_rel_op(u32 op, Item x, Item y); // generate unary op, transforms x -void gen_unary_op(Ctx ctx, u32 op, Item x); +void gen_unary_op(u32 op, Item x); // stores val into var, consuming both -void gen_store(Ctx ctx, Item val, Item var); +void gen_store(Item val, Item var); // sets up call param #n, consuming val -void gen_param(Ctx ctx, u32 n, Item val); +void gen_param(u32 n, Item val); // call func, consumes parameters and func -void gen_call(Ctx, Item func); +void gen_call(Item func); // generate a forward conditional branch // consumes x which must be Bool or Cond // returns address to fixup -u32 gen_branch_cond(Ctx ctx, Item x, bool sense); +u32 gen_branch_cond(Item x, bool sense); // generate a backward branch to addr -void gen_branch_back(Ctx ctx, u32 addr); +void gen_branch_back(u32 addr); // generate an unconditional forward branch // returns address for later fixup -u32 gen_branch_fwd(Ctx ctx); +u32 gen_branch_fwd(); // patches provided list of branch fixups to branch to // the address where we will emit the next instruction -void fixup_branches_fwd(Ctx ctx, Fixup list); +void fixup_branches_fwd(Fixup list); // patches a single branch at addr to branch to the // address where we will emit the next instruction -void fixup_branch_fwd(Ctx ctx, u32 addr); +void fixup_branch_fwd(u32 addr); -String mkstring(Ctx ctx, const char* text, u32 len) { - String str = ctx->strtab; +String mkstring(const char* text, u32 len) { + String str = ctx.strtab; while (str != nil) { if ((str->len == len) && (memcmp(text, str->text, len) == 0)) { return str; @@ -301,14 +304,14 @@ String mkstring(Ctx ctx, const char* text, u32 len) { str->len = len; memcpy(str->text, text, len); str->text[len] = 0; - str->next = ctx->strtab; - ctx->strtab = str; + str->next = ctx.strtab; + ctx.strtab = str; return str; } -Type make_type(Ctx ctx, const char* text, u32 len, u32 kind, u32 size) { - String str = mkstring(ctx, text, len); +Type make_type(const char* text, u32 len, u32 kind, u32 size) { + String str = mkstring(text, len); Type type = malloc(sizeof(TypeRec)); Object obj = malloc(sizeof(ObjectRec)); @@ -327,8 +330,8 @@ Type make_type(Ctx ctx, const char* text, u32 len, u32 kind, u32 size) { obj->type = type; obj->name = str; - obj->next = ctx->typetab; - ctx->typetab = obj; + obj->next = ctx.typetab; + ctx.typetab = obj; return type; } @@ -337,23 +340,23 @@ enum { biPrintHex32, }; -void make_builtin(Ctx ctx, const char* name, u32 id, Type p0, Type p1, Type rtn); +void make_builtin(const char* name, u32 id, Type p0, Type p1, Type rtn); -void init_ctx(Ctx ctx) { - memset(ctx, 0, sizeof(CtxRec)); +void init_ctx() { + memset(&ctx, 0, sizeof(ctx)); // install built-in basic types - ctx->type_void = make_type(ctx, "void", 4, tVoid, 0); - ctx->type_byte = make_type(ctx, "byte", 4, tByte, 1); - ctx->type_bool = make_type(ctx, "bool", 4, tBool, 1); - ctx->type_int32 = make_type(ctx, "i32", 3, tInt32, 4); - ctx->type_nil = make_type(ctx, "nil", 3, tNil, 4); - ctx->type_string = make_type(ctx, "str", 3, tString, 8); + ctx.type_void = make_type("void", 4, tVoid, 0); + ctx.type_byte = make_type("byte", 4, tByte, 1); + ctx.type_bool = make_type("bool", 4, tBool, 1); + ctx.type_int32 = make_type("i32", 3, tInt32, 4); + ctx.type_nil = make_type("nil", 3, tNil, 4); + ctx.type_string = make_type("str", 3, tString, 8); - ctx->scope = &(ctx->global); - ctx->line = ""; + ctx.scope = &(ctx.global); + ctx.line = ""; - make_builtin(ctx, "_hexout_", biPrintHex32, ctx->type_int32, nil, ctx->type_void); + make_builtin("_hexout_", biPrintHex32, ctx.type_int32, nil, ctx.type_void); } bool sametype(Type a, Type b) { @@ -381,52 +384,52 @@ bool sametype(Type a, Type b) { return true; } -void error(Ctx ctx, const char *fmt, ...) { +void error(const char *fmt, ...) { va_list ap; u32 len = 0; - const char *s = ctx->line; + const char *s = ctx.line; while (len < 255) { if ((*s < ' ') && (*s != 9)) break; s++; len++; } - fprintf(stderr,"%s:%d: ", ctx->filename, ctx->linenumber); + fprintf(stderr,"%s:%d: ", ctx.filename, ctx.linenumber); va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); - fprintf(stderr,"\n%.*s\n", len, ctx->line); - if (ctx->flags & cfAbortOnError) { + fprintf(stderr,"\n%.*s\n", len, ctx.line); + if (ctx.flags & cfAbortOnError) { abort(); } else { exit(1); } } -void load(Ctx ctx, const char* filename) { - ctx->filename = filename; - ctx->linenumber = 0; +void load(const char* filename) { + ctx.filename = filename; + ctx.linenumber = 0; int fd; struct stat s; char* data; if ((fd = open(filename, O_RDONLY)) < 0) - error(ctx, "cannot open file"); + error("cannot open file"); if (fstat(fd, &s) < 0) - error(ctx, "cannot stat file"); + error("cannot stat file"); if ((data = malloc(s.st_size + 1)) == NULL) - error(ctx, "cannot allocate memory"); + error("cannot allocate memory"); if (read(fd, data, s.st_size) != s.st_size) - error(ctx, "cannot read file"); + error("cannot read file"); close(fd); data[s.st_size] = 0; - ctx->source = data; - ctx->sptr = data; - ctx->linenumber = 1; + ctx.source = data; + ctx.sptr = data; + ctx.linenumber = 1; } int unhex(u32 ch) { @@ -438,15 +441,15 @@ int unhex(u32 ch) { } } -token_t next_string(Ctx ctx, const char* s) { +token_t next_string(const char* s) { u32 ch, len = 0; while (true) { switch ((ch = *s++)) { - case 0: error(ctx, "unterminated string"); + case 0: error("unterminated string"); case '"': goto done; case '\\': switch ((ch = *s++)) { - case '0': error(ctx, "unterminated string"); + case '0': error("unterminated string"); case 'n': ch = 10; break; case 't': ch = 9; break; case '"': ch = '"'; break; @@ -455,98 +458,98 @@ token_t next_string(Ctx ctx, const char* s) { int x1 = unhex(s[1]); //TODO: if error() is ever non-fatal, this may leave //sptr past end of input - if ((x0 < 0) || (x1 < 0)) error(ctx, "invalid hex escape"); + if ((x0 < 0) || (x1 < 0)) error("invalid hex escape"); ch = (x0 << 4) | x1; s += 2; break; } - default: error(ctx, "invalid string escape 0x%02x", ch); + default: error("invalid string escape 0x%02x", ch); } break; default: break; } - if (len == 255) error(ctx, "string constant too long"); - ctx->tmp[len++] = ch; + if (len == 255) error("string constant too long"); + ctx.tmp[len++] = ch; } done: - ctx->tmp[len] = 0; - ctx->sptr = s; + ctx.tmp[len] = 0; + ctx.sptr = s; return tSTRING; } -token_t next_num(Ctx ctx, u32 n, const char* str, size_t len) { - if (len > 255) error(ctx, "number too large"); - memcpy(ctx->tmp, str, len); - ctx->tmp[len] = 0; - ctx->num = n; - ctx->sptr += len; - return ctx->tok = tNUMBER; +token_t next_num(u32 n, const char* str, size_t len) { + if (len > 255) error("number too large"); + memcpy(ctx.tmp, str, len); + ctx.tmp[len] = 0; + ctx.num = n; + ctx.sptr += len; + return ctx.tok = tNUMBER; } int streq(const char* s1, u32 l1, const char* s2, u32 l2) { return (l1 == l2) && (!memcmp(s1, s2, l1)); } -token_t next_word(Ctx ctx, const char* str, size_t len) { - if (len > 255) error(ctx, "word too large"); - memcpy(ctx->tmp, str, len); - ctx->tmp[len] = 0; - ctx->num = 0; - ctx->sptr += len; +token_t next_word(const char* str, size_t len) { + if (len > 255) error("word too large"); + memcpy(ctx.tmp, str, len); + ctx.tmp[len] = 0; + ctx.num = 0; + ctx.sptr += len; switch (len) { case 2: - if (streq(str, len, "if", 2)) return ctx->tok = tIF; + if (streq(str, len, "if", 2)) return ctx.tok = tIF; break; case 3: - if (streq(str, len, "for", 3)) return ctx->tok = tFOR; - if (streq(str, len, "var", 3)) return ctx->tok = tVAR; - if (streq(str, len, "nil", 3)) return ctx->tok = tNIL; + if (streq(str, len, "for", 3)) return ctx.tok = tFOR; + if (streq(str, len, "var", 3)) return ctx.tok = tVAR; + if (streq(str, len, "nil", 3)) return ctx.tok = tNIL; break; case 4: - if (streq(str, len, "case", 4)) return ctx->tok = tCASE; - if (streq(str, len, "func", 4)) return ctx->tok = tFUNC; - if (streq(str, len, "else", 4)) return ctx->tok = tELSE; - if (streq(str, len, "true", 4)) return ctx->tok = tTRUE; + if (streq(str, len, "case", 4)) return ctx.tok = tCASE; + if (streq(str, len, "func", 4)) return ctx.tok = tFUNC; + if (streq(str, len, "else", 4)) return ctx.tok = tELSE; + if (streq(str, len, "true", 4)) return ctx.tok = tTRUE; break; case 5: - if (streq(str, len, "break", 5)) return ctx->tok = tBREAK; - if (streq(str, len, "while", 5)) return ctx->tok = tWHILE; - if (streq(str, len, "false", 5)) return ctx->tok = tFALSE; + if (streq(str, len, "break", 5)) return ctx.tok = tBREAK; + if (streq(str, len, "while", 5)) return ctx.tok = tWHILE; + if (streq(str, len, "false", 5)) return ctx.tok = tFALSE; break; case 6: - if (streq(str, len, "switch", 6)) return ctx->tok = tSWITCH; - if (streq(str, len, "struct", 6)) return ctx->tok = tSTRUCT; - if (streq(str, len, "return", 6)) return ctx->tok = tRETURN; + if (streq(str, len, "switch", 6)) return ctx.tok = tSWITCH; + if (streq(str, len, "struct", 6)) return ctx.tok = tSTRUCT; + if (streq(str, len, "return", 6)) return ctx.tok = tRETURN; break; case 8: - if (streq(str, len, "continue", 8)) return ctx->tok = tCONTINUE; + if (streq(str, len, "continue", 8)) return ctx.tok = tCONTINUE; break; } - return ctx->tok = tNAME; + return ctx.tok = tNAME; } -#define TOKEN(t) { ctx->sptr++; return ctx->tok = t; } -#define TOKEN2(t) { ctx->sptr+=2; return ctx->tok = t; } +#define TOKEN(t) { ctx.sptr++; return ctx.tok = t; } +#define TOKEN2(t) { ctx.sptr+=2; return ctx.tok = t; } -token_t _next(Ctx ctx) { +token_t _next() { while (true) { - const char* s = ctx->sptr; + const char* s = ctx.sptr; switch (*s) { case 0: - return ctx->tok = tEOF; + return ctx.tok = tEOF; case '\n': - ctx->linenumber++; - ctx->sptr++; - ctx->line = ctx->sptr; - ctx->xref[ctx->pc / 4] = ctx->linenumber; - if (ctx->flags & cfVisibleEOL) return ctx->tok = tEOL; + ctx.linenumber++; + ctx.sptr++; + ctx.line = ctx.sptr; + ctx.xref[ctx.pc / 4] = ctx.linenumber; + if (ctx.flags & cfVisibleEOL) return ctx.tok = tEOL; continue; case ' ': case '\t': case '\r': - ctx->sptr++; + ctx.sptr++; continue; case '0': if (s[1] == 'x') { @@ -555,7 +558,7 @@ token_t _next(Ctx ctx) { for (;;) { s++; int x = unhex(*s); - if (x < 0) return next_num(ctx, n, ctx->sptr, s - ctx->sptr); + if (x < 0) return next_num(n, ctx.sptr, s - ctx.sptr); n = (n << 4) | x; } } @@ -566,7 +569,7 @@ token_t _next(Ctx ctx) { n = (n << 1) | (*s - '0'); s++; } - return next_num(ctx, n, ctx->sptr, s - ctx->sptr); + return next_num(n, ctx.sptr, s - ctx.sptr); } case '1' ... '9': { u32 n = 0; @@ -576,7 +579,7 @@ token_t _next(Ctx ctx) { n = (n * 10) + (*s - '0'); break; default: - return next_num(ctx, n, ctx->sptr, s - ctx->sptr); + return next_num(n, ctx.sptr, s - ctx.sptr); } s++; } @@ -593,7 +596,7 @@ token_t _next(Ctx ctx) { case '_': break; default: - return next_word(ctx, ctx->sptr, s - ctx->sptr); + return next_word(ctx.sptr, s - ctx.sptr); } } case '.': TOKEN(tDOT); @@ -630,21 +633,21 @@ token_t _next(Ctx ctx) { case '/': if (s[1] == '/') { while ((*s != '\n') && (*s != 0)) s++; - ctx->sptr = s; + ctx.sptr = s; continue; } else { TOKEN(tSLASH); } - case '"': return next_string(ctx, ctx->sptr + 1); + case '"': return next_string(ctx.sptr + 1); default: - error(ctx, "unknown character '%c' (0x%02x)\n", + error("unknown character '%c' (0x%02x)\n", ((*s > ' ') && (*s < 128)) ? *s : '.', *s); } } } -token_t next(Ctx ctx) { - return (ctx->tok = _next(ctx)); +token_t next() { + return (ctx.tok = _next()); } void printstr(const char* s) { @@ -668,34 +671,34 @@ void printstr(const char* s) { printf("\""); } -void print(Ctx ctx) { - switch (ctx->tok) { - case tNUMBER: printf("#%u ", ctx->num); break; - case tNAME: printf("@%s ", ctx->tmp); break; +void print() { + switch (ctx.tok) { + case tNUMBER: printf("#%u ", ctx.num); break; + case tNAME: printf("@%s ", ctx.tmp); break; case tEOL: printf("\n"); break; - case tSTRING: printstr(ctx->tmp); break; - default: printf("%s ", tnames[ctx->tok & 0x7F]); break; + case tSTRING: printstr(ctx.tmp); break; + default: printf("%s ", tnames[ctx.tok & 0x7F]); break; } } -void expected(Ctx ctx, const char* what) { - error(ctx, "expected %s, found %s", what, tnames[ctx->tok & 0x7F]); +void expected(const char* what) { + error("expected %s, found %s", what, tnames[ctx.tok & 0x7F]); } -void expect(Ctx ctx, token_t tok) { - if (ctx->tok != tok) { - error(ctx, "expected %s, found %s", tnames[tok], tnames[ctx->tok & 0x7F]); +void expect(token_t tok) { + if (ctx.tok != tok) { + error("expected %s, found %s", tnames[tok], tnames[ctx.tok & 0x7F]); } } -void require(Ctx ctx, token_t tok) { - expect(ctx, tok); - next(ctx); +void require(token_t tok) { + expect(tok); + next(); } // Look for an identifier in the scope stack -Object find(Ctx ctx, String str) { - Scope scope = ctx->scope; +Object find(String str) { + Scope scope = ctx.scope; while (scope != nil) { Object obj = scope->first; while (obj != nil) { @@ -709,38 +712,38 @@ Object find(Ctx ctx, String str) { return nil; } -void make_global(Ctx ctx, Object obj) { - obj->next = ctx->global.first; - ctx->global.first = obj; +void make_global(Object obj) { + obj->next = ctx.global.first; + ctx.global.first = obj; } // push a scope on the scope stack // if obj is non-nil, it is the first of a list of items in that scope -Scope push_scope(Ctx ctx, u32 kind, Object obj) { +Scope push_scope(u32 kind, Object obj) { Scope scope = malloc(sizeof(ScopeRec)); scope->kind = kind; - scope->next = ctx->scope; + scope->next = ctx.scope; scope->first = obj; - scope->level = ctx->scope->level + 1; + scope->level = ctx.scope->level + 1; scope->fixups = nil; - ctx->scope = scope; + ctx.scope = scope; return scope; // XXX lazy scopes } -void pop_scope(Ctx ctx) { - if (ctx->scope->level == 0) { - error(ctx, "cannot pop the global scope"); +void pop_scope() { + if (ctx.scope->level == 0) { + error("cannot pop the global scope"); } - fixup_branches_fwd(ctx, ctx->scope->fixups); + fixup_branches_fwd(ctx.scope->fixups); // XXX delete? - ctx->scope = ctx->scope->next; + ctx.scope = ctx.scope->next; } // find the first surrounding scope of a specified kind -Scope find_scope(Ctx ctx, u32 scope_kind) { - Scope scope = ctx->scope; +Scope find_scope(u32 scope_kind) { + Scope scope = ctx.scope; while (scope != nil) { if (scope->kind == scope_kind) { return scope; @@ -752,19 +755,19 @@ Scope find_scope(Ctx ctx, u32 scope_kind) { // add a fixup for the last-emitted instruction // to the scope (used for return and break) -void add_scope_fixup(Ctx ctx, Scope scope) { +void add_scope_fixup(Scope scope) { Fixup fixup = malloc(sizeof(FixupRec)); fixup->next = scope->fixups; - fixup->pc = ctx->pc - 4; + fixup->pc = ctx.pc - 4; scope->fixups = fixup; } // add a fixup for the last-emitted instruction // to the object (used for forward func refs) -void add_object_fixup(Ctx ctx, Object obj) { +void add_object_fixup(Object obj) { Fixup fixup = malloc(sizeof(FixupRec)); fixup->next = obj->fixups; - fixup->pc = ctx->pc - 4; + fixup->pc = ctx.pc - 4; obj->fixups = fixup; } @@ -783,324 +786,324 @@ u32 invert_relop(u32 op) { } // ================================================================ -void parse_expr(Ctx ctx, Item x); - -void parse_operand(Ctx ctx, Item x) { - if (ctx->tok == tNUMBER) { - setitem(x, iConst, ctx->type_int32, 0, ctx->num, 0); - } else if (ctx->tok == tSTRING) { - error(ctx, "unsupported string const"); - } else if (ctx->tok == tTRUE) { - setitem(x, iConst, ctx->type_bool, 0, 1, 0); - } else if (ctx->tok == tFALSE) { - setitem(x, iConst, ctx->type_bool, 0, 0, 0); - } else if (ctx->tok == tNIL) { - setitem(x, iConst, ctx->type_nil, 0, 0, 0); - } else if (ctx->tok == tOPAREN) { - next(ctx); - parse_expr(ctx, x); - require(ctx, tCPAREN); +void parse_expr(Item x); + +void parse_operand(Item x) { + if (ctx.tok == tNUMBER) { + setitem(x, iConst, ctx.type_int32, 0, ctx.num, 0); + } else if (ctx.tok == tSTRING) { + error("unsupported string const"); + } else if (ctx.tok == tTRUE) { + setitem(x, iConst, ctx.type_bool, 0, 1, 0); + } else if (ctx.tok == tFALSE) { + setitem(x, iConst, ctx.type_bool, 0, 0, 0); + } else if (ctx.tok == tNIL) { + setitem(x, iConst, ctx.type_nil, 0, 0, 0); + } else if (ctx.tok == tOPAREN) { + next(); + parse_expr(x); + require(tCPAREN); return; - } else if (ctx->tok == tNAME) { - String str = mkstring(ctx, ctx->tmp, strlen(ctx->tmp)); - Object obj = find(ctx, str); + } else if (ctx.tok == tNAME) { + String str = mkstring(ctx.tmp, strlen(ctx.tmp)); + Object obj = find(str); if (obj == nil) { - error(ctx, "unknown identifier '%s'", str->text); + error("unknown identifier '%s'", str->text); } if (obj->kind == oParam) { setitem(x, iParam, obj->type, 0, obj->value, 0); } else if (obj->kind == oFunc) { setitem(x, iFunc, obj->type, 0, 0, 0); } else { - error(ctx, "unsupported identifier"); + error("unsupported identifier"); } } - next(ctx); + next(); } -void parse_primary_expr(Ctx ctx, Item x) { - parse_operand(ctx, x); +void parse_primary_expr(Item x) { + parse_operand(x); while (true) { - if (ctx->tok == tOPAREN) { - next(ctx); + if (ctx.tok == tOPAREN) { + next(); if (x->kind != iFunc) { - error(ctx, "cannot call non-function"); + error("cannot call non-function"); } // TODO ptr-to-func u32 n = 0; Object param = x->type->first; while (param != nil) { if (n != 0) { - require(ctx, tCOMMA); + require(tCOMMA); } ItemRec y; - parse_expr(ctx, &y); - gen_param(ctx, n, &y); + parse_expr(&y); + gen_param(n, &y); param = param->next; n++; } - require(ctx, tCPAREN); - gen_call(ctx, x); - } else if (ctx->tok == tDOT) { - error(ctx, "unsupported field deref"); - } else if (ctx->tok == tOBRACK) { - error(ctx, "unsupported array deref"); + require(tCPAREN); + gen_call(x); + } else if (ctx.tok == tDOT) { + error("unsupported field deref"); + } else if (ctx.tok == tOBRACK) { + error("unsupported array deref"); } else { break; } } } -void parse_unary_expr(Ctx ctx, Item x) { - if (ctx->tok == tPLUS) { - next(ctx); - parse_unary_expr(ctx, x); - } else if ((ctx->tok == tMINUS) || (ctx->tok == tBANG) || (ctx->tok == tNOT)) { - u32 op = ctx->tok; - next(ctx); - parse_unary_expr(ctx, x); +void parse_unary_expr(Item x) { + if (ctx.tok == tPLUS) { + next(); + parse_unary_expr(x); + } else if ((ctx.tok == tMINUS) || (ctx.tok == tBANG) || (ctx.tok == tNOT)) { + u32 op = ctx.tok; + next(); + parse_unary_expr(x); if ((x->kind == iComp) && (op == tBANG)) { x->r = invert_relop(x->r); } else { - gen_unary_op(ctx, op, x); + gen_unary_op(op, x); } - } else if (ctx->tok == tAMP) { - next(ctx); - error(ctx, "deref unsupported"); + } else if (ctx.tok == tAMP) { + next(); + error("deref unsupported"); } else { - parse_primary_expr(ctx, x); + parse_primary_expr(x); } } -void parse_mul_expr(Ctx ctx, Item x) { - parse_unary_expr(ctx, x); - while ((ctx->tok >> 8) == tcMULOP) { - u32 mulop = ctx->tok - tSTAR; - next(ctx); +void parse_mul_expr(Item x) { + parse_unary_expr(x); + while ((ctx.tok >> 8) == tcMULOP) { + u32 mulop = ctx.tok - tSTAR; + next(); ItemRec y; - parse_unary_expr(ctx, &y); - gen_mul_op(ctx, mulop, x, &y); + parse_unary_expr(&y); + gen_mul_op(mulop, x, &y); } } -void parse_add_expr(Ctx ctx, Item x) { - parse_mul_expr(ctx, x); - while ((ctx->tok >> 8) == tcADDOP) { - u32 addop = ctx->tok - tPLUS; - next(ctx); +void parse_add_expr(Item x) { + parse_mul_expr(x); + while ((ctx.tok >> 8) == tcADDOP) { + u32 addop = ctx.tok - tPLUS; + next(); ItemRec y; - parse_mul_expr(ctx, &y); - gen_add_op(ctx, addop, x, &y); + parse_mul_expr(&y); + gen_add_op(addop, x, &y); } } -void parse_rel_expr(Ctx ctx, Item x) { - parse_add_expr(ctx, x); - if ((ctx->tok >> 8) == tcRELOP) { - u32 relop = ctx->tok - tEQ; - next(ctx); +void parse_rel_expr(Item x) { + parse_add_expr(x); + if ((ctx.tok >> 8) == tcRELOP) { + u32 relop = ctx.tok - tEQ; + next(); ItemRec y; - parse_add_expr(ctx, &y); - gen_rel_op(ctx, relop, x, &y); + parse_add_expr(&y); + gen_rel_op(relop, x, &y); } } -void parse_and_expr(Ctx ctx, Item x) { - parse_rel_expr(ctx, x); - while (ctx->tok == tAND) { - next(ctx); +void parse_and_expr(Item x) { + parse_rel_expr(x); + while (ctx.tok == tAND) { + next(); ItemRec y; - parse_rel_expr(ctx, &y); - error(ctx, "unsupported and op"); + parse_rel_expr(&y); + error("unsupported and op"); } } -void parse_expr(Ctx ctx, Item x) { - parse_and_expr(ctx, x); - while (ctx->tok == tOR) { - next(ctx); +void parse_expr(Item x) { + parse_and_expr(x); + while (ctx.tok == tOR) { + next(); ItemRec y; - parse_and_expr(ctx, &y); - error(ctx, "unsupported or op"); + parse_and_expr(&y); + error("unsupported or op"); } } -String parse_name(Ctx ctx, const char* what) { - if (ctx->tok != tNAME) { - error(ctx, "expected %s, found %s", what, tnames[ctx->tok & 0x7F]); +String parse_name(const char* what) { + if (ctx.tok != tNAME) { + error("expected %s, found %s", what, tnames[ctx.tok & 0x7F]); } - String str = mkstring(ctx, ctx->tmp, strlen(ctx->tmp)); - next(ctx); + String str = mkstring(ctx.tmp, strlen(ctx.tmp)); + next(); return str; } -Type parse_type(Ctx ctx) { - String tname = parse_name(ctx, "type name"); - Object obj = ctx->typetab; +Type parse_type() { + String tname = parse_name("type name"); + Object obj = ctx.typetab; while (obj != nil) { if (obj->name == tname) { return obj->type; } obj = obj->next; } - error(ctx, "unknown type name '%s'", tname->text); + error("unknown type name '%s'", tname->text); return nil; } -void parse_block(Ctx ctx); +void parse_block(); -void parse_while(Ctx ctx) { +void parse_while() { ItemRec x; - u32 l0_loop = ctx->pc; // for backward branch + u32 l0_loop = ctx.pc; // for backward branch - parse_expr(ctx, &x); - u32 l1_br_false = gen_branch_cond(ctx, &x, false); + parse_expr(&x); + u32 l1_br_false = gen_branch_cond(&x, false); - require(ctx, tOBRACE); - push_scope(ctx, sLoop, nil); - parse_block(ctx); - gen_branch_back(ctx, l0_loop); - pop_scope(ctx); + require(tOBRACE); + push_scope(sLoop, nil); + parse_block(); + gen_branch_back(l0_loop); + pop_scope(); - fixup_branch_fwd(ctx, l1_br_false); + fixup_branch_fwd(l1_br_false); } -void parse_if(Ctx ctx) { - Scope outer = push_scope(ctx, sBlock, nil); +void parse_if() { + Scope outer = push_scope(sBlock, nil); ItemRec x; - parse_expr(ctx, &x); + parse_expr(&x); // branch over "if" code - u32 l0_br_false = gen_branch_cond(ctx, &x, false); + u32 l0_br_false = gen_branch_cond(&x, false); // generate "if" code - require(ctx, tOBRACE); - push_scope(ctx, sBlock, nil); - parse_block(ctx); - pop_scope(ctx); + require(tOBRACE); + push_scope(sBlock, nil); + parse_block(); + pop_scope(); // branch past "else" code - gen_branch_fwd(ctx); - add_scope_fixup(ctx, outer); - - while (ctx->tok == tELSE) { - next(ctx); - fixup_branch_fwd(ctx, l0_br_false); - if (ctx->tok == tIF) { - next(ctx); - parse_expr(ctx, &x); + gen_branch_fwd(); + add_scope_fixup(outer); + + while (ctx.tok == tELSE) { + next(); + fixup_branch_fwd(l0_br_false); + if (ctx.tok == tIF) { + next(); + parse_expr(&x); // branch over "if" code - l0_br_false = gen_branch_cond(ctx, &x, false); + l0_br_false = gen_branch_cond(&x, false); // generate "if else" code - require(ctx, tOBRACE); - push_scope(ctx, sBlock, nil); - parse_block(ctx); - pop_scope(ctx); + require(tOBRACE); + push_scope(sBlock, nil); + parse_block(); + pop_scope(); // branch past "else" code - gen_branch_fwd(ctx); - add_scope_fixup(ctx, outer); + gen_branch_fwd(); + add_scope_fixup(outer); } else { // generate "else" code - require(ctx, tOBRACE); - push_scope(ctx, sBlock, nil); - parse_block(ctx); - pop_scope(ctx); + require(tOBRACE); + push_scope(sBlock, nil); + parse_block(); + pop_scope(); // close outer scope - pop_scope(ctx); + pop_scope(); return; // no further fixups needed } } - fixup_branch_fwd(ctx, l0_br_false); + fixup_branch_fwd(l0_br_false); // close outer scope - pop_scope(ctx); + pop_scope(); } -void parse_return(Ctx ctx) { +void parse_return() { ItemRec x; - if (ctx->tok == tSEMI) { - if (ctx->fn->type->base != ctx->type_void) { - error(ctx, "function requires return type"); + if (ctx.tok == tSEMI) { + if (ctx.fn->type->base != ctx.type_void) { + error("function requires return type"); } - next(ctx); - x.type = ctx->type_void; + next(); + x.type = ctx.type_void; } else { - parse_expr(ctx, &x); - if (!sametype(ctx->fn->type->base, x.type)) { - error(ctx, "return types do not match"); + parse_expr(&x); + if (!sametype(ctx.fn->type->base, x.type)) { + error("return types do not match"); } - require(ctx, tSEMI); + require(tSEMI); } - gen_return(ctx, &x); + gen_return(&x); } -void parse_break(Ctx ctx) { +void parse_break() { // XXX break-to-labeled-loop support - require(ctx, tSEMI); - gen_branch_fwd(ctx); - Scope scope = find_scope(ctx,sLoop); + require(tSEMI); + gen_branch_fwd(); + Scope scope = find_scope(sLoop); if (scope == nil) { - error(ctx, "break must be used from inside a looping construct"); + error("break must be used from inside a looping construct"); } - add_scope_fixup(ctx, scope); + add_scope_fixup(scope); } -void parse_block(Ctx ctx) { +void parse_block() { while (true) { - if (ctx->tok == tCBRACE) { - next(ctx); + if (ctx.tok == tCBRACE) { + next(); break; - } else if (ctx->tok == tRETURN) { - next(ctx); - parse_return(ctx); - } else if (ctx->tok == tBREAK) { - next(ctx); - parse_return(ctx); - } else if (ctx->tok == tWHILE) { - next(ctx); - parse_while(ctx); - } else if (ctx->tok == tIF) { - next(ctx); - parse_if(ctx); - } else if (ctx->tok == tSEMI) { - next(ctx); + } else if (ctx.tok == tRETURN) { + next(); + parse_return(); + } else if (ctx.tok == tBREAK) { + next(); + parse_break(); + } else if (ctx.tok == tWHILE) { + next(); + parse_while(); + } else if (ctx.tok == tIF) { + next(); + parse_if(); + } else if (ctx.tok == tSEMI) { + next(); // empty statement } else { ItemRec x; - parse_expr(ctx, &x); - if (ctx->tok == tASSIGN) { - next(ctx); + parse_expr(&x); + if (ctx.tok == tASSIGN) { + next(); ItemRec y; - parse_expr(ctx, &y); - gen_store(ctx, &y, &x); - } else if ((ctx->tok == tINC) || (ctx->tok == tDEC)) { + parse_expr(&y); + gen_store(&y, &x); + } else if ((ctx.tok == tINC) || (ctx.tok == tDEC)) { ItemRec y; - setitem(&y, iConst, ctx->type_int32, 0, 1, 0); - next(ctx); + setitem(&y, iConst, ctx.type_int32, 0, 1, 0); + next(); } - require(ctx, tSEMI); + require(tSEMI); } } } -void parse_function_body(Ctx ctx, Object fn) { - ctx->fn = fn; - gen_prologue(ctx, fn); - push_scope(ctx, sFunc, fn->first); // scope for parameters - push_scope(ctx, sBlock, nil); // top scope for function body - parse_block(ctx); - pop_scope(ctx); - pop_scope(ctx); - gen_epilogue(ctx, fn); +void parse_function_body(Object fn) { + ctx.fn = fn; + gen_prologue(fn); + push_scope(sFunc, fn->first); // scope for parameters + push_scope(sBlock, nil); // top scope for function body + parse_block(); + pop_scope(); + pop_scope(); + gen_epilogue(fn); } -Object parse_param(Ctx ctx, String fname, u32 n, Object first, Object last) { +Object parse_param(String fname, u32 n, Object first, Object last) { if (n == FNMAXARGS) { - error(ctx, "too many parameters (%d) for '%s'", FNMAXARGS, fname->text); + error("too many parameters (%d) for '%s'", FNMAXARGS, fname->text); } Object param = malloc(sizeof(ObjectRec)); param->kind = oParam; @@ -1108,14 +1111,14 @@ Object parse_param(Ctx ctx, String fname, u32 n, Object first, Object last) { param->value = n; param->next = nil; param->first = nil; - param->name = parse_name(ctx, "parameter name"); - param->type = parse_type(ctx); + param->name = parse_name("parameter name"); + param->type = parse_type(); param->fixups = nil; Object obj = first; while (obj != nil) { if (obj->name == param->name) { - error(ctx, "duplicate parameter name '%s'", fname->text); + error("duplicate parameter name '%s'", fname->text); } obj = obj->next; } @@ -1126,7 +1129,7 @@ Object parse_param(Ctx ctx, String fname, u32 n, Object first, Object last) { return param; } -void make_builtin(Ctx ctx, const char* name, u32 id, Type p0, Type p1, Type rtn) { +void make_builtin(const char* name, u32 id, Type p0, Type p1, Type rtn) { Type type = malloc(sizeof(TypeRec)); Object obj = malloc(sizeof(ObjectRec)); @@ -1143,7 +1146,7 @@ void make_builtin(Ctx ctx, const char* name, u32 id, Type p0, Type p1, Type rtn) obj->next = nil; obj->first = nil; obj->type = type; - obj->name = mkstring(ctx, name, strlen(name)); + obj->name = mkstring(name, strlen(name)); obj->fixups = nil; if (p0 != nil) { @@ -1155,7 +1158,7 @@ void make_builtin(Ctx ctx, const char* name, u32 id, Type p0, Type p1, Type rtn) param->value = 0; param->next = nil; param->first = nil; - param->name = mkstring(ctx, "a", 1); + param->name = mkstring("a", 1); param->type = p0; param->fixups = nil; type->len = 1; @@ -1167,76 +1170,76 @@ void make_builtin(Ctx ctx, const char* name, u32 id, Type p0, Type p1, Type rtn) param->value = 1; param->next = nil; param->first = nil; - param->name = mkstring(ctx, "b", 1); + param->name = mkstring("b", 1); param->type = p1; param->fixups = nil; type->len = 2; } } - make_global(ctx, obj); + make_global(obj); } -void parse_function(Ctx ctx) { +void parse_function() { Object first = nil; Object last = nil; u32 n = 0; - String fname = parse_name(ctx, "funcion name"); - Type ftype = ctx->type_void; + String fname = parse_name("funcion name"); + Type ftype = ctx.type_void; - require(ctx, tOPAREN); + require(tOPAREN); // process parameters - if (ctx->tok != tCPAREN) { - first = parse_param(ctx, fname, n, nil, nil); + if (ctx.tok != tCPAREN) { + first = parse_param(fname, n, nil, nil); last = first; n++; - while (ctx->tok == tCOMMA) { - next(ctx); - last = parse_param(ctx, fname, n, first, last); + while (ctx.tok == tCOMMA) { + next(); + last = parse_param(fname, n, first, last); n++; } } - require(ctx, tCPAREN); + require(tCPAREN); - if ((ctx->tok != tSEMI) && (ctx->tok != tOBRACE)) { - ftype = parse_type(ctx); + if ((ctx.tok != tSEMI) && (ctx.tok != tOBRACE)) { + ftype = parse_type(); } int isdef = 0; - if (ctx->tok == tSEMI) { + if (ctx.tok == tSEMI) { // declaration - next(ctx); - } else if (ctx->tok == tOBRACE) { + next(); + } else if (ctx.tok == tOBRACE) { // definition - next(ctx); + next(); isdef = 1; } else { - expected(ctx, "semi or open brace"); + expected("semi or open brace"); } // Look for an existing declaration or definintion of this function - Object obj = find(ctx, fname); + Object obj = find(fname); if (obj != nil) { // such a named identifier exists // check to see if we are in agreement with it if (obj->kind != oFunc) { - error(ctx, "redefining '%s' as function", fname->text); + error("redefining '%s' as function", fname->text); } if (isdef && (obj->flags & ofDefined)) { - error(ctx, "redefined function '%s'", fname->text); + error("redefined function '%s'", fname->text); } if (ftype != obj->type->base) { - error(ctx, "func '%s' return type differs from decl", fname->text); + error("func '%s' return type differs from decl", fname->text); } if (obj->type->len != n) { - error(ctx, "func '%s' parameter count differs from decl", fname->text); + error("func '%s' parameter count differs from decl", fname->text); } Object pa = first; Object pb = obj->type->first; u32 i = 1; while ((pa != nil) && (pb != nil)) { if (!sametype(pa->type, pb->type)) { - error(ctx, "func '%s' param %u differs from decl", fname->text, i); + error("func '%s' param %u differs from decl", fname->text, i); } pa = pa->next; pb = pb->next; @@ -1262,76 +1265,76 @@ void parse_function(Ctx ctx) { obj->name = fname; obj->fixups = nil; - make_global(ctx, obj); + make_global(obj); } // handle definition if it is one if (isdef) { // patch any forward references - fixup_branches_fwd(ctx, obj->fixups); + fixup_branches_fwd(obj->fixups); // mark as defined and save entry address obj->flags |= ofDefined; - obj->value = ctx->pc; - parse_function_body(ctx, obj); + obj->value = ctx.pc; + parse_function_body(obj); } } -void parse_global_var(Ctx ctx) { - error(ctx, "unsupported"); +void parse_global_var() { + error("unsupported"); } -void parse_program(Ctx ctx) { - next(ctx); +void parse_program() { + next(); for (;;) { - switch (ctx->tok) { + switch (ctx.tok) { case tFUNC: - next(ctx); - parse_function(ctx); + next(); + parse_function(); break; case tVAR: - next(ctx); - parse_global_var(ctx); + next(); + parse_global_var(); break; case tEOF: return; default: - expected(ctx, "func or var"); + expected("func or var"); } } } // ================================================================ -u32 get_reg_tmp(Ctx ctx) { +u32 get_reg_tmp() { u32 n = 8; while (n < 12) { - if (!(ctx->regbits & (1 << n))) { - ctx->regbits |= (1 << n); + if (!(ctx.regbits & (1 << n))) { + ctx.regbits |= (1 << n); //printf("GET REG %u\n", n); return n; } n++; } - error(ctx, "cannot allocate register"); + error("cannot allocate register"); return 0; } -void put_reg(Ctx ctx, u32 r) { +void put_reg(u32 r) { //printf("PUT REG %u\n", r); if (r < 8) { // currently we don't strictly track r0..r7 // they are used for function calls and returns return; } - if (!(ctx->regbits & (1 << r))) { - error(ctx, "freeing non-allocated register %u\n", r); + if (!(ctx.regbits & (1 << r))) { + error("freeing non-allocated register %u\n", r); } - ctx->regbits = ctx->regbits & (~(1 << r)); + ctx.regbits = ctx.regbits & (~(1 << r)); } -void emit(Ctx ctx, u32 ins) { - ctx->code[ctx->pc / 4] = ins; - ctx->pc = ctx->pc + 4; +void emit(u32 ins) { + ctx.code[ctx.pc / 4] = ins; + ctx.pc = ctx.pc + 4; } enum { @@ -1351,53 +1354,53 @@ enum { MOD = 0x001B, // fake op for plumbing (DIV+MOV_H) }; -void emit_op(Ctx ctx, u32 op, u32 a, u32 b, u32 c) { - emit(ctx, (op << 16) | (a << 24) | (b << 20) | c); +void emit_op(u32 op, u32 a, u32 b, u32 c) { + emit((op << 16) | (a << 24) | (b << 20) | c); } -void emit_opi(Ctx ctx, u32 op, u32 a, u32 b, u32 n) { - emit(ctx, ((0x4000 | op) << 16) | (a << 24) | (b << 20) | (n & 0xffff)); +void emit_opi(u32 op, u32 a, u32 b, u32 n) { + emit(((0x4000 | op) << 16) | (a << 24) | (b << 20) | (n & 0xffff)); } // mov (load immediate) using the appropriate one or two // instruction form for the immediate argument -void emit_mov(Ctx ctx, u32 a, u32 n) { +void emit_mov(u32 a, u32 n) { u32 m = n >> 16; if (m == 0) { - emit_opi(ctx, MOV, a, 0, n); + emit_opi(MOV, a, 0, n); } else if (m == 0xFFFF) { - emit_opi(ctx, MOV | 0x1000, a, 0, n); + emit_opi(MOV | 0x1000, a, 0, n); } else { - emit_opi(ctx, MHI, a, 0, m); + emit_opi(MHI, a, 0, m); if ((n & 0xFFFF) != 0) { - emit_opi(ctx, IOR, a, a, n); + emit_opi(IOR, a, a, n); } } } // immediate op, using a temporary register and register op if the // immediate argument does not fit the single instruction form -void emit_opi_n(Ctx ctx, u32 op, u32 a, u32 b, u32 n) { +void emit_opi_n(u32 op, u32 a, u32 b, u32 n) { u32 m = n >> 16; if (m == 0) { - emit_opi(ctx, op, a, b, n); + emit_opi(op, a, b, n); } else if (m == 0xFFFF) { - emit_opi(ctx, op | 0x1000, a, b, n); + emit_opi(op | 0x1000, a, b, n); } else { - u32 t0 = get_reg_tmp(ctx); - emit_opi(ctx, MHI, t0, 0, m); + u32 t0 = get_reg_tmp(); + emit_opi(MHI, t0, 0, m); if ((n & 0xFFFF) != 0) { - emit_opi(ctx, IOR, t0, t0, n); + emit_opi(IOR, t0, t0, n); } - emit_op(ctx, op, a, b, t0); - put_reg(ctx, t0); + emit_op(op, a, b, t0); + put_reg(t0); } } enum { LDW = 8, LDB = 9, STW = 10, STB = 11 }; -void emit_mem(Ctx ctx, u32 op, u32 a, u32 b, u32 off) { - emit(ctx, (op << 28) | (a << 24) | (b << 20) | (off & 0xfffff)); +void emit_mem(u32 op, u32 a, u32 b, u32 off) { + emit((op << 28) | (a << 24) | (b << 20) | (off & 0xfffff)); } enum { @@ -1405,11 +1408,11 @@ enum { PL = 8, NE = 9, CC = 10, VC = 11, HI = 12, GE = 13, GT = 14, NV = 15, L = 0x10, }; -void emit_br(Ctx ctx, u32 op, u32 r) { - emit(ctx, ((0xC0 | op) << 24) | r); +void emit_br(u32 op, u32 r) { + emit(((0xC0 | op) << 24) | r); } -void emit_bi(Ctx ctx, u32 op, u32 off) { - emit(ctx, ((0xE0 | op) << 24) | (off & 0xffffff)); +void emit_bi(u32 op, u32 off) { + emit(((0xE0 | op) << 24) | (off & 0xffffff)); } u8 rel_op_to_cc_tab[6] = { EQ, NE, LT, LE, GT, GE }; @@ -1434,8 +1437,8 @@ u32 mul_op_to_ins(u32 op) { // check to see if the last emitted instruction // loaded a particular register and if so, patch // it to load a different register -bool patch_last_load(Ctx ctx, u32 oldr, u32 newr) { - u32 ins = ctx->code[(ctx->pc - 4) / 4]; +bool patch_last_load(u32 oldr, u32 newr) { + u32 ins = ctx.code[(ctx.pc - 4) / 4]; u32 n = ins >> 29; if ((n == 0b101) || (n == 0b110) || (n == 0b111)) { // store and branch instructions can be ignored @@ -1444,27 +1447,27 @@ bool patch_last_load(Ctx ctx, u32 oldr, u32 newr) { if (((ins >> 24) & 15) != oldr) { return false; } - ctx->code[(ctx->pc - 4) / 4] = (ins & 0xF0FFFFFF) | (newr << 24); + ctx.code[(ctx.pc - 4) / 4] = (ins & 0xF0FFFFFF) | (newr << 24); return true; } // load the value of an item into a specific register -void gen_load_reg(Ctx ctx, Item x, u32 r) { +void gen_load_reg(Item x, u32 r) { if (x->kind == iReg) { if (x->r != r) { - if (patch_last_load(ctx, x->r, r)) { - put_reg(ctx, x->r); + if (patch_last_load(x->r, r)) { + put_reg(x->r); } else { - emit_op(ctx, MOV, r, 0, x->r); - put_reg(ctx, x->r); + emit_op(MOV, r, 0, x->r); + put_reg(x->r); } } } else if (x->kind == iConst) { - emit_mov(ctx, r, x->a); + emit_mov(r, x->a); } else if (x->kind == iParam) { - emit_mem(ctx, LDW, r, SP, 4 + x->a * 4); + emit_mem(LDW, r, SP, 4 + x->a * 4); } else { - error(ctx, "gen_load failed"); + error("gen_load failed"); } x->kind = iReg; x->r = r; @@ -1472,94 +1475,94 @@ void gen_load_reg(Ctx ctx, Item x, u32 r) { // convert an item to value-in-register format // if it's not already in that format -void gen_load(Ctx ctx, Item x) { +void gen_load(Item x) { if (x->kind != iReg) { - gen_load_reg(ctx, x, get_reg_tmp(ctx)); + gen_load_reg(x, get_reg_tmp()); } } -void gen_store(Ctx ctx, Item val, Item var) { - gen_load(ctx, val); +void gen_store(Item val, Item var) { + gen_load(val); if (var->kind == iParam) { - emit_mem(ctx, STW, val->r, SP, 4 + var->a * 4); - put_reg(ctx, val->r); + emit_mem(STW, val->r, SP, 4 + var->a * 4); + put_reg(val->r); } else { - error(ctx, "gen_store: invalid target"); + error("gen_store: invalid target"); } } -u32 gen_branch_cond(Ctx ctx, Item x, bool sense) { +u32 gen_branch_cond(Item x, bool sense) { u32 cc; if (x->kind == iComp) { if (sense == false) { x->r = invert_relop(x->r); } - emit_op(ctx, SUB, x->a, x->a, x->b); - put_reg(ctx, x->a); - put_reg(ctx, x->b); + emit_op(SUB, x->a, x->a, x->b); + put_reg(x->a); + put_reg(x->b); cc = rel_op_to_cc(x->r); - } else if (x->type == ctx->type_bool) { - gen_load(ctx, x); - emit_opi(ctx, SUB, x->r, x->r, 1); - put_reg(ctx, x->r); + } else if (x->type == ctx.type_bool) { + gen_load(x); + emit_opi(SUB, x->r, x->r, 1); + put_reg(x->r); if (sense) { cc = EQ; } else { cc = NE; } } else { - error(ctx, "conditional branch needs comparison or bool"); + error("conditional branch needs comparison or bool"); } - emit_bi(ctx, cc, 0); - return ctx->pc - 4; + emit_bi(cc, 0); + return ctx.pc - 4; } -u32 gen_branch_fwd(Ctx ctx) { - emit_bi(ctx, AL, 0); - return ctx->pc - 4; +u32 gen_branch_fwd() { + emit_bi(AL, 0); + return ctx.pc - 4; } -void gen_branch_back(Ctx ctx, u32 addr) { - emit_bi(ctx, AL, (addr - ctx->pc - 4) >> 2); +void gen_branch_back(u32 addr) { + emit_bi(AL, (addr - ctx.pc - 4) >> 2); } -void gen_return(Ctx ctx, Item x) { - if (x->type != ctx->type_void) { - gen_load_reg(ctx, x, R0); +void gen_return(Item x) { + if (x->type != ctx.type_void) { + gen_load_reg(x, R0); } - emit_bi(ctx, AL, 0); - add_scope_fixup(ctx, find_scope(ctx, sFunc)); + emit_bi(AL, 0); + add_scope_fixup(find_scope(sFunc)); } -void gen_param(Ctx ctx, u32 n, Item val) { +void gen_param(u32 n, Item val) { if (n > 7) { - error(ctx, "gen_param - too many parameters"); + error("gen_param - too many parameters"); } - gen_load_reg(ctx, val, n); + gen_load_reg(val, n); } -void gen_builtin(Ctx ctx, u32 id) { +void gen_builtin(u32 id) { if (id == biPrintHex32) { - emit_mov(ctx, 1, 0xFFFF0000); // MOV R1, IOBASE - emit_mem(ctx, STW, 0, 1, 0x104); // SW R0, [R1, 0x104] + emit_mov(1, 0xFFFF0000); // MOV R1, IOBASE + emit_mem(STW, 0, 1, 0x104); // SW R0, [R1, 0x104] } else { - error(ctx, "unknown builtin function"); + error("unknown builtin function"); } } -void gen_call(Ctx ctx, Item x) { +void gen_call(Item x) { if (x->type->obj->flags & ofBuiltin) { - gen_builtin(ctx, x->type->obj->value); + gen_builtin(x->type->obj->value); } else if (x->type->obj->flags & ofDefined) { u32 fnpc = x->type->obj->value; - emit_bi(ctx, AL|L, (fnpc - ctx->pc - 4) >> 2); + emit_bi(AL|L, (fnpc - ctx.pc - 4) >> 2); } else { - emit_bi(ctx, AL|L, 0); - add_object_fixup(ctx, x->type->obj); + emit_bi(AL|L, 0); + add_object_fixup(x->type->obj); } // item becomes the return value x->type = x->type->base; - if (x->type == ctx->type_void) { + if (x->type == ctx.type_void) { x->kind = iConst; } else { x->kind = iReg; @@ -1569,7 +1572,7 @@ void gen_call(Ctx ctx, Item x) { x->b = 0; } -void gen_add_op(Ctx ctx, u32 op, Item x, Item y) { +void gen_add_op(u32 op, Item x, Item y) { op = add_op_to_ins(op); if ((x->kind == iConst) && (y->kind == iConst)) { // XC = XC op YC @@ -1584,21 +1587,21 @@ void gen_add_op(Ctx ctx, u32 op, Item x, Item y) { } } else if (y->kind == iConst) { // XR = XR op YC - gen_load(ctx, x); + gen_load(x); // for all of these, rhs==0 is no-op if (y->a != 0) { - emit_opi_n(ctx, op, x->r, x->r, y->a); + emit_opi_n(op, x->r, x->r, y->a); } } else { // XR = XR op YR - gen_load(ctx, x); - gen_load(ctx, y); - emit_op(ctx, op, x->r, x->r, y->r); - put_reg(ctx, y->r); + gen_load(x); + gen_load(y); + emit_op(op, x->r, x->r, y->r); + put_reg(y->r); } } -void gen_mul_op(Ctx ctx, u32 op, Item x, Item y) { +void gen_mul_op(u32 op, Item x, Item y) { op = mul_op_to_ins(op); if ((x->kind == iConst) && (y->kind == iConst)) { // XC = XC op YC @@ -1619,45 +1622,45 @@ void gen_mul_op(Ctx ctx, u32 op, Item x, Item y) { } } else if (y->kind == iConst) { // XR = XR op YC - gen_load(ctx, x); + gen_load(x); if (((op == DIV) || (op == MOD)) && (y->a == 0)) { - error(ctx, "divide by zero"); + error("divide by zero"); } else if ((op == MUL) && (y->a == 1)) { return; // x * 1 = x } else if (((op == LSL) || (op == ASR)) && (y->a == 0)) { return; // shift-by-zero } if (op == MOD) { - emit_opi_n(ctx, DIV, x->r, x->r, y->a); - emit_op(ctx, MOV_H, x->r, 0, 0); + emit_opi_n(DIV, x->r, x->r, y->a); + emit_op(MOV_H, x->r, 0, 0); } else { - emit_opi_n(ctx, op, x->r, x->r, y->a); + emit_opi_n(op, x->r, x->r, y->a); } } else { // TODO runtime div-by-zero check // XR = XR op YR - gen_load(ctx, x); - gen_load(ctx, y); + gen_load(x); + gen_load(y); if (op == MOD) { - emit_op(ctx, op, x->r, x->r, y->r); - emit_op(ctx, MOV_H, x->r, 0, 0); + emit_op(op, x->r, x->r, y->r); + emit_op(MOV_H, x->r, 0, 0); } else { - emit_op(ctx, op, x->r, x->r, y->r); + emit_op(op, x->r, x->r, y->r); } - put_reg(ctx, y->r); + put_reg(y->r); } } -void gen_rel_op(Ctx ctx, u32 op, Item x, Item y) { - gen_load(ctx, x); - gen_load(ctx, y); +void gen_rel_op(u32 op, Item x, Item y) { + gen_load(x); + gen_load(y); x->kind = iComp; x->a = x->r; x->b = y->r; x->r = op; } -void gen_unary_op(Ctx ctx, u32 op, Item x) { +void gen_unary_op(u32 op, Item x) { if (x->kind == iConst) { if (op == tMINUS) { x->a = - x->a; @@ -1668,104 +1671,104 @@ void gen_unary_op(Ctx ctx, u32 op, Item x) { } return; } - gen_load(ctx, x); + gen_load(x); if (op == tBANG) { - emit_opi_n(ctx, XOR, x->r, x->r, 1); + emit_opi_n(XOR, x->r, x->r, 1); } else if (op == tNOT) { - emit_opi_n(ctx, XOR, x->r, x->r, 0xFFFFFFFF); + emit_opi_n(XOR, x->r, x->r, 0xFFFFFFFF); } else if (op == tMINUS) { - u32 t0 = get_reg_tmp(ctx); - emit_mov(ctx, t0, 0); - emit_op(ctx, SUB, x->r, t0, x->r); - put_reg(ctx, t0); + u32 t0 = get_reg_tmp(); + emit_mov(t0, 0); + emit_op(SUB, x->r, t0, x->r); + put_reg(t0); } } // patch branch instruction at addr to // branch to current pc -void fixup_branch_fwd(Ctx ctx, u32 addr) { +void fixup_branch_fwd(u32 addr) { #if 0 // disabled for now as this gets tripped up // by stuff like test/1030-flow-control.src (if (n==3) ...) - if (addr == ctx->pc - 4) { + if (addr == ctx.pc - 4) { // if the branch to be patched is the // instruction just previously emitted, we // can simply erase it - ctx->pc -= 4; - fprintf(stderr, "DELETED BRANCH @ 0x%x\n", ctx->pc); + ctx.pc -= 4; + fprintf(stderr, "DELETED BRANCH @ 0x%x\n", ctx.pc); } else #endif { - u32 off = (ctx->pc - addr - 4) >> 2; - u32 ins = ctx->code[addr >> 2] & 0xFF000000; - ctx->code[addr >> 2] = ins | (off & 0x00FFFFFF); + u32 off = (ctx.pc - addr - 4) >> 2; + u32 ins = ctx.code[addr >> 2] & 0xFF000000; + ctx.code[addr >> 2] = ins | (off & 0x00FFFFFF); } } -void fixup_branches_fwd(Ctx ctx, Fixup fixup) { +void fixup_branches_fwd(Fixup fixup) { while (fixup != nil) { - fixup_branch_fwd(ctx, fixup->pc); + fixup_branch_fwd(fixup->pc); fixup = fixup->next; } } -void gen_prologue(Ctx ctx, Object fn) { - fn->value = ctx->pc; - emit_opi(ctx, SUB, SP, SP, 4 + fn->type->len * 4); - emit_mem(ctx, STW, LR, SP, 0); +void gen_prologue(Object fn) { + fn->value = ctx.pc; + emit_opi(SUB, SP, SP, 4 + fn->type->len * 4); + emit_mem(STW, LR, SP, 0); Object param = fn->first; u32 r = 0; while (param != nil) { - emit_mem(ctx, STW, r, SP, (r + 1) * 4); + emit_mem(STW, r, SP, (r + 1) * 4); r++; param = param->next; } } -void gen_epilogue(Ctx ctx, Object fn) { - emit_mem(ctx, LDW, LR, SP, 0); - emit_opi(ctx, ADD, SP, SP, 4 + fn->type->len * 4); - emit_br(ctx, AL, LR); +void gen_epilogue(Object fn) { + emit_mem(LDW, LR, SP, 0); + emit_opi(ADD, SP, SP, 4 + fn->type->len * 4); + emit_br(AL, LR); } -void gen_start(Ctx ctx) { +void gen_start() { // placeholder branch to init - emit_bi(ctx, AL, 0); + emit_bi(AL, 0); } -void gen_end(Ctx ctx) { - ctx->code[0] |= (ctx->pc - 4) >> 2; // patch branch at 0 +void gen_end() { + ctx.code[0] |= (ctx.pc - 4) >> 2; // patch branch at 0 - String str = mkstring(ctx, "start", 5); - Object obj = find(ctx, str); + String str = mkstring("start", 5); + Object obj = find(str); while (obj != nil) { if (obj->type->kind != tFunc) { - error(ctx, "'start' is not a function\n"); + error("'start' is not a function\n"); } if (obj->first != nil) { - error(ctx, "'start' must have no parameters\n"); + error("'start' must have no parameters\n"); } - emit_mov(ctx, 14, 0x100000); // MOV SP, RAMTOP - emit_bi(ctx, AL|L, -((ctx->pc + 4 - obj->value) >> 2)); // BL start - emit_mov(ctx, 1, 0xFFFF0000); // MOV R1, IOBASE - emit_mem(ctx, STW, 0, 1, 0x100); // SW R0, [R1, 0x100] - emit_bi(ctx, AL, -1); // B . + emit_mov(14, 0x100000); // MOV SP, RAMTOP + emit_bi(AL|L, -((ctx.pc + 4 - obj->value) >> 2)); // BL start + emit_mov(1, 0xFFFF0000); // MOV R1, IOBASE + emit_mem(STW, 0, 1, 0x100); // SW R0, [R1, 0x100] + emit_bi(AL, -1); // B . return; } - error(ctx, "no 'start' function\n"); + error("no 'start' function\n"); } -void gen_write(Ctx ctx, const char* outname) { +void gen_write(const char* outname) { int fd = open(outname, O_CREAT | O_TRUNC | O_WRONLY, 0644); if (fd < 0) { - error(ctx, "cannot open '%s' to write", outname); + error("cannot open '%s' to write", outname); } u32 n = 0; - while (n < ctx->pc) { - if (write(fd, ctx->code + (n/4), sizeof(u32)) != sizeof(u32)) { - error(ctx, "error writing '%s'", outname); + while (n < ctx.pc) { + if (write(fd, ctx.code + (n/4), sizeof(u32)) != sizeof(u32)) { + error("error writing '%s'", outname); } n += 4; } @@ -1774,23 +1777,23 @@ void gen_write(Ctx ctx, const char* outname) { #include "risc5.h" -void gen_listing(Ctx ctx, const char* listfn, const char* srcfn) { +void gen_listing(const char* listfn, const char* srcfn) { FILE* fin = fopen(srcfn, "r"); if (fin == NULL) { - error(ctx, "cannot re-read '%s'\n", srcfn); + error("cannot re-read '%s'\n", srcfn); } FILE* fout = fopen(listfn, "w"); if (fout == NULL) { - error(ctx, "cannot write '%s'\n", listfn); + error("cannot write '%s'\n", listfn); } u32 n = 0; u32 line = 1; char buf[1024]; - while (n < ctx->pc) { - u32 ins = ctx->code[n/4]; - if ((line < ctx->xref[n/4]) && fin) { + while (n < ctx.pc) { + u32 ins = ctx.code[n/4]; + if ((line < ctx.xref[n/4]) && fin) { fprintf(fout, "\n"); - while (line < ctx->xref[n/4]) { + while (line < ctx.xref[n/4]) { if (fgets(buf, sizeof(buf), fin) == nil) { fin = nil; break; @@ -1824,21 +1827,20 @@ int main(int argc, char **argv) { const char *lstname = nil; const char *srcname = nil; - CtxRec ctx; - init_ctx(&ctx); + init_ctx(); ctx.filename = "<commandline>"; while (argc > 1) { if (!strcmp(argv[1],"-o")) { if (argc < 2) { - error(&ctx, "option -o requires argument"); + error("option -o requires argument"); } outname = argv[2]; argc--; argv++; } else if (!strcmp(argv[1], "-l")) { if (argc < 2) { - error(&ctx, "option -l requires argument"); + error("option -l requires argument"); } lstname = argv[2]; argc--; @@ -1846,10 +1848,10 @@ int main(int argc, char **argv) { } else if (!strcmp(argv[1], "-A")) { ctx.flags |= cfAbortOnError; } else if (argv[1][0] == '-') { - error(&ctx, "unknown option: %s", argv[1]); + error("unknown option: %s", argv[1]); } else { if (srcname != nil) { - error(&ctx, "multiple source files disallowed"); + error("multiple source files disallowed"); } else { srcname = argv[1]; } @@ -1859,28 +1861,28 @@ int main(int argc, char **argv) { } if (srcname == nil) { - error(&ctx, "no file specified"); + error("no file specified"); } ctx.filename = srcname; - load(&ctx, srcname); + load(srcname); ctx.line = ctx.sptr; ctx.linenumber = 1; #if 0 - ctx->flags |= 1; + ctx.flags |= 1; do { - next(&ctx); - print(&ctx); + next(); + print(); } while (ctx.tok != tEOF); printf("\n"); #else - gen_start(&ctx); - parse_program(&ctx); - gen_end(&ctx); - gen_write(&ctx, outname); + gen_start(); + parse_program(); + gen_end(); + gen_write(outname); if (lstname != nil) { - gen_listing(&ctx, lstname, ctx.filename); + gen_listing(lstname, ctx.filename); } #endif