aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2022-08-11 20:27:48 +0200
committerlemon <lsof@mailbox.org>2022-08-11 20:27:48 +0200
commit19f1093f0929b989a06cdee2e7d175e6db15559c (patch)
treeacf82e3cb1b8e81ff132978b7656c178249c5f15
parentc7961d732e5d67e8ea1b0be05e979bf24361f794 (diff)
things
-rw-r--r--bootstrap/cgen.c11
-rw-r--r--bootstrap/env.c2
-rw-r--r--bootstrap/parse.c58
-rw-r--r--src/all.hff38
-rw-r--r--src/libc.hff9
-rw-r--r--src/main.cff15
-rw-r--r--src/mem.hff62
-rw-r--r--src/parse.cff147
-rw-r--r--src/util.cff35
9 files changed, 336 insertions, 41 deletions
diff --git a/bootstrap/cgen.c b/bootstrap/cgen.c
index f79e112..1629151 100644
--- a/bootstrap/cgen.c
+++ b/bootstrap/cgen.c
@@ -338,7 +338,7 @@ genstmt(struct stmt *stmt) {
pri("if (%e) ", &stmt->ifelse.test);
genblock(stmt->ifelse.t);
if (stmt->ifelse.f) {
- pri("else ");
+ pri("else\n");
genstmt(stmt->ifelse.f);
}
break;
@@ -389,7 +389,7 @@ genstmt(struct stmt *stmt) {
struct euswitchcase c = stmt->euswitch.cs.d[i];
pri("case /* %s */ %d: ", c.fld->name, c.vval);
if (c.capt)
- pri("{ %t %s_%d__ = __stmp.u.%s;\n", c.fld->ty, c.capt, c.captid, c.fld->name);
+ pri("{ %t %s_%d__ = __stmp.u.%s_;\n", c.fld->ty, c.capt, c.captid, c.fld->name);
genblock(c.t);
if (c.capt)
pri("}\n");
@@ -618,7 +618,7 @@ genfn(bool externp, const char *cname, struct fn *fn) {
pri("static ");
pri("%t %s(", fn->retty, cname);
for (int i = 0; i < fn->params.n; ++i) {
- pri("%t %s", fn->params.d[i].ty, fn->params.d[i].name);
+ pri("%t %s", fn->params.d[i].ty, fn->params.d[i].name ? fn->params.d[i].name : "");
if (i < fn->params.n - 1 || fn->variadic)
pri(", ");
}
@@ -752,6 +752,11 @@ defctype(const struct type *ty, void *_) {
*cname = (char *)unconstify(ty)->_cname;
break;
}
+ for (int i = 0; i < ty->agg.flds.n; ++i) {
+ struct aggfield *fld = &ty->agg.flds.d[i];
+ if (fld->ty)
+ defctype(fld->ty, NULL);
+ }
*cname = xasprintf("__ty%s%d", ty->agg.name ? ty->agg.name : "", id++);
pri("typedef struct %s %s;\n", *cname, *cname);
if (!ty->agg.fwd) {
diff --git a/bootstrap/env.c b/bootstrap/env.c
index 773550a..ff2929f 100644
--- a/bootstrap/env.c
+++ b/bootstrap/env.c
@@ -35,6 +35,8 @@ envput(struct env *env, const struct decl *decl) {
// modify existing forward declarations?
if (decl == d0 || !memcmp(d0, decl, sizeof *d0))
return d0;
+ if (d0->t == Ddef && decl->t == Ddef && !memcmp(&d0->var, &decl->var, sizeof d0->var))
+ return d0;
if (d0->t == Dmacro && !memcmp(&decl->macro, &d0->macro, sizeof decl->macro))
return d0;
if (d0->t == Dtepl && !memcmp(&decl->tepl, &d0->tepl, sizeof decl->tepl))
diff --git a/bootstrap/parse.c b/bootstrap/parse.c
index cff303f..d0bea8e 100644
--- a/bootstrap/parse.c
+++ b/bootstrap/parse.c
@@ -266,6 +266,7 @@ readstrlit(struct parser *P, u8 delim, char *s, size_t n) {
fatal(P, P->tokspan, "unterminated %s literal",
delim == '"' ? "string" : "character");
case '\'': s[i++] = '\''; break;
+ case '\\': s[i++] = '\\'; break;
case '"': s[i++] = '"'; break;
case 'n': s[i++] = '\n'; break;
case 'r': s[i++] = '\r'; break;
@@ -576,6 +577,8 @@ finddecl(struct parser *P, const char *name) {
static struct expr parseexpr(struct parser *P);
+
+static const struct type *xident2type(struct parser *P, struct tok tok);
static const struct type *parsetype(struct parser *P);
static const struct type *
@@ -589,9 +592,13 @@ parsefntype(struct parser *P) {
if (lexmatch(P, &tok, '...')) {
ty.fn.variadic = 1;
} else {
- const struct type *param;
- tok = lexexpects(P, TKident, "parameter name");
- param = parsetype(P);
+ const struct type *param ;
+ if (lexmatch(P, &tok, TKident)) {
+ if (lexpeek(P).t == ',' || lexpeek(P).t == ')')
+ param = xident2type(P, tok);
+ } else {
+ param = parsetype(P);
+ }
if (!completetype(param))
fatal(P, tok.span, "parameter type is incomplete (%t)",
param);
@@ -728,6 +735,19 @@ parseexpandtepl(struct parser *P, struct tepl *tepl) {
}
static const struct type *
+xident2type(struct parser *P, struct tok tok) {
+ const struct decl *decl = finddecl(P, tok.str);
+ if (!decl)
+ fatal(P, P->tokspan, "%T is not defined", tok);
+ if (decl->t == Dtype) {
+ return decl->ty;
+ } else if (decl->t == Dtepl && decl->tepl.t == Dtype) {
+ return parseexpandtepl(P, (struct tepl *)&decl->tepl);
+ } else
+ fatal(P, P->tokspan, "%T is not a type", tok);
+}
+
+static const struct type *
parsetype(struct parser *P) {
struct tok tok;
if (lexmatch(P, &tok, '*')) {
@@ -790,15 +810,7 @@ parsetype(struct parser *P) {
} while (!lexmatch(P, &tok, ')'));
return ty;
} else if (lexmatch(P, &tok, TKident)) {
- const struct decl *decl = finddecl(P, tok.str);
- if (!decl)
- fatal(P, P->tokspan, "%T is not defined", tok);
- if (decl->t == Dtype) {
- return decl->ty;
- } else if (decl->t == Dtepl && decl->tepl.t == Dtype) {
- return parseexpandtepl(P, (struct tepl *)&decl->tepl);
- } else
- fatal(P, P->tokspan, "%T is not a type", tok);
+ return xident2type(P, tok);
} else if (lexmatch(P, &tok, TKkw_fn)) {
return parsefntype(P);
} else if (lexmatch(P, &tok, TKtype)) {
@@ -1817,6 +1829,7 @@ parsevardecl(decl_yielder_t yield, void *yarg, struct parser *P, bool let, bool
}
ty2.size = ty->child->size * ty2.length;
ty2.align = ty->child->align;
+ uninterntype(ty);
ty = interntype(ty2);
}
@@ -2409,8 +2422,16 @@ parsefn(struct decl *decl, struct parser *P) {
if (lexmatch(P, &tok, '...')) {
fn->variadic = 1;
} else {
- param.name = (tok = lexexpects(P, TKident, "parameter name")).str;
- param.ty = parsetype(P);
+ if (lexmatch(P, &tok, TKident)) {
+ if (lexpeek(P).t == ',' || lexpeek(P).t == ')') {
+ param.ty = xident2type(P, tok);
+ } else {
+ param.name = tok.str;
+ param.ty = parsetype(P);
+ }
+ } else {
+ param.ty = parsetype(P);
+ }
if (!completetype(param.ty))
fatal(P, tok.span, "parameter type is incomplete (%t)",
param.ty);
@@ -2442,6 +2463,8 @@ parsefn(struct decl *decl, struct parser *P) {
Dfn, fn->name, .fn = *fn, ._cname = decl->_cname
});
for (int i = 0; i < params.length; ++i) {
+ if (!params.data[i].name)
+ continue;
struct decl decl = {
Dlet, params.data[i].name, .var = {
.ty = params.data[i].ty,
@@ -2824,13 +2847,14 @@ doimport(struct parser *P, const char *path) {
for (int i = 0; i < seen.length; ++i)
if (!strcmp(seen.data[i].s, rpath))
return seen.data[i].cf;
- rpath = xstrdup(rpath);
+ rpath = xstrdup(rpath);
// P2.primenv = P->primenv;
- initparser(&P2, xstrdup(path2));
+ initparser(&P2, rpath);
P2.is_header = 1;
- parse(&cf, &P2);
vec_push(&seen, ((struct entry) { rpath, cf }));
+ parse(&cf, &P2);
+ seen.data[seen.length - 1].cf = cf;
return cf;
}
diff --git a/src/all.hff b/src/all.hff
index 13051c6..e1cb26a 100644
--- a/src/all.hff
+++ b/src/all.hff
@@ -26,6 +26,10 @@ defmacro foreach(x, i, a, ...body) [
}
]
+defmacro ALIGNUP(x,a) [ (((x) + ((a) - 1)) & -(a)) ]
+
+defmacro streq(a,b) [ (strcmp(a,b) == 0) ]
+
/// Types
struct Type;
@@ -33,14 +37,15 @@ struct Decl;
struct Expr;
struct Loc {
- fileid u16,
- idx isize,
- col int,
+ fileid i16,
+ col i16,
line int,
+ idx isize,
}
#[lax]
enum TokT {
+ // !sorted
kw_and, kw_as, kw_break, kw_case, kw_const,
kw_continue, kw_def, kw_defmacro, kw_do,
kw_else, kw_enum, kw_extern, kw_fn,
@@ -48,16 +53,31 @@ enum TokT {
kw_or, kw_return, kw_sizeof, kw_static,
kw_struct, kw_switch, kw_typedef, kw_typeof,
kw_union, kw_while,
+ NUM_KEYWORDS,
+ int = -100,
+ flo,
+ bool,
+ str,
+ chr,
+ null,
+ ident,
+ macident,
+ gensym,
+ type,
+ label,
+ strify,
+ eof,
}
struct Tok {
t int,
+ loc Loc,
ty *const Type,
u union {
int i64,
uint u64,
- float f64,
+ flo f64,
bool bool,
str [#]const u8,
},
@@ -68,17 +88,23 @@ struct Decl {
struct Parser {
fp *FILE,
- curfile [#]const u8,
+ curfile *const u8,
tokloc Loc,
curloc Loc,
eof bool,
peekchr Option<int>,
+ peektok Option<Tok>,
}
// parse.cff
-extern fn parse(P *Parser, path *const u8) [#]Decl;
+extern fn parser_init(*Parser, path *const u8) void;
+extern fn parse(*Parser) [#]Decl;
// util.cff
extern fn xmalloc(n usize) *void;
extern fn xrealloc(p *void, n usize) *void;
+def FNV1A_INI u32 = 0x811c9dc5;
+extern fn fnv1a(h u32, [#]const u8) u32;
+extern fn fnv1a_s(h u32, *const u8) u32;
+extern fn addfilepath(*const u8) int;
diff --git a/src/libc.hff b/src/libc.hff
index d686905..7e2268c 100644
--- a/src/libc.hff
+++ b/src/libc.hff
@@ -5,10 +5,19 @@ extern static stdin *FILE,
stderr *FILE;
extern fn printf(fmt *const u8, ...) void;
extern fn fprintf(fp *FILE, fmt *const u8, ...) void;
+extern fn fopen(path *const u8, mode *const u8) *FILE;
+extern fn fclose(fp *FILE) int;
+extern fn fgetc(fp *FILE) int;
+def EOF = -1;
// stdlib.h
extern fn abort() void;
extern fn exit(c int) void;
+extern fn perror(s *const u8) void;
extern fn malloc(n usize) *void;
extern fn realloc(p *void, n usize) *void;
extern fn free(p *void) void;
+
+// string.h
+extern fn strlen(s *const u8) usize;
+extern fn strcmp(a *const u8, b *const u8) int;
diff --git a/src/main.cff b/src/main.cff
index 9d92612..cfb6390 100644
--- a/src/main.cff
+++ b/src/main.cff
@@ -6,18 +6,7 @@ extern fn main(argc int, argv **u8) int {
assert(argc > 1, "args?");
let p = Parser {};
- parse(&p, argv[1]);
-
- let args Vec<*u8> = {};
- for let i = 1; i < argc; ++i {
- args->push(argv[i]);
- }
- foreach(s, i, args->compact(),
- printf("%d: %s\n", i, s);
- )
-
- do {
- printf("hi");
- } while #f;
+ parser_init(&p, argv[1]);
+ parse(&p);
}
diff --git a/src/mem.hff b/src/mem.hff
new file mode 100644
index 0000000..9fee910
--- /dev/null
+++ b/src/mem.hff
@@ -0,0 +1,62 @@
+import "all.hff";
+
+def ARENA_SIZE = 16 * 1024;
+
+struct ArenaRegion {
+ prev *ArenaRegion,
+ idx int,
+ mem [ARENA_SIZE]u8,
+}
+
+struct Arena {
+ r *ArenaRegion,
+
+ fn allocf(a *void, n usize) *void {
+ let a *Arena = a;
+ n = ALIGNUP(n, 16);
+ if ARENA_SIZE < n {
+ return xmalloc(n);
+ } else if a.r == #null {
+ a.r = xcalloc(1, sizeof ArenaRegion);
+ return allocf(a, n);
+ } else if ARENA_SIZE - a.r.idx >= n {
+ let ptr = &a.r.mem[a.r.idx];
+ a.r.idx += n;
+ return ptr;
+ } else {
+ let rp = xmalloc(sizeof ArenaRegion);
+ *rp = a.r;
+ let r = ArenaRegion { .prev: rp };
+ return allocf(a, n);
+ }
+ }
+}
+
+struct Mallocator {
+ fn allocf(*void, n usize) *void {
+ return xmalloc(n);
+ }
+
+ fn freef(*void, ptr *void) void {
+ free(ptr);
+ }
+}
+
+struct Allocator {
+ a *void,
+ allocf *fn(a *void, n usize) *void,
+ freef *fn(a *void, ptr *void) void,
+
+ fn alloc(self *Allocator, n usize) *void {
+ if self.allocf {
+ return self.allocf(self.a, n);
+ }
+ return #null;
+ }
+
+ fn free(self *Allocator, ptr *void) void {
+ if self.freef {
+ self.freef(self.a, ptr);
+ }
+ }
+}
diff --git a/src/parse.cff b/src/parse.cff
index 089d647..f659322 100644
--- a/src/parse.cff
+++ b/src/parse.cff
@@ -1,5 +1,148 @@
import "all.hff";
-extern fn parse(P *Parser, path *const u8) [#]Decl {
- return {};
+///////////
+// Lexer //
+///////////
+
+fn chr(P *Parser) int {
+ let c int #?;
+ switch P.peekchr {
+ case Some pc;
+ c = pc;
+ P.peekchr = :None;
+ case None;
+ c = fgetc(P.fp);
+ }
+
+ ++P.curloc.idx;
+ ++P.curloc.col;
+ if c == '\n' {
+ P.curloc.col = 1;
+ ++P.curloc.line;
+ }
+ if c == EOF {
+ P.eof = #t;
+ }
+ return c;
+}
+
+fn chrpeek(P *Parser) int {
+ switch P.peekchr {
+ case Some c; return c;
+ }
+ let c = fgetc(P.fp);
+ P.peekchr = :Some c;
+ return c;
+}
+
+fn chrmatch(P *Parser, c int) bool {
+ if chrpeek(P) == c {
+ chr(P);
+ return #t;
+ }
+ return #f;
+}
+
+fn isspace(c u8) bool {
+ switch c {
+ case ' ', '\t', '\n', '\r', '\v', '\f';
+ return #t;
+ }
+ return #f;
+}
+
+fn isdigit(c u8) bool {
+ return c >= '0' and c <= '9';
+}
+
+fn isxdigit(c u8) bool {
+ return isdigit(c)
+ or (c >= 'A' and c <= 'F')
+ or (c >= 'a' and c <= 'f');
+}
+
+fn isalpha(c u8) bool {
+ return (c >= 'a' and c <= 'z')
+ or (c >= 'A' and c <= 'z');
+}
+
+fn issep(c u8) bool {
+ if isspace(c) {
+ return #t;
+ }
+ switch (c) {
+ case '(', ')', '[', ']', '{', '}', '.', ',',
+ ';', '?', '+', '-', '*', '/', '&', '|',
+ '^', '~', '=', '\'', '"', '<', '>', ':',
+ '@', '#', '\\', '`';
+ return #t;
+ }
+ return #f;
+}
+
+fn eatspaces(P *Parser) void {
+ for ;;chr(P) {
+ if not isspace(chrpeek(P)) {
+ break;
+ }
+ }
+}
+
+// !sorted
+static keyword2str []*const u8 = {
+ "and", "as", "break", "case", "const",
+ "continue", "def", "defmacro", "do",
+ "else", "enum", "extern", "fn",
+ "for", "if", "import", "let", "not",
+ "or", "return", "sizeof", "static",
+ "struct", "switch", "typedef", "typeof",
+ "union", "while",
+};
+
+fn str2keyword(s *const u8) int {
+ let i = 0, j = keyword2str.#len - 1;
+ while i <= j {
+ let k = (j + i) / 2;
+ let cmp = strcmp(keyword2str[k], s);
+ if cmp == 0 {
+ return k;
+ } else if cmp < 0 {
+ i = k + 1;
+ } else {
+ j = k - 1;
+ }
+ }
+ return -1;
+}
+
+fn lex(P *Parser) Tok {
+ let c int #?;
+ let tok Tok = {};
+
+ switch P.peektok {
+ case Some pt;
+ P.peektok = :None;
+ return pt;
+ }
+
+ eatspaces(P);
+ tok.loc = (P.tokloc = P.curloc);
+ if isdigit(c = chrpeek(P)) {
+ let s [80]u8 = {};
+ }
+}
+
+extern fn parse(P *Parser) [#]Decl {
+ let tok = lex(P);
+}
+
+extern fn parser_init(P *Parser, path *const u8) void {
+ *P = {};
+ P.curfile = path;
+ if (P.fp = fopen(path, "r")) == #null {
+ perror(path);
+ exit(1);
+ }
+ P.tokloc = (P.curloc = { addfilepath(path), 0, 1, 1 });
+ P.peekchr = :None;
}
diff --git a/src/util.cff b/src/util.cff
index 36a0c13..33bce84 100644
--- a/src/util.cff
+++ b/src/util.cff
@@ -12,3 +12,38 @@ extern fn xrealloc(p *void, n usize) *void {
return p;
}
+
+extern fn fnv1a(h u32, d [#]const u8) u32 {
+ foreach(i, x, d,
+ h ^= x;
+ h *= 0x01000193;
+ )
+ return h;
+}
+
+extern fn fnv1a_s(h u32, str *const u8) u32 {
+ while *str != 0 {
+ h ^= *str++;
+ h *= 0x01000193;
+ }
+ return h;
+}
+
+static filepaths [64]*const u8 = {};
+static nfilepaths int = 0;
+
+extern fn addfilepath(s *const u8) int {
+ let i0 = fnv1a_s(FNV1A_INI, s) % filepaths.#len;
+ let i int = i0;
+ do {
+ if filepaths[i] == #null {
+ break;
+ } else if streq(filepaths[i], s) {
+ return i;
+ }
+ } while ++i != i0;
+
+ assert(nfilepaths++ < filepaths.#len, "too many files");
+ filepaths[i] = s;
+ return i;
+}