add parser

This commit is contained in:
sfja 2026-09-28 03:31:04 +02:00
parent 92ab4b519d
commit b6bec01193
11 changed files with 575 additions and 119 deletions

View File

@ -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 gcc $^ -o $@ -std=c23 -pedantic -Wall -Wextra -g -fsanitize=address

98
ast.h
View File

@ -8,57 +8,101 @@ typedef struct {
int col; int col;
} Loc; } 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 { typedef enum : unsigned int {
AstSpec_Typedef = 1 << 0, AstSpec_Int = 1 << 0,
// AstSpec_Constexpr = 1 << 1, AstSpec_Char = 1 << 1,
// AstSpec_Auto = 1 << 2, AstSpec_DefTy = 1 << 6,
// AstSpec_Register = 1 << 3, AstSpec_Unsigned = 1 << 7,
AstSpec_Static = 1 << 4, AstSpec_Static = 1 << 8,
// AstSpec_Extern = 1 << 5, AstSpec_Const = 1 << 9,
// AstSpec_ThreadLocal = 1 << 6, AstSpec_Inline = 1 << 10,
AstSpec_Const = 1 << 7, AstSpec_Typedef = 1 << 11,
// AstSpec_Volatile = 1 << 8, AstSpec_Enum = 1 << 12,
// AstSpec_Restrict = 1 << 9, AstSpec_Struct = 1 << 13,
// AstSpec_Atomic = 1 << 10, AstSpec_Union = 1 << 14,
AstSpec_Inline = 1 << 11,
} AstSpec; } AstSpec;
struct AstDecl {
AstSpec spec;
ARRAY_FIELD(AstDeclar*, declars);
AstStmtBlock* function_body;
Loc loc;
};
typedef enum { typedef enum {
AstDeclar_Ident, AstDeclar_Ident,
AstDeclar_Pointer, AstDeclar_Pointer,
AstDeclar_Array, AstDeclar_Array,
AstDeclar_Function,
} AstDeclarTy; } AstDeclarTy;
typedef struct AstDeclar AstDeclar;
struct AstDeclar { struct AstDeclar {
AstDeclarTy ty; AstDeclarTy ty;
Loc loc; Loc loc;
AstExpr* init_expr;
union { union {
char* ident; char* ident;
struct { struct {
AstDeclar* declar; AstDeclar* declar;
AstSpec spec; AstSpec spec;
} pointer; } 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 { typedef enum {
AstStmt_Decl, AstExpr_Str,
} AstStmtTy; AstExpr_Call,
} AstExprTy;
typedef struct { struct AstExpr {
AstStmtTy ty; AstExprTy ty;
union { union {
AstDecl decl; char* str_val;
struct {
AstExpr* expr;
ARRAY_FIELD(AstExpr*, args);
} call;
}; };
} AstStmt; };
#endif #endif

View File

@ -225,3 +225,10 @@ void arena_array_push(Arena* arena,
arena_realloc_wrap, arena_realloc_wrap,
arena); arena);
} }
char* arena_strdup(Arena* a, const char* str)
{
char* p = arena_alloc(a, strlen(str) + 1);
strcpy(p, str);
return p;
}

View File

@ -74,4 +74,6 @@ void arena_array_push(Arena* arena,
void* elem, void* elem,
size_t elem_size); size_t elem_size);
char* arena_strdup(Arena* a, const char* str);
#endif #endif

36
lex.c
View File

