#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"); return nil; } static void openscope(Parser *p) { if (++p->sp >= arrend(p->spstk)) panicf("scope stack overflow"); } /* * 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("scope stack underflow"); forgetall(&p->sp->objs); forgetall(&p->sp->tags); p->sp--; } /* temporary stack helpers */ static Dtor* getdtor(Parser *p) { if (p->dt >= arrend(p->dtstk)) panicf("dtor stack overflow"); return p->dt++; } static void putdtor(Parser *p) { if (p->dt <= p->dtstk) panicf("dtor stack underflow"); *p->dt-- = (Dtor){0}; } static Name* getname(Parser *p) { if (p->nm >= arrend(p->nmstk)) panicf("name stack overflow"); return p->nm++; } static void putname(Parser *p) { if (p->nm <= p->nmstk) panicf("name stack underflow"); *p->nm-- = (Name){0}; } static void declareobj(Parser *p, Decl *d) { Sym *sym; string ident; uint32 kind; struct Decls *link; kind = (d->spec & Mtype) ? Stype : Svar; switch (d->kind) { case Dfunc: case Dobj: ident = d->name; break; case Dobjs: while (link = &d->objs, link != nil) { ident = link->name; sym = lookup(&p->sp->objs, ident); if (sym) { errorat(peek(p, 0).pos, "redeclaration of name '%s' in object space", ident); return; } sym = define(&p->sp->objs, ident, kind); sym->obj = d; } break; default: panicf("unrecognized node kind %d inside declaration", d->kind); } sym = lookup(&p->sp->objs, ident); if (sym) { errorat(peek(p, 0).pos, "redeclaration of name '%s' in object space", ident); return; } sym = define(&p->sp->objs, ident, kind); sym->obj = d; } /* enters the object identifier space */ static void declareenum(Parser *p, int n, string *elts, Expr *vals) { int i; Sym *s; for (i = 0; i < n; i++) { s = lookup(&p->sp->objs, elts[i]); if (s) { errorat(peek(p, 0).pos, "redeclaration of name %s in object space", elts[i]); continue; } s = define(&p->sp->objs, elts[i], Senum); s->val = vals + i; } } static void declaretag(Parser *p, Type *t, string name) { Sym *sym; sym = lookup(&p->sp->tags, name); if (sym) { errorat(peek(p, 0).pos, "redeclaration of name '%s' in tag space", name); return; } sym = define(&p->sp->tags, name, Stype); sym->typ = t; } 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 *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; } // ----------------------------------------------------------------------- // types Type * ptrtype(Type *base, uint32 qual) { Type *t; t = type(); t->kind = Tptr; t->ptr.base = base; t->ptr.qual = qual; t->size = pointer.size; t->align = pointer.align; t->sign = pointer.sign; return t; } Type* arraytype(Type *base, uint32 qual, Expr *ix) { int n; Type *t; /* TODO: evaluate the length */ n = 10; t = type(); t->kind = Tarray; t->ptr.base = base; t->size = n * base->size; t->align = base->align; t->sign = 0; return t; } Type* functype(Type *ret, int n, Field *args, int dots) { int i; Type *t; t = type(); t->kind = Tfunc; t->size = pointer.size; t->align = pointer.align; t->sign = pointer.sign; t->func.ret = ret; t->func.n = n; t->func.arg = args; t->func.dots = dots; return t; } #define ALIGN_DOWN(n, a) ((n) & ~((a)-1)) #define ALIGN_UP(n, a) ALIGN_DOWN((n) + (a)-1, (a)) Type * structtype(int n, Field *field, Expr *bits) { Type *t; Field *f, *e; t = type(); t->kind = Tstruct; t->size = 0; t->align = 0; for (f = field, e = field+n; f != e; ++f) { t->size += f->type->size + ALIGN_UP(t->size, f->type->align); t->align = MAX(t->align, f->type->align); } t->aggr.len = n; t->aggr.f = field; t->aggr.x = bits; return t; } Type * uniontype(int n, Field *field, Expr *bits) { Type *t; Field *f, *e; t = type(); t->kind = Tstruct; t->size = 0; t->align = 0; for (f = field, e = field+n; f != e; ++f) { t->size = MAX(t->size, f->type->size); t->align = MAX(t->align, f->type->align); } t->aggr.len = n; t->aggr.f = field; t->aggr.x = bits; return t; } Type * enumtype(int n, string *elts, Expr *vals) { Type *t; Field *f, *e; t = type(); t->kind = Tenum; /* TODO: dont hardcode int32 */ t->size = 4; t->align = 4; t->enm.len = n; t->enm.elt = elts; t->enm.val = vals; return t; } #undef ALIGN_UP #undef ALIGN_DOWN /* unpacking C declarations into sensible types */ static Type * typeofname(Name *name, Type *base) { switch (name->kind) { case Nident: return base; case Nparen: return typeofdtor(name->paren, base); case Nindex: return typeofname(name->sfx.name, arraytype(base, name->sfx.idx.q, name->sfx.idx.x)); case Ncall: return typeofname(name->sfx.name, functype(base, name->sfx.call.n, name->sfx.call.arg, name->sfx.call.dots)); default: panicf("unreachable"); } return nil; } static Type * typeofdtor(Dtor *decl, Type* base) { int n; Ptr *p; uint64 b, tmp; n = 0; p = &decl->ptr; b = p->kind; while (b & 1) { base = ptrtype(base, b >> 1); if (++n >= 8) { p = p->link; b = p->kind; } else { b >>= 6; } } return typeofname(decl->name, base); } static Type* basetype(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; } static string namedecl(Parser *p, Lexer *lx, Type **base) { Dtor *dt; string name; Type *t; dt = getdtor(p); name = nil; if (dtor(p, lx, dt, 0)) { errorat(lx->pos, "invalid declarator"); goto End; } name = nameof(dt->name); *base = typeofdtor(dt, *base); End: putdtor(p); return nil; } // ----------------------------------------------------------------------- // declarations static Type * enumerate(Parser *p, Lexer *lx, string name) { int i, n; uint64 s; Token tk; Type *t; /* TODO: think of a better soln */ string nm[1024], *elts; Expr *cx[1024], *vals; for (n = 0; tk.kind != Arbrace && n < arrlen(nm); n++) { if (tk.kind != Aident) { errorat(tk.pos, "invalid token %s in enum declaration", tokens[tk.kind]); goto Bad; } nm[n] = tk.val.s; cx[n] = nil; tk = advance(p, lx); switch(tk.kind) { case Aeq: advance(p, lx); cx[n] = expr(p, lx); tk = peek(p, 0); if (tk.kind != Acomma) continue; /* fallthrough */ case Acomma: tk = advance(p, lx); } } copyarray(elts, nm, n); copyarray(vals, cx, n); t = enumtype(n, elts, vals); declareenum(p, n, elts, vals); return t; Bad: errorat(tk.pos, "failed to parse enum declaration"); return nil; } static Type * aggregate(Parser *p, Lexer *lx, string name, int kind) { int n; uint64 s; Token tk; /* TODO: think of a better soln */ Field fs[1024], *f; Expr *cx[1024], *x; for (n = 0; tk.kind != Arbrace && n < arrlen(fs); n++) { fs[n].type = basetype(p, lx, &s); fs[n].qual = (uint32)s; Field: fs[n].name = namedecl(p, lx, &fs[n].type); 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; } } copyarray(f, fs, n); copyarray(x, cx, n); return structtype(n, f, x); 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, "aggregate 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 = aggregate(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; } } if (name) declaretag(p, tag, name); break; case Kenum: if (s & Tenum) { errorat(lx->pos, "more than one enum type specifier found"); goto Bad; } s += Bit(n); t = advance(p, lx); if (t.kind != Aident && t.kind != Albrace) { errorat(t.pos, "enum 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 = enumerate(p, lx, name); if (nomatch(t, Arbrace)) { errorat(t.pos, "invalid token %s in enum declaration", tokens[t.kind]); goto Bad; } } if (name) declaretag(p, tag, name); break; 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; } /* name declaration */ static error name(Parser *p, Lexer *lx, Name **nmp, int ab) { Token t; int n, k; uint64 s; Sym *sym; Name *nm, *tmp; /* max args = 100 */ struct Field 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("ident stack overflow"); args[nm->sfx.call.n++] = (struct Field) { .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"); args[nm->sfx.call.n].type = basetype(p, lx, &s); if (!args[nm->sfx.call.n].type) { errorat(lx->pos, "could not parse base type in function call"); goto Bad; } args[nm->sfx.call.n].qual = (uint32)s; args[nm->sfx.call.n].name = namedecl(p, lx, &args[nm->sfx.call.n].type); nm->sfx.call.n++; } 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; Type *base, *type; string name; struct Decls *ds; alloc(d); d->kind = 0; d->pos.beg = lx->pos; base = basetype(p, lx, &s); if (!base) { errorat(lx->pos, "could not parse type declaration"); goto Bad; } x = nil; d->spec = (uint32)s; d->type = base; d->name = namedecl(p, lx, &d->type); switch (t = peek(p, 0), t.kind) { case Aeq: t = advance(p, lx); x = expr(p, lx); if (t.kind != Acomma) { d->kind = Dobj; d->init = x; break; } /* fallthrough */ case Acomma: d->kind = Dobjs; d->objs.init = x; /* move singleton data over */ name = d->name; type = d->type; d->objs.name = name; d->objs.type = type; ds = &d->objs; /* iterate until we hit end of list */ while (t.kind == Acomma) { t = advance(p, lx); alloc(ds->link); ds = ds->link; ds->type = base; ds->name = namedecl(p, lx, &ds->type); t = peek(p, 0); if (t.kind == Aeq) { t = advance(p, lx); ds->init = expr(p, lx); } else ds->init = nil; } 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); return d; Bad: 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; }