aboutsummaryrefslogtreecommitdiff
path: root/bootstrap/parse.c
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2022-08-05 09:31:06 +0200
committerlemon <lsof@mailbox.org>2022-08-05 09:31:06 +0200
commite0630766450d402455d9c8368087f96d8075c07c (patch)
tree57c6815ff9c4e4264e39f4643e60e4d0be7c192c /bootstrap/parse.c
parent9667272414380e2d50113e0a0c6408a02e7c23eb (diff)
headers, import
Diffstat (limited to 'bootstrap/parse.c')
-rw-r--r--bootstrap/parse.c152
1 files changed, 105 insertions, 47 deletions
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 <linux/limits.h>
#include <stdint.h>
+#include <stdlib.h>
#include <strings.h>
/***********/
@@ -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);
}