more parser

This commit is contained in:
sfja 2026-09-29 04:22:57 +02:00
parent b6bec01193
commit 9bf5fc06db
10 changed files with 681 additions and 115 deletions

View File

@ -1,5 +1,5 @@
larpcc: main.c lex.c preproc.c collection.c parse.c syms.c
gcc $^ -o $@ -std=c23 -pedantic -Wall -Wextra -g -fsanitize=address
larpcc: main.c lex.c preproc.c collection.c parse.c syms.c ast_str.c
gcc $^ -o $@ -std=c23 -pedantic -Wall -Wextra -g -fsanitize=address -Werror=switch

18
ast.h
View File

@ -57,6 +57,7 @@ typedef enum : unsigned int {
struct AstDecl {
AstSpec spec;
char* type_ident;
ARRAY_FIELD(AstDeclar*, declars);
AstStmtBlock* function_body;
Loc loc;
@ -84,7 +85,8 @@ struct AstDeclar {
AstExpr* expr;
} array;
struct {
ARRAY_FIELD(AstDecl, params);
AstDeclar* declar;
ARRAY_FIELD(AstDecl*, params);
} function;
};
};
@ -96,6 +98,7 @@ typedef enum {
struct AstExpr {
AstExprTy ty;
Loc loc;
union {
char* str_val;
struct {
@ -105,4 +108,17 @@ struct AstExpr {
};
};
typedef struct {
ARRAY_FIELD(char, string);
Arena* arena;
int depth;
} AstStringifier;
void ast_stringifier_init(AstStringifier* s, Arena* arena);
void ast_stmt_block_to_string(AstStringifier* s, const AstStmtBlock* node);
void ast_stmt_to_string(AstStringifier* s, const AstStmt* node);
void ast_decl_to_string(AstStringifier* s, const AstDecl* node);
void ast_declar_to_string(AstStringifier* s, const AstDeclar* node);
void ast_expr_to_string(AstStringifier* s, const AstExpr* node);
#endif

283
ast_str.c Normal file
View File

@ -0,0 +1,283 @@
#include "ast.h"
#include "collection.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
static void push(AstStringifier* s, const char* str)
{
for (; *str; ++str) {
arena_array_push(s->arena,
(void**)&s->string,
&s->string_cap,
&s->string_size,
(void*)str,
sizeof(*str));
}
char ch = '\0';
arena_array_push(s->arena,
(void**)&s->string,
&s->string_cap,
&s->string_size,
(void*)&ch,
sizeof(ch));
s->string_size -= 1;
}
#define pushf(S, ...) \
do { \
size_t len = snprintf(nullptr, 0, __VA_ARGS__); \
char* buf = calloc(len + 1, 1); \
snprintf(buf, len + 1, __VA_ARGS__); \
push(S, buf); \
free(buf); \
} while (false)
static void indent(AstStringifier* s)
{
for (int i = 0; i < s->depth; ++i) {
push(s, " ");
}
}
void ast_stringifier_init(AstStringifier* s, Arena* arena)
{
*s = (AstStringifier) {
ARRAY_FIELD_INIT(string),
.arena = arena,
.depth = 0,
};
}
void ast_stmt_block_to_string(AstStringifier* s, const AstStmtBlock* node)
{
pushf(s, "StmtBlock %d:%d {\n", node->loc.line, node->loc.col);
s->depth += 1;
indent(s);
push(s, "stmts: [");
if (node->stmts_size) {
s->depth += 1;
push(s, "\n");
for (size_t i = 0; i < node->stmts_size; ++i) {
indent(s);
ast_stmt_to_string(s, node->stmts[i]);
push(s, ",\n");
}
s->depth -= 1;
indent(s);
}
push(s, "],");
s->depth -= 1;
indent(s);
push(s, "}");
}
void ast_stmt_to_string(AstStringifier* s, const AstStmt* node)
{
switch (node->ty) {
case AstStmt_Decl: {
pushf(s, "Stmt::Decl %d:%d {\n", node->loc.line, node->loc.col);
s->depth += 1;
indent(s);
push(s, "decl: ");
ast_decl_to_string(s, node->decl);
push(s, ",\n");
s->depth -= 1;
indent(s);
push(s, "}");
break;
}
case AstStmt_Expr: {
pushf(s, "Stmt::Expr %d:%d {\n", node->loc.line, node->loc.col);
s->depth += 1;
indent(s);
push(s, "expr: ");
ast_expr_to_string(s, node->expr);
push(s, ",\n");
s->depth -= 1;
indent(s);
push(s, "}");
break;
}
}
}
static void spec_to_string(AstStringifier* s, AstSpec spec)
{
struct {
AstSpec specifier;
const char* ident;
} spec_idents[] = {
{ AstSpec_Int, "int" },
{ AstSpec_Char, "char" },
{ AstSpec_Unsigned, "unsigned" },
{ AstSpec_Static, "static" },
{ AstSpec_Const, "const" },
{ AstSpec_Inline, "inline" },
{ AstSpec_Typedef, "typedef" },
{ AstSpec_Enum, "enum" },
{ AstSpec_Struct, "struct" },
{ AstSpec_Union, "union" },
};
bool first = true;
for (size_t i = 0; i < sizeof(spec_idents) / sizeof(spec_idents[0]); ++i) {
if (spec & spec_idents[i].specifier) {
if (!first)
push(s, " ");
first = false;
push(s, spec_idents[i].ident);
}
}
}
void ast_decl_to_string(AstStringifier* s, const AstDecl* node)
{
pushf(s, "Decl %d:%d {\n", node->loc.line, node->loc.col);
s->depth += 1;
indent(s);
push(s, "spec: [");
spec_to_string(s, node->spec);
push(s, "],\n");
if (node->spec & AstSpec_DefTy) {
assert(node->type_ident);
indent(s);
pushf(s, "type_ident: \"%s\",\n", node->type_ident);
}
indent(s);
push(s, "declars: [");
if (node->declars_size) {
push(s, "\n");
s->depth += 1;
for (size_t i = 0; i < node->declars_size; ++i) {
indent(s);
ast_declar_to_string(s, node->declars[i]);
push(s, ",\n");
}
s->depth -= 1;
indent(s);
push(s, "],\n");
} else {
push(s, "],\n");
}
if (node->function_body) {
indent(s);
push(s, "function_body: ");
ast_stmt_block_to_string(s, node->function_body);
push(s, ",\n");
}
s->depth -= 1;
indent(s);
push(s, "}");
}
void ast_declar_to_string(AstStringifier* s, const AstDeclar* node)
{
switch (node->ty) {
case AstDeclar_Ident: {
pushf(s, "Declar::Ident %d:%d {\n", node->loc.line, node->loc.col);
s->depth += 1;
indent(s);
pushf(s, "ident: \"%s\",\n", node->ident);
break;
}
case AstDeclar_Pointer: {
pushf(
s, "Declar::Pointer %d:%d {\n", node->loc.line, node->loc.col);
s->depth += 1;
indent(s);
push(s, "declar: ");
ast_declar_to_string(s, node->pointer.declar);
push(s, ",\n");
indent(s);
push(s, "spec: [");
spec_to_string(s, node->pointer.spec);
push(s, "],\n");
break;
}
case AstDeclar_Array: {
pushf(s, "Declar::Array %d:%d {\n", node->loc.line, node->loc.col);
s->depth += 1;
indent(s);
push(s, "declar: ");
ast_declar_to_string(s, node->array.declar);
push(s, ",\n");
indent(s);
push(s, "expr: ");
ast_expr_to_string(s, node->array.expr);
push(s, ",\n");
break;
}
case AstDeclar_Function: {
pushf(
s, "Declar::Function %d:%d {\n", node->loc.line, node->loc.col);
s->depth += 1;
indent(s);
push(s, "declar: ");
ast_declar_to_string(s, node->array.declar);
push(s, ",\n");
indent(s);
push(s, "params: [");
if (node->function.params_size) {
push(s, "\n");
s->depth += 1;
for (size_t i = 0; i < node->function.params_size; ++i) {
indent(s);
ast_decl_to_string(s, node->function.params[i]);
push(s, ",\n");
}
s->depth -= 1;
indent(s);
push(s, "],\n");
} else {
push(s, "],\n");
}
break;
}
}
if (node->init_expr) {
indent(s);
push(s, "decl: ");
ast_expr_to_string(s, node->init_expr);
push(s, ",\n");
}
s->depth -= 1;
indent(s);
push(s, "}");
}
void ast_expr_to_string(AstStringifier* s, const AstExpr* node)
{
push(s, "<expr>");
}

View File

@ -76,4 +76,20 @@ void arena_array_push(Arena* arena,
char* arena_strdup(Arena* a, const char* str);
#define ARENA_ARRAY_FIELD_PUSH(ARENA, STRUCT_PTR, FIELD_NAME, ELEM_PTR) \
arena_array_push((ARENA), \
(void**)&(STRUCT_PTR)->FIELD_NAME, \
&(STRUCT_PTR)->FIELD_NAME##_cap, \
&(STRUCT_PTR)->FIELD_NAME##_size, \
(ELEM_PTR), \
sizeof(*(ELEM_PTR)))
#define ARENA_ARRAY_VAR_PUSH(ARENA, VAR_NAME, ELEM_PTR) \
arena_array_push((ARENA), \
(void**)&VAR_NAME, \
&VAR_NAME##_cap, \
&VAR_NAME##_size, \
(ELEM_PTR), \
sizeof(*(ELEM_PTR)))
#endif

View File

@ -2,5 +2,5 @@
-pedantic-errors
-Wall
-Wextra
-Werror=switch

13
lex.c
View File

@ -78,9 +78,18 @@ const char* tokty_str(TokTy ty)
return "Asterisk";
case Tok_Hashtag:
return "Hashtag";
default:
return "<unknown>";
case Tok_Comma:
return "Comma";
case Tok_KwInt:
return "KwInt";
case Tok_KwChar:
return "KwChar";
case Tok_KwConst:
return "KwConst";
case Tok_EndOfMacroInvocation:
return "EndOfMacroInvocation";
}
return "<unknown>";
}
void source_iter_init(SourceIter* r, const char* text)

101
main.c
View File

@ -1,3 +1,4 @@
#include "ast.h"
#include "collection.h"
#include "parse.h"
#include <assert.h>
@ -20,39 +21,83 @@ int main(int argc, char* argv[])
printf("--- text ---\n%s\n", text);
Arena tok_arena;
arena_init(&tok_arena, 4096);
{
Preproc* preproc = preproc_new(strdup(filename), text, &tok_arena);
Arena tok_arena;
arena_init(&tok_arena, 4096);
TokStream tokstream;
tokstream_init(&tokstream, preproc, &tok_arena);
Preproc* preproc
= preproc_new(strdup(filename), strdup(text), &tok_arena);
printf("--- tokens ---\n");
TokStream tokstream;
tokstream_init(&tokstream, preproc, &tok_arena);
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);
Loc tok_loc = tok.loc;
if (loc.line > tok_loc.line) {
loc.line = 0;
printf("--- tokens ---\n");
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);
Loc tok_loc = tok.loc;
if (loc.line > tok_loc.line) {
loc.line = 0;
}
while (loc.line < tok_loc.line) {
printf("\n");
loc.line += 1;
loc.col = 1;
}
while (loc.col < tok_loc.col) {
printf(" ");
loc.col += 1;
}
printf("%s", tok.text);
loc.line = tok_loc.line;
loc.col = tok_loc.col + strlen(tok.text);
}
while (loc.line < tok_loc.line) {
printf("\n");
loc.line += 1;
loc.col = 1;
}
while (loc.col < tok_loc.col) {
printf(" ");
loc.col += 1;
}
printf("%s", tok.text);
loc.line = tok_loc.line;
loc.col = tok_loc.col + strlen(tok.text);
fputs("\n", stdout);
preproc_free(preproc);
arena_deinit(&tok_arena);
}
fputs("\n", stdout);
preproc_free(preproc);
arena_deinit(&tok_arena);
{
Arena tok_arena;
arena_init(&tok_arena, 4096);
Preproc* preproc = preproc_new(strdup(filename), text, &tok_arena);
TokStream tokstream;
tokstream_init(&tokstream, preproc, &tok_arena);
Arena ast_arena;
arena_init(&ast_arena, 4096);
printf("--- ast ---\n");
Parser* parser = parser_new(&tokstream, &ast_arena);
AstStmt* stmt;
while (!parser_done(parser)) {
stmt = parser_parse_stmt(parser);
Arena s_arena;
arena_init(&s_arena, 4096);
AstStringifier s = { };
ast_stringifier_init(&s, &s_arena);
ast_stmt_to_string(&s, stmt);
printf("%s\n", s.string);
arena_deinit(&s_arena);
}
parser_free(parser);
preproc_free(preproc);
arena_deinit(&tok_arena);
arena_deinit(&ast_arena);
}
}

