add parser
This commit is contained in:
parent
92ab4b519d
commit
b6bec01193
2
Makefile
2
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
|
||||
|
||||
|
||||
|
||||
98
ast.h
98
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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
36
lex.c
36
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);
|
||||
}
|
||||
|
||||
22
main.c
22
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);
|
||||
|
||||
|
||||
336
parse.c
336
parse.c
@ -1,5 +1,7 @@
|
||||
#include "parse.h"
|
||||
#include "ast.h"
|
||||
#include "collection.h"
|
||||
#include "syms.h"
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
11
parse.h
11
parse.h
@ -1,7 +1,9 @@
|
||||
#ifndef PARSE_H
|
||||
#define PARSE_H
|
||||
|
||||
#include "ast.h"
|
||||
#include "collection.h"
|
||||
#include "syms.h"
|
||||
#include <stddef.h>
|
||||
|
||||
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
|
||||
|
||||
105
preproc.c
105
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);
|
||||
}
|
||||
|
||||
|
||||
52
syms.c
Normal file
52
syms.c
Normal 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
23
syms.h
Normal 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
|
||||
Loading…
x
Reference in New Issue
Block a user