diff options
| author | 2022-08-11 20:27:48 +0200 | |
|---|---|---|
| committer | 2022-08-11 20:27:48 +0200 | |
| commit | 19f1093f0929b989a06cdee2e7d175e6db15559c (patch) | |
| tree | acf82e3cb1b8e81ff132978b7656c178249c5f15 | |
| parent | c7961d732e5d67e8ea1b0be05e979bf24361f794 (diff) | |
things
| -rw-r--r-- | bootstrap/cgen.c | 11 | ||||
| -rw-r--r-- | bootstrap/env.c | 2 | ||||
| -rw-r--r-- | bootstrap/parse.c | 58 | ||||
| -rw-r--r-- | src/all.hff | 38 | ||||
| -rw-r--r-- | src/libc.hff | 9 | ||||
| -rw-r--r-- | src/main.cff | 15 | ||||
| -rw-r--r-- | src/mem.hff | 62 | ||||
| -rw-r--r-- | src/parse.cff | 147 | ||||
| -rw-r--r-- | src/util.cff | 35 |
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; +} |