diff --git a/Makefile b/Makefile index 5237a31..1b9f97e 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ -larpcc: main.c lex.c preproc.c collection.c +larpcc: main.c lex.c preproc.c collection.c parse.c syms.c gcc $^ -o $@ -std=c23 -pedantic -Wall -Wextra -g -fsanitize=address diff --git a/ast.h b/ast.h index 0f87f59..99f57de 100644 --- a/ast.h +++ b/ast.h @@ -8,57 +8,101 @@ typedef struct { int col; } Loc; +typedef struct AstStmt AstStmt; +typedef struct AstDecl AstDecl; +typedef struct AstDeclar AstDeclar; +typedef struct AstExpr AstExpr; + +typedef struct AstStmtBlock AstStmtBlock; + +struct AstStmtBlock { + ARRAY_FIELD(AstStmt*, stmts); + Loc loc; +}; + +typedef struct AstDeclBlock AstDeclBlock; + +struct AstDeclBlock { + ARRAY_FIELD(AstDecl*, decls); + Loc loc; +}; + +typedef enum { + AstStmt_Decl, + AstStmt_Expr, +} AstStmtTy; + +struct AstStmt { + AstStmtTy ty; + Loc loc; + union { + AstDecl* decl; + AstExpr* expr; + }; +}; + typedef enum : unsigned int { - AstSpec_Typedef = 1 << 0, - // AstSpec_Constexpr = 1 << 1, - // AstSpec_Auto = 1 << 2, - // AstSpec_Register = 1 << 3, - AstSpec_Static = 1 << 4, - // AstSpec_Extern = 1 << 5, - // AstSpec_ThreadLocal = 1 << 6, - AstSpec_Const = 1 << 7, - // AstSpec_Volatile = 1 << 8, - // AstSpec_Restrict = 1 << 9, - // AstSpec_Atomic = 1 << 10, - AstSpec_Inline = 1 << 11, + AstSpec_Int = 1 << 0, + AstSpec_Char = 1 << 1, + AstSpec_DefTy = 1 << 6, + AstSpec_Unsigned = 1 << 7, + AstSpec_Static = 1 << 8, + AstSpec_Const = 1 << 9, + AstSpec_Inline = 1 << 10, + AstSpec_Typedef = 1 << 11, + AstSpec_Enum = 1 << 12, + AstSpec_Struct = 1 << 13, + AstSpec_Union = 1 << 14, } AstSpec; +struct AstDecl { + AstSpec spec; + ARRAY_FIELD(AstDeclar*, declars); + AstStmtBlock* function_body; + Loc loc; +}; + typedef enum { AstDeclar_Ident, AstDeclar_Pointer, AstDeclar_Array, + AstDeclar_Function, } AstDeclarTy; -typedef struct AstDeclar AstDeclar; - struct AstDeclar { AstDeclarTy ty; Loc loc; + AstExpr* init_expr; union { char* ident; struct { AstDeclar* declar; AstSpec spec; } pointer; + struct { + AstDeclar* declar; + AstExpr* expr; + } array; + struct { + ARRAY_FIELD(AstDecl, params); + } function; }; }; -typedef struct { - AstSpec spec; - unsigned long type_id; - ARRAY_FIELD(AstDeclar, declars); - Loc loc; -} AstDecl; - typedef enum { - AstStmt_Decl, -} AstStmtTy; + AstExpr_Str, + AstExpr_Call, +} AstExprTy; -typedef struct { - AstStmtTy ty; +struct AstExpr { + AstExprTy ty; union { - AstDecl decl; + char* str_val; + struct { + AstExpr* expr; + ARRAY_FIELD(AstExpr*, args); + } call; }; -} AstStmt; +}; #endif diff --git a/collection.c b/collection.c index 4d77324..94edff4 100644 --- a/collection.c +++ b/collection.c @@ -225,3 +225,10 @@ void arena_array_push(Arena* arena, arena_realloc_wrap, arena); } + +char* arena_strdup(Arena* a, const char* str) +{ + char* p = arena_alloc(a, strlen(str) + 1); + strcpy(p, str); + return p; +} diff --git a/collection.h b/collection.h index 7e3c47f..e2044d9 100644 --- a/collection.h +++ b/collection.h @@ -74,4 +74,6 @@ void arena_array_push(Arena* arena, void* elem, size_t elem_size); +char* arena_strdup(Arena* a, const char* str); + #endif diff --git a/lex.c b/lex.c index d0ec168..3e64bb5 100644 --- a/lex.c +++ b/lex.c @@ -96,8 +96,7 @@ void source_iter_init(SourceIter* r, const char* text) Char source_iter_next(SourceIter* r) { char ch = r->text[r->i]; - int line = r->line; - int col = r->col; + Loc loc = { r->line, r->col }; if (r->text[r->i] != '\0') { if (ch == '\n') { @@ -109,7 +108,7 @@ Char source_iter_next(SourceIter* r) r->i += 1; } - return (Char) { ch, line, col }; + return (Char) { ch, loc }; } void lsl_iter_init(LslIter* r, SourceIter* source_char_iter) @@ -149,13 +148,13 @@ void lexer_init(Lexer* r, LslIter* lsl_char_iter, Arena* arena) }; } -static Tok tok(Lexer* l, TokTy ty, const char* text, int line, int col) +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, line, col }; + return (Tok) { ty, text_dup, loc }; } static bool done(Lexer* l) @@ -176,14 +175,13 @@ static void step(Lexer* l, char text[], size_t* text_len) Tok lexer_next(Lexer* l) { - int line = l->curr.line; - int col = l->curr.col; + 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, line, col); + return tok(l, Tok_Eof, text, loc); } bool matched = false; @@ -193,7 +191,7 @@ Tok lexer_next(Lexer* l) } if (matched) { if (l->lex_whitespace) { - return tok(l, Tok_Whitespace, text, line, col); + return tok(l, Tok_Whitespace, text, loc); } return lexer_next(l); } @@ -206,7 +204,7 @@ Tok lexer_next(Lexer* l) step(l, text, &text_len); } if (matched) { - return tok(l, Tok_Ident, text, line, col); + return tok(l, Tok_Ident, text, loc); } while ((l->curr.ch >= '1' && l->curr.ch <= '9') @@ -215,7 +213,7 @@ Tok lexer_next(Lexer* l) step(l, text, &text_len); } if (matched) { - return tok(l, Tok_Int, text, line, col); + return tok(l, Tok_Int, text, loc); } if (l->lex_headername && (l->curr.ch == '"' || l->curr.ch == '<')) { @@ -228,11 +226,11 @@ Tok lexer_next(Lexer* l) fprintf(stderr, "error: malformed header name, expected '%c' on line %d\n", ter, - l->curr.line); + l->curr.loc.line); return lexer_next(l); } step(l, text, &text_len); - return tok(l, Tok_HeaderName, text, line, col); + return tok(l, Tok_HeaderName, text, loc); } if (l->curr.ch == '"') { @@ -248,11 +246,11 @@ Tok lexer_next(Lexer* l) if (done(l) || l->curr.ch != '"') { fprintf(stderr, "error: malformed string literal on line %d\n", - l->curr.line); + l->curr.loc.line); return lexer_next(l); } step(l, text, &text_len); - return tok(l, Tok_Str, text, line, col); + return tok(l, Tok_Str, text, loc); } if (l->curr.ch == '\'') { @@ -266,22 +264,22 @@ Tok lexer_next(Lexer* l) if (done(l) && l->curr.ch != '\'') { fprintf(stderr, "error: malformed character literal on line %d\n", - l->curr.line); + l->curr.loc.line); return lexer_next(l); } step(l, text, &text_len); - return tok(l, Tok_Char, text, line, col); + 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, line, col); + return tok(l, ty, text, loc); } fprintf(stderr, "error: illegal character '%c' on line %d\n", l->curr.ch, - l->curr.line); + l->curr.loc.line); step(l, text, &text_len); return lexer_next(l); } diff --git a/main.c b/main.c index 1cce045..913a264 100644 --- a/main.c +++ b/main.c @@ -30,26 +30,26 @@ int main(int argc, char* argv[]) printf("--- tokens ---\n"); - int line = 1; - int col = 1; + Loc loc = { 1, 1 }; Tok tok; while ((tok = tokstream_next(&tokstream)).ty != Tok_Eof) { // printf("%s\t%s\n", tokty_str(tok.ty), tok.text); - if (line > tok.line) { - line = 0; + Loc tok_loc = tok.loc; + if (loc.line > tok_loc.line) { + loc.line = 0; } - while (line < tok.line) { + while (loc.line < tok_loc.line) { printf("\n"); - line += 1; - col = 1; + loc.line += 1; + loc.col = 1; } - while (col < tok.col) { + while (loc.col < tok_loc.col) { printf(" "); - col += 1; + loc.col += 1; } printf("%s", tok.text); - line = tok.line; - col = tok.col + strlen(tok.text); + loc.line = tok_loc.line; + loc.col = tok_loc.col + strlen(tok.text); } fputs("\n", stdout); diff --git a/parse.c b/parse.c index 7071fda..99dae39 100644 --- a/parse.c +++ b/parse.c @@ -1,5 +1,7 @@ #include "parse.h" +#include "ast.h" #include "collection.h" +#include "syms.h" #include #include #include @@ -41,11 +43,11 @@ static KwNodeOpt* kwmatcher_create_path( .idx = new_idx, }; arena_array_push(&m->arena, - (void**)&(m)->nodes, - &(m)->nodes_cap, - &(m)->nodes_size, - (&new_node), - sizeof(*(&new_node))); + (void**)&m->nodes, + &m->nodes_cap, + &m->nodes_size, + &new_node, + sizeof(new_node)); KwNode* node = &m->nodes[new_idx]; KwNodeOpt new_opt = { @@ -57,8 +59,8 @@ static KwNodeOpt* kwmatcher_create_path( (void**)&node->opts, &node->opts_cap, &node->opts_size, - (&new_opt), - sizeof(*(&new_opt))); + &new_opt, + sizeof(new_opt)); opt = &node->opts[node->opts_size - 1]; } @@ -147,7 +149,7 @@ static Tok kwmatcher_next(KwMatcher* m) return tok; TokTy ty = kwmatcher_match(m, tok.text); if (ty != Tok_Ident) - printf("info: matched '%s' on line %d\n", tok.text, tok.line); + printf("info: matched '%s' on line %d\n", tok.text, tok.loc.line); tok.ty = ty; return tok; } @@ -155,6 +157,11 @@ static Tok kwmatcher_next(KwMatcher* m) struct Parser { KwMatcher kwmatcher; Arena* arena; + Arena sym_arena; + + Syms* ord_ns; + Syms* label_ns; + Syms* tag_ns; Tok curr; }; @@ -166,6 +173,11 @@ Parser* parser_new(TokStream* tokstream, Arena* arena) *p = (Parser) { .kwmatcher = { }, .arena = arena, + .sym_arena = { }, + + .ord_ns = syms_new(), + .label_ns = syms_new(), + .tag_ns = syms_new(), .curr = { }, }; @@ -181,3 +193,311 @@ void parser_free(Parser* p) kwmatcher_deinit(&p->kwmatcher); free(p); } + +static void step(Parser* p) +{ + p->curr = kwmatcher_next(&p->kwmatcher); +} + +#define DEFINE_NEW(TYPE, FN_NAME) \ + [[maybe_unused]] static TYPE* new_##FN_NAME(Parser* p, TYPE init) \ + { \ + TYPE* val = arena_alloc(p->arena, sizeof(TYPE)); \ + *val = init; \ + return val; \ + } + +DEFINE_NEW(AstStmt, stmt) +DEFINE_NEW(AstDecl, decl) +DEFINE_NEW(AstDeclar, declar) + +static bool is_decl_start_kw(TokTy ty) +{ + switch (ty) { + case Tok_KwInt: + case Tok_KwChar: + case Tok_KwConst: + return true; + default: + return false; + } +} + +static bool is_defty_ident(Parser* p, Tok tok) +{ + if (tok.ty != Tok_Ident) + return false; + Sym* sym = syms_get(p->ord_ns, tok.text); + return sym && sym->ty == Sym_Typedef; +} + +AstStmt* parser_parse_stmt(Parser* p) +{ + Loc loc = p->curr.loc; + + if (is_decl_start_kw(p->curr.ty) || is_defty_ident(p, p->curr)) { + AstDecl* decl = parser_parse_decl(p); + + return new_stmt(p, + (AstStmt) { + .ty = AstStmt_Decl, + .loc = loc, + .decl = decl, + }); + } + + AstExpr* expr = parser_parse_expr(p); + + return new_stmt(p, + (AstStmt) { + .ty = AstStmt_Expr, + .loc = loc, + .expr = expr, + }); +} + +static AstDeclar* parse_declar(Parser* p); +static AstSpec parse_decl_spec(Parser* p); + +static AstStmtBlock* parse_stmt_block(Parser* p); + +AstDecl* parser_parse_decl(Parser* p) +{ + Loc loc = p->curr.loc; + + AstSpec spec = parse_decl_spec(p); + + ARRAY_VAR(AstDeclar*, declars); + + AstDeclar* first = parse_declar(p); + + array_push((void**)&declars, + &declars_cap, + &declars_size, + (&first), + sizeof(*(&first))); + + if (first->ty == AstDeclar_Function && p->curr.ty == '{') { + AstStmtBlock* block = parse_stmt_block(p); + return new_decl(p, + (AstDecl) { + .spec = spec, + .declars = declars, + .declars_cap = declars_cap, + .declars_size = declars_size, + .function_body = block, + .loc = loc, + }); + } + + while (p->curr.ty == ',') { + step(p); + + AstDeclar* declar = parse_declar(p); + + array_push((void**)&declars, + &declars_cap, + &declars_size, + (&declar), + sizeof(*(&declar))); + } + + return new_decl(p, + (AstDecl) { + .spec = spec, + .declars = declars, + .declars_cap = declars_cap, + .declars_size = declars_size, + .function_body = nullptr, + .loc = loc, + }); +} + +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(Parser* p) +{ + AstDeclar* declar = parse_declar_l1(p); + + if (p->curr.ty == '=') { + step(p); + AstExpr* expr = parser_parse_expr(p); + declar->init_expr = expr; + } + + return declar; +} + +static AstDeclar* parse_declar_l1(Parser* p) +{ + Loc loc = p->curr.loc; + + if (p->curr.ty == '*') { + step(p); + + AstSpec spec = parse_decl_spec(p); + + AstDeclar* declar = parse_declar_l1(p); + return new_declar(p, + (AstDeclar) { + .ty = AstDeclar_Pointer, + .loc = loc, + .pointer = { + .declar = declar, + .spec = spec, + }, + }); + } + + return parse_declar_l2(p); +} + +static AstDeclar* parse_declar_l2(Parser* p) +{ + Loc loc = p->curr.loc; + + AstDeclar* declar = parse_declar_l3(p); + + while (p->curr.ty == '[') { + step(p); + AstExpr* expr = nullptr; + if (p->curr.ty != ']') { + expr = parser_parse_expr(p); + } + if (p->curr.ty != ']') { + fprintf( + stderr, "error: expected ']' on line %d\n", p->curr.loc.line); + exit(1); + } + step(p); + declar = new_declar(p, + (AstDeclar) { + .ty = AstDeclar_Array, + .loc = loc, + .array = { + .declar = declar, + .expr = expr, + }, + }); + } + + return declar; +} + +static AstDeclar* parse_declar_l3(Parser* p) +{ + Loc loc = p->curr.loc; + + if (p->curr.ty == Tok_Ident) { + char* ident = arena_strdup(p->arena, p->curr.text); + step(p); + return new_declar(p, + (AstDeclar) { + .ty = AstDeclar_Array, + .loc = loc, + .ident = ident, + }); + } + + if (p->curr.ty == '(') { + step(p); + + AstDeclar* declar = parse_declar_l1(p); + + if (p->curr.ty != ')') { + fprintf( + stderr, "error: expected ')' on line %d\n", p->curr.loc.line); + exit(1); + } + step(p); + + if (p->curr.ty != '(') { + return declar; + } + step(p); + + ARRAY_VAR(AstDecl, params); + + while (true) { + AstDecl* d = parser_parse_decl(p); + arena_array_push(p->arena, + (void**)¶ms, + ¶ms_cap, + ¶ms_size, + (&d), + sizeof(*(&d))); + + if (p->curr.ty != ',') + break; + step(p); + } + + if (p->curr.ty != '(') { + fprintf( + stderr, "error: expected '(' on line %d\n", p->curr.loc.line); + exit(1); + } + step(p); + + return new_declar(p, + (AstDeclar) { + .ty = AstDeclar_Function, + .loc = loc, + .function = { + .params = params, + .params_cap = params_cap, + .params_size = params_size, + }, + }); + } + + fprintf( + stderr, "error: expected declarator on line %d\n", p->curr.loc.line); + exit(1); +} + +static AstSpec parse_decl_spec(Parser* p) +{ + AstSpec spec = 0; + + while (true) { + switch (p->curr.ty) { + case Tok_Ident: { + Sym* sym = syms_get(p->ord_ns, p->curr.text); + if (sym->ty != Sym_Typedef) + break; + spec |= AstSpec_DefTy; + step(p); + continue; + } + case Tok_KwInt: + spec |= AstSpec_Int; + step(p); + continue; + case Tok_KwChar: + spec |= AstSpec_Char; + step(p); + continue; + case Tok_KwConst: + spec |= AstSpec_Const; + step(p); + continue; + default: + } + + break; + } + + return spec; +} + +static AstStmtBlock* parse_stmt_block(Parser* p) +{ + Loc loc = p->curr.loc; +} + +AstExpr* parser_parse_expr(Parser* p) +{ +} diff --git a/parse.h b/parse.h index e694e09..864a8ab 100644 --- a/parse.h +++ b/parse.h @@ -1,7 +1,9 @@ #ifndef PARSE_H #define PARSE_H +#include "ast.h" #include "collection.h" +#include "syms.h" #include char* read_textfile(const char* filename); @@ -13,8 +15,7 @@ char* read_textfile(const char* filename); typedef struct { char ch; - int line; - int col; + Loc loc; } Char; typedef struct { @@ -70,8 +71,7 @@ const char* tokty_str(TokTy ty); typedef struct { TokTy ty; char* text; - int line; - int col; + Loc loc; } Tok; typedef struct { @@ -108,5 +108,8 @@ typedef struct Parser Parser; Parser* parser_new(TokStream* tokstream, Arena* arena); void parser_free(Parser* p); +AstStmt* parser_parse_stmt(Parser* p); +AstDecl* parser_parse_decl(Parser* p); +AstExpr* parser_parse_expr(Parser* p); #endif diff --git a/preproc.c b/preproc.c index 8f42f61..2fb3ece 100644 --- a/preproc.c +++ b/preproc.c @@ -8,19 +8,19 @@ typedef struct { ARRAY_FIELD(Hashmap, maps); -} Syms; +} PPSyms; -static void syms_push_layer(Syms* s); +static void ppsyms_push_layer(PPSyms* s); -static void syms_init(Syms* s) +static void ppsyms_init(PPSyms* s) { - *s = (Syms) { + *s = (PPSyms) { ARRAY_FIELD_INIT(maps), }; - syms_push_layer(s); + ppsyms_push_layer(s); } -static void syms_deinit(Syms* s) +static void ppsyms_deinit(PPSyms* s) { if (s->maps) { for (size_t i = 0; i < s->maps_size; ++i) { @@ -30,14 +30,14 @@ static void syms_deinit(Syms* s) } } -static void syms_push_layer(Syms* s) +static void ppsyms_push_layer(PPSyms* s) { Hashmap m = { }; hashmap_init(&m, sizeof(size_t)); array_push((void**)&s->maps, &s->maps_cap, &s->maps_size, &m, sizeof(m)); } -static void syms_pop_layer(Syms* s) +static void ppsyms_pop_layer(PPSyms* s) { assert(s->maps_size > 0); @@ -45,19 +45,19 @@ static void syms_pop_layer(Syms* s) s->maps_size -= 1; } -static Hashmap* syms_current(Syms* s) +static Hashmap* ppsyms_current(PPSyms* s) { assert(s->maps_size > 0); return &s->maps[s->maps_size - 1]; } -static void syms_define(Syms* s, const char* ident, size_t def_idx) +static void ppsyms_define(PPSyms* s, const char* ident, size_t def_idx) { - Hashmap* m = syms_current(s); + Hashmap* m = ppsyms_current(s); hashmap_set(m, ident, &def_idx); } -static size_t* syms_get(Syms* s, const char* ident) +static size_t* ppsyms_get(PPSyms* s, const char* ident) { for (size_t i = 0; i < s->maps_size; ++i) { Hashmap* m = &s->maps[s->maps_size - i - 1]; @@ -114,7 +114,7 @@ struct Preproc { Tok curr; ARRAY_FIELD(Def, defs); - Syms syms; + PPSyms syms; CondStack condstack; @@ -159,7 +159,7 @@ Preproc* preproc_new(char* filename, char* text, Arena* arena) // null-definition at idx 0 ARRAY_FIELD_PUSH(p, defs, &(Def) { }); - syms_init(&p->syms); + ppsyms_init(&p->syms); return p; } @@ -180,7 +180,7 @@ void preproc_free(Preproc* p) } free(p->defs); } - syms_deinit(&p->syms); + ppsyms_deinit(&p->syms); free(p); } @@ -206,7 +206,7 @@ static void step(Preproc* p) p->tok_stack_size -= 1; if (p->curr.ty == Tok_EndOfMacroInvocation) { - syms_pop_layer(&p->syms); + ppsyms_pop_layer(&p->syms); step(p); return; } @@ -217,7 +217,7 @@ static void collect_arg(Preproc* p, size_t def_idx, size_t arg_idx) if (arg_idx >= p->defs[def_idx].params_size) { fprintf(stderr, "error: too many arguments for macro on line %d\n", - p->curr.line); + p->curr.loc.line); exit(1); } @@ -248,8 +248,9 @@ static void collect_arg(Preproc* p, size_t def_idx, size_t arg_idx) if (p->curr.ty != ',' && p->curr.ty != ')') { assert(p->curr.ty == Tok_Eof); - fprintf( - stderr, "error: expected ',' or ')' on line %d\n", p->curr.line); + fprintf(stderr, + "error: expected ',' or ')' on line %d\n", + p->curr.loc.line); exit(1); } @@ -260,7 +261,7 @@ static void collect_arg(Preproc* p, size_t def_idx, size_t arg_idx) .toks_size = toks_size, })); - syms_define(&p->syms, p->defs[def_idx].params[arg_idx], p->defs_size - 1); + ppsyms_define(&p->syms, p->defs[def_idx].params[arg_idx], p->defs_size - 1); } #define A(B, C) B C @@ -282,7 +283,7 @@ static void collect_args(Preproc* p, size_t def_idx) } } if (p->curr.ty != ')') { - fprintf(stderr, "error: expected ')' on line %d\n", p->curr.line); + fprintf(stderr, "error: expected ')' on line %d\n", p->curr.loc.line); exit(1); } @@ -290,7 +291,7 @@ static void collect_args(Preproc* p, size_t def_idx) if (idx > p->defs[def_idx].params_size) { fprintf(stderr, "error: too few arguments for macro on line %d\n", - p->curr.line); + p->curr.loc.line); exit(1); } } @@ -299,7 +300,7 @@ static Tok expand_tok(Preproc* p) { Tok tok = p->curr; size_t* def_idx; - if (tok.ty != Tok_Ident || !(def_idx = syms_get(&p->syms, tok.text))) { + if (tok.ty != Tok_Ident || !(def_idx = ppsyms_get(&p->syms, tok.text))) { step(p); return tok; } @@ -308,8 +309,8 @@ static Tok expand_tok(Preproc* p) // when seeing the same macro a second time // in the invocation tree, treat it as a normal token. // undefine it at this layer. - syms_push_layer(&p->syms); - syms_define(&p->syms, tok.text, 0); + ppsyms_push_layer(&p->syms); + ppsyms_define(&p->syms, tok.text, 0); if (p->defs[*def_idx].params) { step(p); @@ -323,8 +324,7 @@ static Tok expand_tok(Preproc* p) for (size_t i = 0; i < p->defs[*def_idx].toks_size; ++i) { Def* def = &p->defs[*def_idx]; Tok expanded_tok = def->toks[def->toks_size - i - 1]; - expanded_tok.line = tok.line; - expanded_tok.col = tok.col; + expanded_tok.loc = tok.loc; ARRAY_FIELD_PUSH(p, tok_stack, &expanded_tok); } @@ -338,8 +338,9 @@ static Tok do_define(Preproc* p) { step(p); if (p->curr.ty != Tok_Ident) { - fprintf( - stderr, "error: expected identifier on line %d\n", p->curr.line); + fprintf(stderr, + "error: expected identifier on line %d\n", + p->curr.loc.line); exit(1); } Tok ident_tok = p->curr; @@ -374,7 +375,8 @@ static Tok do_define(Preproc* p) } if (p->curr.ty != ')') { - fprintf(stderr, "error: expected ')' on line %d\n", p->curr.line); + fprintf( + stderr, "error: expected ')' on line %d\n", p->curr.loc.line); exit(1); } step(p); @@ -402,12 +404,13 @@ static Tok do_define(Preproc* p) def.toks_size = toks_size; ARRAY_FIELD_PUSH(p, defs, &def); - syms_define(&p->syms, ident_tok.text, p->defs_size - 1); + ppsyms_define(&p->syms, ident_tok.text, p->defs_size - 1); return p->curr; error_expected_identifier: - fprintf(stderr, "error: expected identifier on line %d\n", p->curr.line); + fprintf( + stderr, "error: expected identifier on line %d\n", p->curr.loc.line); exit(1); } @@ -416,8 +419,9 @@ static Tok do_undef(Preproc* p) step(p); if (p->curr.ty != Tok_Ident) { - fprintf( - stderr, "error: expected identifier on line %d\n", p->curr.line); + fprintf(stderr, + "error: expected identifier on line %d\n", + p->curr.loc.line); exit(1); } Tok ident_tok = p->curr; @@ -425,11 +429,11 @@ static Tok do_undef(Preproc* p) if (p->curr.ty != Tok_Eof && p->curr.ty != Tok_Eol) { fprintf(stderr, "error: unexpected extra tokens on line %d\n", - p->curr.line); + p->curr.loc.line); exit(1); } - syms_define(&p->syms, ident_tok.text, 0); + ppsyms_define(&p->syms, ident_tok.text, 0); return p->curr; } @@ -445,8 +449,9 @@ static Tok do_include(Preproc* p) curr_file->lexer.lex_headername = false; if (p->curr.ty != Tok_HeaderName) { - fprintf( - stderr, "error: expected header name on line %d\n", p->curr.line); + fprintf(stderr, + "error: expected header name on line %d\n", + p->curr.loc.line); exit(1); } @@ -456,7 +461,7 @@ static Tok do_include(Preproc* p) if (p->curr.ty != Tok_Eof && p->curr.ty != Tok_Eol) { fprintf(stderr, "error: unexpected extra tokens on line %d\n", - p->curr.line); + p->curr.loc.line); exit(1); } @@ -506,12 +511,13 @@ static Tok interpret_directive(Preproc* p); static Tok do_ifndef(Preproc* p) { - int original_line = p->curr.line; + int original_line = p->curr.loc.line; step(p); if (p->curr.ty != Tok_Ident) { - fprintf( - stderr, "error: expected identifier on line %d\n", p->curr.line); + fprintf(stderr, + "error: expected identifier on line %d\n", + p->curr.loc.line); exit(1); } Tok ident = p->curr; @@ -520,11 +526,11 @@ static Tok do_ifndef(Preproc* p) if (p->curr.ty != Tok_Eof && p->curr.ty != Tok_Eol) { fprintf(stderr, "error: unexpected extra tokens on line %d\n", - p->curr.line); + p->curr.loc.line); exit(1); } - bool cond = syms_get(&p->syms, ident.text) == nullptr; + bool cond = ppsyms_get(&p->syms, ident.text) == nullptr; condstack_push(&p->condstack, cond); @@ -561,7 +567,7 @@ static Tok do_endif(Preproc* p) if (p->curr.ty != Tok_Eof && p->curr.ty != Tok_Eol) { fprintf(stderr, "error: unexpected extra tokens on line %d\n", - p->curr.line); + p->curr.loc.line); exit(1); } @@ -576,8 +582,9 @@ static Tok interpret_directive(Preproc* p) return p->curr; if (p->curr.ty != Tok_Ident) { - fprintf( - stderr, "error: expected identifier on line %d\n", p->curr.line); + fprintf(stderr, + "error: expected identifier on line %d\n", + p->curr.loc.line); exit(1); } @@ -617,7 +624,7 @@ static Tok interpret_directive(Preproc* p) fprintf(stderr, "error: '%s' is not a preprocessor instruction on line %d\n", kw.text, - kw.line); + kw.loc.line); exit(1); } @@ -659,7 +666,7 @@ Tok tokstream_next(TokStream* s) text[0] = '\0'; strncat(text, curr.text, strlen(curr.text) - 1); strcat(text, next.text + 1); - s->curr = (Tok) { .ty = Tok_Str, text, curr.line, curr.col }; + s->curr = (Tok) { .ty = Tok_Str, text, curr.loc }; return tokstream_next(s); } diff --git a/syms.c b/syms.c new file mode 100644 index 0000000..6ea8b91 --- /dev/null +++ b/syms.c @@ -0,0 +1,52 @@ +#include "syms.h" +#include "collection.h" +#include +#include + +struct Syms { + ARRAY_FIELD(Hashmap, maps); +}; + +Syms* syms_new() +{ + Syms* s = malloc(sizeof(Syms)); + *s = (Syms) { + ARRAY_FIELD_INIT(maps), + }; + + ARRAY_FIELD_PUSH(s, maps, &(Hashmap) { }); + hashmap_init(&s->maps[0], sizeof(Sym*)); + + return s; +} + +void syms_free(Syms* s) +{ + free(s); +} + +void syms_push_scope(Syms* s) +{ + ARRAY_FIELD_PUSH(s, maps, &(Hashmap) { }); + hashmap_init(&s->maps[s->maps_size - 1], sizeof(Sym*)); +} + +void syms_pop_scope(Syms* 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, Sym* sym) +{ + Hashmap* m = &s->maps[s->maps_size - 1]; + hashmap_set(m, ident, &sym); +} + +Sym* syms_get(Syms* s, const char* ident) +{ + Hashmap* m = &s->maps[s->maps_size - 1]; + Sym** res = hashmap_get(m, ident); + return res ? *res : nullptr; +} diff --git a/syms.h b/syms.h new file mode 100644 index 0000000..97d34c3 --- /dev/null +++ b/syms.h @@ -0,0 +1,23 @@ +#ifndef SYMS_H +#define SYMS_H + +typedef enum { + Sym_Typedef, +} SymTy; + +typedef struct { + SymTy ty; +} Sym; + +typedef struct Syms Syms; + +Syms* syms_new(); +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); + +#endif