diff --git a/Makefile b/Makefile index 144a6f2..984d873 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ -larpcc: main.c lex.c preproc.c collection.c parse.c ast_print.c resolve.c +larpcc: main.c lex.c preproc.c collection.c parse.c ast_print.c resolve.c sema.c gcc $^ -o $@ -std=c23 -pedantic -Wall -Wextra -g -fsanitize=address -Werror=switch diff --git a/examples/hello.c b/examples/hello.c index 6daaf9f..576d6ab 100644 --- a/examples/hello.c +++ b/examples/hello.c @@ -1,6 +1,6 @@ #include "not_stdio.h" -int main() +int main(void) { puts("hello world"); } diff --git a/lex.c b/lex.c index 620aefd..4cb9eab 100644 --- a/lex.c +++ b/lex.c @@ -86,6 +86,8 @@ const char* tokty_str(TokTy ty) return "KwChar"; case Tok_KwConst: return "KwConst"; + case Tok_KwVoid: + return "KwVoid"; case Tok_EndOfMacroInvocation: return "EndOfMacroInvocation"; } diff --git a/main.c b/main.c index 249ec30..a37ad38 100644 --- a/main.c +++ b/main.c @@ -2,6 +2,7 @@ #include "collection.h" #include "parse.h" #include "resolve.h" +#include "sema.h" #include #include #include @@ -71,16 +72,18 @@ int main(int argc, char* argv[]) TokStream tokstream; tokstream_init(&tokstream, preproc, &tok_arena); + Sema* sema = sema_new(); + Arena ast_arena; arena_init(&ast_arena, 4096); printf("--- ast ---\n"); - Parser* parser = parser_new(&tokstream, &ast_arena); + Parser* parser = parser_new(&tokstream, sema, &ast_arena); - Arena sym_arena; - arena_init(&sym_arena, 4096); - Resolver* resolver = resolver_new(&sym_arena); + // Arena sym_arena; + // arena_init(&sym_arena, 4096); + // Resolver* resolver = resolver_new(&sym_arena); AstStmt* stmt; while (!parser_done(parser)) { @@ -90,16 +93,18 @@ int main(int argc, char* argv[]) printf("\n"); - resolver_resolve_top_stmt(resolver, stmt); + // resolver_resolve_top_stmt(resolver, stmt); } - resolver_free(resolver); + // resolver_free(resolver); parser_free(parser); - preproc_free(preproc); arena_deinit(&tok_arena); + arena_deinit(&ast_arena); - arena_deinit(&sym_arena); + // arena_deinit(&sym_arena); + + sema_free(sema); } } diff --git a/parse.c b/parse.c index e04e379..88b891a 100644 --- a/parse.c +++ b/parse.c @@ -2,6 +2,7 @@ #include "ast.h" #include "collection.h" #include "resolve.h" +#include "sema.h" #include #include #include @@ -115,6 +116,7 @@ static void kwmatcher_init(KwMatcher* m, TokStream* tokstream) { Tok_KwInt, "int" }, { Tok_KwChar, "char" }, { Tok_KwConst, "const" }, + { Tok_KwVoid, "void" }, }; for (size_t i = 0; i < sizeof(kws) / sizeof(kws[0]); ++i) { @@ -150,6 +152,7 @@ typedef enum : unsigned int { struct Parser { KwMatcher kwmatcher; + Sema* sema; Arena* arena; Arena sym_arena; @@ -160,12 +163,13 @@ struct Parser { ParserFlags flags; }; -Parser* parser_new(TokStream* tokstream, Arena* arena) +Parser* parser_new(TokStream* tokstream, Sema* sema, Arena* arena) { Parser* p = malloc(sizeof(Parser)); *p = (Parser) { .kwmatcher = { }, + .sema = sema, .arena = arena, .sym_arena = { }, @@ -194,20 +198,21 @@ static void step(Parser* p) p->curr = kwmatcher_next(&p->kwmatcher); } -#define DEFINE_NEW(TYPE, FN_NAME) \ +#define DEFINE_NEW(TYPE, FN_NAME, POST) \ [[maybe_unused]] static TYPE* new_##FN_NAME(Parser* p, TYPE init) \ { \ TYPE* val = arena_alloc(p->arena, sizeof(TYPE)); \ *val = init; \ + POST; \ return val; \ } -DEFINE_NEW(AstStmt, stmt) -DEFINE_NEW(AstDecl, decl) -DEFINE_NEW(AstDeclar, declar) -DEFINE_NEW(AstExpr, expr) +DEFINE_NEW(AstStmt, stmt, { sema_visit_stmt(p->sema, val); }) +DEFINE_NEW(AstDecl, decl, { }) +DEFINE_NEW(AstDeclar, declar, { }) +DEFINE_NEW(AstExpr, expr, { sema_visit_expr(p->sema, val); }) -DEFINE_NEW(AstStmtBlock, stmt_block) +DEFINE_NEW(AstStmtBlock, stmt_block, { }) static AstStmtBlock* parse_stmt_block(Parser* p); static AstStmt* parse_stmt(Parser* p); @@ -260,8 +265,8 @@ static bool is_defty_ident(Parser* p, Tok tok) { if (tok.ty != Tok_Ident) return false; - Sym* sym = syms_get(p->syms, tok.text); - return sym && sym->ty == Sym_Typedef; + OldSym* sym = syms_get(p->syms, tok.text); + return sym && sym->ty == OldSym_Typedef; } static AstStmt* parse_stmt(Parser* p) @@ -322,7 +327,11 @@ static AstDecl* parse_decl(Parser* p, bool is_param) bool multi_allowed = !is_param; if (!is_param && first->ty == AstDeclar_Function && p->curr.ty == '{') { + + sema_function_enter(p->sema, declars[0]); function_body = parse_stmt_block(p); + sema_function_leave(p->sema); + multi_allowed = false; } @@ -432,7 +441,9 @@ static AstDeclar* parse_declar_l3(Parser* p) ARRAY_VAR(AstDecl*, params); - if (p->curr.ty != Tok_Eof && p->curr.ty != ')') { + if (p->curr.ty == Tok_KwVoid) { + step(p); + } else if (p->curr.ty != Tok_Eof && p->curr.ty != ')') { AstDecl* d = parse_decl(p, true); ARENA_ARRAY_VAR_PUSH(p->arena, params, &d); @@ -509,8 +520,8 @@ static AstSpec parse_decl_spec(Parser* p) while (true) { switch (p->curr.ty) { case Tok_Ident: { - Sym* sym = syms_get(p->syms, p->curr.text); - if (!sym || sym->ty != Sym_Typedef) + OldSym* sym = syms_get(p->syms, p->curr.text); + if (!sym || sym->ty != OldSym_Typedef) break; spec |= AstSpec_DefTy; step(p); diff --git a/parse.h b/parse.h index 8b0d529..ad2a877 100644 --- a/parse.h +++ b/parse.h @@ -3,6 +3,7 @@ #include "ast.h" #include "collection.h" +#include "sema.h" #include char* read_textfile(const char* filename); @@ -47,6 +48,7 @@ typedef enum { Tok_Char, Tok_Whitespace, Tok_HeaderName, + Tok_Eol = '\n', // NOTE: has value 10 Tok_Semicolon = ';', Tok_LParen = '(', @@ -57,12 +59,14 @@ typedef enum { Tok_Asterisk = '*', Tok_Hashtag = '#', - Tok_KwInt, + Tok_KwInt = 256, Tok_KwChar, Tok_KwConst, + Tok_KwVoid, // used internally in preprocessor Tok_EndOfMacroInvocation, + } TokTy; const char* tokty_str(TokTy ty); @@ -105,7 +109,7 @@ Tok tokstream_next(TokStream* s); typedef struct Parser Parser; -Parser* parser_new(TokStream* tokstream, Arena* arena); +Parser* parser_new(TokStream* tokstream, Sema* sema, Arena* arena); void parser_free(Parser* p); AstStmt* parser_parse_stmt(Parser* p); bool parser_done(Parser* p); diff --git a/resolve.c b/resolve.c index 60a21e0..5cab692 100644 --- a/resolve.c +++ b/resolve.c @@ -17,7 +17,7 @@ Syms* syms_new() }; ARRAY_FIELD_PUSH(s, maps, &(Hashmap) { }); - hashmap_init(&s->maps[0], sizeof(Sym*)); + hashmap_init(&s->maps[0], sizeof(OldSym*)); return s; } @@ -33,7 +33,7 @@ void syms_free(Syms* s) void syms_push_scope(Syms* s) { ARRAY_FIELD_PUSH(s, maps, &(Hashmap) { }); - hashmap_init(&s->maps[s->maps_size - 1], sizeof(Sym*)); + hashmap_init(&s->maps[s->maps_size - 1], sizeof(OldSym*)); } void syms_pop_scope(Syms* s) @@ -43,60 +43,21 @@ void syms_pop_scope(Syms* s) s->maps_size -= 1; } -void syms_define(Syms* s, const char* ident, Sym* sym) +void syms_define(Syms* s, const char* ident, OldSym* sym) { Hashmap* m = &s->maps[s->maps_size - 1]; hashmap_set(m, ident, &sym); } -Sym* syms_get(Syms* s, const char* ident) +OldSym* syms_get(Syms* s, const char* ident) { - Sym** res; + OldSym** res; for (size_t i = 0; i < s->maps_size; ++i) if ((res = hashmap_get(&s->maps[s->maps_size - i - 1], ident))) return *res; return nullptr; } -static void print_sym(Sym* s) -{ - switch (s->ty) { - case Sym_Typedef: - printf("Typedef"); - break; - case Sym_Declarator: - printf("Declarator"); - break; - } -} - -struct SymPrinter { - int depth; -}; - -static void print_sym_hashmap(void* self, const char* key, void* val) -{ - struct SymPrinter* p = self; - Sym* sym = *(Sym**)val; - - printf(" "); - for (int i = 0; i < p->depth; ++i) - printf(" "); - printf("'%s' -> ", key); - print_sym(sym); - printf("\n"); -} - -void syms_print(Syms* s) -{ - for (size_t i = 0; i < s->maps_size; ++i) { - struct SymPrinter p = { - .depth = i, - }; - hashmap_for_each(&s->maps[i], print_sym_hashmap, &p); - } -} - typedef enum : unsigned int { ResolverFlags_InTypedef, } ResolverFlags; @@ -130,7 +91,7 @@ Resolver* resolver_new(Arena* arena) .flags = 0, }; - keymap_init(&r->resol_map, sizeof(Sym*)); + keymap_init(&r->resol_map, sizeof(OldSym*)); return r; } @@ -226,9 +187,9 @@ static AstVisitorResult visit_declar(AstVisitor* v, AstDeclar* node) if (node->ty == AstDeclar_Ident) { assert(r->current_decl_stmt); - Sym* sym = arena_alloc(r->arena, sizeof(Sym)); - *sym = (Sym) { - .ty = Sym_Declarator, + OldSym* sym = arena_alloc(r->arena, sizeof(OldSym)); + *sym = (OldSym) { + .ty = OldSym_Declarator, .declarator = { .stmt = r->current_decl_stmt, .declar = node, @@ -247,15 +208,12 @@ static AstVisitorResult visit_expr(AstVisitor* v, AstExpr* node) if (node->ty == AstExpr_Ident) { - Sym* sym = syms_get(r->ord_syms, node->ident); + OldSym* sym = syms_get(r->ord_syms, node->ident); if (!sym) { fprintf(stderr, "error: use of undeclared '%s' on line %d\n", node->ident, node->loc.line); - - syms_print(r->ord_syms); - exit(1); } } diff --git a/resolve.h b/resolve.h index aadb17a..d5bd7b6 100644 --- a/resolve.h +++ b/resolve.h @@ -5,19 +5,19 @@ #include "collection.h" typedef enum { - Sym_Typedef, - Sym_Declarator, -} SymTy; + OldSym_Typedef, + OldSym_Declarator, +} OldSymTy; typedef struct { - SymTy ty; + OldSymTy ty; union { struct { AstStmt* stmt; AstDeclar* declar; } declarator; }; -} Sym; +} OldSym; typedef struct Syms Syms; @@ -27,8 +27,8 @@ void syms_free(Syms* s); void syms_push_scope(Syms* s); void syms_pop_scope(Syms* s); -void syms_define(Syms* s, const char* ident, Sym* sym); -Sym* syms_get(Syms* s, const char* ident); +void syms_define(Syms* s, const char* ident, OldSym* sym); +OldSym* syms_get(Syms* s, const char* ident); typedef struct Resolver Resolver; diff --git a/sema.c b/sema.c new file mode 100644 index 0000000..5ef46f6 --- /dev/null +++ b/sema.c @@ -0,0 +1,106 @@ +#include "sema.h" +#include "ast.h" +#include "collection.h" +#include +#include + +typedef struct { + Hashmap ord_syms; + Hashmap tag_syms; +} Rib; + +static void rib_init(Rib* r) +{ + *r = (Rib) { + .ord_syms = { }, + .tag_syms = { }, + }; + hashmap_init(&r->ord_syms, sizeof(Sym*)); + hashmap_init(&r->tag_syms, sizeof(Sym*)); +} + +static void rib_deinit(Rib* r) +{ + hashmap_deinit(&r->ord_syms); + hashmap_deinit(&r->tag_syms); +} + +struct Sema { + Arena sym_arena; + ARRAY_FIELD(Rib, ribs); + Hashmap labels; +}; + +Sema* sema_new(void) +{ + Sema* s = malloc(sizeof(Sema)); + *s = (Sema) { + .sym_arena = { }, + ARRAY_FIELD_INIT(ribs), + .labels = { }, + }; + + arena_init(&s->sym_arena, 1024); + + ARRAY_FIELD_PUSH(s, ribs, (&(Rib) { })); + rib_init(&s->ribs[0]); + + hashmap_init(&s->labels, sizeof(LabelSym*)); + + return s; +} + +void sema_free(Sema* s) +{ + arena_deinit(&s->sym_arena); + for (size_t i = 0; i < s->ribs_size; ++i) + rib_deinit(&s->ribs[i]); + if (s->ribs) + free(s->ribs); + hashmap_deinit(&s->labels); + free(s); +} + +void sema_scope_enter(Sema* s) +{ + ARRAY_FIELD_PUSH(s, ribs, (&(Rib) { })); + rib_init(&s->ribs[s->ribs_size - 1]); +} + +void sema_scope_leave(Sema* s) +{ + assert(s->ribs_size > 0); + rib_deinit(&s->ribs[s->ribs_size - 1]); + s->ribs_size -= 1; +} + +void sema_function_enter(Sema* s, AstDeclar* declar) +{ + assert(declar->ty == AstDeclar_Function); + + // clear label map + hashmap_deinit(&s->labels); + hashmap_init(&s->labels, sizeof(LabelSym*)); + + sema_scope_enter(s); + + for (size_t i = 0; i < declar->function.params_size; ++i) { } +} + +void sema_function_leave(Sema* s) +{ + sema_scope_leave(s); +} + +void sema_visit_function_declar(Sema* s, AstDeclar* declar) +{ +} + +void sema_visit_stmt(Sema* s, AstStmt* stmt) +{ + if (stmt->ty == AstStmt_Decl) { } +} + +void sema_visit_expr(Sema* s, AstExpr* expr) +{ +} diff --git a/sema.h b/sema.h new file mode 100644 index 0000000..f278eb0 --- /dev/null +++ b/sema.h @@ -0,0 +1,31 @@ +#ifndef SEMA_H +#define SEMA_H + +#include "ast.h" +typedef enum { + Sym_Declar, +} SymTy; + +typedef struct { + SymTy ty; +} Sym; + +typedef struct { + int _; +} LabelSym; + +typedef struct Sema Sema; + +Sema* sema_new(void); +void sema_free(Sema* s); + +void sema_scope_enter(Sema* s); +void sema_scope_leave(Sema* s); + +void sema_function_enter(Sema* s, AstDeclar* declar); +void sema_function_leave(Sema* s); + +void sema_visit_stmt(Sema* s, AstStmt* stmt); +void sema_visit_expr(Sema* s, AstExpr* expr); + +#endif