@ -96,8 +96,7 @@ void source_iter_init(SourceIter* r, const char* text)
Char source_iter_next(SourceIter* r) Char source_iter_next(SourceIter* r)
{ {
char ch = r->text[r->i]; char ch = r->text[r->i];
int line = r->line; Loc loc = { r->line, r->col };
int col = r->col;
if (r->text[r->i] != '\0') { if (r->text[r->i] != '\0') {
if (ch == '\n') { if (ch == '\n') {
@ -109,7 +108,7 @@ Char source_iter_next(SourceIter* r)
r->i += 1; r->i += 1;
} }
return (Char) { ch, line, col }; return (Char) { ch, loc };
} }
void lsl_iter_init(LslIter* r, SourceIter* source_char_iter) 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); char* text_dup = arena_alloc(l->arena, strlen(text) + 1);
text_dup[0] = '\0'; text_dup[0] = '\0';
strcpy(text_dup, text); strcpy(text_dup, text);
return (Tok) { ty, text_dup, line, col }; return (Tok) { ty, text_dup, loc };
} }
static bool done(Lexer* l) 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) Tok lexer_next(Lexer* l)
{ {
int line = l->curr.line; Loc loc = l->curr.loc;
int col = l->curr.col;
char text[max_token_text_len] = ""; char text[max_token_text_len] = "";
size_t text_len = 0; size_t text_len = 0;
if (done(l)) { if (done(l)) {
return tok(l, Tok_Eof, text, line, col); return tok(l, Tok_Eof, text, loc);
} }
bool matched = false; bool matched = false;
@ -193,7 +191,7 @@ Tok lexer_next(Lexer* l)
} }
if (matched) { if (matched) {
if (l->lex_whitespace) { if (l->lex_whitespace) {
return tok(l, Tok_Whitespace, text, line, col); return tok(l, Tok_Whitespace, text, loc);
} }
return lexer_next(l); return lexer_next(l);
} }
@ -206,7 +204,7 @@ Tok lexer_next(Lexer* l)
step(l, text, &text_len); step(l, text, &text_len);
} }
if (matched) { 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') while ((l->curr.ch >= '1' && l->curr.ch <= '9')
@ -215,7 +213,7 @@ Tok lexer_next(Lexer* l)
step(l, text, &text_len); step(l, text, &text_len);
} }
if (matched) { 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 == '<')) { if (l->lex_headername && (l->curr.ch == '"' || l->curr.ch == '<')) {
@ -228,11 +226,11 @@ Tok lexer_next(Lexer* l)
fprintf(stderr, fprintf(stderr,
"error: malformed header name, expected '%c' on line %d\n", "error: malformed header name, expected '%c' on line %d\n",
ter, ter,
l->curr.line); l->curr.loc.line);
return lexer_next(l); return lexer_next(l);
} }
step(l, text, &text_len); step(l, text, &text_len);
return tok(l, Tok_HeaderName, text, line, col); return tok(l, Tok_HeaderName, text, loc);
} }
if (l->curr.ch == '"') { if (l->curr.ch == '"') {
@ -248,11 +246,11 @@ Tok lexer_next(Lexer* l)
if (done(l) || l->curr.ch != '"') { if (done(l) || l->curr.ch != '"') {
fprintf(stderr, fprintf(stderr,
"error: malformed string literal on line %d\n", "error: malformed string literal on line %d\n",
l->curr.line); l->curr.loc.line);
return lexer_next(l); return lexer_next(l);
} }
step(l, text, &text_len); step(l, text, &text_len);
return tok(l, Tok_Str, text, line, col); return tok(l, Tok_Str, text, loc);
} }
if (l->curr.ch == '\'') { if (l->curr.ch == '\'') {
@ -266,22 +264,22 @@ Tok lexer_next(Lexer* l)
if (done(l) && l->curr.ch != '\'') { if (done(l) && l->curr.ch != '\'') {
fprintf(stderr, fprintf(stderr,
"error: malformed character literal on line %d\n", "error: malformed character literal on line %d\n",
l->curr.line); l->curr.loc.line);
return lexer_next(l); return lexer_next(l);
} }
step(l, text, &text_len); 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)) { if (strchr("\n;(){},*#", l->curr.ch)) {
TokTy ty = (TokTy)l->curr.ch; TokTy ty = (TokTy)l->curr.ch;
step(l, text, &text_len); step(l, text, &text_len);
return tok(l, ty, text, line, col); return tok(l, ty, text, loc);
} }
fprintf(stderr, fprintf(stderr,
"error: illegal character '%c' on line %d\n", "error: illegal character '%c' on line %d\n",
l->curr.ch, l->curr.ch,
l->curr.line); l->curr.loc.line);
step(l, text, &text_len); step(l, text, &text_len);
return lexer_next(l); return lexer_next(l);
} }

