From ce05175372a9ddca1a225db0765ace1127a39293 Mon Sep 17 00:00:00 2001 From: Nicholas Date: Fri, 12 Nov 2021 09:22:01 -0800 Subject: chore: simplified organizational structure --- src/cmd/cc/cc.c | 409 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 409 insertions(+) create mode 100644 src/cmd/cc/cc.c (limited to 'src/cmd/cc/cc.c') diff --git a/src/cmd/cc/cc.c b/src/cmd/cc/cc.c new file mode 100644 index 0000000..8ad0022 --- /dev/null +++ b/src/cmd/cc/cc.c @@ -0,0 +1,409 @@ +#include "cc.h" +#include + +// ----------------------------------------------------------------------- +// string interning + +/* jenkins' one at a time hash */ +static +int32 +hash_string(byte* s) +{ + int32 h; + + h = 0; + if (s != nil) { + for (; *s; ++s) { + h += *s; + h = (h << 10); + h = (h >> 6); + } + } + + h += (h << 3); + h ^= (h >> 11); + h += (h >> 11); + + return h; +} + +static +int +streq(byte *s, byte *t) +{ + if (s == nil) { + if (t == nil) + return 1; + else + return 0; + } + + return (t == nil) ? 0 : strcmp(s, t) == 0; +} + +#define HASH(s) hash_string(s) +#define EQUAL(s, t) (streq(s, t)) +static +int +getstr(string key, int *ok) +{ + int idx; + MAP_GET(idx, (&C.strs), key, HASH, EQUAL); + + *ok = idx < C.strs.n_buckets; + return idx; +} + +static +void +·free(void* _, void* ptr) { + return free(ptr); +} + +static +void * +·alloc(void* _, uint n, ulong size) { + return malloc(n*size); +} + +static +void * +·calloc(void* _, uint n, ulong size) { + return calloc(n, size); +} + +static +int +morestrtab(StrTab *tab, int n) +{ + MAP_GROW(tab, string, int32, n, HASH, ·calloc, ·free, nil); +} + +static +int +putstr(byte *s, error *err) +{ + int sz; + sz = C.strs.size; + MAP_PUT((&C.strs), s, sz, HASH, EQUAL, morestrtab, err); +} +#undef HASH +#undef EQUAL + +int32 +intern(byte **s) +{ + int i, ok; + + i = getstr(*s, &ok); + if (ok) { + *s = C.strs.keys[i]; + goto END; + } + + *s = str·make(*s); + i = putstr(*s, &ok); + C.strs.vals[i] = C.strs.size - 1; + +END: + return C.strs.vals[i]; +} + +// ----------------------------------------------------------------------- +// type interning + +/* TODO: intern types for memory savings */ +int +type() +{ + if (C.type.len >= C.type.cap) { + C.type.cap += 100; + C.type.info = realloc(C.type.info, C.type.cap * sizeof(*C.type.info)); + } + + return C.type.len++; +} + +// ----------------------------------------------------------------------- +// universal compiler builtins + +#define KEYWORD(a, b) b, +byte *keywords[NUM_KEYWORDS] = { KEYWORDS }; +#undef KEYWORD + +#define DIRECTIVE(a, b, c) b, +byte *directives[NUM_DIRECTIVES] = { DIRECTIVES }; +#undef DIRECTIVE + +struct Compiler C = { 0 }; + +// ----------------------------------------------------------------------- +// cli flag handlers + +void +pushinclude(byte *dirs) +{ + string d, s, *it, *end; + + while (*dirs != '\0') { + d = strchr(dirs, ' '); + if (d != nil) + *d = '\0'; + + s = dirs; + intern(&s); + for (it = C.inc.dir, end = it + C.inc.len; it != end; ++it) { + if ((uintptr)s == (uintptr)(*it)) + goto Nextdir; + } + + if (C.inc.len == C.inc.cap) { + C.inc.cap += 20; + C.inc.dir = realloc(C.inc.dir, C.inc.cap*sizeof(*C.inc.dir)); + } + C.inc.dir[C.inc.len++] = s; +Nextdir: + if (d == nil) + break; + dirs = d + 1; + } +} + +// ----------------------------------------------------------------------- +// error reporting + +void +errorat(Pos x, byte *fmt, ...) +{ + va_list args; + va_start(args, fmt); + + printf("error:%s:%d:%d: ", os·basename(x.path), x.line, x.col); + vprintf(fmt, args); + printf("\n"); + + va_end(args); + assert(0); +} + +void +warnat(Pos x, byte *fmt, ...) +{ + va_list args; + va_start(args, fmt); + + printf("warning:%s:%d:%d: ", os·basename(x.path), x.line, x.col); + vprintf(fmt, args); + printf("\n"); + + va_end(args); +} + +// ----------------------------------------------------------------------- +// main point of entry + +void +init(void) +{ + int i; + + for (i = 0; i < arrlen(keywords); i++) + intern(&keywords[i]); + + for (i = 0; i < arrlen(directives); i++) + intern(&directives[i]); + + C.heap = mem·makearena(mem·sys, nil); + + /* compiler definitions */ + C.def.len = 0; + C.def.cap = 100; + C.def.val = calloc(C.def.cap, sizeof(*C.def.val)); + + /* compiler include paths */ + C.inc.len = 0; + C.inc.cap = 100; + C.inc.dir = calloc(C.inc.cap, sizeof(*C.inc.dir)); + C.inc.dir[C.inc.len++] = "."; + + C.outfile = nil; + + /* type info */ + C.type.len = arrlen(basetypes); + C.type.cap = 100 + arrlen(basetypes); + C.type.info = calloc(C.type.cap, sizeof(*C.type.info)); + + memcpy(C.type.info, basetypes, C.type.len * sizeof(*C.type.info)); + + /* builtins */ + C.builtin.vargs = (Decl) { + .pos = (Range) { + .beg = { + .col = 0, + .line = 0, + .path = "", + }, + .end = { + .col = 0, + .line = 0, + .path = "", + }, + }, + .kind = Dtype, + .spec = Mtype, + .type = 1, + .name = "__builtin_va_list", + }; + + intern(&C.builtin.vargs.name); +} + +void +initlx(Lexer *lx) +{ + int i; + + memset(lx, 0, sizeof(*lx)); + lx->b = lx->buf; + + /* predefine macros */ + dodefine(lx, "__LINE__"); + dodefine(lx, "__FILE__"); + lx->macline = (uintptr)lookup(&lx->sym, "__LINE__"); + lx->macfile = (uintptr)lookup(&lx->sym, "__FILE__"); + + for (i = 0; i < C.def.len; i++) + dodefine(lx, C.def.val[i]); + + lx->omit.len = 0; + lx->omit.cap = 100; + lx->omit.path = calloc(lx->omit.cap, sizeof(*C.inc.dir)); + + lx->new = lx->iostk; + lx->new->link = nil; + memset(lx->iostk, 0, sizeof(lx->iostk)); + + lx->sym = (SymTab){ 0 }; +} + +void +freelx(Lexer *lx) +{ + free(lx->omit.path); +} + +void +initp(Parser *p) +{ + /* initialize temporary buffers */ + memset(p->spstk, 0, sizeof(p->spstk)); + memset(p->nmstk, 0, sizeof(p->nmstk)); + memset(p->dtstk, 0, sizeof(p->dtstk)); + memset(p->ptstk, 0, sizeof(p->ptstk)); + + p->sp = p->spstk; + p->nm = p->nmstk; + p->dt = p->dtstk; + p->pt = p->ptstk; + + /* initialize ast */ + p->ast.cap = 0; + p->ast.len = 0; + p->ast.decls = nil; +} + +error +compile(byte *path) +{ + Lexer lx; + Parser p; + error err; + byte *sep, out[400]; + + intern(&path); + strcpy(out, path); + + sep = utf8·findrrune(out, '/'); + if (sep) + *sep++ = '\0'; + else + sep = out; + + if (!C.outfile) { + C.outfile = sep; + if (C.outfile) { + if ((sep = utf8·findrrune(C.outfile, '.'))) { + sep[0] = '.'; + sep[1] = 'o'; + sep[2] = '\0'; + } + } else { + C.outfile = "/dev/null"; + } + } + + initlx(&lx); + initp(&p); + + lx.io = openio(&lx, path); + lx.pos = (Pos){ + .path = path, + .line = 1, + .col = 1, + }; + + err = parse(&p, &lx); + freelx(&lx); + return err; +} + +error +main(int argc, byte *argv[]) +{ + byte *a, *src; + int err; + + init(); + + ARGBEGIN { + case 'o': + C.outfile = ARGF(); + break; + + case 'D': + a = ARGF(); + if (a) { + intern(&a); + if (C.def.len >= C.def.cap) { + C.def.cap += 20; + C.def.val = realloc(C.def.val, C.def.cap * sizeof(*C.def.val)); + } + C.def.val[C.def.len++] = a; + } + break; + + case 'I': + a = ARGF(); + if (a) + pushinclude(a); + break; + } ARGEND + + if (argc < 1 && C.outfile == nil) { + printf("usage: cc [-options] files\n"); + exit(1); + } + + // NOTE: This is just for my comfort during debugging. + pushinclude("/home/nolln/root/include"); + pushinclude("/home/nolln/root/include/vendor/libc"); + + src = (argc == 0) ? "" : argv[0]; + intern(&src); + + if ((err = compile(src)), err) { + exit(2); + } + + exit(0); +} -- cgit v1.2.1