diff options
Diffstat (limited to 'bootstrap/parse.c')
| -rw-r--r-- | bootstrap/parse.c | 207 |
1 files changed, 150 insertions, 57 deletions
diff --git a/bootstrap/parse.c b/bootstrap/parse.c index 96a185c..3d609c4 100644 --- a/bootstrap/parse.c +++ b/bootstrap/parse.c @@ -227,6 +227,7 @@ readstrlit(struct parser *P, u8 delim, char *s, size_t n) { #define MAX_MACROEXPAND_ITER 100 +/* // guard used at macro arg expansion to avoid it expanding into itself, e.g.: // defmacro foo(x,y) [(x+y)] // let x, y ...; @@ -240,6 +241,7 @@ ismacrodupe(struct parser *P, struct toktree toks) { } return 0; } +*/ static struct tok lex(struct parser *P) { @@ -269,18 +271,15 @@ lex(struct parser *P) { } tok = ep->toks.d[ep->idx++]; // expand macro arg? - if (tok.t == TKident) { + if (tok.t == TKmacident) { for (struct expan *ep = P->curexpan; ep; ep = ep->prev) { for (int i = 0; i < ep->args.n; ++i) { if (!strcmp(tok.str, ep->args.d[i].name)) { - if (!ismacrodupe(P, ep->args.d[i].toks)) { - ++P->expanno; - P->curexpan = memcpy(xmalloc(sizeof *ep), &(struct expan) { - P->curexpan, {0}, ep->args.d[i].toks, - }, sizeof *ep); - return lex(P); - } else - return tok; + ++P->expanno; + P->curexpan = memcpy(xmalloc(sizeof *ep), &(struct expan) { + P->curexpan, {0}, ep->args.d[i].toks, + }, sizeof *ep); + return lex(P); } } } @@ -314,6 +313,8 @@ lex(struct parser *P) { tok.boolit = s[1] == 't'; } else if (!strcmp(s, "#null")) { tok.t = TKnullit; + } else if (!strcmp(s, "##")) { + tok.t = '##'; } else if (c == '#') { fatal(P, P->tokspan, "identifier cannot start with '#'"); } else if (c == '$') { @@ -333,7 +334,7 @@ lex(struct parser *P) { n = readstrlit(P, delim, s, sizeof s); if (delim == '"') { tok.t = TKstrlit; - tok.str = strcpy(xmalloc(n + 1), s); + tok.str = memcpy(xmalloc(n + 1), s, n + 1); tok.strlen = n; } else { if (n == 0) @@ -651,6 +652,12 @@ typeof2(const struct type *a, const struct type *b) { } if (a == b) return a; + if (unconstify(a) == b) + return a; + if (a == unconstify(b)) + return b; + if (a->t == TYarr && b->t == TYarr) + a = arraydecay(a); if (a->t == TYptr && b->t == TYarr) b = arraydecay(b); if (a->t == TYarr && b->t == TYptr) @@ -707,6 +714,13 @@ exprdup(struct expr ex) { static struct blockstmt parseblock0(struct parser *P); static struct stmt parseblock(struct parser *P); static void parseexpandmacro(struct parser *P, const struct macro *macro); +static const struct type * +mkarraytype(const struct type *child, size_t n) { + return interntype((struct type) { + TYarr, n * child->size, 1, 0, + .child = child, .length = n + }); +} static struct expr pexprimary(struct parser *P) { @@ -728,10 +742,13 @@ pexprimary(struct parser *P) { ex.span = tok.span; ex.strlit.d = tok.str; ex.strlit.n = tok.strlen; - ex.ty = interntype((struct type) { - TYarr, tok.strlen + 1, 1, 0, - .child = constify(ty_u8), .length = tok.strlen + 1 - }); + while (lexmatch(P, &tok, TKstrlit)) { + ex.strlit.d = xrealloc((char *)ex.strlit.d, ex.strlit.n + tok.strlen + 1); + memcpy((char *)ex.strlit.d + ex.strlit.n, tok.str, tok.strlen + 1); + free((char *)tok.str); + ex.strlit.n += tok.strlen; + } + ex.ty = mkarraytype(constify(ty_u8), ex.strlit.n + 1); } else if (lexmatch(P, &tok, TKboolit)) { ex.t = Eboolit; ex.span = tok.span; @@ -759,18 +776,35 @@ pexprimary(struct parser *P) { ex.t = Ename; ex.span = tok.span; ex.ref = decl; - if (decl->t == Dvar) { + if (decl->t == Dlet) { if (decl->var.fnid != P->curfn->id) fatal(P, tok.span, "cannot access local variable `%s' belonging to outer function", tok.str); ex.ty = decl->var.ty; + } else if (decl->t == Dstatic) { + ex.ty = decl->var.ty; } else if (decl->t == Dfn) { ex.ty = decl->fn.selfty; } else assert(0); } } else if (lexmatch(P, &tok, '(')) { - ex = parseexpr(P); + if (lexpeek(P).t == TKkw_do) { + struct blockstmt block; + lex(P); + block = parseblock0(P); + ex.t = Eblock; + ex.block = block; + ex.ty = ty_void; + if (ex.block.stmts.n > 0) { + struct stmt *last = &block.stmts.d[block.stmts.n - 1]; + if (last->t == Sexpr) + ex.ty = last->expr.ty; + + } + } else { + ex = parseexpr(P); + } lexexpect(P, ')'); } else { fatal(P, tok.span, "expected expression (near %s)", tok2str(tok)); @@ -894,7 +928,7 @@ pexprefix(struct parser *P) { struct expr ex = pexprefix(P); if (ex.ty->t != TYptr) fatal(P, ex.span, "invalid operand type to dereference, not pointer"); - if (!completetype(ex.ty->child)) + if (!completetype(ex.ty->child) && ex.ty->child->t != TYfn) fatal(P, ex.span, "invalid operand type to dereference, incomplete"); return (struct expr) { Eprefix, tok.span, ex.ty->child, .unop = { @@ -904,7 +938,7 @@ pexprefix(struct parser *P) { } else if (lexmatch(P, &tok, '&')) { struct expr ex = pexprefix(P); struct type ty2 = { TYptr, g_targ.ptrsize, .child = ex.ty}; - if (!islvalue(&ex)) + if (!islvalue(&ex) && !(ex.t == Ename && ex.ref->t == Dfn)) fatal(P, ex.span, "invalid operand type to address-of, not an lvalue"); return (struct expr) { Eprefix, tok.span, interntype(ty2), .unop = { @@ -927,6 +961,8 @@ peeksbitarithop(struct parser *P, struct tok* tokp) { return 1; case '&': case '|': case '^': case '<<': case '>>': return 2; + case '##': + return 3; } return 0; } @@ -957,7 +993,7 @@ pexbitarith(struct parser *P) { } } else if (tokt == '-' && ex.ty->t == TYptr && rhs.ty->t == TYptr) { ty = ty_isize; - } else if (!isnumtype(ty)) { + } else if (tokt != '##' && !isnumtype(ty)) { err: fatal(P, tok.span, "invalid operands to binary operator %s", tokt2str(tokt)); @@ -965,11 +1001,28 @@ pexbitarith(struct parser *P) { if (oret == 2 && ty->t == TYfloat) fatal(P, tok.span, "invalid operands to bitwise operator: not integral", tokt2str(tokt)); - ex = (struct expr) { - Ebinop, tok.span, ty, .binop = { - tokt, exprdup(ex), exprdup(rhs) - } - }; + if (tokt != '##') { + ex = (struct expr) { + Ebinop, tok.span, ty, .binop = { + tokt, exprdup(ex), exprdup(rhs) + } + }; + } else { + char *s; + size_t n = ex.strlit.n + rhs.strlit.n; + + /// TODO fold + if (ex.t != Estrlit || rhs.t != Estrlit) + fatal(P, tok.span, + "operands to `##' operator are not string literals"); + s = xmalloc(n + 1); + memcpy(s, ex.strlit.d, ex.strlit.n); + memcpy(s + ex.strlit.n, rhs.strlit.d, rhs.strlit.n + 1); + ex = (struct expr) { + Estrlit, tok.span, mkarraytype(constify(ty_u8), n + 1), + .strlit.d = s, .strlit.n = n, + }; + } } @@ -1128,9 +1181,8 @@ stmtdup(struct stmt st) { return memcpy(xmalloc(sizeof st), &st, sizeof st); } -static struct stmt -pstlet(struct parser *P) { - struct stmt st = {0}; +static void +parsevardecl(struct parser *P, struct decl *decl) { struct tok tok; const char *name; const struct type *ty = NULL; @@ -1148,10 +1200,13 @@ pstlet(struct parser *P) { ty = ini->ty; } else { ty = parsetype(P); - lexexpect(P, '='); - ini = exprdup(parseexpr(P)); + if (lexmatch(P, NULL, '=')) { + ini = exprdup(parseexpr(P)); + } else if (decl->t == Dlet) { + fatal(P, tok.span, "variable must be initialized"); + } } - if (!typeof2(ty, ini->ty)) + if (ini && !typeof2(ty, ini->ty)) fatal(P, tok.span, "incompatible initializer type"); if (!completetype(ty)) @@ -1161,15 +1216,18 @@ pstlet(struct parser *P) { ty = constify(ty); assert(ty); - st.t = Sdecl; - st.decl = (struct decl) { - Dvar, name, .var = { - .ty = ty, - .ini = ini, - .fnid = P->curfn->id, - } - }; - putdecl(P, tok.span, &st.decl); + decl->name = name; + decl->var.ty = ty; + decl->var.ini = ini; + decl->var.fnid = P->curfn ? P->curfn->id : -1; +} + +static struct stmt +pstlet(struct parser *P) { + struct stmt st = {Sdecl}; + st.decl.t = Dlet; + parsevardecl(P, &st.decl); + putdecl(P, st.decl.span, &st.decl); return st; } @@ -1296,7 +1354,8 @@ static void parsedecl(struct decl *, struct parser *, bool toplevel); static bool isdecltokt(int tokt) { switch (tokt) - case TKkw_extern: case TKkw_fn: case TKkw_typedef: case TKkw_defmacro: + case TKkw_extern: case TKkw_fn: case TKkw_typedef: + case TKkw_defmacro: case TKkw_static: return 1; return 0; } @@ -1404,39 +1463,49 @@ parsestmt(struct parser *P) { struct stmt st = {0}; struct tok tok; - if (lexmatch(P, NULL, '{')) { - return parseblock(P); - } else if (lexmatch(P, NULL, TKkw_let)) { + if (lexmatch(P, &tok, '{')) { + st.span = tok.span; + st = parseblock(P); + } else if (lexmatch(P, &tok, TKkw_let)) { st = pstlet(P); + st.span = tok.span; lexexpect(P, ';'); - } else if (lexmatch(P, NULL, TKkw_if)) { + } else if (lexmatch(P, &tok, TKkw_if)) { + st.span = tok.span; st = pstifelse(P); - } else if (lexmatch(P, NULL, TKkw_while)) { + } else if (lexmatch(P, &tok, TKkw_while)) { st.t = Swhile; + st.span = tok.span; st.loop.test = parseexpr(P); if (st.loop.test.ty->t != TYbool && st.loop.test.ty->t != TYptr) fatal(P, st.loop.test.span, "while statement condition must be bool or pointer"); lexexpect(P, '{'); st.loop.body = parseblock(P).block; - } else if (lexmatch(P, NULL, TKkw_for)) { + } else if (lexmatch(P, &tok, TKkw_for)) { + st.span = tok.span; st = pstfor(P); - } else if (lexmatch(P, NULL, TKkw_switch)) { + } else if (lexmatch(P, &tok, TKkw_switch)) { st = pstswitch(P); + st.span = tok.span; } else if (lexmatch(P, &tok, TKkw_return)) { + if (!P->curfn) + fatal(P, tok.span, "return disallowed here"); st.t = Sreturn; - if (!lexmatch(P, NULL, ';')) { + st.span = tok.span; + if (!lexmatch(P, &tok, ';')) { st.retex = exprdup(parseexpr(P)); lexexpect(P, ';'); - if (P->curfn->retty == ty_void) + if (!typeof2(st.retex->ty, P->curfn->retty)) fatal(P, st.retex->span, - "return statement in void function must not return a value"); + "incompatible type in return statement"); } else if (P->curfn->retty != ty_void) { fatal(P, tok.span, "return statement in non-void function must return a value"); } } else if (isdecltokt((tok = lexpeek(P)).t)) { st.t = Sdecl; + st.span = tok.span; parsedecl(&st.decl, P, 0); if (st.decl.t == Dfn && !st.decl.externp && !st.decl.fn.body) fatal(P, tok.span, @@ -1447,6 +1516,7 @@ parsestmt(struct parser *P) { "cannot define external function inside another function"); } else { struct expr ex; + st.span = tok.span; if ((tok = lexpeek(P)).t == TKident) { const struct decl *decl; @@ -1550,7 +1620,7 @@ parsefn(struct decl *decl, struct parser *P) { }); for (int i = 0; i < params.length; ++i) { struct decl decl = { - Dvar, params.data[i].name, .var = { + Dlet, params.data[i].name, .var = { .ty = params.data[i].ty, .fnid = fn->id, } @@ -1613,7 +1683,11 @@ parsemacrocase(struct parser *P) { case TKeof: fatal(P, espan, "unterminated macro definition"); } - if (tok.t == TKgensym) { + if (tok.t == TKident) { + for (int i = 0; i < params.length; ++i) + if (!strcmp(params.data[i], tok.str)) + tok.t = TKmacident; + } else if (tok.t == TKgensym) { struct gensyms *gs; for (gs = gensyms; gs; gs = gs->next) { if (!strcmp(gs->name, tok.str)) { @@ -1625,8 +1699,7 @@ parsemacrocase(struct parser *P) { gs->name = tok.str; gs->tok.t = TKident; gs->tok.span = tok.span; - gs->tok.str = xmalloc(strlen(tok.str) + 24); - sprintf((char *)gs->tok.str, "__fG%s_%d", tok.str, gensymid++); + gs->tok.str = xasprintf("__fG%s_%d", tok.str, gensymid++); tok = gs->tok; gs->next = gensyms; gensyms = gs; @@ -1636,6 +1709,12 @@ parsemacrocase(struct parser *P) { } (void)vec_pop(&body); + for (struct gensyms *gs = gensyms, *next; gs; gs = next) { + next = gs->next; + free((char *)gs->name); + free(gs); + } + vec_slice_cpy(&c.params, ¶ms); vec_slice_cpy(&c.body, &body); return c; @@ -1673,9 +1752,8 @@ parsedecl(struct decl *decl, struct parser *P, bool toplevel) { bool externp = 0; memset(decl, 0, sizeof *decl); - if (lexmatch(P, &tok, TKkw_extern)) { + if (lexmatch(P, &tok, TKkw_extern)) externp = 1; - } if (lexmatch(P, &tok, TKkw_fn)) { const char *name = lexexpects(P, TKident, "function name").str; @@ -1685,19 +1763,34 @@ parsedecl(struct decl *decl, struct parser *P, bool toplevel) { decl->_cname = xcalloc(1, sizeof (char *)); parsefn(decl, P); decl->externp = externp; + } else if (lexmatch(P, &tok, TKkw_static)) { + decl->t = Dstatic; + decl->externp = externp; + decl->_cname = xcalloc(1, sizeof (char *)); + parsevardecl(P, decl); + if (!toplevel && !externp && !decl->var.ini) + fatal(P, decl->span, + "static variable inside function cannot be forward-declared"); + if (!toplevel && externp && decl->var.ini) + fatal(P, decl->span, + "extern static variable inside function cannot be initialized"); + lexexpect(P, ';'); } else if (lexmatch(P, &tok, TKkw_typedef)) { + if (externp) + fatal(P, tok.span, "typedef cannot be `extern'"); decl->t = Dtype; decl->name = lexexpects(P, TKident, "typedef name").str; decl->ty = parsetype(P); decl->_cname = xcalloc(1, sizeof(char *)); lexexpect(P, ';'); } else if (lexmatch(P, &tok, TKkw_defmacro)) { + if (externp) + fatal(P, tok.span, "macro cannot be `extern'"); const char *name = lexexpects(P, TKident, "macro name").str; decl->t = Dmacro; decl->name = name; decl->macro = parsemacro(P); decl->macro.name = name; - } else { fatal(P, tok.span, "expected declaration (near %s)", tok2str(tok)); |