diff options
Diffstat (limited to 'src')
| -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 |
6 files changed, 285 insertions, 21 deletions
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; +} |