338
parse.c
View File

@ -6,6 +6,7 @@
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char ch;
@ -22,17 +23,34 @@ typedef struct {
TokStream* tokstream;
Arena arena;
ARRAY_FIELD(KwNode, nodes);
KwNode* root;
} KwMatcher;
static void kw_tree_print(KwMatcher* m, KwNode* node, int depth)
{
for (size_t i = 0; i < node->opts_size; ++i) {
for (int i = 0; i < depth; ++i)
printf(" ");
printf("%c", node->opts[i].ch);
if (node->opts[i].is_term) {
printf(" = %s\n", tokty_str(node->opts[i].val));
} else {
printf("\n");
kw_tree_print(m, &m->nodes[node->opts[i].val], depth + 1);
}
}
}
static KwNodeOpt* kwmatcher_create_path(
KwMatcher* m, KwNode* node, const char* kw)
KwMatcher* m, size_t node_idx, const char* kw)
{
assert(kw[0]);
KwNode* node = &m->nodes[node_idx];
KwNodeOpt* opt = nullptr;
for (size_t i = 0; i < node->opts_size; ++i) {
if (node->opts[i].ch == kw[0]) {
opt = &node->opts[i];
break;
}
}
if (!opt) {
@ -48,7 +66,8 @@ static KwNodeOpt* kwmatcher_create_path(
&m->nodes_size,
&new_node,
sizeof(new_node));
KwNode* node = &m->nodes[new_idx];
// might have been relocated
node = &m->nodes[node_idx];
KwNodeOpt new_opt = {
.ch = kw[0],
@ -67,13 +86,12 @@ static KwNodeOpt* kwmatcher_create_path(
if (!kw[1])
return opt;
KwNode* next_node = &m->nodes[opt->val];
return kwmatcher_create_path(m, next_node, &kw[1]);
return kwmatcher_create_path(m, opt->val, &kw[1]);
}
static void kwmatcher_add(KwMatcher* m, const char* kw, TokTy tokty)
{
KwNodeOpt* opt = kwmatcher_create_path(m, m->root, kw);
KwNodeOpt* opt = kwmatcher_create_path(m, 0, kw);
opt->is_term = true;
opt->val = tokty;
}
@ -97,8 +115,8 @@ static KwNodeOpt* kwmatcher_find_node(
static TokTy kwmatcher_match(KwMatcher* m, const char* kw)
{
KwNodeOpt* opt = kwmatcher_find_node(m, m->root, kw);
if (!opt->is_term)
KwNodeOpt* opt = kwmatcher_find_node(m, &m->nodes[0], kw);
if (!opt || !opt->is_term)
return Tok_Ident;
return opt->val;
}
@ -109,7 +127,6 @@ static void kwmatcher_init(KwMatcher* m, TokStream* tokstream)
.tokstream = tokstream,
.arena = { },
ARRAY_FIELD_INIT(nodes),
.root = nullptr,
};
arena_init(&m->arena, 512);
@ -121,8 +138,6 @@ static void kwmatcher_init(KwMatcher* m, TokStream* tokstream)
(&(KwNode) { .idx = 0 }),
sizeof(*(&(KwNode) { .idx = 0 })));
m->root = &m->nodes[0];
struct {
TokTy ty;
const char* kw;
@ -135,6 +150,8 @@ static void kwmatcher_init(KwMatcher* m, TokStream* tokstream)
for (size_t i = 0; i < sizeof(kws) / sizeof(kws[0]); ++i) {
kwmatcher_add(m, kws[i].kw, kws[i].ty);
}
kw_tree_print(m, &m->nodes[0], 0);
}
static void kwmatcher_deinit(KwMatcher* m)
@ -146,11 +163,18 @@ static Tok kwmatcher_next(KwMatcher* m)
{
Tok tok = tokstream_next(m->tokstream);
if (tok.ty != Tok_Ident)
return tok;
goto exit;
TokTy ty = kwmatcher_match(m, tok.text);
if (ty != Tok_Ident)
printf("info: matched '%s' on line %d\n", tok.text, tok.loc.line);
tok.ty = ty;
exit:
printf(" - %s(%s) %d:%d\n",
tokty_str(tok.ty),
tok.text,
tok.loc.line,
tok.loc.col);
return tok;
}
@ -210,6 +234,47 @@ static void step(Parser* p)
DEFINE_NEW(AstStmt, stmt)
DEFINE_NEW(AstDecl, decl)
DEFINE_NEW(AstDeclar, declar)
DEFINE_NEW(AstExpr, expr)
DEFINE_NEW(AstStmtBlock, stmt_block)
static AstStmtBlock* parse_stmt_block(Parser* p);
static AstDecl* parse_decl(Parser* p);
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;
assert(p->curr.ty == '{');
ARRAY_VAR(AstStmt*, stmts);
while (p->curr.ty != Tok_Eof && p->curr.ty != '}') {
AstStmt* stmt = parser_parse_stmt(p);
arena_array_push(p->arena,
(void**)&stmts,
&stmts_cap,
&stmts_size,
(&stmt),
sizeof(*(&stmt)));
}
if (p->curr.ty != '}') {
fprintf(stderr, "error: expected '}' on line %d\n", p->curr.loc.line);
exit(1);
}
step(p);
return new_stmt_block(p,
(AstStmtBlock) {
.stmts = stmts,
.stmts_cap = stmts_cap,
.stmts_size = stmts_size,
.loc = loc,
});
}
static bool is_decl_start_kw(TokTy ty)
{
@ -231,12 +296,19 @@ static bool is_defty_ident(Parser* p, Tok tok)
return sym && sym->ty == Sym_Typedef;
}
AstStmt* parser_parse_stmt(Parser* p)
static AstStmt* 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);
AstDecl* decl = parse_decl(p);
if (!decl->function_body && p->curr.ty != ';') {
fprintf(
stderr, "error: expected ';' on line %d\n", p->curr.loc.line);
exit(1);
}
step(p);
return new_stmt(p,
(AstStmt) {
@ -246,7 +318,7 @@ AstStmt* parser_parse_stmt(Parser* p)
});
}
AstExpr* expr = parser_parse_expr(p);
AstExpr* expr = parse_expr(p);
return new_stmt(p,
(AstStmt) {
@ -256,12 +328,7 @@ AstStmt* parser_parse_stmt(Parser* p)
});
}
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)
static AstDecl* parse_decl(Parser* p)
{
Loc loc = p->curr.loc;
@ -271,11 +338,7 @@ AstDecl* parser_parse_decl(Parser* p)
AstDeclar* first = parse_declar(p);
array_push((void**)&declars,
&declars_cap,
&declars_size,
(&first),
sizeof(*(&first)));
ARENA_ARRAY_VAR_PUSH(p->arena, declars, &first);
if (first->ty == AstDeclar_Function && p->curr.ty == '{') {
AstStmtBlock* block = parse_stmt_block(p);
@ -316,6 +379,7 @@ AstDecl* parser_parse_decl(Parser* p)
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(Parser* p)
{
@ -323,7 +387,7 @@ static AstDeclar* parse_declar(Parser* p)
if (p->curr.ty == '=') {
step(p);
AstExpr* expr = parser_parse_expr(p);
AstExpr* expr = parse_expr(p);
declar->init_expr = expr;
}
@ -364,7 +428,7 @@ static AstDeclar* parse_declar_l2(Parser* p)
step(p);
AstExpr* expr = nullptr;
if (p->curr.ty != ']') {
expr = parser_parse_expr(p);
expr = parse_expr(p);
}
if (p->curr.ty != ']') {
fprintf(
@ -390,6 +454,49 @@ static AstDeclar* parse_declar_l3(Parser* p)
{
Loc loc = p->curr.loc;
AstDeclar* declar = parse_declar_l4(p);
if (p->curr.ty == '(') {
step(p);
ARRAY_VAR(AstDecl*, params);
while (true) {
AstDecl* d = parse_decl(p);
ARENA_ARRAY_VAR_PUSH(p->arena, params, &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);
declar = new_declar(p,
(AstDeclar) {
.ty = AstDeclar_Function,
.loc = loc,
.function = {
.declar = declar,
.params = params,
.params_cap = params_cap,
.params_size = params_size,
},
});
}
return declar;
}
static AstDeclar* parse_declar_l4(Parser* p)
{
Loc loc = p->curr.loc;
if (p->curr.ty == Tok_Ident) {
char* ident = arena_strdup(p->arena, p->curr.text);
step(p);
@ -413,44 +520,7 @@ static AstDeclar* parse_declar_l3(Parser* p)
}
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,
},
});
return declar;
}
fprintf(
@ -466,7 +536,7 @@ static AstSpec parse_decl_spec(Parser* p)
switch (p->curr.ty) {
case Tok_Ident: {
Sym* sym = syms_get(p->ord_ns, p->curr.text);
if (sym->ty != Sym_Typedef)
if (!sym || sym->ty != Sym_Typedef)
break;
spec |= AstSpec_DefTy;
step(p);
@ -493,11 +563,139 @@ static AstSpec parse_decl_spec(Parser* p)
return spec;
}
static AstStmtBlock* parse_stmt_block(Parser* p)
static AstExpr* parse_expr_1(Parser* p);
static AstExpr* parse_expr_2(Parser* p);
static AstExpr* parse_expr(Parser* p)
{
Loc loc = p->curr.loc;
return parse_expr_1(p);
}
AstExpr* parser_parse_expr(Parser* p)
static AstExpr* parse_expr_1(Parser* p)
{
Loc loc = p->curr.loc;
AstExpr* expr = parse_expr_2(p);
while (true) {
if (p->curr.ty == '(') {
step(p);
ARRAY_VAR(AstExpr*, args);
if (p->curr.ty != ')') {
do {
step(p);
AstExpr* arg = parse_expr(p);
ARRAY_VAR_PUSH(args, &arg);
} while (p->curr.ty == ',');
}
if (p->curr.ty != ')') {
fprintf(stderr,
"error: expected ')' on line %d\n",
p->curr.loc.line);
exit(1);
}
step(p);
expr = new_expr(p,
(AstExpr) {
.ty = AstExpr_Call,
.loc = loc,
.call = {
.expr = expr,
.args = args,
.args_cap = args_cap,
.args_size = args_size,
},
});
}
break;
}
return expr;
}
static size_t unescape_string(char* dest, const char* src)
{
size_t dest_i = 0;
size_t src_len = strlen(src);
assert(src[0] == '"' && src[src_len - 1] == '"');
src -= 1;
src_len -= 2;
for (size_t i = 0; i < src_len; ++i) {
char ch = src[i];
char dest_ch;
if (ch == '\\') {
i += 1;
assert(i < src_len);
ch = src[i];
switch (ch) {
case 't':
dest_ch = '\t';
break;
case 'r':
dest_ch = '\r';
break;
case 'n':
dest_ch = '\n';
break;
case '0':
dest_ch = '\0';
break;
default:
dest_ch = ch;
}
} else {
dest_ch = ch;
}
if (dest)
dest[dest_i] = dest_ch;
dest_i += 1;
}
return dest_i;
}
static AstExpr* parse_expr_2(Parser* p)
{
Loc loc = p->curr.loc;
if (p->curr.ty == Tok_Str) {
size_t unescaped_len = unescape_string(nullptr, p->curr.text);
char* unescaped_str = arena_alloc(p->arena, unescaped_len + 1);
unescape_string(unescaped_str, p->curr.text);
step(p);
return new_expr(p,
(AstExpr) {
.ty = AstExpr_Str,
.loc = loc,
.str_val = unescaped_str,
});
}
fprintf(
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;
}

View File

@ -109,7 +109,6 @@ 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);
bool parser_done(Parser* p);
#endif

View File

@ -637,6 +637,14 @@ Tok preproc_next(Preproc* p)
return expand_tok(p);
}
static Tok tokstream_next_filtered(TokStream* s)
{
Tok tok;
while ((tok = preproc_next(s->preproc)).ty == Tok_Eol
|| tok.ty == Tok_Whitespace) { }
return tok;
}
void tokstream_init(TokStream* s, Preproc* preproc, Arena* arena)
{
*s = (TokStream) {
@ -644,15 +652,7 @@ void tokstream_init(TokStream* s, Preproc* preproc, Arena* arena)
.arena = arena,
.curr = { },
};
s->curr = preproc_next(s->preproc);
}
static Tok tokstream_next_filtered(TokStream* s)
{
Tok tok;
while ((tok = preproc_next(s->preproc)).ty == Tok_Eol
|| tok.ty == Tok_Whitespace) { }
return tok;
s->curr = tokstream_next_filtered(s);
}
Tok tokstream_next(TokStream* s)