From e0630766450d402455d9c8368087f96d8075c07c Mon Sep 17 00:00:00 2001 From: lemon Date: Fri, 5 Aug 2022 09:31:06 +0200 Subject: headers, import --- bootstrap/parse.c | 152 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 105 insertions(+), 47 deletions(-) (limited to 'bootstrap/parse.c') diff --git a/bootstrap/parse.c b/bootstrap/parse.c index 9cdb7de..58f9e79 100644 --- a/bootstrap/parse.c +++ b/bootstrap/parse.c @@ -1,6 +1,8 @@ #include "all.h" #include "vec.h" +#include #include +#include #include /***********/ @@ -1536,7 +1538,8 @@ pstswitch(struct parser *P) { } } -static void parsedecl(struct decl *, struct parser *, bool toplevel); +typedef void (*decl_yielder_t)(const struct decl *, void *); +static void parsedecl(decl_yielder_t, void *, struct parser *, bool toplevel); static bool isdecltokt(int tokt) { @@ -1646,6 +1649,12 @@ ok: P->curexpan = memcpy(xmalloc(sizeof expan), &expan, sizeof expan); } +static void +yieldstdecl(const struct decl *d0, void *arg) { + struct decl *decl = arg; + *decl = *d0; +} + static struct stmt parsestmt(struct parser *P) { struct stmt st = {0}; @@ -1697,7 +1706,7 @@ parsestmt(struct parser *P) { } else if (isdecltokt((tok = lexpeek(P)).t)) { st.t = Sdecl; st.span = tok.span; - parsedecl(&st.decl, P, 0); + parsedecl(yieldstdecl, &st.decl, P, 0); if (st.decl.t == Dfn && !st.decl.externp && !st.decl.fn.body) fatal(P, tok.span, "cannot forward-declare non-external function inside another function"); @@ -2058,13 +2067,35 @@ parseagg(struct parser *P, const char *name, int kind) { return interntype(ty); } +static struct comfile +doimport(struct parser *P, const char *path) { + static vec_t(const char *) seen; + char _rpath[PATH_MAX], *rpath; + struct comfile cf = {0}; + struct parser P2; + + if (!(rpath = realpath(path, _rpath))) + fatal(P, P->tokspan, "import %q: %s", path, strerror(errno)); + for (int i = 0; i < seen.length; ++i) + if (!strcmp(seen.data[i], rpath)) + return cf; + rpath = xstrdup(rpath); + vec_push(&seen, rpath); + + P2.primenv = P->primenv; + initparser(&P2, path); + P2.is_header = 1; + parse(&cf, &P2); + return cf; +} + static void -parsedecl(struct decl *decl, struct parser *P, bool toplevel) { +parsedecl(decl_yielder_t yield, void *yarg, struct parser *P, bool toplevel) { struct tok tok = { .span = P->tokspan }; bool externp = 0; const char *name; int kind; - memset(decl, 0, sizeof *decl); + struct decl decl = {0}; if (lexmatch(P, &tok, TKkw_extern)) externp = 1; @@ -2072,96 +2103,123 @@ parsedecl(struct decl *decl, struct parser *P, bool toplevel) { if (lexmatch(P, &tok, TKkw_fn)) { name = lexexpects(P, TKident, "function name").str; - decl->t = Dfn; - decl->name = decl->fn.name = name; - decl->_cname = xcalloc(1, sizeof (char *)); - parsefn(decl, P); - decl->externp = externp; + decl.t = Dfn; + decl.name = decl.fn.name = name; + decl._cname = xcalloc(1, sizeof (char *)); + decl.span = tok.span; + parsefn(&decl, P); + decl.externp = externp; + if (P->is_header && externp && decl.fn.body) + fatal(P, decl.span, + "cannot define extern function in header"); } 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, + decl.t = Dstatic; + decl.externp = externp; + decl._cname = xcalloc(1, sizeof (char *)); + decl.span = tok.span; + 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, + if (!toplevel && externp && decl.var.ini) + fatal(P, decl.span, "extern static variable inside function cannot be initialized"); + if (P->is_header && externp && decl.var.ini) + fatal(P, decl.span, + "cannot define extern variable in header"); 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 *)); + 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'"); name = lexexpects(P, TKident, "macro name").str; - decl->t = Dmacro; - decl->name = name; - decl->macro = parsemacro(P); - decl->macro.name = name; + decl.t = Dmacro; + decl.name = name; + decl.macro = parsemacro(P); + decl.macro.name = name; } else if (lexmatch(P, &tok, TKkw_enum)) { if (externp) fatal(P, tok.span, "enum cannot be `extern'"); - decl->name = lexexpects(P, TKident, "enum name").str; - decl->ty = parseenum(P, decl->name); + decl.name = lexexpects(P, TKident, "enum name").str; + decl.ty = parseenum(P, decl.name); } else if (lexmatch(P, &tok, TKkw_struct)) { struct decl *d2; kind = TYstruct; if (externp) fatal(P, tok.span, "struct cannot be `extern'"); agg: - decl->name = lexexpects(P, TKident, "struct name").str; - decl->ty = parseagg(P, decl->name, kind); - d2 = (struct decl *)finddecl(P, decl->name); + decl.name = lexexpects(P, TKident, "struct name").str; + decl.ty = parseagg(P, decl.name, kind); + d2 = (struct decl *)finddecl(P, decl.name); if (d2 && d2->t == Dtype && d2->ty->t == kind && d2->ty->agg.fwd) { // modify existing forward declaration - *(size_t *)&d2->ty->size = decl->ty->size; - *(size_t *)&d2->ty->align = decl->ty->align; + *(size_t *)&d2->ty->size = decl.ty->size; + *(size_t *)&d2->ty->align = decl.ty->align; *(bool *)&d2->ty->agg.fwd = 0; - memcpy((void *)&d2->ty->agg.flds, &decl->ty->agg.flds, + memcpy((void *)&d2->ty->agg.flds, &decl.ty->agg.flds, sizeof d2->ty->agg.flds); - uninterntype(decl->ty); - decl = d2; + uninterntype(decl.ty); + d2->span = tok.span; envput(P->curenv, d2); - goto noputdecl; + return; } } else if (lexmatch(P, &tok, TKkw_union)) { if (externp) fatal(P, tok.span, "union cannot be `extern'"); kind = TYunion; goto agg; + } else if (lexmatch(P, &tok, TKkw_import)) { + const char *path; + struct comfile cf; + assert(toplevel); + path = lexexpect(P, TKstrlit).str; + cf = doimport(P, path); + for (int i = 0; i < cf.decls.n; ++i) { + putdecl(P, tok.span, &cf.decls.d[i]); + yield(&cf.decls.d[i], yarg); + } + free(cf.decls.d); + lexexpect(P, ';'); + return; } else { fatal(P, tok.span, "expected declaration (near %s)", tok2str(tok)); } - putdecl(P, tok.span, decl); -noputdecl: - decl->span = tok.span; + decl.span = tok.span; + putdecl(P, tok.span, &decl); + yield(&decl, yarg); +} + +static void +yieldexdecl(const struct decl *decl, void *arg) { + vec_t(struct decl) *decls = arg; + vec_push(decls, *decl); } void -parse(struct transunit *tu, struct parser *P) { +parse(struct comfile *cf, struct parser *P) { vec_t(struct decl) decls = {0}; - int i = 0; - while (!P->eof && lexpeek(P).t != TKeof) { - vec_push(&decls, (struct decl){0}); - parsedecl(&decls.data[i++], P, 1); - } - vec_slice_cpy(&tu->decls, &decls); + while (!P->eof && lexpeek(P).t != TKeof) + parsedecl(yieldexdecl, &decls, P, 1); + vec_slice_cpy(&cf->decls, &decls); } void initparser(struct parser *P, const char *fname) { + struct env *primenv = P->primenv; assert(NUM_KEYWORDS - 1 < '!'); memset(P, 0, sizeof *P); + P->primenv = primenv; P->curfile = fname; if (!(P->fp = fopen(fname, "r"))) perror(fname), exit(1); P->tokspan = P->curspan = (struct span) { addfilepath(fname), 0, 1, 1 }; P->peekchr = -1; P->curenv = P->tlenv = xcalloc(1, sizeof *P->tlenv); - P->primenv = xcalloc(1, sizeof *P->primenv); + if (!P->primenv) + P->primenv = xcalloc(1, sizeof *P->primenv); putprimtypes(P->primenv); } -- cgit v1.2.3