diff options
| -rw-r--r-- | bootstrap/all.h | 17 | ||||
| -rw-r--r-- | bootstrap/cgen.c | 6 | ||||
| -rw-r--r-- | bootstrap/dump.c | 6 | ||||
| -rw-r--r-- | bootstrap/libc.hff | 2 | ||||
| -rw-r--r-- | bootstrap/main.c | 6 | ||||
| -rw-r--r-- | bootstrap/parse.c | 152 | ||||
| -rw-r--r-- | bootstrap/test.cff | 4 |
7 files changed, 130 insertions, 63 deletions
diff --git a/bootstrap/all.h b/bootstrap/all.h index fa24479..3048d99 100644 --- a/bootstrap/all.h +++ b/bootstrap/all.h @@ -2,6 +2,7 @@ #include "vec.h" #include <assert.h> +#include <errno.h> #include <limits.h> #include <stdarg.h> #include <stddef.h> @@ -42,6 +43,7 @@ struct span { _(fn) \ _(for) \ _(if) \ + _(import) \ _(let) \ _(not) \ _(or) \ @@ -124,6 +126,7 @@ struct parser { int expanno; const struct type *targty; bool used_targty; + bool is_header; }; enum typetype { @@ -366,8 +369,12 @@ struct stmt { }; }; -struct transunit { - slice_t(struct decl) decls; +struct declsl { + slice_t(struct decl); +}; + +struct comfile { + struct declsl decls; }; /************/ @@ -447,7 +454,7 @@ void noreturn fatal(struct parser *, struct span, const char *fmt, ...); /** parse.c **/ extern const char *keyword2str[]; -void parse(struct transunit *, struct parser *); +void parse(struct comfile *, struct parser *); void initparser(struct parser *, const char *fname); /** types.c **/ @@ -481,7 +488,7 @@ bool envput(struct env *, const struct decl *decl); struct env *mkenv(const struct env *parent); /** dump.c **/ -void dumptransunit(const struct transunit *); +void dumpcomfile(const struct comfile *); const char *tokt2str(int); const char *tok2str(struct tok); void pritoktree(struct toktree); @@ -489,7 +496,7 @@ void epri(const char *fmt, ...); void vepri(const char *fmt, va_list); /** cgen.c **/ -void cgen(FILE *, const struct transunit *); +void cgen(FILE *, const struct comfile *); /** fold.c **/ int fold(struct expr *); diff --git a/bootstrap/cgen.c b/bootstrap/cgen.c index 2f92375..b4cea42 100644 --- a/bootstrap/cgen.c +++ b/bootstrap/cgen.c @@ -593,13 +593,13 @@ prelude() { } void -cgen(FILE *fp, const struct transunit *tu) { +cgen(FILE *fp, const struct comfile *cf) { outfp = fp; prelude(); visittypes(defctype, NULL); - for (int i = 0; i < tu->decls.n; ++i) { - gendecl(&tu->decls.d[i], 1); + for (int i = 0; i < cf->decls.n; ++i) { + gendecl(&cf->decls.d[i], 1); } } diff --git a/bootstrap/dump.c b/bootstrap/dump.c index ced692d..5d83503 100644 --- a/bootstrap/dump.c +++ b/bootstrap/dump.c @@ -407,7 +407,7 @@ dumpdecl(const struct decl *decl, int ws) { } void -dumptransunit(const struct transunit *tu) { - for (int i = 0; i < tu->decls.n; ++i) - dumpdecl(&tu->decls.d[i], 0); +dumpcomfile(const struct comfile *cf) { + for (int i = 0; i < cf->decls.n; ++i) + dumpdecl(&cf->decls.d[i], 0); } diff --git a/bootstrap/libc.hff b/bootstrap/libc.hff new file mode 100644 index 0000000..0667b3f --- /dev/null +++ b/bootstrap/libc.hff @@ -0,0 +1,2 @@ +extern fn printf(fmt *const u8, ...) int; +extern fn qsort(base *void, nmemb usize, size usize, compar *fn(l *const void, r *const void, _ *void) int) void; diff --git a/bootstrap/main.c b/bootstrap/main.c index 4acf913..95759af 100644 --- a/bootstrap/main.c +++ b/bootstrap/main.c @@ -3,12 +3,12 @@ int main(int argc, char **argv) { struct parser P; - struct transunit tu = {0}; + struct comfile cf = {0}; assert(argc > 1); inittypes(); initparser(&P, argv[1]); - parse(&tu, &P); + parse(&cf, &P); // dumptransunit(&tu); - cgen(stdout, &tu); + cgen(stdout, &cf); } 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); } diff --git a/bootstrap/test.cff b/bootstrap/test.cff index f74619a..5e74cf1 100644 --- a/bootstrap/test.cff +++ b/bootstrap/test.cff @@ -1,3 +1,5 @@ +import "libc.hff"; +import "libc.hff"; struct Vec2f; struct Vec2f { @@ -18,7 +20,6 @@ enum Color { static xs *void = {}; fn isort(xs *int, n usize) void { - extern fn qsort(base *void, nmemb usize, size usize, compar *fn(l *const void, r *const void, _ *void) int) void; fn icmp(lhs *const void, rhs *const void, _ *void) int { let lhs = *as(*int)lhs; let rhs = *as(*int)rhs; @@ -28,7 +29,6 @@ fn isort(xs *int, n usize) void { } extern fn main (argc int, argv **u8) int { - extern fn printf(fmt *const u8, ...) int; let colors [3]Color = { :Red, :Green, :Blue } ; let x = Vec2f { .y: 1, .x: 2.4 }; |