22
main.c
View File

@ -30,26 +30,26 @@ int main(int argc, char* argv[])
printf("--- tokens ---\n"); printf("--- tokens ---\n");
int line = 1; Loc loc = { 1, 1 };
int col = 1;
Tok tok; Tok tok;
while ((tok = tokstream_next(&tokstream)).ty != Tok_Eof) { while ((tok = tokstream_next(&tokstream)).ty != Tok_Eof) {
// printf("%s\t%s\n", tokty_str(tok.ty), tok.text); // printf("%s\t%s\n", tokty_str(tok.ty), tok.text);
if (line > tok.line) { Loc tok_loc = tok.loc;
line = 0; if (loc.line > tok_loc.line) {
loc.line = 0;
} }
while (line < tok.line) { while (loc.line < tok_loc.line) {
printf("\n"); printf("\n");
line += 1; loc.line += 1;
col = 1; loc.col = 1;
} }
while (col < tok.col) { while (loc.col < tok_loc.col) {
printf(" "); printf(" ");
col += 1; loc.col += 1;
} }
printf("%s", tok.text); printf("%s", tok.text);
line = tok.line; loc.line = tok_loc.line;
col = tok.col + strlen(tok.text); loc.col = tok_loc.col + strlen(tok.text);
} }
fputs("\n", stdout); fputs("\n", stdout);

336
parse.c
View File

@ -1,5 +1,7 @@
#include "parse.h" #include "parse.h"
#include "ast.h"
#include "collection.h" #include "collection.h"
#include "syms.h"
#include <assert.h> #include <assert.h>
#include <stddef.h> #include <stddef.h>
#include <stdio.h> #include <stdio.h>
@ -41,11 +43,11 @@ static KwNodeOpt* kwmatcher_create_path(
.idx = new_idx, .idx = new_idx,
}; };
arena_array_push(&m->arena, arena_array_push(&m->arena,
(void**)&(m)->nodes, (void**)&m->nodes,
&(m)->nodes_cap, &m->nodes_cap,
&(m)->nodes_size, &m->nodes_size,
(&new_node), &new_node,
sizeof(*(&new_node))); sizeof(new_node));
KwNode* node = &m->nodes[new_idx]; KwNode* node = &m->nodes[new_idx];
KwNodeOpt new_opt = { KwNodeOpt new_opt = {
@ -57,8 +59,8 @@ static KwNodeOpt* kwmatcher_create_path(
(void**)&node->opts, (void**)&node->opts,
&node->opts_cap, &node->opts_cap,
&node->opts_size, &node->opts_size,
(&new_opt), &new_opt,
sizeof(*(&new_opt))); sizeof(new_opt));
opt = &node->opts[node->opts_size - 1]; opt = &node->opts[node->opts_size - 1];
} }
@ -147,7 +149,7 @@ static Tok kwmatcher_next(KwMatcher* m)
return tok; return tok;
TokTy ty = kwmatcher_match(m, tok.text); TokTy ty = kwmatcher_match(m, tok.text);
if (ty != Tok_Ident) 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; tok.ty = ty;
return tok; return tok;
} }
@ -155,6 +157,11 @@ static Tok kwmatcher_next(KwMatcher* m)
struct Parser { struct Parser {
KwMatcher kwmatcher; KwMatcher kwmatcher;
Arena* arena; Arena* arena;
Arena sym_arena;
Syms* ord_ns;
Syms* label_ns;
Syms* tag_ns;
Tok curr; Tok curr;
}; };
@ -166,6 +173,11 @@ Parser* parser_new(TokStream* tokstream, Arena* arena)
*p = (Parser) { *p = (Parser) {
.kwmatcher = { }, .kwmatcher = { },
.arena = arena, .arena = arena,
.sym_arena = { },
.ord_ns = syms_new(),
.label_ns = syms_new(),
.tag_ns = syms_new(),
.curr = { }, .curr = { },
}; };
@ -181,3 +193,311 @@ void parser_free(Parser* p)
kwmatcher_deinit(&p->kwmatcher); kwmatcher_deinit(&p->kwmatcher);
free(p); 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**)&params,
&params_cap,
&params_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)
{
}

