more parser
This commit is contained in:
parent
b6bec01193
commit
9bf5fc06db
4
Makefile
4
Makefile
@ -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
18
ast.h
@ -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
283
ast_str.c
Normal 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>");
|
||||
}
|
||||
16
collection.h
16
collection.h
@ -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
|
||||
|
||||
@ -2,5 +2,5 @@
|
||||
-pedantic-errors
|
||||
-Wall
|
||||
-Wextra
|
||||
|
||||
-Werror=switch
|
||||
|
||||
|
||||
13
lex.c
13
lex.c
@ -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
101
main.c
@ -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
338
parse.c
@ -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**)¶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,
|
||||
},
|
||||
});
|
||||
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;
|
||||
}
|
||||
|
||||
3
parse.h
3
parse.h
@ -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
|
||||
|
||||
18
preproc.c
18
preproc.c
@ -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)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user