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
|
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
|
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 {
|
struct AstDecl {
|
||||||
AstSpec spec;
|
AstSpec spec;
|
||||||
|
char* type_ident;
|
||||||
ARRAY_FIELD(AstDeclar*, declars);
|
ARRAY_FIELD(AstDeclar*, declars);
|
||||||
AstStmtBlock* function_body;
|
AstStmtBlock* function_body;
|
||||||
Loc loc;
|
Loc loc;
|
||||||
@ -84,7 +85,8 @@ struct AstDeclar {
|
|||||||
AstExpr* expr;
|
AstExpr* expr;
|
||||||
} array;
|
} array;
|
||||||
struct {
|
struct {
|
||||||
ARRAY_FIELD(AstDecl, params);
|
AstDeclar* declar;
|
||||||
|
ARRAY_FIELD(AstDecl*, params);
|
||||||
} function;
|
} function;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@ -96,6 +98,7 @@ typedef enum {
|
|||||||
|
|
||||||
struct AstExpr {
|
struct AstExpr {
|
||||||
AstExprTy ty;
|
AstExprTy ty;
|
||||||
|
Loc loc;
|
||||||
union {
|
union {
|
||||||
char* str_val;
|
char* str_val;
|
||||||
struct {
|
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
|
#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);
|
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
|
#endif
|
||||||
|
|||||||
@ -2,5 +2,5 @@
|
|||||||
-pedantic-errors
|
-pedantic-errors
|
||||||
-Wall
|
-Wall
|
||||||
-Wextra
|
-Wextra
|
||||||
|
-Werror=switch
|
||||||
|
|
||||||
|
|||||||
13
lex.c
13
lex.c
@ -78,9 +78,18 @@ const char* tokty_str(TokTy ty)
|
|||||||
return "Asterisk";
|
return "Asterisk";
|
||||||
case Tok_Hashtag:
|
case Tok_Hashtag:
|
||||||
return "Hashtag";
|
return "Hashtag";
|
||||||
default:
|
case Tok_Comma:
|
||||||
return "<unknown>";
|
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)
|
void source_iter_init(SourceIter* r, const char* text)
|
||||||
|
|||||||
47
main.c
47
main.c
@ -1,3 +1,4 @@
|
|||||||
|
#include "ast.h"
|
||||||
#include "collection.h"
|
#include "collection.h"
|
||||||
#include "parse.h"
|
#include "parse.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
@ -20,10 +21,13 @@ int main(int argc, char* argv[])
|
|||||||
|
|
||||||
printf("--- text ---\n%s\n", text);
|
printf("--- text ---\n%s\n", text);
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
Arena tok_arena;
|
Arena tok_arena;
|
||||||
arena_init(&tok_arena, 4096);
|
arena_init(&tok_arena, 4096);
|
||||||
|
|
||||||
Preproc* preproc = preproc_new(strdup(filename), text, &tok_arena);
|
Preproc* preproc
|
||||||
|
= preproc_new(strdup(filename), strdup(text), &tok_arena);
|
||||||
|
|
||||||
TokStream tokstream;
|
TokStream tokstream;
|
||||||
tokstream_init(&tokstream, preproc, &tok_arena);
|
tokstream_init(&tokstream, preproc, &tok_arena);
|
||||||
@ -56,3 +60,44 @@ int main(int argc, char* argv[])
|
|||||||
preproc_free(preproc);
|
preproc_free(preproc);
|
||||||
arena_deinit(&tok_arena);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
336
parse.c
336
parse.c
@ -6,6 +6,7 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char ch;
|
char ch;
|
||||||
@ -22,17 +23,34 @@ typedef struct {
|
|||||||
TokStream* tokstream;
|
TokStream* tokstream;
|
||||||
Arena arena;
|
Arena arena;
|
||||||
ARRAY_FIELD(KwNode, nodes);
|
ARRAY_FIELD(KwNode, nodes);
|
||||||
KwNode* root;
|
|
||||||
} KwMatcher;
|
} 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(
|
static KwNodeOpt* kwmatcher_create_path(
|
||||||
KwMatcher* m, KwNode* node, const char* kw)
|
KwMatcher* m, size_t node_idx, const char* kw)
|
||||||
{
|
{
|
||||||
assert(kw[0]);
|
assert(kw[0]);
|
||||||
|
KwNode* node = &m->nodes[node_idx];
|
||||||
|
|
||||||
KwNodeOpt* opt = nullptr;
|
KwNodeOpt* opt = nullptr;
|
||||||
for (size_t i = 0; i < node->opts_size; ++i) {
|
for (size_t i = 0; i < node->opts_size; ++i) {
|
||||||
if (node->opts[i].ch == kw[0]) {
|
if (node->opts[i].ch == kw[0]) {
|
||||||
opt = &node->opts[i];
|
opt = &node->opts[i];
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!opt) {
|
if (!opt) {
|
||||||
@ -48,7 +66,8 @@ static KwNodeOpt* kwmatcher_create_path(
|
|||||||
&m->nodes_size,
|
&m->nodes_size,
|
||||||
&new_node,
|
&new_node,
|
||||||
sizeof(new_node));
|
sizeof(new_node));
|
||||||
KwNode* node = &m->nodes[new_idx];
|
// might have been relocated
|
||||||
|
node = &m->nodes[node_idx];
|
||||||
|
|
||||||
KwNodeOpt new_opt = {
|
KwNodeOpt new_opt = {
|
||||||
.ch = kw[0],
|
.ch = kw[0],
|
||||||
@ -67,13 +86,12 @@ static KwNodeOpt* kwmatcher_create_path(
|
|||||||
if (!kw[1])
|
if (!kw[1])
|
||||||
return opt;
|
return opt;
|
||||||
|
|
||||||
KwNode* next_node = &m->nodes[opt->val];
|
return kwmatcher_create_path(m, opt->val, &kw[1]);
|
||||||
return kwmatcher_create_path(m, next_node, &kw[1]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void kwmatcher_add(KwMatcher* m, const char* kw, TokTy tokty)
|
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->is_term = true;
|
||||||
opt->val = tokty;
|
opt->val = tokty;
|
||||||
}
|
}
|
||||||
@ -97,8 +115,8 @@ static KwNodeOpt* kwmatcher_find_node(
|
|||||||
|
|
||||||
static TokTy kwmatcher_match(KwMatcher* m, const char* kw)
|
static TokTy kwmatcher_match(KwMatcher* m, const char* kw)
|
||||||
{
|
{
|
||||||
KwNodeOpt* opt = kwmatcher_find_node(m, m->root, kw);
|
KwNodeOpt* opt = kwmatcher_find_node(m, &m->nodes[0], kw);
|
||||||
if (!opt->is_term)
|
if (!opt || !opt->is_term)
|
||||||
return Tok_Ident;
|
return Tok_Ident;
|
||||||
return opt->val;
|
return opt->val;
|
||||||
}
|
}
|
||||||
@ -109,7 +127,6 @@ static void kwmatcher_init(KwMatcher* m, TokStream* tokstream)
|
|||||||
.tokstream = tokstream,
|
.tokstream = tokstream,
|
||||||
.arena = { },
|
.arena = { },
|
||||||
ARRAY_FIELD_INIT(nodes),
|
ARRAY_FIELD_INIT(nodes),
|
||||||
.root = nullptr,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
arena_init(&m->arena, 512);
|
arena_init(&m->arena, 512);
|
||||||
@ -121,8 +138,6 @@ static void kwmatcher_init(KwMatcher* m, TokStream* tokstream)
|
|||||||
(&(KwNode) { .idx = 0 }),
|
(&(KwNode) { .idx = 0 }),
|
||||||
sizeof(*(&(KwNode) { .idx = 0 })));
|
sizeof(*(&(KwNode) { .idx = 0 })));
|
||||||
|
|
||||||
m->root = &m->nodes[0];
|
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
TokTy ty;
|
TokTy ty;
|
||||||
const char* kw;
|
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) {
|
for (size_t i = 0; i < sizeof(kws) / sizeof(kws[0]); ++i) {
|
||||||
kwmatcher_add(m, kws[i].kw, kws[i].ty);
|
kwmatcher_add(m, kws[i].kw, kws[i].ty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kw_tree_print(m, &m->nodes[0], 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void kwmatcher_deinit(KwMatcher* m)
|
static void kwmatcher_deinit(KwMatcher* m)
|
||||||
@ -146,11 +163,18 @@ static Tok kwmatcher_next(KwMatcher* m)
|
|||||||
{
|
{
|
||||||
Tok tok = tokstream_next(m->tokstream);
|
Tok tok = tokstream_next(m->tokstream);
|
||||||
if (tok.ty != Tok_Ident)
|
if (tok.ty != Tok_Ident)
|
||||||
return tok;
|
goto exit;
|
||||||
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.loc.line);
|
printf("info: matched '%s' on line %d\n", tok.text, tok.loc.line);
|
||||||
tok.ty = ty;
|
tok.ty = ty;
|
||||||
|
|
||||||
|
exit:
|
||||||
|
printf(" - %s(%s) %d:%d\n",
|
||||||
|
tokty_str(tok.ty),
|
||||||
|
tok.text,
|
||||||
|
tok.loc.line,
|
||||||
|
tok.loc.col);
|
||||||
return tok;
|
return tok;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -210,6 +234,47 @@ static void step(Parser* p)
|
|||||||
DEFINE_NEW(AstStmt, stmt)
|
DEFINE_NEW(AstStmt, stmt)
|
||||||
DEFINE_NEW(AstDecl, decl)
|
DEFINE_NEW(AstDecl, decl)
|
||||||
DEFINE_NEW(AstDeclar, declar)
|
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)
|
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;
|
return sym && sym->ty == Sym_Typedef;
|
||||||
}
|
}
|
||||||
|
|
||||||
AstStmt* parser_parse_stmt(Parser* p)
|
static AstStmt* parse_stmt(Parser* p)
|
||||||
{
|
{
|
||||||
Loc loc = p->curr.loc;
|
Loc loc = p->curr.loc;
|
||||||
|
|
||||||
if (is_decl_start_kw(p->curr.ty) || is_defty_ident(p, p->curr)) {
|
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,
|
return new_stmt(p,
|
||||||
(AstStmt) {
|
(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,
|
return new_stmt(p,
|
||||||
(AstStmt) {
|
(AstStmt) {
|
||||||
@ -256,12 +328,7 @@ AstStmt* parser_parse_stmt(Parser* p)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static AstDeclar* parse_declar(Parser* p);
|
static AstDecl* parse_decl(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;
|
Loc loc = p->curr.loc;
|
||||||
|
|
||||||
@ -271,11 +338,7 @@ AstDecl* parser_parse_decl(Parser* p)
|
|||||||
|
|
||||||
AstDeclar* first = parse_declar(p);
|
AstDeclar* first = parse_declar(p);
|
||||||
|
|
||||||
array_push((void**)&declars,
|
ARENA_ARRAY_VAR_PUSH(p->arena, declars, &first);
|
||||||
&declars_cap,
|
|
||||||
&declars_size,
|
|
||||||
(&first),
|
|
||||||
sizeof(*(&first)));
|
|
||||||
|
|
||||||
if (first->ty == AstDeclar_Function && p->curr.ty == '{') {
|
if (first->ty == AstDeclar_Function && p->curr.ty == '{') {
|
||||||
AstStmtBlock* block = parse_stmt_block(p);
|
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_l1(Parser* p);
|
||||||
static AstDeclar* parse_declar_l2(Parser* p);
|
static AstDeclar* parse_declar_l2(Parser* p);
|
||||||
static AstDeclar* parse_declar_l3(Parser* p);
|
static AstDeclar* parse_declar_l3(Parser* p);
|
||||||
|
static AstDeclar* parse_declar_l4(Parser* p);
|
||||||
|
|
||||||
static AstDeclar* parse_declar(Parser* p)
|
static AstDeclar* parse_declar(Parser* p)
|
||||||
{
|
{
|
||||||
@ -323,7 +387,7 @@ static AstDeclar* parse_declar(Parser* p)
|
|||||||
|
|
||||||
if (p->curr.ty == '=') {
|
if (p->curr.ty == '=') {
|
||||||
step(p);
|
step(p);
|
||||||
AstExpr* expr = parser_parse_expr(p);
|
AstExpr* expr = parse_expr(p);
|
||||||
declar->init_expr = expr;
|
declar->init_expr = expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -364,7 +428,7 @@ static AstDeclar* parse_declar_l2(Parser* p)
|
|||||||
step(p);
|
step(p);
|
||||||
AstExpr* expr = nullptr;
|
AstExpr* expr = nullptr;
|
||||||
if (p->curr.ty != ']') {
|
if (p->curr.ty != ']') {
|
||||||
expr = parser_parse_expr(p);
|
expr = parse_expr(p);
|
||||||
}
|
}
|
||||||
if (p->curr.ty != ']') {
|
if (p->curr.ty != ']') {
|
||||||
fprintf(
|
fprintf(
|
||||||
@ -390,6 +454,49 @@ static AstDeclar* parse_declar_l3(Parser* p)
|
|||||||
{
|
{
|
||||||
Loc loc = p->curr.loc;
|
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) {
|
if (p->curr.ty == Tok_Ident) {
|
||||||
char* ident = arena_strdup(p->arena, p->curr.text);
|
char* ident = arena_strdup(p->arena, p->curr.text);
|
||||||
step(p);
|
step(p);
|
||||||
@ -413,45 +520,8 @@ static AstDeclar* parse_declar_l3(Parser* p)
|
|||||||
}
|
}
|
||||||
step(p);
|
step(p);
|
||||||
|
|
||||||
if (p->curr.ty != '(') {
|
|
||||||
return declar;
|
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(
|
fprintf(
|
||||||
stderr, "error: expected declarator on line %d\n", p->curr.loc.line);
|
stderr, "error: expected declarator on line %d\n", p->curr.loc.line);
|
||||||
@ -466,7 +536,7 @@ static AstSpec parse_decl_spec(Parser* p)
|
|||||||
switch (p->curr.ty) {
|
switch (p->curr.ty) {
|
||||||
case Tok_Ident: {
|
case Tok_Ident: {
|
||||||
Sym* sym = syms_get(p->ord_ns, p->curr.text);
|
Sym* sym = syms_get(p->ord_ns, p->curr.text);
|
||||||
if (sym->ty != Sym_Typedef)
|
if (!sym || sym->ty != Sym_Typedef)
|
||||||
break;
|
break;
|
||||||
spec |= AstSpec_DefTy;
|
spec |= AstSpec_DefTy;
|
||||||
step(p);
|
step(p);
|
||||||
@ -493,11 +563,139 @@ static AstSpec parse_decl_spec(Parser* p)
|
|||||||
return spec;
|
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);
|
Parser* parser_new(TokStream* tokstream, Arena* arena);
|
||||||
void parser_free(Parser* p);
|
void parser_free(Parser* p);
|
||||||
AstStmt* parser_parse_stmt(Parser* p);
|
AstStmt* parser_parse_stmt(Parser* p);
|
||||||
AstDecl* parser_parse_decl(Parser* p);
|
bool parser_done(Parser* p);
|
||||||
AstExpr* parser_parse_expr(Parser* p);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
18
preproc.c
18
preproc.c
@ -637,6 +637,14 @@ Tok preproc_next(Preproc* p)
|
|||||||
return expand_tok(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)
|
void tokstream_init(TokStream* s, Preproc* preproc, Arena* arena)
|
||||||
{
|
{
|
||||||
*s = (TokStream) {
|
*s = (TokStream) {
|
||||||
@ -644,15 +652,7 @@ void tokstream_init(TokStream* s, Preproc* preproc, Arena* arena)
|
|||||||
.arena = arena,
|
.arena = arena,
|
||||||
.curr = { },
|
.curr = { },
|
||||||
};
|
};
|
||||||
s->curr = preproc_next(s->preproc);
|
s->curr = tokstream_next_filtered(s);
|
||||||
}
|
|
||||||
|
|
||||||
static Tok tokstream_next_filtered(TokStream* s)
|
|
||||||
{
|
|
||||||
Tok tok;
|
|
||||||
while ((tok = preproc_next(s->preproc)).ty == Tok_Eol
|
|
||||||
|| tok.ty == Tok_Whitespace) { }
|
|
||||||
return tok;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Tok tokstream_next(TokStream* s)
|
Tok tokstream_next(TokStream* s)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user