From e45e72249fd48e58e30531397dfa01e31437a260 Mon Sep 17 00:00:00 2001 From: sfja Date: Tue, 20 Oct 2026 01:27:50 +0200 Subject: [PATCH] make parser and sema work --- Makefile | 12 +- ast.h | 12 +- ast_print.c | 5 + collection.c | 2 +- diagnostics.c | 18 +++ diagnostics.h | 12 ++ examples/not_stdio.h | 2 +- lex.c | 296 ---------------------------------- main.c | 13 +- parse.c | 143 +++++++---------- parse.h | 119 ++++---------- preproc.c | 372 ++++++++++++++++++++++++++++++++++++++----- preproc.h | 110 +++++++++++++ resolve.c | 58 +++---- resolve.h | 20 +-- sema.c | 95 +++++++++-- 16 files changed, 709 insertions(+), 580 deletions(-) create mode 100644 diagnostics.c create mode 100644 diagnostics.h delete mode 100644 lex.c create mode 100644 preproc.h diff --git a/Makefile b/Makefile index 984d873..ee8049c 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,13 @@ -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 +CFLAGS := -std=c23 -pedantic -Wall -Wextra -g -Werror=switch + +# CFLAGS += -fsanitize=address + +c_files := $(wildcard *.c) +h_files := $(wildcard *.h) + + +larpcc: $(c_files) $(h_files) + gcc $(c_files) -o $@ -std=c23 -pedantic -Wall -Wextra -g -Werror=switch diff --git a/ast.h b/ast.h index ec2d0fa..613a1bf 100644 --- a/ast.h +++ b/ast.h @@ -2,13 +2,9 @@ #define AST_H #include "collection.h" +#include "diagnostics.h" #include -typedef struct { - int line; - int col; -} Loc; - typedef struct AstStmt AstStmt; typedef struct AstDecl AstDecl; typedef struct AstDeclar AstDeclar; @@ -19,6 +15,7 @@ typedef struct AstStmtBlock AstStmtBlock; struct AstStmtBlock { ARRAY_FIELD(AstStmt*, stmts); Loc loc; + int id; }; typedef struct AstDeclBlock AstDeclBlock; @@ -36,6 +33,7 @@ typedef enum { struct AstStmt { AstStmtTy ty; Loc loc; + int id; union { AstDecl* decl; AstExpr* expr; @@ -63,9 +61,11 @@ struct AstDecl { ARRAY_FIELD(AstDeclar*, declars); AstStmtBlock* function_body; Loc loc; + int id; }; typedef enum { + AstDeclar_Anon, AstDeclar_Ident, AstDeclar_Pointer, AstDeclar_Array, @@ -75,6 +75,7 @@ typedef enum { struct AstDeclar { AstDeclarTy ty; Loc loc; + int id; AstExpr* init_expr; union { char* ident; @@ -102,6 +103,7 @@ typedef enum { struct AstExpr { AstExprTy ty; Loc loc; + int id; union { char* ident; char* str_val; diff --git a/ast_print.c b/ast_print.c index fd4334a..bf88c4b 100644 --- a/ast_print.c +++ b/ast_print.c @@ -137,6 +137,10 @@ void ast_decl_print(FILE* f, const AstDecl* node, int depth) void ast_declar_print(FILE* f, const AstDeclar* node, int depth) { switch (node->ty) { + case AstDeclar_Anon: { + fprintf(f, "Declar::Anon %d:%d", node->loc.line, node->loc.col); + return; + } case AstDeclar_Ident: { fprintf( f, "Declar::Ident %d:%d {\n", node->loc.line, node->loc.col); @@ -329,6 +333,7 @@ void ast_declar_visit(AstVisitor* v, AstDeclar* node) void ast_declar_visit_body(AstVisitor* v, AstDeclar* node) { switch (node->ty) { + case AstDeclar_Anon: case AstDeclar_Ident: break; case AstDeclar_Pointer: diff --git a/collection.c b/collection.c index 9ff0618..5993af3 100644 --- a/collection.c +++ b/collection.c @@ -240,7 +240,7 @@ struct KeymapEntry { void keymap_init(Keymap* m, size_t elem_size) { - size_t entry_size = sizeof(KeymapEntry) + (elem_size + 7ul & ~7ul); + size_t entry_size = sizeof(KeymapEntry) + ((elem_size + 7ul) & ~7ul); *m = (Keymap) { ARRAY_FIELD_INIT(entries), diff --git a/diagnostics.c b/diagnostics.c new file mode 100644 index 0000000..bbff64b --- /dev/null +++ b/diagnostics.c @@ -0,0 +1,18 @@ +#include "diagnostics.h" +#include +#include + +void diag_error(Loc loc, const char* fmt, ...) +{ + va_list va; + va_start(va, fmt); + + fprintf(stderr, + "\x1b[1;97m%s:%d:%d: \x1b[1;91merror: \x1b[0m\n", + loc.file, + loc.line, + loc.col); + vfprintf(stderr, fmt, va); + + va_end(va); +} diff --git a/diagnostics.h b/diagnostics.h new file mode 100644 index 0000000..14f5898 --- /dev/null +++ b/diagnostics.h @@ -0,0 +1,12 @@ +#ifndef DIAGNOSTICS_H +#define DIAGNOSTICS_H + +typedef struct { + int line; + int col; + const char* file; +} Loc; + +void diag_error(Loc loc, const char* fmt, ...); + +#endif diff --git a/examples/not_stdio.h b/examples/not_stdio.h index 3107203..8e6ee9a 100644 --- a/examples/not_stdio.h +++ b/examples/not_stdio.h @@ -1,6 +1,6 @@ #ifndef NOT_STDIO_H #define NOT_STDIO_H -int puts(const char* __s); +int puts(const char*); #endif diff --git a/lex.c b/lex.c deleted file mode 100644 index 4cb9eab..0000000 --- a/lex.c +++ /dev/null @@ -1,296 +0,0 @@ -#include "collection.h" -#include "parse.h" -#include -#include -#include -#include -#include -#include - -char* read_textfile(const char* filename) -{ - FILE* fp = fopen(filename, "r"); - if (!fp) { - goto couldnt_read_file; - } - - if (fseek(fp, 0, SEEK_END) != 0) { - goto couldnt_read_file; - } - - long file_size = ftell(fp); - if (file_size < 0) { - goto couldnt_read_file; - } - - if (fseek(fp, 0, SEEK_SET) != 0) { - goto couldnt_read_file; - } - - char* buffer = malloc(file_size + 1); - assert(buffer); - - if (fread(buffer, sizeof(char), file_size, fp) != (size_t)file_size) { - goto couldnt_read_file; - } - - buffer[file_size] = '\0'; - return buffer; - -couldnt_read_file: - fprintf(stderr, - "error: couldn't read file '%s': %s\n", - filename, - strerror(errno)); - return nullptr; -} - -const char* tokty_str(TokTy ty) -{ - switch (ty) { - case Tok_Eof: - return "Eof"; - case Tok_Ident: - return "Ident"; - case Tok_Int: - return "Int"; - case Tok_Str: - return "Str"; - case Tok_Char: - return "Char"; - case Tok_Whitespace: - return "Whitespace"; - case Tok_HeaderName: - return "HeaderName"; - case Tok_Eol: - return "Eol"; - case Tok_Semicolon: - return "Semicolon"; - case Tok_LParen: - return "LParen"; - case Tok_RParen: - return "RParen"; - case Tok_LBrace: - return "LBrace"; - case Tok_RBrace: - return "RBrace"; - case Tok_Asterisk: - return "Asterisk"; - case Tok_Hashtag: - return "Hashtag"; - case Tok_Comma: - return "Comma"; - case Tok_KwInt: - return "KwInt"; - case Tok_KwChar: - return "KwChar"; - case Tok_KwConst: - return "KwConst"; - case Tok_KwVoid: - return "KwVoid"; - case Tok_EndOfMacroInvocation: - return "EndOfMacroInvocation"; - } - return ""; -} - -void source_iter_init(SourceIter* r, const char* text) -{ - *r = (SourceIter) { - .text = text, - .i = 0, - .line = 1, - .col = 1, - }; -} - -Char source_iter_next(SourceIter* r) -{ - char ch = r->text[r->i]; - Loc loc = { r->line, r->col }; - - if (r->text[r->i] != '\0') { - if (ch == '\n') { - r->line += 1; - r->col = 1; - } else { - r->col += 1; - } - r->i += 1; - } - - return (Char) { ch, loc }; -} - -void lsl_iter_init(LslIter* r, SourceIter* source_char_iter) -{ - Char curr = source_iter_next(source_char_iter); - - *r = (LslIter) { - .source_char_iter = source_char_iter, - .curr = curr, - }; -} - -Char lsl_iter_next(LslIter* r) -{ - Char next = source_iter_next(r->source_char_iter); - - if (r->curr.ch == '\\' && next.ch == '\n') { - r->curr = source_iter_next(r->source_char_iter); - return lsl_iter_next(r); - } - - Char curr = r->curr; - r->curr = next; - return curr; -} - -void lexer_init(Lexer* r, LslIter* lsl_char_iter, Arena* arena) -{ - Char curr = lsl_iter_next(lsl_char_iter); - - *r = (Lexer) { - .lsl_iter = lsl_char_iter, - .arena = arena, - .curr = curr, - .lex_whitespace = false, - .lex_headername = false, - }; -} - -static Tok tok(Lexer* l, TokTy ty, const char* text, Loc loc) -{ - char* text_dup = arena_alloc(l->arena, strlen(text) + 1); - text_dup[0] = '\0'; - strcpy(text_dup, text); - - return (Tok) { ty, text_dup, loc }; -} - -static bool done(Lexer* l) -{ - return l->curr.ch == '\0'; -} - -constexpr size_t max_token_text_len = 64; - -static void step(Lexer* l, char text[], size_t* text_len) -{ - assert(*text_len < max_token_text_len); - text[*text_len] = l->curr.ch; - *text_len += 1; - - l->curr = lsl_iter_next(l->lsl_iter); -} - -Tok lexer_next(Lexer* l) -{ - Loc loc = l->curr.loc; - - char text[max_token_text_len] = ""; - size_t text_len = 0; - - if (done(l)) { - return tok(l, Tok_Eof, text, loc); - } - - bool matched = false; - while (strchr(" \t\r", l->curr.ch)) { - matched = true; - step(l, text, &text_len); - } - if (matched) { - if (l->lex_whitespace) { - return tok(l, Tok_Whitespace, text, loc); - } - return lexer_next(l); - } - - while ((l->curr.ch >= 'a' && l->curr.ch <= 'z') - || (l->curr.ch >= 'A' && l->curr.ch <= 'Z') - || (matched && l->curr.ch >= '0' && l->curr.ch <= '9') - || strchr("_", l->curr.ch)) { - matched = true; - step(l, text, &text_len); - } - if (matched) { - return tok(l, Tok_Ident, text, loc); - } - - while ((l->curr.ch >= '1' && l->curr.ch <= '9') - || (matched && l->curr.ch == '0')) { - matched = true; - step(l, text, &text_len); - } - if (matched) { - return tok(l, Tok_Int, text, loc); - } - - if (l->lex_headername && (l->curr.ch == '"' || l->curr.ch == '<')) { - char ter = l->curr.ch == '<' ? '>' : '"'; - step(l, text, &text_len); - while (l->curr.ch != '\0' && l->curr.ch != '\n' && l->curr.ch != ter) { - step(l, text, &text_len); - } - if (l->curr.ch != ter) { - fprintf(stderr, - "error: malformed header name, expected '%c' on line %d\n", - ter, - l->curr.loc.line); - return lexer_next(l); - } - step(l, text, &text_len); - return tok(l, Tok_HeaderName, text, loc); - } - - if (l->curr.ch == '"') { - step(l, text, &text_len); - while (l->curr.ch != '"') { - if (l->curr.ch == '\\') { - step(l, text, &text_len); - if (done(l)) - break; - } - step(l, text, &text_len); - } - if (done(l) || l->curr.ch != '"') { - fprintf(stderr, - "error: malformed string literal on line %d\n", - l->curr.loc.line); - return lexer_next(l); - } - step(l, text, &text_len); - return tok(l, Tok_Str, text, loc); - } - - if (l->curr.ch == '\'') { - step(l, text, &text_len); - if (l->curr.ch == '\\') { - step(l, text, &text_len); - } - if (!done(l)) { - step(l, text, &text_len); - } - if (done(l) && l->curr.ch != '\'') { - fprintf(stderr, - "error: malformed character literal on line %d\n", - l->curr.loc.line); - return lexer_next(l); - } - step(l, text, &text_len); - return tok(l, Tok_Char, text, loc); - } - - if (strchr("\n;(){},*#", l->curr.ch)) { - TokTy ty = (TokTy)l->curr.ch; - step(l, text, &text_len); - return tok(l, ty, text, loc); - } - fprintf(stderr, - "error: illegal character '%c' on line %d\n", - l->curr.ch, - l->curr.loc.line); - step(l, text, &text_len); - return lexer_next(l); -} diff --git a/main.c b/main.c index a37ad38..d589c0b 100644 --- a/main.c +++ b/main.c @@ -1,7 +1,7 @@ #include "ast.h" #include "collection.h" #include "parse.h" -#include "resolve.h" +#include "preproc.h" #include "sema.h" #include #include @@ -36,7 +36,7 @@ int main(int argc, char* argv[]) printf("--- tokens ---\n"); - Loc loc = { 1, 1 }; + Loc loc = { 1, 1, nullptr }; Tok tok; while ((tok = tokstream_next(&tokstream)).ty != Tok_Eof) { // printf("%s\t%s\n", tokty_str(tok.ty), tok.text); @@ -79,15 +79,16 @@ int main(int argc, char* argv[]) printf("--- ast ---\n"); - Parser* parser = parser_new(&tokstream, sema, &ast_arena); + Parser parser; + parser_init(&parser, &tokstream, sema, &ast_arena); // Arena sym_arena; // arena_init(&sym_arena, 4096); // Resolver* resolver = resolver_new(&sym_arena); AstStmt* stmt; - while (!parser_done(parser)) { - stmt = parser_parse_stmt(parser); + while (!parser_done(&parser)) { + stmt = parser_parse_stmt(&parser); ast_stmt_print(stdout, stmt, 0); @@ -98,7 +99,7 @@ int main(int argc, char* argv[]) // resolver_free(resolver); - parser_free(parser); + parser_deinit(&parser); preproc_free(preproc); arena_deinit(&tok_arena); diff --git a/parse.c b/parse.c index 0de34b9..e3918cd 100644 --- a/parse.c +++ b/parse.c @@ -9,23 +9,6 @@ #include #include -typedef struct { - char ch; - bool is_term; - unsigned short val; -} KwNodeOpt; - -typedef struct { - ARRAY_FIELD(KwNodeOpt, opts); - size_t idx; -} KwNode; - -typedef struct { - TokStream* tokstream; - Arena arena; - ARRAY_FIELD(KwNode, nodes); -} KwMatcher; - static KwNodeOpt* kwmatcher_create_path( KwMatcher* m, size_t node_idx, const char* kw) { @@ -97,7 +80,7 @@ static TokTy kwmatcher_match(KwMatcher* m, const char* kw) return opt->val; } -static void kwmatcher_init(KwMatcher* m, TokStream* tokstream) +void kwmatcher_init(KwMatcher* m, TokStream* tokstream) { *m = (KwMatcher) { .tokstream = tokstream, @@ -124,12 +107,12 @@ static void kwmatcher_init(KwMatcher* m, TokStream* tokstream) } } -static void kwmatcher_deinit(KwMatcher* m) +void kwmatcher_deinit(KwMatcher* m) { arena_deinit(&m->arena); } -static Tok kwmatcher_next(KwMatcher* m) +Tok kwmatcher_next(KwMatcher* m) { Tok tok = tokstream_next(m->tokstream); if (tok.ty != Tok_Ident) @@ -138,42 +121,30 @@ static Tok kwmatcher_next(KwMatcher* m) tok.ty = ty; exit: - printf(" - %-10s %-10s %d:%d\n", - tokty_str(tok.ty), - tok.text, - tok.loc.line, - tok.loc.col); + // printf(" - %-10s %-10s %d:%d\n", + // tokty_str(tok.ty), + // tok.text, + // tok.loc.line, + // tok.loc.col); return tok; } -typedef enum : unsigned int { - ParserFlags_ParsingTypedef = 1 << 0, -} ParserFlags; +static AstStmtBlock* parse_stmt_block(Parser* p); +static AstStmt* parse_stmt(Parser* p); +static AstDecl* parse_decl(Parser* p, bool is_param); +static AstDeclar* parse_declar(Parser* p, bool allow_anon); +static AstSpec parse_decl_spec(Parser* p); +static AstExpr* parse_expr(Parser* p); -struct Parser { - KwMatcher kwmatcher; - Sema* sema; - Arena* arena; - Arena sym_arena; - - Syms* syms; - - Tok curr; - - ParserFlags flags; -}; - -Parser* parser_new(TokStream* tokstream, Sema* sema, Arena* arena) +void parser_init(Parser* p, TokStream* tokstream, Sema* sema, Arena* arena) { - Parser* p = malloc(sizeof(Parser)); - *p = (Parser) { .kwmatcher = { }, .sema = sema, .arena = arena, .sym_arena = { }, - .syms = syms_new(), + .old_syms = oldsyms_new(), .curr = { }, @@ -182,15 +153,22 @@ Parser* parser_new(TokStream* tokstream, Sema* sema, Arena* arena) kwmatcher_init(&p->kwmatcher, tokstream); p->curr = kwmatcher_next(&p->kwmatcher); - - return p; } -void parser_free(Parser* p) +void parser_deinit(Parser* p) { kwmatcher_deinit(&p->kwmatcher); - syms_free(p->syms); - free(p); + oldsyms_free(p->old_syms); +} + +AstStmt* parser_parse_stmt(Parser* p) +{ + return parse_stmt(p); +} + +bool parser_done(Parser* p) +{ + return p->curr.ty == Tok_Eof; } static void step(Parser* p) @@ -203,6 +181,8 @@ static void step(Parser* p) { \ TYPE* val = arena_alloc(p->arena, sizeof(TYPE)); \ *val = init; \ + static int ids = 0; \ + val->id = ids++; \ POST; \ return val; \ } @@ -214,13 +194,6 @@ DEFINE_NEW(AstExpr, expr, { sema_visit_expr(p->sema, val); }) DEFINE_NEW(AstStmtBlock, stmt_block, { }) -static AstStmtBlock* parse_stmt_block(Parser* p); -static AstStmt* parse_stmt(Parser* p); -static AstDecl* parse_decl(Parser* p, bool is_param); -static AstDeclar* parse_declar(Parser* p); -static AstSpec parse_decl_spec(Parser* p); -static AstExpr* parse_expr(Parser* p); - static AstStmtBlock* parse_stmt_block(Parser* p) { Loc loc = p->curr.loc; @@ -265,7 +238,7 @@ static bool is_defty_ident(Parser* p, Tok tok) { if (tok.ty != Tok_Ident) return false; - OldSym* sym = syms_get(p->syms, tok.text); + OldSym* sym = oldsyms_get(p->old_syms, tok.text); return sym && sym->ty == OldSym_Typedef; } @@ -319,7 +292,7 @@ static AstDecl* parse_decl(Parser* p, bool is_param) ARRAY_VAR(AstDeclar*, declars); - AstDeclar* first = parse_declar(p); + AstDeclar* first = parse_declar(p, is_param); ARENA_ARRAY_VAR_PUSH(p->arena, declars, &first); @@ -338,7 +311,7 @@ static AstDecl* parse_decl(Parser* p, bool is_param) while (multi_allowed && p->curr.ty == ',') { step(p); - AstDeclar* declar = parse_declar(p); + AstDeclar* declar = parse_declar(p, false); ARENA_ARRAY_VAR_PUSH(p->arena, declars, &declar); } @@ -356,14 +329,14 @@ static AstDecl* parse_decl(Parser* p, bool is_param) }); } -static AstDeclar* parse_declar_l1(Parser* p); -static AstDeclar* parse_declar_l2(Parser* p); -static AstDeclar* parse_declar_l3(Parser* p); -static AstDeclar* parse_declar_l4(Parser* p); +static AstDeclar* parse_declar_l1(Parser* p, bool allow_anon); +static AstDeclar* parse_declar_l2(Parser* p, bool allow_anon); +static AstDeclar* parse_declar_l3(Parser* p, bool allow_anon); +static AstDeclar* parse_declar_l4(Parser* p, bool allow_anon); -static AstDeclar* parse_declar(Parser* p) +static AstDeclar* parse_declar(Parser* p, bool allow_anon) { - AstDeclar* declar = parse_declar_l1(p); + AstDeclar* declar = parse_declar_l1(p, allow_anon); if (p->curr.ty == '=') { step(p); @@ -374,7 +347,7 @@ static AstDeclar* parse_declar(Parser* p) return declar; } -static AstDeclar* parse_declar_l1(Parser* p) +static AstDeclar* parse_declar_l1(Parser* p, bool allow_anon) { Loc loc = p->curr.loc; @@ -383,7 +356,7 @@ static AstDeclar* parse_declar_l1(Parser* p) AstSpec spec = parse_decl_spec(p); - AstDeclar* declar = parse_declar_l1(p); + AstDeclar* declar = parse_declar_l1(p, allow_anon); return new_declar(p, (AstDeclar) { .ty = AstDeclar_Pointer, @@ -395,14 +368,14 @@ static AstDeclar* parse_declar_l1(Parser* p) }); } - return parse_declar_l2(p); + return parse_declar_l2(p, allow_anon); } -static AstDeclar* parse_declar_l2(Parser* p) +static AstDeclar* parse_declar_l2(Parser* p, bool allow_anon) { Loc loc = p->curr.loc; - AstDeclar* declar = parse_declar_l3(p); + AstDeclar* declar = parse_declar_l3(p, allow_anon); while (p->curr.ty == '[') { step(p); @@ -430,11 +403,11 @@ static AstDeclar* parse_declar_l2(Parser* p) return declar; } -static AstDeclar* parse_declar_l3(Parser* p) +static AstDeclar* parse_declar_l3(Parser* p, bool allow_anon) { Loc loc = p->curr.loc; - AstDeclar* declar = parse_declar_l4(p); + AstDeclar* declar = parse_declar_l4(p, allow_anon); if (p->curr.ty == '(') { step(p); @@ -478,10 +451,18 @@ static AstDeclar* parse_declar_l3(Parser* p) return declar; } -static AstDeclar* parse_declar_l4(Parser* p) +static AstDeclar* parse_declar_l4(Parser* p, bool allow_anon) { Loc loc = p->curr.loc; + if (allow_anon && (p->curr.ty == ',' || p->curr.ty == ')')) { + return new_declar(p, + (AstDeclar) { + .ty = AstDeclar_Anon, + .loc = loc, + }); + } + if (p->curr.ty == Tok_Ident) { char* ident = arena_strdup(p->arena, p->curr.text); step(p); @@ -496,7 +477,7 @@ static AstDeclar* parse_declar_l4(Parser* p) if (p->curr.ty == '(') { step(p); - AstDeclar* declar = parse_declar_l1(p); + AstDeclar* declar = parse_declar_l1(p, allow_anon); if (p->curr.ty != ')') { fprintf( @@ -520,7 +501,7 @@ static AstSpec parse_decl_spec(Parser* p) while (true) { switch (p->curr.ty) { case Tok_Ident: { - OldSym* sym = syms_get(p->syms, p->curr.text); + OldSym* sym = oldsyms_get(p->old_syms, p->curr.text); if (!sym || sym->ty != OldSym_Typedef) break; spec |= AstSpec_DefTy; @@ -686,13 +667,3 @@ static AstExpr* parse_expr_2(Parser* p) stderr, "error: expected expression on line %d\n", p->curr.loc.line); exit(1); } - -AstStmt* parser_parse_stmt(Parser* p) -{ - return parse_stmt(p); -} - -bool parser_done(Parser* p) -{ - return p->curr.ty == Tok_Eof; -} diff --git a/parse.h b/parse.h index ad2a877..7fb68bd 100644 --- a/parse.h +++ b/parse.h @@ -1,116 +1,51 @@ #ifndef PARSE_H #define PARSE_H -#include "ast.h" #include "collection.h" +#include "preproc.h" +#include "resolve.h" #include "sema.h" -#include - -char* read_textfile(const char* filename); - -// phases: -// https://en.cppreference.com/c/language/translation_phases - -// phase 1 - source chars typedef struct { char ch; - Loc loc; -} Char; + bool is_term; + unsigned short val; +} KwNodeOpt; typedef struct { - const char* text; - size_t i; - int line; - int col; -} SourceIter; - -void source_iter_init(SourceIter* r, const char* text); -Char source_iter_next(SourceIter* r); - -// phase 2 - logical source lines + ARRAY_FIELD(KwNodeOpt, opts); + size_t idx; +} KwNode; typedef struct { - SourceIter* source_char_iter; - Char curr; -} LslIter; + TokStream* tokstream; + Arena arena; + ARRAY_FIELD(KwNode, nodes); +} KwMatcher; -void lsl_iter_init(LslIter* r, SourceIter* source_iter); -Char lsl_iter_next(LslIter* r); +void kwmatcher_init(KwMatcher* m, TokStream* tokstream); +void kwmatcher_deinit(KwMatcher* m); +Tok kwmatcher_next(KwMatcher* m); -// phase 3 - preprocessor tokens +typedef enum : unsigned int { + ParserFlags_ParsingTypedef = 1 << 0, +} ParserFlags; -typedef enum { - Tok_Eof, - Tok_Ident, - Tok_Int, - Tok_Str, - Tok_Char, - Tok_Whitespace, - Tok_HeaderName, - - Tok_Eol = '\n', // NOTE: has value 10 - Tok_Semicolon = ';', - Tok_LParen = '(', - Tok_RParen = ')', - Tok_LBrace = '{', - Tok_RBrace = '}', - Tok_Comma = ',', - Tok_Asterisk = '*', - Tok_Hashtag = '#', - - Tok_KwInt = 256, - Tok_KwChar, - Tok_KwConst, - Tok_KwVoid, - - // used internally in preprocessor - Tok_EndOfMacroInvocation, - -} TokTy; - -const char* tokty_str(TokTy ty); - -typedef struct { - TokTy ty; - char* text; - Loc loc; -} Tok; - -typedef struct { - LslIter* lsl_iter; +typedef struct Parser { + KwMatcher kwmatcher; + Sema* sema; Arena* arena; - Char curr; - bool lex_whitespace; - bool lex_headername; -} Lexer; + Arena sym_arena; -void lexer_init(Lexer* r, LslIter* lsl_iter, Arena* arena); -Tok lexer_next(Lexer* l); + OldSyms* old_syms; -// phase 4 - preprocessor - -typedef struct Preproc Preproc; - -Preproc* preproc_new(char* filename, char* text, Arena* arena); -void preproc_free(Preproc* p); -Tok preproc_next(Preproc* p); - -// phase 5, 6 - preprocessor cleanup, concat strings - -typedef struct { - Preproc* preproc; - Arena* arena; Tok curr; -} TokStream; -void tokstream_init(TokStream* s, Preproc* preproc, Arena* arena); -Tok tokstream_next(TokStream* s); + ParserFlags flags; +} Parser; -typedef struct Parser Parser; - -Parser* parser_new(TokStream* tokstream, Sema* sema, Arena* arena); -void parser_free(Parser* p); +void parser_init(Parser* p, TokStream* tokstream, Sema* sema, Arena* arena); +void parser_deinit(Parser* p); AstStmt* parser_parse_stmt(Parser* p); bool parser_done(Parser* p); diff --git a/preproc.c b/preproc.c index 212cbf1..8bd10c5 100644 --- a/preproc.c +++ b/preproc.c @@ -1,11 +1,301 @@ +#include "preproc.h" #include "collection.h" -#include "parse.h" #include +#include #include #include #include #include +char* read_textfile(const char* filename) +{ + FILE* fp = fopen(filename, "r"); + if (!fp) { + goto couldnt_read_file; + } + + if (fseek(fp, 0, SEEK_END) != 0) { + goto couldnt_read_file; + } + + long file_size = ftell(fp); + if (file_size < 0) { + goto couldnt_read_file; + } + + if (fseek(fp, 0, SEEK_SET) != 0) { + goto couldnt_read_file; + } + + char* buffer = malloc(file_size + 1); + assert(buffer); + + if (fread(buffer, sizeof(char), file_size, fp) != (size_t)file_size) { + goto couldnt_read_file; + } + + buffer[file_size] = '\0'; + return buffer; + +couldnt_read_file: + fprintf(stderr, + "error: couldn't read file '%s': %s\n", + filename, + strerror(errno)); + return nullptr; +} + +const char* tokty_str(TokTy ty) +{ + switch (ty) { + case Tok_Eof: + return "Eof"; + case Tok_Ident: + return "Ident"; + case Tok_Int: + return "Int"; + case Tok_Str: + return "Str"; + case Tok_Char: + return "Char"; + case Tok_Whitespace: + return "Whitespace"; + case Tok_HeaderName: + return "HeaderName"; + case Tok_Eol: + return "Eol"; + case Tok_Semicolon: + return "Semicolon"; + case Tok_LParen: + return "LParen"; + case Tok_RParen: + return "RParen"; + case Tok_LBrace: + return "LBrace"; + case Tok_RBrace: + return "RBrace"; + case Tok_Asterisk: + return "Asterisk"; + case Tok_Hashtag: + return "Hashtag"; + case Tok_Comma: + return "Comma"; + case Tok_KwInt: + return "KwInt"; + case Tok_KwChar: + return "KwChar"; + case Tok_KwConst: + return "KwConst"; + case Tok_KwVoid: + return "KwVoid"; + case Tok_EndOfMacroInvocation: + return "EndOfMacroInvocation"; + } + return ""; +} + +void source_iter_init(SourceIter* r, const char* filename, const char* text) +{ + *r = (SourceIter) { + .filename = filename, + .text = text, + .i = 0, + .line = 1, + .col = 1, + }; +} + +Char source_iter_next(SourceIter* r) +{ + char ch = r->text[r->i]; + Loc loc = { r->line, r->col, r->filename }; + + if (r->text[r->i] != '\0') { + if (ch == '\n') { + r->line += 1; + r->col = 1; + } else { + r->col += 1; + } + r->i += 1; + } + + return (Char) { ch, loc }; +} + +void lsl_iter_init(LslIter* r, SourceIter* source_char_iter) +{ + Char curr = source_iter_next(source_char_iter); + + *r = (LslIter) { + .source_char_iter = source_char_iter, + .curr = curr, + }; +} + +Char lsl_iter_next(LslIter* r) +{ + Char next = source_iter_next(r->source_char_iter); + + if (r->curr.ch == '\\' && next.ch == '\n') { + r->curr = source_iter_next(r->source_char_iter); + return lsl_iter_next(r); + } + + Char curr = r->curr; + r->curr = next; + return curr; +} + +void lexer_init(Lexer* r, LslIter* lsl_char_iter, Arena* arena) +{ + Char curr = lsl_iter_next(lsl_char_iter); + + *r = (Lexer) { + .lsl_iter = lsl_char_iter, + .arena = arena, + .curr = curr, + .lex_whitespace = false, + .lex_headername = false, + }; +} + +static Tok l_tok(Lexer* l, TokTy ty, const char* text, Loc loc) +{ + char* text_dup = arena_alloc(l->arena, strlen(text) + 1); + text_dup[0] = '\0'; + strcpy(text_dup, text); + + return (Tok) { ty, text_dup, loc }; +} + +static bool l_done(Lexer* l) +{ + return l->curr.ch == '\0'; +} + +constexpr size_t max_token_text_len = 64; + +static void l_step(Lexer* l, char text[], size_t* text_len) +{ + assert(*text_len < max_token_text_len); + text[*text_len] = l->curr.ch; + *text_len += 1; + + l->curr = lsl_iter_next(l->lsl_iter); +} + +Tok lexer_next(Lexer* l) +{ + Loc loc = l->curr.loc; + + char text[max_token_text_len] = ""; + size_t text_len = 0; + + if (l_done(l)) { + return l_tok(l, Tok_Eof, text, loc); + } + + bool matched = false; + while (strchr(" \t\r", l->curr.ch)) { + matched = true; + l_step(l, text, &text_len); + } + if (matched) { + if (l->lex_whitespace) { + return l_tok(l, Tok_Whitespace, text, loc); + } + return lexer_next(l); + } + + while ((l->curr.ch >= 'a' && l->curr.ch <= 'z') + || (l->curr.ch >= 'A' && l->curr.ch <= 'Z') + || (matched && l->curr.ch >= '0' && l->curr.ch <= '9') + || strchr("_", l->curr.ch)) { + matched = true; + l_step(l, text, &text_len); + } + if (matched) { + return l_tok(l, Tok_Ident, text, loc); + } + + while ((l->curr.ch >= '1' && l->curr.ch <= '9') + || (matched && l->curr.ch == '0')) { + matched = true; + l_step(l, text, &text_len); + } + if (matched) { + return l_tok(l, Tok_Int, text, loc); + } + + if (l->lex_headername && (l->curr.ch == '"' || l->curr.ch == '<')) { + char ter = l->curr.ch == '<' ? '>' : '"'; + l_step(l, text, &text_len); + while (l->curr.ch != '\0' && l->curr.ch != '\n' && l->curr.ch != ter) { + l_step(l, text, &text_len); + } + if (l->curr.ch != ter) { + fprintf(stderr, + "error: malformed header name, expected '%c' on line %d\n", + ter, + l->curr.loc.line); + return lexer_next(l); + } + l_step(l, text, &text_len); + return l_tok(l, Tok_HeaderName, text, loc); + } + + if (l->curr.ch == '"') { + l_step(l, text, &text_len); + while (l->curr.ch != '"') { + if (l->curr.ch == '\\') { + l_step(l, text, &text_len); + if (l_done(l)) + break; + } + l_step(l, text, &text_len); + } + if (l_done(l) || l->curr.ch != '"') { + fprintf(stderr, + "error: malformed string literal on line %d\n", + l->curr.loc.line); + return lexer_next(l); + } + l_step(l, text, &text_len); + return l_tok(l, Tok_Str, text, loc); + } + + if (l->curr.ch == '\'') { + l_step(l, text, &text_len); + if (l->curr.ch == '\\') { + l_step(l, text, &text_len); + } + if (!l_done(l)) { + l_step(l, text, &text_len); + } + if (l_done(l) && l->curr.ch != '\'') { + fprintf(stderr, + "error: malformed character literal on line %d\n", + l->curr.loc.line); + return lexer_next(l); + } + l_step(l, text, &text_len); + return l_tok(l, Tok_Char, text, loc); + } + + if (strchr("\n;(){},*#", l->curr.ch)) { + TokTy ty = (TokTy)l->curr.ch; + l_step(l, text, &text_len); + return l_tok(l, ty, text, loc); + } + fprintf(stderr, + "error: illegal character '%c' on line %d\n", + l->curr.ch, + l->curr.loc.line); + l_step(l, text, &text_len); + return lexer_next(l); +} + typedef struct { ARRAY_FIELD(Hashmap, maps); } PPSyms; @@ -73,7 +363,7 @@ typedef struct { size_t depth; } CondStack; -void condstack_push(CondStack* s, bool cond) +static void condstack_push(CondStack* s, bool cond) { if (cond) { s->conds |= 1ul << s->depth; @@ -83,7 +373,7 @@ void condstack_push(CondStack* s, bool cond) s->depth += 1; } -bool condstack_pop(CondStack* s) +static bool condstack_pop(CondStack* s) { assert(s->depth > 0); s->depth -= 1; @@ -151,7 +441,7 @@ Preproc* preproc_new(char* filename, char* text, Arena* arena) })); File* file = &p->files[0]; - source_iter_init(&file->source_iter, text); + source_iter_init(&file->source_iter, filename, text); lsl_iter_init(&file->lsl_iter, &file->source_iter); lexer_init(&file->lexer, &file->lsl_iter, p->arena); p->curr = lexer_next(&file->lexer); @@ -184,7 +474,7 @@ void preproc_free(Preproc* p) free(p); } -static void step(Preproc* p) +static void p_step(Preproc* p) { p->next_can_be_directive = p->curr.ty == Tok_Eol; @@ -197,7 +487,7 @@ static void step(Preproc* p) free(curr_file->text); p->files_size -= 1; - step(p); + p_step(p); } return; @@ -207,12 +497,12 @@ static void step(Preproc* p) if (p->curr.ty == Tok_EndOfMacroInvocation) { ppsyms_pop_layer(&p->syms); - step(p); + p_step(p); return; } } -static void collect_arg(Preproc* p, size_t def_idx, size_t arg_idx) +static void p_collect_arg(Preproc* p, size_t def_idx, size_t arg_idx) { if (arg_idx >= p->defs[def_idx].params_size) { fprintf(stderr, @@ -243,7 +533,7 @@ static void collect_arg(Preproc* p, size_t def_idx, size_t arg_idx) (&p->curr), sizeof(*(&p->curr))); - step(p); + p_step(p); } if (p->curr.ty != ',' && p->curr.ty != ')') { @@ -264,21 +554,19 @@ static void collect_arg(Preproc* p, size_t def_idx, size_t arg_idx) ppsyms_define(&p->syms, p->defs[def_idx].params[arg_idx], p->defs_size - 1); } -#define A(B, C) B C - -static void collect_args(Preproc* p, size_t def_idx) +static void p_collect_args(Preproc* p, size_t def_idx) { assert(p->curr.ty == '('); - step(p); + p_step(p); size_t idx = 0; if (p->curr.ty != Tok_Eof && p->curr.ty != ')') { - collect_arg(p, def_idx, idx); + p_collect_arg(p, def_idx, idx); idx += 1; while (p->curr.ty == ',') { - step(p); - collect_arg(p, def_idx, idx); + p_step(p); + p_collect_arg(p, def_idx, idx); idx += 1; } } @@ -296,12 +584,12 @@ static void collect_args(Preproc* p, size_t def_idx) } } -static Tok expand_tok(Preproc* p) +static Tok p_expand_tok(Preproc* p) { Tok tok = p->curr; size_t* def_idx; if (tok.ty != Tok_Ident || !(def_idx = ppsyms_get(&p->syms, tok.text))) { - step(p); + p_step(p); return tok; } @@ -313,11 +601,11 @@ static Tok expand_tok(Preproc* p) ppsyms_define(&p->syms, tok.text, 0); if (p->defs[*def_idx].params) { - step(p); + p_step(p); // function-like macros without arg-lists are ignored. if (p->curr.ty != '(') return tok; - collect_args(p, *def_idx); + p_collect_args(p, *def_idx); } ARRAY_FIELD_PUSH(p, tok_stack, (&(Tok) { .ty = Tok_EndOfMacroInvocation })); @@ -329,14 +617,14 @@ static Tok expand_tok(Preproc* p) } // step into the new invocation - step(p); + p_step(p); - return expand_tok(p); + return p_expand_tok(p); } static Tok do_define(Preproc* p) { - step(p); + p_step(p); if (p->curr.ty != Tok_Ident) { fprintf(stderr, "error: expected identifier on line %d\n", @@ -346,13 +634,13 @@ static Tok do_define(Preproc* p) Tok ident_tok = p->curr; p->files[p->files_size - 1].lexer.lex_whitespace = true; - step(p); + p_step(p); p->files[p->files_size - 1].lexer.lex_whitespace = false; Def def = { }; if (p->curr.ty == '(') { - step(p); + p_step(p); ARRAY_VAR(char*, params); @@ -361,16 +649,16 @@ static Tok do_define(Preproc* p) goto error_expected_identifier; ARRAY_VAR_PUSH(params, &p->curr.text); - step(p); + p_step(p); while (p->curr.ty == ',') { - step(p); + p_step(p); if (p->curr.ty != Tok_Ident) goto error_expected_identifier; ARRAY_VAR_PUSH(params, &p->curr.text); - step(p); + p_step(p); } } @@ -379,14 +667,14 @@ static Tok do_define(Preproc* p) stderr, "error: expected ')' on line %d\n", p->curr.loc.line); exit(1); } - step(p); + p_step(p); def.params = params; def.params_size = params_size; } if (p->curr.ty == Tok_Whitespace) - step(p); + p_step(p); ARRAY_VAR(Tok, toks); @@ -397,7 +685,7 @@ static Tok do_define(Preproc* p) &toks_size, (&p->curr), sizeof(*(&p->curr))); - step(p); + p_step(p); } def.toks = toks; @@ -416,7 +704,7 @@ error_expected_identifier: static Tok do_undef(Preproc* p) { - step(p); + p_step(p); if (p->curr.ty != Tok_Ident) { fprintf(stderr, @@ -445,7 +733,7 @@ static Tok do_include(Preproc* p) File* curr_file = &p->files[p->files_size - 1]; curr_file->lexer.lex_headername = true; - step(p); + p_step(p); curr_file->lexer.lex_headername = false; if (p->curr.ty != Tok_HeaderName) { @@ -456,7 +744,7 @@ static Tok do_include(Preproc* p) } Tok headername_tok = p->curr; - step(p); + p_step(p); if (p->curr.ty != Tok_Eof && p->curr.ty != Tok_Eol) { fprintf(stderr, @@ -497,7 +785,7 @@ static Tok do_include(Preproc* p) })); File* file = &p->files[p->files_size - 1]; - source_iter_init(&file->source_iter, text); + source_iter_init(&file->source_iter, filename, text); lsl_iter_init(&file->lsl_iter, &file->source_iter); lexer_init(&file->lexer, &file->lsl_iter, p->arena); p->curr = lexer_next(&file->lexer); @@ -513,7 +801,7 @@ static Tok do_ifndef(Preproc* p) { int original_line = p->curr.loc.line; - step(p); + p_step(p); if (p->curr.ty != Tok_Ident) { fprintf(stderr, "error: expected identifier on line %d\n", @@ -521,7 +809,7 @@ static Tok do_ifndef(Preproc* p) exit(1); } Tok ident = p->curr; - step(p); + p_step(p); if (p->curr.ty != Tok_Eof && p->curr.ty != Tok_Eol) { fprintf(stderr, @@ -539,10 +827,10 @@ static Tok do_ifndef(Preproc* p) while (p->curr.ty != Tok_Eof) { while (p->curr.ty != Tok_Eof && (!p->next_can_be_directive || p->curr.ty != '#')) - step(p); + p_step(p); if (p->curr.ty == Tok_Eof) break; - step(p); + p_step(p); if (p->curr.ty != Tok_Ident) continue; if (strcmp(p->curr.text, "endif") == 0) @@ -562,7 +850,7 @@ static Tok do_ifndef(Preproc* p) static Tok do_endif(Preproc* p) { - step(p); + p_step(p); if (p->curr.ty != Tok_Eof && p->curr.ty != Tok_Eol) { fprintf(stderr, @@ -631,10 +919,10 @@ static Tok interpret_directive(Preproc* p) Tok preproc_next(Preproc* p) { if (p->next_can_be_directive && p->curr.ty == '#') { - step(p); + p_step(p); return interpret_directive(p); } - return expand_tok(p); + return p_expand_tok(p); } static Tok tokstream_next_filtered(TokStream* s) diff --git a/preproc.h b/preproc.h new file mode 100644 index 0000000..4226ecb --- /dev/null +++ b/preproc.h @@ -0,0 +1,110 @@ +#ifndef TOKS_H +#define TOKS_H + +#include "collection.h" +#include "diagnostics.h" +#include + +char* read_textfile(const char* filename); + +// phases: +// https://en.cppreference.com/c/language/translation_phases + +// phase 1 - source chars + +typedef struct { + char ch; + Loc loc; +} Char; + +typedef struct { + const char* filename; + const char* text; + size_t i; + int line; + int col; +} SourceIter; + +void source_iter_init(SourceIter* r, const char* filename, const char* text); +Char source_iter_next(SourceIter* r); + +// phase 2 - logical source lines + +typedef struct { + SourceIter* source_char_iter; + Char curr; +} LslIter; + +void lsl_iter_init(LslIter* r, SourceIter* source_iter); +Char lsl_iter_next(LslIter* r); + +// phase 3 - preprocessor tokens + +typedef enum { + Tok_Eof, + Tok_Ident, + Tok_Int, + Tok_Str, + Tok_Char, + Tok_Whitespace, + Tok_HeaderName, + + Tok_Eol = '\n', // NOTE: has value 10 + Tok_Semicolon = ';', + Tok_LParen = '(', + Tok_RParen = ')', + Tok_LBrace = '{', + Tok_RBrace = '}', + Tok_Comma = ',', + Tok_Asterisk = '*', + Tok_Hashtag = '#', + + Tok_KwInt = 256, + Tok_KwChar, + Tok_KwConst, + Tok_KwVoid, + + // used internally in preprocessor + Tok_EndOfMacroInvocation, + +} TokTy; + +const char* tokty_str(TokTy ty); + +typedef struct { + TokTy ty; + char* text; + Loc loc; +} Tok; + +typedef struct { + LslIter* lsl_iter; + Arena* arena; + Char curr; + bool lex_whitespace; + bool lex_headername; +} Lexer; + +void lexer_init(Lexer* r, LslIter* lsl_iter, Arena* arena); +Tok lexer_next(Lexer* l); + +// phase 4 - preprocessor + +typedef struct Preproc Preproc; + +Preproc* preproc_new(char* filename, char* text, Arena* arena); +void preproc_free(Preproc* p); +Tok preproc_next(Preproc* p); + +// phase 5, 6 - preprocessor cleanup, concat strings + +typedef struct { + Preproc* preproc; + Arena* arena; + Tok curr; +} TokStream; + +void tokstream_init(TokStream* s, Preproc* preproc, Arena* arena); +Tok tokstream_next(TokStream* s); + +#endif diff --git a/resolve.c b/resolve.c index 5cab692..27cb8a8 100644 --- a/resolve.c +++ b/resolve.c @@ -5,14 +5,14 @@ #include #include -struct Syms { +struct OldSyms { ARRAY_FIELD(Hashmap, maps); }; -Syms* syms_new() +OldSyms* oldsyms_new() { - Syms* s = malloc(sizeof(Syms)); - *s = (Syms) { + OldSyms* s = malloc(sizeof(OldSyms)); + *s = (OldSyms) { ARRAY_FIELD_INIT(maps), }; @@ -22,7 +22,7 @@ Syms* syms_new() return s; } -void syms_free(Syms* s) +void oldsyms_free(OldSyms* s) { for (size_t i = 0; i < s->maps_size; ++i) hashmap_deinit(&s->maps[i]); @@ -30,26 +30,26 @@ void syms_free(Syms* s) free(s); } -void syms_push_scope(Syms* s) +void oldsyms_push_scope(OldSyms* s) { ARRAY_FIELD_PUSH(s, maps, &(Hashmap) { }); hashmap_init(&s->maps[s->maps_size - 1], sizeof(OldSym*)); } -void syms_pop_scope(Syms* s) +void oldsyms_pop_scope(OldSyms* s) { assert(s->maps_size > 0); hashmap_deinit(&s->maps[s->maps_size - 1]); s->maps_size -= 1; } -void syms_define(Syms* s, const char* ident, OldSym* sym) +void oldsyms_define(OldSyms* s, const char* ident, OldSym* sym) { Hashmap* m = &s->maps[s->maps_size - 1]; hashmap_set(m, ident, &sym); } -OldSym* syms_get(Syms* s, const char* ident) +OldSym* oldsyms_get(OldSyms* s, const char* ident) { OldSym** res; for (size_t i = 0; i < s->maps_size; ++i) @@ -63,9 +63,9 @@ typedef enum : unsigned int { } ResolverFlags; struct Resolver { - Syms* ord_syms; - Syms* tag_syms; - Syms* label_syms; + OldSyms* ord_syms; + OldSyms* tag_syms; + OldSyms* label_syms; Arena* arena; @@ -75,13 +75,13 @@ struct Resolver { ResolverFlags flags; }; -Resolver* resolver_new(Arena* arena) +Resolver* oldresolver_new(Arena* arena) { Resolver* r = malloc(sizeof(Resolver)); *r = (Resolver) { - .ord_syms = syms_new(), - .tag_syms = syms_new(), - .label_syms = syms_new(), + .ord_syms = oldsyms_new(), + .tag_syms = oldsyms_new(), + .label_syms = oldsyms_new(), .arena = arena, @@ -96,24 +96,24 @@ Resolver* resolver_new(Arena* arena) return r; } -void resolver_free(Resolver* r) +void oldresolver_free(Resolver* r) { keymap_deinit(&r->resol_map); - syms_free(r->ord_syms); - syms_free(r->tag_syms); - syms_free(r->label_syms); + oldsyms_free(r->ord_syms); + oldsyms_free(r->tag_syms); + oldsyms_free(r->label_syms); free(r); } static AstVisitorResult visit_stmt_block(AstVisitor* v, AstStmtBlock* node) { Resolver* r = v->op; - syms_push_scope(r->ord_syms); + oldsyms_push_scope(r->ord_syms); ast_stmt_block_visit_body(v, node); - syms_pop_scope(r->ord_syms); + oldsyms_pop_scope(r->ord_syms); return AstVisitor_Break; } @@ -154,14 +154,14 @@ static AstVisitorResult visit_decl(AstVisitor* v, AstDecl* node) ast_declar_visit(v, d->function.declar); - syms_push_scope(r->ord_syms); + oldsyms_push_scope(r->ord_syms); for (size_t i = 0; i < d->function.params_size; ++i) ast_decl_visit(v, d->function.params[i]); ast_stmt_block_visit(v, node->function_body); - syms_pop_scope(r->ord_syms); + oldsyms_pop_scope(r->ord_syms); return AstVisitor_Break; } @@ -175,12 +175,12 @@ static AstVisitorResult visit_declar(AstVisitor* v, AstDeclar* node) if (node->ty == AstDeclar_Function) { ast_declar_visit(v, node->function.declar); - syms_push_scope(r->ord_syms); + oldsyms_push_scope(r->ord_syms); for (size_t i = 0; i < node->function.params_size; ++i) ast_decl_visit(v, node->function.params[i]); - syms_pop_scope(r->ord_syms); + oldsyms_pop_scope(r->ord_syms); return AstVisitor_Break; } @@ -195,7 +195,7 @@ static AstVisitorResult visit_declar(AstVisitor* v, AstDeclar* node) .declar = node, }, }; - syms_define(r->ord_syms, node->ident, sym); + oldsyms_define(r->ord_syms, node->ident, sym); return AstVisitor_Break; } @@ -208,7 +208,7 @@ static AstVisitorResult visit_expr(AstVisitor* v, AstExpr* node) if (node->ty == AstExpr_Ident) { - OldSym* sym = syms_get(r->ord_syms, node->ident); + OldSym* sym = oldsyms_get(r->ord_syms, node->ident); if (!sym) { fprintf(stderr, "error: use of undeclared '%s' on line %d\n", @@ -221,7 +221,7 @@ static AstVisitorResult visit_expr(AstVisitor* v, AstExpr* node) return AstVisitor_Continue; } -void resolver_resolve_top_stmt(Resolver* r, AstStmt* stmt) +void oldresolver_resolve_top_stmt(Resolver* r, AstStmt* stmt) { if (stmt->ty != AstStmt_Decl) { fprintf( diff --git a/resolve.h b/resolve.h index d5bd7b6..138ee7b 100644 --- a/resolve.h +++ b/resolve.h @@ -19,22 +19,22 @@ typedef struct { }; } OldSym; -typedef struct Syms Syms; +typedef struct OldSyms OldSyms; -Syms* syms_new(); -void syms_free(Syms* s); +OldSyms* oldsyms_new(); +void oldsyms_free(OldSyms* s); -void syms_push_scope(Syms* s); -void syms_pop_scope(Syms* s); +void oldsyms_push_scope(OldSyms* s); +void oldsyms_pop_scope(OldSyms* s); -void syms_define(Syms* s, const char* ident, OldSym* sym); -OldSym* syms_get(Syms* s, const char* ident); +void oldsyms_define(OldSyms* s, const char* ident, OldSym* sym); +OldSym* oldsyms_get(OldSyms* s, const char* ident); typedef struct Resolver Resolver; -Resolver* resolver_new(Arena* arena); -void resolver_free(Resolver* r); +Resolver* oldresolver_new(Arena* arena); +void oldresolver_free(Resolver* r); -void resolver_resolve_top_stmt(Resolver* r, AstStmt* stmt); +void oldresolver_resolve_top_stmt(Resolver* r, AstStmt* stmt); #endif diff --git a/sema.c b/sema.c index 38e352f..f83624f 100644 --- a/sema.c +++ b/sema.c @@ -55,9 +55,21 @@ void type_print(FILE* file, const Type* type) } if (type->ty == Type_Pointer) { - fprintf(file, " * "); - type_spec_print(file, type->pointer.spec); type_print(file, type->pointer.inner); + fprintf(file, " *"); + type_spec_print(file, type->pointer.spec); + return; + } + + if (type->ty == Type_Function) { + type_print(file, type->function.return_type); + fprintf(file, "()("); + for (size_t i = 0; i < type->function.params_size; ++i) { + if (i > 0) + fprintf(file, ", "); + type_print(file, type->function.params[i]); + } + fprintf(file, ")"); return; } @@ -144,11 +156,16 @@ void sema_scope_leave(Sema* s) static Sym* get_ord_sym(Sema* s, const char* ident) { - Sym* sym = nullptr; + Sym** sym = nullptr; for (size_t i = 0; i < s->ribs_size; ++i) if ((sym = hashmap_get(&s->ribs[s->ribs_size - i - 1].ord_syms, ident))) break; - return sym; + return *sym; +} + +static void define_ord_sym(Sema* s, const char* ident, Sym* sym) +{ + hashmap_set(&s->ribs[s->ribs_size - 1].ord_syms, ident, &sym); } static void error_if_multi_spec( @@ -227,6 +244,11 @@ static void check_declar(Sema* s, const char** out_declar_ident) { switch (declar->ty) { + case AstDeclar_Anon: { + *out_declar_type = type; + *out_declar_ident = nullptr; + return; + } case AstDeclar_Ident: { *out_declar_type = type; *out_declar_ident = declar->ident; @@ -284,6 +306,9 @@ static void check_declar(Sema* s, &s->type_arena, &new_type->function, params, &declar_type); } + assert( + new_type->function.params_size == declar->function.params_size); + // TODO: handle forward declarations check_declar(s, @@ -319,7 +344,7 @@ void sema_function_enter(Sema* s, AstSpec spec, AstDeclar* declar) .type = type, }, }; - hashmap_set(&rib->ord_syms, declar->ident, &sym); + define_ord_sym(s, declar->ident, sym); sema_scope_enter(s); @@ -335,6 +360,9 @@ void sema_function_enter(Sema* s, AstSpec spec, AstDeclar* declar) Type* declar_type; check_declar(s, param_declar, decl_type, &declar_type, &declar_ident); + if (!declar_ident) + continue; + Rib* rib = &s->ribs[s->ribs_size - 1]; error_if_redefinition(&rib->ord_syms, declar->ident, declar->loc); @@ -346,7 +374,7 @@ void sema_function_enter(Sema* s, AstSpec spec, AstDeclar* declar) .idx = i, }, }; - hashmap_set(&rib->ord_syms, declar_ident, &sym); + define_ord_sym(s, declar_ident, sym); } } @@ -387,6 +415,41 @@ void sema_visit_stmt(Sema* s, AstStmt* stmt) } } +static bool is_arg_passable_as_param(const Type* arg, const Type* param) +{ + // printf("comparing "); + // type_print(stdout, arg); + // printf(" with "); + // type_print(stdout, param); + // printf("\n"); + // + if (arg == param) + return true; + + if (arg->ty == Type_Pointer && param->ty == Type_Pointer) { + if (!(arg->spec & TypeSpec_Const) && (param->spec & TypeSpec_Const)) + return false; + return is_arg_passable_as_param( + arg->pointer.inner, param->pointer.inner); + } + + if (arg->ty == Type_Char && arg->ty == param->ty) + return true; + + return false; +} + +static Type* get_expr_type(Sema* s, const AstExpr* expr) +{ + Type** res = keymap_get(&s->expr_types, (size_t)expr); + return res ? *res : nullptr; +} + +static void set_expr_type(Sema* s, const AstExpr* expr, Type* type) +{ + keymap_set(&s->expr_types, (size_t)expr, &type); +} + void sema_visit_expr(Sema* s, AstExpr* expr) { Type* type = nullptr; @@ -431,14 +494,26 @@ void sema_visit_expr(Sema* s, AstExpr* expr) break; }; case AstExpr_Call: { - Type* inner_type - = keymap_get(&s->expr_types, (size_t)expr->call.expr); + Type* inner_type = get_expr_type(s, expr->call.expr); + assert(inner_type); - printf("inner_type->ty == %d\n", inner_type->ty); assert(inner_type->ty == Type_Function); + assert(expr->call.args_size == inner_type->function.params_size); + + for (size_t i = 0; i < expr->call.args_size; ++i) { + Type* arg_type = get_expr_type(s, expr->call.args[i]); + Type* param_type = inner_type->function.params[i]; + assert(is_arg_passable_as_param(arg_type, param_type)); + } + + type = inner_type->function.return_type; + break; } } - keymap_set(&s->expr_types, (KeymapKey)expr, &type); + // printf(" expr(%d) -> ", expr->id); + // type_print(stdout, type); + // printf("\n"); + set_expr_type(s, expr, type); }