#include "cc.h" // ----------------------------------------------------------------------- // helper macros #define alloc(ptr) (ptr) = mem·arenaalloc(C.heap, 1, sizeof *(ptr)) #define copyarray(dst, arr, n) (dst) = mem·arenaalloc(C.heap, (n), sizeof *(arr)), memcpy((dst), (arr), n * sizeof *(arr)) #define movearray(dst, arr, n) copyarray(dst,arr,n), free(arr) #define attop(prs) ((uintptr)prs->sp == (uintptr)prs->spstk) #define peek(p, i) (p->tok[i]) #define iskw(t, k) (((t).kind == Akeywd) && (t).val.i == (k)) #define advance(p, l) (p->tok[0] = p->tok[1], p->tok[1] = lex(l), p->tok[0]) #define Bit(i) (1 << (i)) // ----------------------------------------------------------------------- // helper functions static string nameof(Name *n) { switch (n->kind) { case Nident: return n->ident; case Nparen: return nameof(n->paren->name); case Nindex: case Ncall: return nameof(n->sfx.name); } panicf("unreachable"); } static void openscope(Parser *p) { if (++p->sp == p->spstk + arrlen(p->spstk)) panicf("too many nested scopes: crashing"); } /* * TODO: save the symbol table with the ast node * write a "copy(move)scope" */ static void closescope(Parser *p) { if (p->sp == p->spstk) panicf("attempting to close the top level scope: crashing"); forgetall(&p->sp->objs); forgetall(&p->sp->tags); p->sp--; } static Dtor* getdtor(Parser *p) { if (p->dt >= p->dtstk + arrlen(p->dtstk)) { panicf("out of dtor buffer space"); } return p->dt++; } static void putdtor(Parser *p) { if (p->dt == p->dtstk) { panicf("too many frees of dtor buffer space"); } *p->dt-- = (Dtor){0}; } static Name* getname(Parser *p) { if (p->nm >= p->nmstk + arrlen(p->nmstk)) { panicf("out of dtor buffer space"); } return p->nm++; } static void putname(Parser *p) { if (p->nm == p->nmstk) { panicf("too many frees of dtor buffer space"); } *p->nm-- = (Name){0}; } #if 0 static void declareobj(Parser *p, Decl *d) { Sym *sym; string ident; struct Decls *link; switch (d->kind) { case Dfunc: ident = nameof(&d->func.name); break; case Dvar: ident = nameof(&d->var.name); break; case Dtype: ident = nameof(&d->type.name); break; case Dvars: while (link = d->var.link, link != nil) { ident = nameof(&link->name); sym = lookup(&p->sp->objs, ident); if (sym) { errorat(peek(p, 0).pos, "redeclaration of name '%s' in object space", ident); return; } define(&p->sp->objs, ident, Sobj); } return; default: panicf("unrecognized node kind %d inside declaraction", d->kind); } sym = lookup(&p->sp->objs, ident); if (sym) { errorat(peek(p, 0).pos, "redeclaration of name '%s' in object space", ident); return; } define(&p->sp->objs, ident, Sobj); } static Sym * declaretag(Parser *p, Type *t) { Sym *sym; sym = lookup(&p->sp->tags, t->ident); if (sym) { errorat(peek(p, 0).pos, "redeclaration of name '%s' in tag space", t->ident); return sym; } return define(&p->sp->tags, t->ident, Stype); } #endif static Sym * lookupobj(Parser *p, string ident) { Sym *sym; Scope *it; it = p->sp; do { sym = lookup(&it->objs, ident); } while (sym == nil && --it >= p->spstk); return sym; } static Sym * lookuptag(Parser *p, string ident) { Sym *sym; Scope *it; it = p->sp; do { sym = lookup(&it->tags, ident); } while (sym == nil && --it >= p->spstk); return sym; } static int nomatch(Token t, vlong kind) { if (t.kind == kind) return 0; errorat(t.pos, "expected token '%s', instead found '%s'", tokens[t.kind], tokens[kind]); return 1; } // ----------------------------------------------------------------------- // needed forward declarations static error spec(Parser *, Lexer *, uint64 *); static error dtor(Parser *p, Lexer *lx, Dtor *d, int ab); static Type *typeofspec(Parser *, Lexer *, uint64 *); static Type *typeofdtor(Dtor *, Type *); static Decl *decl(Parser *, Lexer *); static Expr *expr(Parser *, Lexer *); static error blkstmt(Parser *, Lexer *, Stmt **); #define MAKEX(x, state) alloc((x)), (x)->kind = X##state // ----------------------------------------------------------------------- // expressions static Expr* primary(Parser *p, Lexer *lx) { int k; Expr *x; Token t; Pos b; t = peek(p, 0); b = t.pos; switch (k = (t.kind & Vmask)) { case Aident: MAKEX(x, ident); x->pos.beg = b; x->pos.end = lx->pos; return x; case Alit: MAKEX(x, lit); x->pos.beg = b; x->pos.end = lx->pos; x->val.kind = t.kind & ~Vmask; return x; case Alparen: advance(p, lx); x = expr(p, lx); t = peek(p, 0); if (nomatch(t, Arparen)) { errorat(lx->pos, "unterminated paren expression"); goto Bad; } advance(p, lx); return x; default: ; } panicf("unreachable"); Bad: errorat(lx->pos, "unable to parse operand expression"); return nil; } static Expr* postfix(Parser *p, Lexer *lx) { Pos b; Token t; int c, n; Expr *x, *y, **a; struct Key *k; x = primary(p, lx); for (;;) { b = x->pos.beg; switch (t.kind) { case Ainc: MAKEX(y, postinc); goto Postfix; case Adec: MAKEX(y, postdec); Postfix: y->pos.beg = b; y->pos.end = lx->pos; y->unary.post = x; x = y, y = nil; break; case Adot: MAKEX(y, self); goto Select; case Aarrow: MAKEX(y, selp); Select: t = advance(p, lx); if (t.kind != Aident) { errorat(t.pos, "invalid operand of selector expression"); goto Bad; } y->pos.beg = b; y->pos.end = lx->pos; y->idx.f = t.val.s; y->idx.x = x; x = y, y = nil; break; case Albrakt: t = advance(p, lx); if (t.kind == Arbrakt) { errorat(t.pos, "empty index expression"); goto Bad; } MAKEX(y, index); y->idx.x = x; y->idx.i = expr(p, lx); t = peek(p, 0); if (t.kind != Albrakt) { errorat(t.pos, "malformed index expression"); goto Bad; } x = y, y = nil; break; case Alparen: t = advance(p, lx); MAKEX(y, call); y->call.fn = x; y->pos.beg = b; y->call.n = 0; if (t.kind == Arparen) { y->call.arg = nil; goto Endfunc; } c = 0; a = nil; Arg: if (y->call.n >= c) { c += 20; a = realloc(a, c * sizeof(*a)); } a[y->call.n++] = expr(p, lx); t = peek(p, 0); if (t.kind == Acomma) { advance(p, lx); goto Arg; } if (t.kind != Arparen) { errorat(t.pos, "invalid token '%s' found in call argument"); goto Bad; } movearray(y->call.arg, a, y->call.n); Endfunc: advance(p, lx); y->pos.end = lx->pos; x = y, y = nil; break; case Albrace: t = advance(p, lx); MAKEX(y, cmpdlit); y->pos.beg = b; y->cmpd.n = 0; if (t.kind == Arbrace) { x->cmpd.key = nil; x->cmpd.val = nil; goto EndCmpd; } c = 0, n = 0; a = nil, k = nil; Key0: if (n >= c) { c += 20; k = realloc(k, c * sizeof(*k)); a = realloc(a, c * sizeof(*a)); } Key1: switch (t.kind) { case Adot: t = advance(p, lx); if (t.kind != Aident) { errorat(t.pos, "dot designator must be followed by identifier"); goto Bad; } k[n++] = (struct Key) { .kind = (uint32)x->cmpd.n, .s = t.val.s, }; t = advance(p, lx); goto Key0; case Albrakt: t = advance(p, lx); k[n++] = (struct Key) { .kind = (uint32)x->cmpd.n | (1ULL << 32), .x = expr(p, lx), }; t = peek(p, 0); goto Key0; case Aeq: t = advance(p, lx); if (t.kind == Albrakt) a[x->cmpd.n++] = postfix(p, lx); else a[x->cmpd.n++] = expr(p, lx); t = peek(p, 0); switch (t.kind) { case Arbrakt: break; case Acomma: advance(p, lx); default: goto Key0; } break; default: errorat(t.pos, "unrecognized token '%s' in compound literal", tokens[t.kind]); goto Bad; } movearray(x->cmpd.key, k, n); movearray(x->cmpd.val, a, x->cmpd.n); EndCmpd: break; default: ; } t = advance(p, lx); } return x; Bad: errorat(lx->pos, "failed to parse primary expression"); return nil; } #if 0 static Type* type(Parser *p, Lexer *lx) { uint64 sp; Dtor *dt; dt = getdtor(p); if (spec(p, lx, &sp)) { errorat(lx->pos, "invalid type specification"); goto Bad; } if (sp & MaskMem) { errorat(lx->pos, "invalid type specifier"); goto Bad; } if (dtor(p, lx, dt, 1)) { errorat(lx->pos, "invalid declarator"); goto Bad; } if (nameof(dt->name) != nil) { errorat(lx->pos, "abstract declarator can not have an identifier"); goto Bad; } Bad: errorat(lx->pos, "failed to parse type expression"); return nil; } #endif static Expr* unary(Parser *p, Lexer *lx) { Expr *x; Token t; t = peek(p, 0); switch (t.kind) { case Aneg: MAKEX(x, neg); goto Prefix; case Aand: MAKEX(x, ref); goto Prefix; case Anot: MAKEX(x, not); goto Prefix; case Astar: MAKEX(x, star); goto Prefix; case Aadd: MAKEX(x, plus); goto Prefix; case Asub: MAKEX(x, minus); goto Prefix; case Ainc: MAKEX(x, preinc); goto Prefix; case Adec: MAKEX(x, predec); goto Prefix; Prefix: x->pos.beg = t.pos; x->unary.pre = unary(p, lx); x->pos.end = x->unary.pre->pos.end; return x; case Alparen: advance(p, lx); MAKEX(x, cast); x->pos.beg = t.pos; x->cast.to = type(p, lx); if (!x->cast.to) { errorat(lx->pos, "invalid type operand of cast"); goto Bad; } t = peek(p, 0); if (nomatch(t, Arparen)) { errorat(lx->pos, "missing closing paren after cast expression"); goto Bad; } advance(p, lx); x->cast.x = unary(p, lx); x->pos.beg = lx->pos; return x; case Akeywd: switch (t.val.i) { case Ksizeof: MAKEX(x, sizeof); goto Key; case Kalignof: MAKEX(x, alignof); goto Key; Key: advance(p, lx); x->unary.post = unary(p, lx); default: ; } default: return postfix(p, lx); } Bad: return nil; } /* static data for binary operators */ #define OPERATORS \ OPERATOR(Astar, 10, Xmul) \ OPERATOR(Adiv, 10, Xdiv) \ OPERATOR(Amod, 10, Xmod) \ OPERATOR(Aadd, 9, Xadd) \ OPERATOR(Asub, 9, Xsub) \ OPERATOR(Alsft, 8, Xlsft) \ OPERATOR(Arsft, 8, Xrsft) \ OPERATOR(Agteq, 7, Xgteq) \ OPERATOR(Alteq, 7, Xlteq) \ OPERATOR(Alt, 7, Xlt) \ OPERATOR(Agt, 7, Xgt) \ OPERATOR(Aeq, 6, Xeql) \ OPERATOR(Aneq, 6, Xneq) \ OPERATOR(Aand, 5, Xand) \ OPERATOR(Axor, 4, Xxor) \ OPERATOR(Aor, 3, Xor) \ OPERATOR(Aandand, 2, Xandand) \ OPERATOR(Aoror, 1, Xoror) static int prectab[NUM_TOKENS] = { #define OPERATOR(a, b, c) [a] = b, OPERATORS #undef OPERATOR }; static int optab[NUM_TOKENS] = { #define OPERATOR(a, b, c) [a] = c, OPERATORS #undef OPERATOR }; #undef OPERATORS static Expr* binary(Parser *p, Lexer *lx, int prec) { Token t; int k, np; Expr *l, *r, *x; l = unary(p, lx); for (;;) { t = peek(p, 0); k = t.kind; np = prectab[t.kind]; if (np < prec) return x; alloc(x); x->pos.beg = l->pos.beg; x->kind = optab[k]; x->binary.l = l; x->binary.r = r = binary(p, lx, np + 1); x->pos.end = r->pos.end; l = x; } return l; Bad: errorat(t.pos, "failed to parse expression"); return nil; } static Expr* ternary(Parser *p, Lexer *lx) { Pos b; Token t; Expr *x, *y; x = binary(p, lx, 1); t = peek(p, 0); b = t.pos; switch (t.kind) { case Aqmark: t = advance(p, lx); y = x; MAKEX(x, ternary); x->pos.beg = b; x->kind = Xternary; x->cond.c = y; x->cond.t = expr(p, lx); if (nomatch(t, Acolon)) { errorat(t.pos, "ternary expression missing ':'"); goto Bad; } t = advance(p, lx); x->cond.e = expr(p, lx); x->pos.end = lx->pos; break; case Aasn: MAKEX(y, asn); goto Assign; case Aorasn: MAKEX(y, orasn); goto Assign; case Axorasn: MAKEX(y, xorasn); goto Assign; case Aandasn: MAKEX(y, andasn); goto Assign; case Asubasn: MAKEX(y, subasn); goto Assign; case Amulasn: MAKEX(y, mulasn); goto Assign; case Adivasn: MAKEX(y, divasn); goto Assign; case Amodasn: MAKEX(y, modasn); goto Assign; case Alsftasn: MAKEX(y, lsftasn); goto Assign; case Arsftasn: MAKEX(y, rsftasn); goto Assign; Assign: y->asn.l = x; y->asn.r = ternary(p, lx); x = y; x->pos.beg = b; x->pos.end = lx->pos; break; default: ; } return x; Bad: errorat(lx->pos, "failing expression parse"); return nil; } static Expr* expr(Parser *p, Lexer *lx) { Pos b; Token t; Expr *x, *y; x = ternary(p, lx); while (t = peek(p, 0), t.kind == Acomma) { advance(p, lx); y = x; MAKEX(x, comma); x->pos.beg = y->pos.beg; x->comma.x[0] = y; x->comma.x[1] = ternary(p, lx); x->pos.end = lx->pos; y = nil; } return x; } // ----------------------------------------------------------------------- // statements static struct Node* stmt(Parser *p, Lexer *lx) { int k; Stmt *s; Sym *sym; Token t; t = peek(p, 0); k = t.kind; /* intercept decl before allocating a statement */ if (k == Aident) { if (peek(p, 1).kind == Acolon) goto Tlabel; sym = lookupobj(p, t.val.s); if (!sym) { errorat(lx->pos, "unrecognized type identifier '%s'", t.val.s); goto Bad; } if (sym->kind == Stype) goto Tdecl; if (sym->kind == Sobj) goto Texpr; errorat(lx->pos, "bad symbol type used as type identifier"); goto Bad; } if (k == Akeywd) { if ((Kauto <= k && k <= Katomic) || (Ksigned <= k && k <= Klong)) { Tdecl: return (Node *)decl(p, lx); } } alloc(s); s->pos.beg = lx->pos; switch (k) { case Akeywd: switch (k = t.val.i) { case Kif: t = advance(p, lx); s->kind = Sif; if (nomatch(t, Alparen)) { errorat(lx->pos, "missing opening paren before if conditional"); goto Bad; } s->br.cond = expr(p, lx); if (nomatch(t, Arparen)) { errorat(lx->pos, "missing closing paren after if conditional"); goto Bad; } s->br.body = stmt(p, lx); t = peek(p, 0); if (iskw(t, Kelse)) s->br.orelse = stmt(p, lx); else s->br.orelse = nil; break; case Kswitch: t = advance(p, lx); s->kind = Sswitch; if (nomatch(t, Alparen)) { errorat(lx->pos, "missing opening paren before switch conditional"); goto Bad; } s->br.cond = expr(p, lx); if (nomatch(t, Arparen)) { errorat(lx->pos, "missing closing paren after switch conditional"); goto Bad; } s->br.body = stmt(p, lx); s->br.orelse = nil; break; case Kfor: t = advance(p, lx); s->kind = Sfor; if (nomatch(t, Alparen)) { errorat(lx->pos, "missing opening paren before for loop preamble"); goto Bad; } if (t.kind == Asemi) s->loop.init = nil; else { // TODO: test for declaration s->loop.init = (Node *)expr(p, lx); } if (nomatch(t, Asemi)) { errorat(lx->pos, "missing semicolon"); goto Bad; } if (t.kind == Asemi) s->loop.cond = nil; else s->loop.cond = expr(p, lx); if (nomatch(t, Asemi)) { errorat(lx->pos, "missing semicolon"); goto Bad; } if (t.kind == Asemi) s->loop.step = nil; else s->loop.step = expr(p, lx); if (nomatch(t, Alparen)) { errorat(lx->pos, "missing closing paren after for loop preamble"); goto Bad; } s->loop.body = stmt(p, lx); break; case Kwhile: t = advance(p, lx); s->kind = Swhile; if (nomatch(t, Alparen)) { errorat(lx->pos, "missing opening paren before while loop conditional"); goto Bad; } s->loop.cond = expr(p, lx); if (nomatch(t, Arparen)) { errorat(t.pos, "missing closing paren after while loop conditional"); goto Bad; } s->loop.init = nil; s->loop.step = nil; s->loop.body = stmt(p, lx); break; case Kdo: t = advance(p, lx); s->kind = Sdo; s->loop.body = stmt(p, lx); if (!iskw(t, Kwhile)) { errorat(t.pos, "missing while statement conditional after do body"); goto Bad; } t = advance(p, lx); if (nomatch(t, Alparen)) { errorat(t.pos, "missing open paren after while conditional"); goto Bad; } s->loop.init = nil; s->loop.step = nil; s->loop.cond = expr(p, lx); break; case Kgoto: t = advance(p, lx); s->kind = Sgoto; if (t.kind != Aident) { errorat(t.pos, "invalid argument to goto"); goto Bad; } s->jmp.lbl = t.val.s; t = advance(p, lx); if (nomatch(t, Asemi)) { errorat(t.pos, "missing semicolon after goto"); goto Bad; } advance(p, lx); break; case Kcontinue: t = advance(p, lx); s->kind = Scontin; s->jmp.lbl = nil; s->jmp.x = nil; if (nomatch(t, Asemi)) { errorat(t.pos, "missing semicolon after continue"); goto Bad; } advance(p, lx); break; case Kbreak: t = advance(p, lx); s->kind = Sbreak; s->jmp.lbl = nil; s->jmp.x = nil; if (nomatch(t, Asemi)) { errorat(t.pos, "missing semicolon after break"); goto Bad; } advance(p, lx); break; case Kreturn: t = advance(p, lx); s->kind = Sreturn; s->jmp.lbl = nil; s->jmp.x = (t.kind == Asemi) ? nil : expr(p, lx); t = peek(p, 0); if (nomatch(t, Asemi)) { errorat(t.pos, "missing semicolon after return statement"); goto Bad; } break; case Kcase: t = advance(p, lx); s->kind = Scase; s->lbl.x = expr(p, lx); if (nomatch(t, Acolon)) { errorat(t.pos, "missing colon after default label"); goto Bad; } t = advance(p, lx); s->lbl.stmt = stmt(p, lx); break; case Kdefault: t = advance(p, lx); s->kind = Scase; s->lbl.x = nil; if (nomatch(t, Acolon)) { errorat(t.pos, "missing colon after default label"); goto Bad; } t = advance(p, lx); s->lbl.stmt = stmt(p, lx); break; default: panicf("unexpected statement keyword %s", keywords[k]); } break; case Albrace: s->kind = Sblock; openscope(p); if (blkstmt(p, lx, &s)) { errorat(lx->pos, "failed to parse block statement"); goto Bad; } closescope(p); break; case Asemi: t = advance(p, lx); s->kind = Sempty; break; case Aident: Tlabel: t = advance(p, lx); s->kind = Slabel; if (nomatch(t, Acolon)) { errorat(t.pos, "missing colon after labelled block"); goto Bad; } t = advance(p, lx); s->lbl.stmt = stmt(p, lx); break; default: Texpr: t = advance(p, lx); s->kind = Sexpr; s->x = expr(p, lx); } s->pos.end = lx->pos; return (Node *)s; Bad: errorat(lx->pos, "failed to parse statement"); return nil; } static error blkstmt(Parser *p, Lexer *lx, Stmt **s) { Token t; int len; int cap; Node **ns; alloc(*s); (*s)->kind = Sblock; (*s)->pos.beg = lx->pos; t = peek(p, 0); if (nomatch(t, Albrakt)) goto Bad; t = advance(p, lx); len = 0, cap = 20; ns = malloc(cap*sizeof(*ns)); while (t.kind != Arbrakt) { if (cap == len) { cap += 20; ns = realloc(ns, cap*sizeof(*ns)); } ns[len++] = stmt(p, lx); t = peek(p, 0); } (*s)->pos.end = lx->pos; (*s)->blk.n = len; movearray((*s)->blk.item, ns, len); return 0; Bad: errorat(lx->pos, "failed to parse block statement"); free(ns); return 1; } // ----------------------------------------------------------------------- // declarations static Type * typeofname(Name *name, Type *type) { switch (name->kind) { case Nident: return type; case Nparen: return typeofdtor(name->paren, type); case Nindex: return typeofname(name->sfx.name, array(type, name->sfx.idx.q, name->sfx.idx.x)); case Ncall: return typeofname(name->sfx.name, func(type, name->sfx.call.n, name->sfx.call.arg, name->sfx.call.dots)); default: panicf("unreachable"); } } static Type * typeofdtor(Dtor *decl, Type* type) { int n; Ptr *p; uint64 b, tmp; n = 0; p = &decl->ptr; b = p->kind; while (b & 1) { type = ptr(type, b >> 1); if (++n >= 8) { p = p->link; b = p->kind; } else { b >>= 6; } } return typeofname(decl->name, type); } static Type * aggr(Parser *p, Lexer *lx, string name, int kind) { int n; uint64 s; Dtor *dt; Token tk; Type *t; Type *fs[1024]; byte *nm[1024]; Expr *cx[1024]; n = -1; for (;tk.kind != Arbrace && n < arrlen(fs); n++) { t = typeofspec(p, lx, &s); Field: dt = getdtor(p); dtor(p, lx, dt, 0); fs[n] = typeofdtor(dt, t); nm[n] = nameof(dt->name); putdtor(p); tk = peek(p, 0); switch (tk.kind) { case Acolon: advance(p, lx); cx[n] = expr(p, lx); tk = peek(p, 0); if (tk.kind == Asemi) { tk = advance(p, lx); continue; } if (tk.kind != Acomma) { errorat(tk.pos, "unrecognized token %s in struct field declaration", tokens[tk.kind]); goto Bad; } /* fallthrough */ case Acomma: advance(p, lx); n++; goto Field; case Asemi: tk = advance(p, lx); continue; default: errorat(tk.pos, "unrecognized token %s in struct field declaration", tokens[tk.kind]); goto Bad; } } Bad: errorat(tk.pos, "failed to parse aggregate declaration"); return nil; } static error spec(Parser *p, Lexer *lx, uint64 *spec) { Token t; int n; Sym *typ; string name; Type *tag; uint64 s, sm; s = 0; while (t = peek(p, 0), t.kind >= Aident) { /* typename */ if (t.kind == Aident) { typ = lookupobj(p, t.val.s); if (!typ || typ->kind != Stype) { errorat(t.pos, "invalid type name '%s' in specifier", t.val.s); goto Bad; } sm = typ->typ - C.type.info; s |= sm << 32; continue; } /* keyword */ switch (n = t.val.i) { case Kauto: case Kregister: case Kstatic: case Kextern: case Ktypedef: if (s & MaskMem) { errorat(lx->pos, "multiple storage class specifiers: second was %s", keywords[n]); goto Bad; } break; case Kconst: case Kvolatile: if (s & Bit(n)) warnat(lx->pos, "duplicate %s specifier found in declaration", keywords[n]); break; case Ksigned: case Kunsigned: if (s & MaskSgn) { if (s & Bit(n)) { warnat(lx->pos, "duplicated storage class specifier: second was %s", keywords[n]); break; } errorat(lx->pos, "multiple storage class specifiers"); goto Bad; } break; case Kshort: if (s & Tshort) { warnat(lx->pos, "duplicated short specifier"); break; } break; case Klong: if ((s >> Klong) & 2) { errorat(lx->pos, "cannot chain three or more long specifiers"); goto Bad; } s += Bit(n); continue; case Kvoid: case Kchar: case Kint: case Kfloat: case Kdouble: if (s & MaskTyp) { errorat(lx->pos, "more than one base type specified"); goto Bad; } s += Bit(n); break; case Kstruct: case Kunion: if (s & (Tstruct | Tunion)) { errorat(lx->pos, "more than one aggregate type specified"); goto Bad; } s += Bit(n); t = advance(p, lx); if (t.kind != Aident && t.kind != Albrace) { errorat(t.pos, "struct specifier missing valid declaration"); goto Bad; } name = nil; tag = nil; if (t.kind == Aident) { name = t.val.s; t = advance(p, lx); } if (t.kind == Albrace) { t = advance(p, lx); tag = aggr(p, lx, name, s & (Tstruct | Tunion)); if (nomatch(t, Arbrace)) { errorat(t.pos, "invalid token %s in struct/union declaration", tokens[t.kind]); goto Bad; } } break; case Kenum: if (s & Tenum) { errorat(lx->pos, "more than one enum type specifier found"); goto Bad; } s += Bit(n); panicf("need to implement"); break; default: errorat(t.pos, "invalid keyword '%s' found in declaration specifier", keywords[n]); } s |= Bit(n); advance(p, lx); } *spec = s; return 0; /* TODO: serialize bitflags to string for nice error message */ errorat(lx->pos, "invalid type specifier: ''"); Bad: errorat(lx->pos, "ignoring specifier"); *spec = Sbad; return 1; } static Type* typeofspec(Parser *p, Lexer *lx, uint64 *s) { int n; uint64 m; if (spec(p, lx, s)) { errorat(lx->pos, "failed to parse type specifier"); return nil; } m = (((*s<<32)>>32) & ~(MaskQul | MaskMem)); for (n = 0; n < arrlen(validtypespec); n++) { if (validtypespec[n] == m) if (indextypespec < 0) { m = *s >> 32; if (!m) { errorat(lx->pos, "not a valid type identifier"); return nil; } return C.type.info + m; } return C.type.info + indextypespec[n]; } errorat(lx->pos, "invalid type specifier"); return nil; } /* name declaration */ static error name(Parser *p, Lexer *lx, Name **nmp, int ab) { Token t; int n, k; uint64 s; Sym *sym; Dtor *dt; Name *nm, *tmp; /* max args = 100 */ struct Obj args[100]; nm = *nmp; t = peek(p, 0); switch (k = t.kind) { case Aident: if (ab) { errorat(t.pos, "identifier not allowed in abstract declarator"); goto Bad; } nm->kind = Nident; nm->ident = t.val.s; break; case Alparen: nm->kind = Nparen; nm->paren = getdtor(p); if (dtor(p, lx, nm->paren, ab)) { putdtor(p); nm->paren = nil; errorat(lx->pos, "invalid declarator in parenthesis"); goto Bad; } t = peek(p, 0); if (t.kind != Arparen) { putdtor(p); nm->paren = nil; errorat(lx->pos, "missing closing paren in declarator"); goto Bad; } break; case Albrakt: if (ab) break; errorat(lx->pos, "missing identifier in non-abstract declarator"); default: errorat(lx->pos, "invalid token '%s' in name declaration", tokens[k]); goto Bad; } t = advance(p, lx); for (;;) { switch (k = t.kind) { case Albrakt: tmp = getname(p); tmp->kind = Nindex; tmp->sfx.name = nm; nm = tmp, tmp = nil; t = advance(p, lx); if (t.kind == Arbrakt) { nm->sfx.idx.q = 0; Iend: nm->sfx.idx.x = nil; t = advance(p, lx); break; } if (t.kind == Astar) { nm->sfx.idx.q = -1; IStar: nm->sfx.idx.x = nil; t = advance(p, lx); if (t.kind != Arbrakt) { errorat(t.pos, "invalid '*' syntax in index expression"); goto Bad; } t = advance(p, lx); break; } if (spec(p, lx, &s)) { errorat(lx->pos, "invalid type qualifier list in index expression"); goto Bad; } nm->sfx.idx.q = (uint32)s; t = peek(p, 0); if (t.kind == Astar) goto IStar; if (t.kind == Arbrakt) goto Iend; nm->sfx.idx.x = expr(p, lx); t = peek(p, 0); if (nomatch(t, Arbrakt)) { errorat(lx->pos, "unterminated index expression"); goto Bad; } t = advance(p, lx); continue; case Alparen: tmp = getname(p); tmp->kind = Ncall; tmp->sfx.name = nm; nm = tmp, tmp = nil; t = advance(p, lx); nm->sfx.call.n = 0; switch (t.kind) { case Arparen: nm->sfx.call.arg = nil; break; case Aident: sym = lookupobj(p, t.val.s); if (!sym || (sym && sym->kind != Stype)) { while (t.kind == Aident) { if (nm->sfx.call.n >= arrlen(args)) panicf("out of ident buffer"); args[nm->sfx.call.n++] = (struct Obj) { .qual = 0, .type = nil, .name = t.val.s, }; t = advance(p, lx); } if (nomatch(t, Arparen)) { errorat(t.pos, "token '%s' found in function parameter identifier list"); goto Bad; } copyarray(nm->sfx.call.arg, args, nm->sfx.call.n); break; } goto Params; case Akeywd: if (t.val.i < Kconst || t.val.i > Kenum) { errorat(t.pos, "invalid keyword %s inside function signature"); goto Bad; } Params: do { if (nm->sfx.call.n >= arrlen(args)-1) panicf("out of argument buffer"); if (spec(p, lx, &s)) { errorat(lx->pos, "invalid type qualifier list in function signature"); goto Bad; } dt = getdtor(p); if (dtor(p, lx, dt, 0)) { errorat(lx->pos, "could not parse declarator of function argument"); putdtor(p); goto Bad; } pack(s, dt, &args[nm->sfx.call.n++]); putdtor(p); } while (t = peek(p, 0), t.kind == Acomma); if (t.kind == Aellip) { nm->sfx.call.dots = 1; t = advance(p, lx); } if (nomatch(t, Arparen)) { errorat(t.pos, "token '%s' found in function parameter list"); goto Bad; } copyarray(nm->sfx.call.arg, args, nm->sfx.call.n); break; default: errorat(t.pos, "invalid token %s inside function call signature", tokens[t.kind]); goto Bad; } t = advance(p, lx); continue; default: break; } break; } *nmp = nm; return 0; Bad: return 1; } /* pointer kind is partitioned into 8x6 regions */ static error dtor(Parser *p, Lexer *lx, Dtor *d, int ab) { int n, k; error err; Token t; Dtor *link; Ptr *ptr, *x; err = 1; ptr = &d->ptr; ptr->kind = 0; ptr->link = nil; t = peek(p, 0); if (t.kind != Astar) if (t.kind == Aident || t.kind == Arparen) goto Name; goto Bad; Ptr: ptr->kind |= Bit(n); advance(p, lx); Key: t = peek(p, 0); switch (k = t.kind) { case Akeywd: if (Kconst <= k && k <= Katomic) ptr->kind |= Bit(6*n + (t.val.i - Kconst + 1)); else { errorat(lx->pos, "invalid keyword '%s' modifies pointer", keywords[t.val.i]); goto Bad; } advance(p, lx); goto Key; case Astar: if (++n >= 8) { alloc(x); x->kind = 0; x->link = nil; ptr->link = x; ptr = x; n = 0; } goto Ptr; case Aident: case Alparen: goto Name; default: errorat(lx->pos, "invalid token '%s' modifies pointer specification", tokens[t.kind]); goto Bad; } Name: return name(p, lx, &d->name, ab); Bad: return err; } static Decl * decl(Parser *p, Lexer *lx) { uint64 s; Token t; Decl *d; Expr *x; Dtor *dt, *dt0; struct Decls *ds; alloc(d); d->kind = 0; d->pos.beg = lx->pos; if (spec(p, lx, &s)) { errorat(lx->pos, "invalid declaration specifier"); goto Bad; } dt = getdtor(p); dt0 = dt; if (dtor(p, lx, dt, 0)) { errorat(lx->pos, "invalid declarator"); goto Bad; } x = nil; ds = &d->vars; d->spec = (uint32)s; switch (t = peek(p, 0), t.kind) { case Aeq: t = advance(p, lx); x = expr(p, lx); if (t.kind != Acomma) { d->kind = Dvar; d->init = x; break; } /* fallthrough */ case Acomma: d->kind = Dvars; d->vars.init = x; while (t.kind == Acomma) { alloc(ds->link); ds = ds->link; t = advance(p, lx); dt = getdtor(p); if (dtor(p, lx, dt, 0)) { errorat(lx->pos, "invalid declarator"); goto Bad; } t = peek(p, 0); if (t.kind == Aeq) { t = advance(p, lx); ds->init = expr(p, lx); } } break; case Albrace: d->kind = Dfunc; alloc(d->body); if (!attop(p)) { errorat(lx->pos, "nested function declarations"); goto Bad; } if (d->kind != 0) { errorat(lx->pos, "attempting to define a function for a variable declaration"); goto Bad; } openscope(p); if (blkstmt(p, lx, &d->body)) { errorat(lx->pos, "failed to parse function body"); goto Bad; } closescope(p); default: ; } d->pos.end = lx->pos; // declareobj(p, d); while (dt-- >= dt0) putdtor(p); return d; Bad: while (dt-- >= dt0) putdtor(p); errorat(lx->pos, "failed to parse top level declaration"); return nil; } // ----------------------------------------------------------------------- // top level api error parse(Parser *p, Lexer *lx) { Token tok; while ((tok = peek(p, 0)), tok.kind > Aeof) { if (p->ast.len >= p->ast.cap) { p->ast.cap += 20; p->ast.decls = realloc(p->ast.decls, p->ast.cap*sizeof(*p->ast.decls)); } p->ast.decls[p->ast.len++] = decl(p, lx); } return 0; }