aboutsummaryrefslogtreecommitdiff
path: root/bootstrap
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
parent9667272414380e2d50113e0a0c6408a02e7c23eb (diff)
headers, import
Diffstat (limited to 'bootstrap')
-rw-r--r--bootstrap/all.h17
-rw-r--r--bootstrap/cgen.c6
-rw-r--r--bootstrap/dump.c6
-rw-r--r--bootstrap/libc.hff2
-rw-r--r--bootstrap/main.c6
-rw-r--r--bootstrap/parse.c152
-rw-r--r--bootstrap/test.cff4
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 };