11
parse.h
View File

@ -1,7 +1,9 @@
#ifndef PARSE_H #ifndef PARSE_H
#define PARSE_H #define PARSE_H
#include "ast.h"
#include "collection.h" #include "collection.h"
#include "syms.h"
#include <stddef.h> #include <stddef.h>
char* read_textfile(const char* filename); char* read_textfile(const char* filename);
@ -13,8 +15,7 @@ char* read_textfile(const char* filename);
typedef struct { typedef struct {
char ch; char ch;
int line; Loc loc;
int col;
} Char; } Char;
typedef struct { typedef struct {
@ -70,8 +71,7 @@ const char* tokty_str(TokTy ty);
typedef struct { typedef struct {
TokTy ty; TokTy ty;
char* text; char* text;
int line; Loc loc;
int col;
} Tok; } Tok;
typedef struct { typedef struct {
@ -108,5 +108,8 @@ typedef struct Parser Parser;
Parser* parser_new(TokStream* tokstream, Arena* arena); Parser* parser_new(TokStream* tokstream, Arena* arena);
void parser_free(Parser* p); void parser_free(Parser* p);
AstStmt* parser_parse_stmt(Parser* p);
AstDecl* parser_parse_decl(Parser* p);
AstExpr* parser_parse_expr(Parser* p);
#endif #endif

105
preproc.c
View File

@ -8,19 +8,19 @@
typedef struct { typedef struct {
ARRAY_FIELD(Hashmap, maps); 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), 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) { if (s->maps) {
for (size_t i = 0; i < s->maps_size; ++i) { 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 m = { };
hashmap_init(&m, sizeof(size_t)); hashmap_init(&m, sizeof(size_t));
array_push((void**)&s->maps, &s->maps_cap, &s->maps_size, &m, sizeof(m)); 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); assert(s->maps_size > 0);
@ -45,19 +45,19 @@ static void syms_pop_layer(Syms* s)
s->maps_size -= 1; s->maps_size -= 1;
} }
static Hashmap* syms_current(Syms* s) static Hashmap* ppsyms_current(PPSyms* s)
{ {
assert(s->maps_size > 0); assert(s->maps_size > 0);
return &s->maps[s->maps_size - 1]; 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); 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) { for (size_t i = 0; i < s->maps_size; ++i) {
Hashmap* m = &s->maps[s->maps_size - i - 1]; Hashmap* m = &s->maps[s->maps_size - i - 1];
@ -114,7 +114,7 @@ struct Preproc {
Tok curr; Tok curr;
ARRAY_FIELD(Def, defs); ARRAY_FIELD(Def, defs);
Syms syms; PPSyms syms;
CondStack condstack; CondStack condstack;
@ -159,7 +159,7 @@ Preproc* preproc_new(char* filename, char* text, Arena* arena)
// null-definition at idx 0 // null-definition at idx 0
ARRAY_FIELD_PUSH(p, defs, &(Def) { }); ARRAY_FIELD_PUSH(p, defs, &(Def) { });
syms_init(&p->syms); ppsyms_init(&p->syms);
return p; return p;
} }
@ -180,7 +180,7 @@ void preproc_free(Preproc* p)
} }
free(p->defs); free(p->defs);
} }
syms_deinit(&p->syms); ppsyms_deinit(&p->syms);
free(p); free(p);
} }
@ -206,7 +206,7 @@ static void step(Preproc* p)
p->tok_stack_size -= 1; p->tok_stack_size -= 1;
if (p->curr.ty == Tok_EndOfMacroInvocation) { if (p->curr.ty == Tok_EndOfMacroInvocation) {
syms_pop_layer(&p->syms); ppsyms_pop_layer(&p->syms);
step(p); step(p);
return; 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) { if (arg_idx >= p->defs[def_idx].params_size) {
fprintf(stderr, fprintf(stderr,
"error: too many arguments for macro on line %d\n", "error: too many arguments for macro on line %d\n",
p->curr.line); p->curr.loc.line);
exit(1); 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 != ')') { if (p->curr.ty != ',' && p->curr.ty != ')') {
assert(p->curr.ty == Tok_Eof); assert(p->curr.ty == Tok_Eof);
fprintf( fprintf(stderr,
stderr, "error: expected ',' or ')' on line %d\n", p->curr.line); "error: expected ',' or ')' on line %d\n",
p->curr.loc.line);
exit(1); exit(1);
} }
@ -260,7 +261,7 @@ static void collect_arg(Preproc* p, size_t def_idx, size_t arg_idx)
.toks_size = toks_size, .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 #define A(B, C) B C
@ -282,7 +283,7 @@ static void collect_args(Preproc* p, size_t def_idx)
} }
} }
if (p->curr.ty != ')') { 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); exit(1);
} }
@ -290,7 +291,7 @@ static void collect_args(Preproc* p, size_t def_idx)
if (idx > p->defs[def_idx].params_size) { if (idx > p->defs[def_idx].params_size) {
fprintf(stderr, fprintf(stderr,
"error: too few arguments for macro on line %d\n", "error: too few arguments for macro on line %d\n",
p->curr.line); p->curr.loc.line);
exit(1); exit(1);
} }
} }
@ -299,7 +300,7 @@ static Tok expand_tok(Preproc* p)
{ {
Tok tok = p->curr; Tok tok = p->curr;
size_t* def_idx; 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); step(p);
return tok; return tok;
} }
@ -308,8 +309,8 @@ static Tok expand_tok(Preproc* p)
// when seeing the same macro a second time // when seeing the same macro a second time
// in the invocation tree, treat it as a normal token. // in the invocation tree, treat it as a normal token.
// undefine it at this layer. // undefine it at this layer.
syms_push_layer(&p->syms); ppsyms_push_layer(&p->syms);
syms_define(&p->syms, tok.text, 0); ppsyms_define(&p->syms, tok.text, 0);
if (p->defs[*def_idx].params) { if (p->defs[*def_idx].params) {
step(p); 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) { for (size_t i = 0; i < p->defs[*def_idx].toks_size; ++i) {
Def* def = &p->defs[*def_idx]; Def* def = &p->defs[*def_idx];
Tok expanded_tok = def->toks[def->toks_size - i - 1]; Tok expanded_tok = def->toks[def->toks_size - i - 1];
expanded_tok.line = tok.line; expanded_tok.loc = tok.loc;
expanded_tok.col = tok.col;
ARRAY_FIELD_PUSH(p, tok_stack, &expanded_tok); ARRAY_FIELD_PUSH(p, tok_stack, &expanded_tok);
} }
@ -338,8 +338,9 @@ static Tok do_define(Preproc* p)
{ {
step(p); step(p);
if (p->curr.ty != Tok_Ident) { if (p->curr.ty != Tok_Ident) {
fprintf( fprintf(stderr,
stderr, "error: expected identifier on line %d\n", p->curr.line); "error: expected identifier on line %d\n",
p->curr.loc.line);
exit(1); exit(1);
} }
Tok ident_tok = p->curr; Tok ident_tok = p->curr;
@ -374,7 +375,8 @@ static Tok do_define(Preproc* p)
} }
if (p->curr.ty != ')') { 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); exit(1);
} }
step(p); step(p);
@ -402,12 +404,13 @@ static Tok do_define(Preproc* p)
def.toks_size = toks_size; def.toks_size = toks_size;
ARRAY_FIELD_PUSH(p, defs, &def); 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; return p->curr;
error_expected_identifier: 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); exit(1);
} }
@ -416,8 +419,9 @@ static Tok do_undef(Preproc* p)
step(p); step(p);
if (p->curr.ty != Tok_Ident) { if (p->curr.ty != Tok_Ident) {
fprintf( fprintf(stderr,
stderr, "error: expected identifier on line %d\n", p->curr.line); "error: expected identifier on line %d\n",
p->curr.loc.line);
exit(1); exit(1);
} }
Tok ident_tok = p->curr; 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) { if (p->curr.ty != Tok_Eof && p->curr.ty != Tok_Eol) {
fprintf(stderr, fprintf(stderr,
"error: unexpected extra tokens on line %d\n", "error: unexpected extra tokens on line %d\n",
p->curr.line); p->curr.loc.line);
exit(1); exit(1);
} }
syms_define(&p->syms, ident_tok.text, 0); ppsyms_define(&p->syms, ident_tok.text, 0);
return p->curr; return p->curr;
} }
@ -445,8 +449,9 @@ static Tok do_include(Preproc* p)
curr_file->lexer.lex_headername = false; curr_file->lexer.lex_headername = false;
if (p->curr.ty != Tok_HeaderName) { if (p->curr.ty != Tok_HeaderName) {
fprintf( fprintf(stderr,
stderr, "error: expected header name on line %d\n", p->curr.line); "error: expected header name on line %d\n",
p->curr.loc.line);
exit(1); exit(1);
} }
@ -456,7 +461,7 @@ static Tok do_include(Preproc* p)
if (p->curr.ty != Tok_Eof && p->curr.ty != Tok_Eol) { if (p->curr.ty != Tok_Eof && p->curr.ty != Tok_Eol) {
fprintf(stderr, fprintf(stderr,
"error: unexpected extra tokens on line %d\n", "error: unexpected extra tokens on line %d\n",
p->curr.line); p->curr.loc.line);
exit(1); exit(1);
} }
@ -506,12 +511,13 @@ static Tok interpret_directive(Preproc* p);
static Tok do_ifndef(Preproc* p) static Tok do_ifndef(Preproc* p)
{ {
int original_line = p->curr.line; int original_line = p->curr.loc.line;
step(p); step(p);
if (p->curr.ty != Tok_Ident) { if (p->curr.ty != Tok_Ident) {
fprintf( fprintf(stderr,
stderr, "error: expected identifier on line %d\n", p->curr.line); "error: expected identifier on line %d\n",
p->curr.loc.line);
exit(1); exit(1);
} }
Tok ident = p->curr; 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) { if (p->curr.ty != Tok_Eof && p->curr.ty != Tok_Eol) {
fprintf(stderr, fprintf(stderr,
"error: unexpected extra tokens on line %d\n", "error: unexpected extra tokens on line %d\n",
p->curr.line); p->curr.loc.line);
exit(1); 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); 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) { if (p->curr.ty != Tok_Eof && p->curr.ty != Tok_Eol) {
fprintf(stderr, fprintf(stderr,
"error: unexpected extra tokens on line %d\n", "error: unexpected extra tokens on line %d\n",
p->curr.line); p->curr.loc.line);
exit(1); exit(1);
} }
@ -576,8 +582,9 @@ static Tok interpret_directive(Preproc* p)
return p->curr; return p->curr;
if (p->curr.ty != Tok_Ident) { if (p->curr.ty != Tok_Ident) {
fprintf( fprintf(stderr,
stderr, "error: expected identifier on line %d\n", p->curr.line); "error: expected identifier on line %d\n",
p->curr.loc.line);
exit(1); exit(1);
} }
@ -617,7 +624,7 @@ static Tok interpret_directive(Preproc* p)
fprintf(stderr, fprintf(stderr,
"error: '%s' is not a preprocessor instruction on line %d\n", "error: '%s' is not a preprocessor instruction on line %d\n",
kw.text, kw.text,
kw.line); kw.loc.line);
exit(1); exit(1);
} }
@ -659,7 +666,7 @@ Tok tokstream_next(TokStream* s)
text[0] = '\0'; text[0] = '\0';
strncat(text, curr.text, strlen(curr.text) - 1); strncat(text, curr.text, strlen(curr.text) - 1);
strcat(text, next.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); return tokstream_next(s);
} }

52
syms.c Normal file
View File

@ -0,0 +1,52 @@
#include "syms.h"
#include "collection.h"
#include <assert.h>
#include <stdlib.h>
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;
}

23
syms.h Normal file
View File

@ -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