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
|
gcc $^ -o $@ -std=c23 -pedantic -Wall -Wextra -g -fsanitize=address
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
98
ast.h
98
ast.h
@ -8,57 +8,101 @@ typedef struct {
|
|||||||
int col;
|
int col;
|
||||||
} Loc;
|
} Loc;
|
||||||
|
|
||||||
|
typedef struct AstStmt AstStmt;
|
||||||
|
typedef struct AstDecl AstDecl;
|
||||||
|
typedef struct AstDeclar AstDeclar;
|
||||||
|
typedef struct AstExpr AstExpr;
|
||||||
|
|
||||||
|
typedef struct AstStmtBlock AstStmtBlock;
|
||||||
|
|
||||||
|
struct AstStmtBlock {
|
||||||
|
ARRAY_FIELD(AstStmt*, stmts);
|
||||||
|
Loc loc;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct AstDeclBlock AstDeclBlock;
|
||||||
|
|
||||||
|
struct AstDeclBlock {
|
||||||
|
ARRAY_FIELD(AstDecl*, decls);
|
||||||
|
Loc loc;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
AstStmt_Decl,
|
||||||
|
AstStmt_Expr,
|
||||||
|
} AstStmtTy;
|
||||||
|
|
||||||
|
struct AstStmt {
|
||||||
|
AstStmtTy ty;
|
||||||
|
Loc loc;
|
||||||
|
union {
|
||||||
|
AstDecl* decl;
|
||||||
|
AstExpr* expr;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
typedef enum : unsigned int {
|
typedef enum : unsigned int {
|
||||||
AstSpec_Typedef = 1 << 0,
|
AstSpec_Int = 1 << 0,
|
||||||
// AstSpec_Constexpr = 1 << 1,
|
AstSpec_Char = 1 << 1,
|
||||||
// AstSpec_Auto = 1 << 2,
|
AstSpec_DefTy = 1 << 6,
|
||||||
// AstSpec_Register = 1 << 3,
|
AstSpec_Unsigned = 1 << 7,
|
||||||
AstSpec_Static = 1 << 4,
|
AstSpec_Static = 1 << 8,
|
||||||
// AstSpec_Extern = 1 << 5,
|
AstSpec_Const = 1 << 9,
|
||||||
// AstSpec_ThreadLocal = 1 << 6,
|
AstSpec_Inline = 1 << 10,
|
||||||
AstSpec_Const = 1 << 7,
|
AstSpec_Typedef = 1 << 11,
|
||||||
// AstSpec_Volatile = 1 << 8,
|
AstSpec_Enum = 1 << 12,
|
||||||
// AstSpec_Restrict = 1 << 9,
|
AstSpec_Struct = 1 << 13,
|
||||||
// AstSpec_Atomic = 1 << 10,
|
AstSpec_Union = 1 << 14,
|
||||||
AstSpec_Inline = 1 << 11,
|
|
||||||
} AstSpec;
|
} AstSpec;
|
||||||
|
|
||||||
|
struct AstDecl {
|
||||||
|
AstSpec spec;
|
||||||
|
ARRAY_FIELD(AstDeclar*, declars);
|
||||||
|
AstStmtBlock* function_body;
|
||||||
|
Loc loc;
|
||||||
|
};
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
AstDeclar_Ident,
|
AstDeclar_Ident,
|
||||||
AstDeclar_Pointer,
|
AstDeclar_Pointer,
|
||||||
AstDeclar_Array,
|
AstDeclar_Array,
|
||||||
|
AstDeclar_Function,
|
||||||
} AstDeclarTy;
|
} AstDeclarTy;
|
||||||
|
|
||||||
typedef struct AstDeclar AstDeclar;
|
|
||||||
|
|
||||||
struct AstDeclar {
|
struct AstDeclar {
|
||||||
AstDeclarTy ty;
|
AstDeclarTy ty;
|
||||||
Loc loc;
|
Loc loc;
|
||||||
|
AstExpr* init_expr;
|
||||||
union {
|
union {
|
||||||
char* ident;
|
char* ident;
|
||||||
struct {
|
struct {
|
||||||
AstDeclar* declar;
|
AstDeclar* declar;
|
||||||
AstSpec spec;
|
AstSpec spec;
|
||||||
} pointer;
|
} pointer;
|
||||||
|
struct {
|
||||||
|
AstDeclar* declar;
|
||||||
|
AstExpr* expr;
|
||||||
|
} array;
|
||||||
|
struct {
|
||||||
|
ARRAY_FIELD(AstDecl, params);
|
||||||
|
} function;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
AstSpec spec;
|
|
||||||
unsigned long type_id;
|
|
||||||
ARRAY_FIELD(AstDeclar, declars);
|
|
||||||
Loc loc;
|
|
||||||
} AstDecl;
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
AstStmt_Decl,
|
AstExpr_Str,
|
||||||
} AstStmtTy;
|
AstExpr_Call,
|
||||||
|
} AstExprTy;
|
||||||
|
|
||||||
typedef struct {
|
struct AstExpr {
|
||||||
AstStmtTy ty;
|
AstExprTy ty;
|
||||||
union {
|
union {
|
||||||
AstDecl decl;
|
char* str_val;
|
||||||
|
struct {
|
||||||
|
AstExpr* expr;
|
||||||
|
ARRAY_FIELD(AstExpr*, args);
|
||||||
|
} call;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
} AstStmt;
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -225,3 +225,10 @@ void arena_array_push(Arena* arena,
|
|||||||
arena_realloc_wrap,
|
arena_realloc_wrap,
|
||||||
arena);
|
arena);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char* arena_strdup(Arena* a, const char* str)
|
||||||
|
{
|
||||||
|
char* p = arena_alloc(a, strlen(str) + 1);
|
||||||
|
strcpy(p, str);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|||||||
@ -74,4 +74,6 @@ void arena_array_push(Arena* arena,
|
|||||||
void* elem,
|
void* elem,
|
||||||
size_t elem_size);
|
size_t elem_size);
|
||||||
|
|
||||||
|
char* arena_strdup(Arena* a, const char* str);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
36
lex.c
36
lex.c
@ -96,8 +96,7 @@ void source_iter_init(SourceIter* r, const char* text)
|
|||||||
Char source_iter_next(SourceIter* r)
|
Char source_iter_next(SourceIter* r)
|
||||||
{
|
{
|
||||||
char ch = r->text[r->i];
|
char ch = r->text[r->i];
|
||||||
int line = r->line;
|
Loc loc = { r->line, r->col };
|
||||||
int col = r->col;
|
|
||||||
|
|
||||||
if (r->text[r->i] != '\0') {
|
if (r->text[r->i] != '\0') {
|
||||||
if (ch == '\n') {
|
if (ch == '\n') {
|
||||||
@ -109,7 +108,7 @@ Char source_iter_next(SourceIter* r)
|
|||||||
r->i += 1;
|
r->i += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (Char) { ch, line, col };
|
return (Char) { ch, loc };
|
||||||
}
|
}
|
||||||
|
|
||||||
void lsl_iter_init(LslIter* r, SourceIter* source_char_iter)
|
void lsl_iter_init(LslIter* r, SourceIter* source_char_iter)
|
||||||
@ -149,13 +148,13 @@ void lexer_init(Lexer* r, LslIter* lsl_char_iter, Arena* arena)
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static Tok tok(Lexer* l, TokTy ty, const char* text, int line, int col)
|
static Tok tok(Lexer* l, TokTy ty, const char* text, Loc loc)
|
||||||
{
|
{
|
||||||
char* text_dup = arena_alloc(l->arena, strlen(text) + 1);
|
char* text_dup = arena_alloc(l->arena, strlen(text) + 1);
|
||||||
text_dup[0] = '\0';
|
text_dup[0] = '\0';
|
||||||
strcpy(text_dup, text);
|
strcpy(text_dup, text);
|
||||||
|
|
||||||
return (Tok) { ty, text_dup, line, col };
|
return (Tok) { ty, text_dup, loc };
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool done(Lexer* l)
|
static bool done(Lexer* l)
|
||||||
@ -176,14 +175,13 @@ static void step(Lexer* l, char text[], size_t* text_len)
|
|||||||
|
|
||||||
Tok lexer_next(Lexer* l)
|
Tok lexer_next(Lexer* l)
|
||||||
{
|
{
|
||||||
int line = l->curr.line;
|
Loc loc = l->curr.loc;
|
||||||
int col = l->curr.col;
|
|
||||||
|
|
||||||
char text[max_token_text_len] = "";
|
char text[max_token_text_len] = "";
|
||||||
size_t text_len = 0;
|
size_t text_len = 0;
|
||||||
|
|
||||||
if (done(l)) {
|
if (done(l)) {
|
||||||
return tok(l, Tok_Eof, text, line, col);
|
return tok(l, Tok_Eof, text, loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool matched = false;
|
bool matched = false;
|
||||||
@ -193,7 +191,7 @@ Tok lexer_next(Lexer* l)
|
|||||||
}
|
}
|
||||||
if (matched) {
|
if (matched) {
|
||||||
if (l->lex_whitespace) {
|
if (l->lex_whitespace) {
|
||||||
return tok(l, Tok_Whitespace, text, line, col);
|
return tok(l, Tok_Whitespace, text, loc);
|
||||||
}
|
}
|
||||||
return lexer_next(l);
|
return lexer_next(l);
|
||||||
}
|
}
|
||||||
@ -206,7 +204,7 @@ Tok lexer_next(Lexer* l)
|
|||||||
step(l, text, &text_len);
|
step(l, text, &text_len);
|
||||||
}
|
}
|
||||||
if (matched) {
|
if (matched) {
|
||||||
return tok(l, Tok_Ident, text, line, col);
|
return tok(l, Tok_Ident, text, loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((l->curr.ch >= '1' && l->curr.ch <= '9')
|
while ((l->curr.ch >= '1' && l->curr.ch <= '9')
|
||||||
@ -215,7 +213,7 @@ Tok lexer_next(Lexer* l)
|
|||||||
step(l, text, &text_len);
|
step(l, text, &text_len);
|
||||||
}
|
}
|
||||||
if (matched) {
|
if (matched) {
|
||||||
return tok(l, Tok_Int, text, line, col);
|
return tok(l, Tok_Int, text, loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (l->lex_headername && (l->curr.ch == '"' || l->curr.ch == '<')) {
|
if (l->lex_headername && (l->curr.ch == '"' || l->curr.ch == '<')) {
|
||||||
@ -228,11 +226,11 @@ Tok lexer_next(Lexer* l)
|
|||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"error: malformed header name, expected '%c' on line %d\n",
|
"error: malformed header name, expected '%c' on line %d\n",
|
||||||
ter,
|
ter,
|
||||||
l->curr.line);
|
l->curr.loc.line);
|
||||||
return lexer_next(l);
|
return lexer_next(l);
|
||||||
}
|
}
|
||||||
step(l, text, &text_len);
|
step(l, text, &text_len);
|
||||||
return tok(l, Tok_HeaderName, text, line, col);
|
return tok(l, Tok_HeaderName, text, loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (l->curr.ch == '"') {
|
if (l->curr.ch == '"') {
|
||||||
@ -248,11 +246,11 @@ Tok lexer_next(Lexer* l)
|
|||||||
if (done(l) || l->curr.ch != '"') {
|
if (done(l) || l->curr.ch != '"') {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"error: malformed string literal on line %d\n",
|
"error: malformed string literal on line %d\n",
|
||||||
l->curr.line);
|
l->curr.loc.line);
|
||||||
return lexer_next(l);
|
return lexer_next(l);
|
||||||
}
|
}
|
||||||
step(l, text, &text_len);
|
step(l, text, &text_len);
|
||||||
return tok(l, Tok_Str, text, line, col);
|
return tok(l, Tok_Str, text, loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (l->curr.ch == '\'') {
|
if (l->curr.ch == '\'') {
|
||||||
@ -266,22 +264,22 @@ Tok lexer_next(Lexer* l)
|
|||||||
if (done(l) && l->curr.ch != '\'') {
|
if (done(l) && l->curr.ch != '\'') {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"error: malformed character literal on line %d\n",
|
"error: malformed character literal on line %d\n",
|
||||||
l->curr.line);
|
l->curr.loc.line);
|
||||||
return lexer_next(l);
|
return lexer_next(l);
|
||||||
}
|
}
|
||||||
step(l, text, &text_len);
|
step(l, text, &text_len);
|
||||||
return tok(l, Tok_Char, text, line, col);
|
return tok(l, Tok_Char, text, loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strchr("\n;(){},*#", l->curr.ch)) {
|
if (strchr("\n;(){},*#", l->curr.ch)) {
|
||||||
TokTy ty = (TokTy)l->curr.ch;
|
TokTy ty = (TokTy)l->curr.ch;
|
||||||
step(l, text, &text_len);
|
step(l, text, &text_len);
|
||||||
return tok(l, ty, text, line, col);
|
return tok(l, ty, text, loc);
|
||||||
}
|
}
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"error: illegal character '%c' on line %d\n",
|
"error: illegal character '%c' on line %d\n",
|
||||||
l->curr.ch,
|
l->curr.ch,
|
||||||
l->curr.line);
|
l->curr.loc.line);
|
||||||
step(l, text, &text_len);
|
step(l, text, &text_len);
|
||||||
return lexer_next(l);
|
return lexer_next(l);
|
||||||
}
|
}
|
||||||
|
|||||||
22
main.c
22
main.c
@ -30,26 +30,26 @@ int main(int argc, char* argv[])
|
|||||||
|
|
||||||
printf("--- tokens ---\n");
|
printf("--- tokens ---\n");
|
||||||
|
|
||||||
int line = 1;
|
Loc loc = { 1, 1 };
|
||||||
int col = 1;
|
|
||||||
Tok tok;
|
Tok tok;
|
||||||
while ((tok = tokstream_next(&tokstream)).ty != Tok_Eof) {
|
while ((tok = tokstream_next(&tokstream)).ty != Tok_Eof) {
|
||||||
// printf("%s\t%s\n", tokty_str(tok.ty), tok.text);
|
// printf("%s\t%s\n", tokty_str(tok.ty), tok.text);
|
||||||
if (line > tok.line) {
|
Loc tok_loc = tok.loc;
|
||||||
line = 0;
|
if (loc.line > tok_loc.line) {
|
||||||
|
loc.line = 0;
|
||||||
}
|
}
|
||||||
while (line < tok.line) {
|
while (loc.line < tok_loc.line) {
|
||||||
printf("\n");
|
printf("\n");
|
||||||
line += 1;
|
loc.line += 1;
|
||||||
col = 1;
|
loc.col = 1;
|
||||||
}
|
}
|
||||||
while (col < tok.col) {
|
while (loc.col < tok_loc.col) {
|
||||||
printf(" ");
|
printf(" ");
|
||||||
col += 1;
|
loc.col += 1;
|
||||||
}
|
}
|
||||||
printf("%s", tok.text);
|
printf("%s", tok.text);
|
||||||
line = tok.line;
|
loc.line = tok_loc.line;
|
||||||
col = tok.col + strlen(tok.text);
|
loc.col = tok_loc.col + strlen(tok.text);
|
||||||
}
|
}
|
||||||
fputs("\n", stdout);
|
fputs("\n", stdout);
|
||||||
|
|
||||||
|
|||||||
336
parse.c
336
parse.c
@ -1,5 +1,7 @@
|
|||||||
#include "parse.h"
|
#include "parse.h"
|
||||||
|
#include "ast.h"
|
||||||
#include "collection.h"
|
#include "collection.h"
|
||||||
|
#include "syms.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@ -41,11 +43,11 @@ static KwNodeOpt* kwmatcher_create_path(
|
|||||||
.idx = new_idx,
|
.idx = new_idx,
|
||||||
};
|
};
|
||||||
arena_array_push(&m->arena,
|
arena_array_push(&m->arena,
|
||||||
(void**)&(m)->nodes,
|
(void**)&m->nodes,
|
||||||
&(m)->nodes_cap,
|
&m->nodes_cap,
|
||||||
&(m)->nodes_size,
|
&m->nodes_size,
|
||||||
(&new_node),
|
&new_node,
|
||||||
sizeof(*(&new_node)));
|
sizeof(new_node));
|
||||||
KwNode* node = &m->nodes[new_idx];
|
KwNode* node = &m->nodes[new_idx];
|
||||||
|
|
||||||
KwNodeOpt new_opt = {
|
KwNodeOpt new_opt = {
|
||||||
@ -57,8 +59,8 @@ static KwNodeOpt* kwmatcher_create_path(
|
|||||||
(void**)&node->opts,
|
(void**)&node->opts,
|
||||||
&node->opts_cap,
|
&node->opts_cap,
|
||||||
&node->opts_size,
|
&node->opts_size,
|
||||||
(&new_opt),
|
&new_opt,
|
||||||
sizeof(*(&new_opt)));
|
sizeof(new_opt));
|
||||||
|
|
||||||
opt = &node->opts[node->opts_size - 1];
|
opt = &node->opts[node->opts_size - 1];
|
||||||
}
|
}
|
||||||
@ -147,7 +149,7 @@ static Tok kwmatcher_next(KwMatcher* m)
|
|||||||
return tok;
|
return tok;
|
||||||
TokTy ty = kwmatcher_match(m, tok.text);
|
TokTy ty = kwmatcher_match(m, tok.text);
|
||||||
if (ty != Tok_Ident)
|
if (ty != Tok_Ident)
|
||||||
printf("info: matched '%s' on line %d\n", tok.text, tok.line);
|
printf("info: matched '%s' on line %d\n", tok.text, tok.loc.line);
|
||||||
tok.ty = ty;
|
tok.ty = ty;
|
||||||
return tok;
|
return tok;
|
||||||
}
|
}
|
||||||
@ -155,6 +157,11 @@ static Tok kwmatcher_next(KwMatcher* m)
|
|||||||
struct Parser {
|
struct Parser {
|
||||||
KwMatcher kwmatcher;
|
KwMatcher kwmatcher;
|
||||||
Arena* arena;
|
Arena* arena;
|
||||||
|
Arena sym_arena;
|
||||||
|
|
||||||
|
Syms* ord_ns;
|
||||||
|
Syms* label_ns;
|
||||||
|
Syms* tag_ns;
|
||||||
|
|
||||||
Tok curr;
|
Tok curr;
|
||||||
};
|
};
|
||||||
@ -166,6 +173,11 @@ Parser* parser_new(TokStream* tokstream, Arena* arena)
|
|||||||
*p = (Parser) {
|
*p = (Parser) {
|
||||||
.kwmatcher = { },
|
.kwmatcher = { },
|
||||||
.arena = arena,
|
.arena = arena,
|
||||||
|
.sym_arena = { },
|
||||||
|
|
||||||
|
.ord_ns = syms_new(),
|
||||||
|
.label_ns = syms_new(),
|
||||||
|
.tag_ns = syms_new(),
|
||||||
|
|
||||||
.curr = { },
|
.curr = { },
|
||||||
};
|
};
|
||||||
@ -181,3 +193,311 @@ void parser_free(Parser* p)
|
|||||||
kwmatcher_deinit(&p->kwmatcher);
|
kwmatcher_deinit(&p->kwmatcher);
|
||||||
free(p);
|
free(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void step(Parser* p)
|
||||||
|
{
|
||||||
|
p->curr = kwmatcher_next(&p->kwmatcher);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DEFINE_NEW(TYPE, FN_NAME) \
|
||||||
|
[[maybe_unused]] static TYPE* new_##FN_NAME(Parser* p, TYPE init) \
|
||||||
|
{ \
|
||||||
|
TYPE* val = arena_alloc(p->arena, sizeof(TYPE)); \
|
||||||
|
*val = init; \
|
||||||
|
return val; \
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_NEW(AstStmt, stmt)
|
||||||
|
DEFINE_NEW(AstDecl, decl)
|
||||||
|
DEFINE_NEW(AstDeclar, declar)
|
||||||
|
|
||||||
|
static bool is_decl_start_kw(TokTy ty)
|
||||||
|
{
|
||||||
|
switch (ty) {
|
||||||
|
case Tok_KwInt:
|
||||||
|
case Tok_KwChar:
|
||||||
|
case Tok_KwConst:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool is_defty_ident(Parser* p, Tok tok)
|
||||||
|
{
|
||||||
|
if (tok.ty != Tok_Ident)
|
||||||
|
return false;
|
||||||
|
Sym* sym = syms_get(p->ord_ns, tok.text);
|
||||||
|
return sym && sym->ty == Sym_Typedef;
|
||||||
|
}
|
||||||
|
|
||||||
|
AstStmt* parser_parse_stmt(Parser* p)
|
||||||
|
{
|
||||||
|
Loc loc = p->curr.loc;
|
||||||
|
|
||||||
|
if (is_decl_start_kw(p->curr.ty) || is_defty_ident(p, p->curr)) {
|
||||||
|
AstDecl* decl = parser_parse_decl(p);
|
||||||
|
|
||||||
|
return new_stmt(p,
|
||||||
|
(AstStmt) {
|
||||||
|
.ty = AstStmt_Decl,
|
||||||
|
.loc = loc,
|
||||||
|
.decl = decl,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
AstExpr* expr = parser_parse_expr(p);
|
||||||
|
|
||||||
|
return new_stmt(p,
|
||||||
|
(AstStmt) {
|
||||||
|
.ty = AstStmt_Expr,
|
||||||
|
.loc = loc,
|
||||||
|
.expr = expr,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static AstDeclar* parse_declar(Parser* p);
|
||||||
|
static AstSpec parse_decl_spec(Parser* p);
|
||||||
|
|
||||||
|
static AstStmtBlock* parse_stmt_block(Parser* p);
|
||||||
|
|
||||||
|
AstDecl* parser_parse_decl(Parser* p)
|
||||||
|
{
|
||||||
|
Loc loc = p->curr.loc;
|
||||||
|
|
||||||
|
AstSpec spec = parse_decl_spec(p);
|
||||||
|
|
||||||
|
ARRAY_VAR(AstDeclar*, declars);
|
||||||
|
|
||||||
|
AstDeclar* first = parse_declar(p);
|
||||||
|
|
||||||
|
array_push((void**)&declars,
|
||||||
|
&declars_cap,
|
||||||
|
&declars_size,
|
||||||
|
(&first),
|
||||||
|
sizeof(*(&first)));
|
||||||
|
|
||||||
|
if (first->ty == AstDeclar_Function && p->curr.ty == '{') {
|
||||||
|
AstStmtBlock* block = parse_stmt_block(p);
|
||||||
|
return new_decl(p,
|
||||||
|
(AstDecl) {
|
||||||
|
.spec = spec,
|
||||||
|
.declars = declars,
|
||||||
|
.declars_cap = declars_cap,
|
||||||
|
.declars_size = declars_size,
|
||||||
|
.function_body = block,
|
||||||
|
.loc = loc,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
while (p->curr.ty == ',') {
|
||||||
|
step(p);
|
||||||
|
|
||||||
|
AstDeclar* declar = parse_declar(p);
|
||||||
|
|
||||||
|
array_push((void**)&declars,
|
||||||
|
&declars_cap,
|
||||||
|
&declars_size,
|
||||||
|
(&declar),
|
||||||
|
sizeof(*(&declar)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new_decl(p,
|
||||||
|
(AstDecl) {
|
||||||
|
.spec = spec,
|
||||||
|
.declars = declars,
|
||||||
|
.declars_cap = declars_cap,
|
||||||
|
.declars_size = declars_size,
|
||||||
|
.function_body = nullptr,
|
||||||
|
.loc = loc,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static AstDeclar* parse_declar_l1(Parser* p);
|
||||||
|
static AstDeclar* parse_declar_l2(Parser* p);
|
||||||
|
static AstDeclar* parse_declar_l3(Parser* p);
|
||||||
|
|
||||||
|
static AstDeclar* parse_declar(Parser* p)
|
||||||
|
{
|
||||||
|
AstDeclar* declar = parse_declar_l1(p);
|
||||||
|
|
||||||
|
if (p->curr.ty == '=') {
|
||||||
|
step(p);
|
||||||
|
AstExpr* expr = parser_parse_expr(p);
|
||||||
|
declar->init_expr = expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return declar;
|
||||||
|
}
|
||||||
|
|
||||||
|
static AstDeclar* parse_declar_l1(Parser* p)
|
||||||
|
{
|
||||||
|
Loc loc = p->curr.loc;
|
||||||
|
|
||||||
|
if (p->curr.ty == '*') {
|
||||||
|
step(p);
|
||||||
|
|
||||||
|
AstSpec spec = parse_decl_spec(p);
|
||||||
|
|
||||||
|
AstDeclar* declar = parse_declar_l1(p);
|
||||||
|
return new_declar(p,
|
||||||
|
(AstDeclar) {
|
||||||
|
.ty = AstDeclar_Pointer,
|
||||||
|
.loc = loc,
|
||||||
|
.pointer = {
|
||||||
|
.declar = declar,
|
||||||
|
.spec = spec,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return parse_declar_l2(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
static AstDeclar* parse_declar_l2(Parser* p)
|
||||||
|
{
|
||||||
|
Loc loc = p->curr.loc;
|
||||||
|
|
||||||
|
AstDeclar* declar = parse_declar_l3(p);
|
||||||
|
|
||||||
|
while (p->curr.ty == '[') {
|
||||||
|
step(p);
|
||||||
|
AstExpr* expr = nullptr;
|
||||||
|
if (p->curr.ty != ']') {
|
||||||
|
expr = parser_parse_expr(p);
|
||||||
|
}
|
||||||
|
if (p->curr.ty != ']') {
|
||||||
|
fprintf(
|
||||||
|
stderr, "error: expected ']' on line %d\n", p->curr.loc.line);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
step(p);
|
||||||
|
declar = new_declar(p,
|
||||||
|
(AstDeclar) {
|
||||||
|
.ty = AstDeclar_Array,
|
||||||
|
.loc = loc,
|
||||||
|
.array = {
|
||||||
|
.declar = declar,
|
||||||
|
.expr = expr,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return declar;
|
||||||
|
}
|
||||||
|
|
||||||
|
static AstDeclar* parse_declar_l3(Parser* p)
|
||||||
|
{
|
||||||
|
Loc loc = p->curr.loc;
|
||||||
|
|
||||||
|
if (p->curr.ty == Tok_Ident) {
|
||||||
|
char* ident = arena_strdup(p->arena, p->curr.text);
|
||||||
|
step(p);
|
||||||
|
return new_declar(p,
|
||||||
|
(AstDeclar) {
|
||||||
|
.ty = AstDeclar_Array,
|
||||||
|
.loc = loc,
|
||||||
|
.ident = ident,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p->curr.ty == '(') {
|
||||||
|
step(p);
|
||||||
|
|
||||||
|
AstDeclar* declar = parse_declar_l1(p);
|
||||||
|
|
||||||
|
if (p->curr.ty != ')') {
|
||||||
|
fprintf(
|
||||||
|
stderr, "error: expected ')' on line %d\n", p->curr.loc.line);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
step(p);
|
||||||
|
|
||||||
|
if (p->curr.ty != '(') {
|
||||||
|
return declar;
|
||||||
|
}
|
||||||
|
step(p);
|
||||||
|
|
||||||
|
ARRAY_VAR(AstDecl, params);
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
AstDecl* d = parser_parse_decl(p);
|
||||||
|
arena_array_push(p->arena,
|
||||||
|
(void**)¶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
|
#ifndef PARSE_H
|
||||||
#define PARSE_H
|
#define PARSE_H
|
||||||
|
|
||||||
|
#include "ast.h"
|
||||||
#include "collection.h"
|
#include "collection.h"
|
||||||
|
#include "syms.h"
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
char* read_textfile(const char* filename);
|
char* read_textfile(const char* filename);
|
||||||
@ -13,8 +15,7 @@ char* read_textfile(const char* filename);
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char ch;
|
char ch;
|
||||||
int line;
|
Loc loc;
|
||||||
int col;
|
|
||||||
} Char;
|
} Char;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -70,8 +71,7 @@ const char* tokty_str(TokTy ty);
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
TokTy ty;
|
TokTy ty;
|
||||||
char* text;
|
char* text;
|
||||||
int line;
|
Loc loc;
|
||||||
int col;
|
|
||||||
} Tok;
|
} Tok;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -108,5 +108,8 @@ typedef struct Parser Parser;
|
|||||||
|
|
||||||
Parser* parser_new(TokStream* tokstream, Arena* arena);
|
Parser* parser_new(TokStream* tokstream, Arena* arena);
|
||||||
void parser_free(Parser* p);
|
void parser_free(Parser* p);
|
||||||
|
AstStmt* parser_parse_stmt(Parser* p);
|
||||||
|
AstDecl* parser_parse_decl(Parser* p);
|
||||||
|
AstExpr* parser_parse_expr(Parser* p);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
105
preproc.c
105
preproc.c
@ -8,19 +8,19 @@
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
ARRAY_FIELD(Hashmap, maps);
|
ARRAY_FIELD(Hashmap, maps);
|
||||||
} Syms;
|
} PPSyms;
|
||||||
|
|
||||||
static void syms_push_layer(Syms* s);
|
static void ppsyms_push_layer(PPSyms* s);
|
||||||
|
|
||||||
static void syms_init(Syms* s)
|
static void ppsyms_init(PPSyms* s)
|
||||||
{
|
{
|
||||||
*s = (Syms) {
|
*s = (PPSyms) {
|
||||||
ARRAY_FIELD_INIT(maps),
|
ARRAY_FIELD_INIT(maps),
|
||||||
};
|
};
|
||||||
syms_push_layer(s);
|
ppsyms_push_layer(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void syms_deinit(Syms* s)
|
static void ppsyms_deinit(PPSyms* s)
|
||||||
{
|
{
|
||||||
if (s->maps) {
|
if (s->maps) {
|
||||||
for (size_t i = 0; i < s->maps_size; ++i) {
|
for (size_t i = 0; i < s->maps_size; ++i) {
|
||||||
@ -30,14 +30,14 @@ static void syms_deinit(Syms* s)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void syms_push_layer(Syms* s)
|
static void ppsyms_push_layer(PPSyms* s)
|
||||||
{
|
{
|
||||||
Hashmap m = { };
|
Hashmap m = { };
|
||||||
hashmap_init(&m, sizeof(size_t));
|
hashmap_init(&m, sizeof(size_t));
|
||||||
array_push((void**)&s->maps, &s->maps_cap, &s->maps_size, &m, sizeof(m));
|
array_push((void**)&s->maps, &s->maps_cap, &s->maps_size, &m, sizeof(m));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void syms_pop_layer(Syms* s)
|
static void ppsyms_pop_layer(PPSyms* s)
|
||||||
{
|
{
|
||||||
assert(s->maps_size > 0);
|
assert(s->maps_size > 0);
|
||||||
|
|
||||||
@ -45,19 +45,19 @@ static void syms_pop_layer(Syms* s)
|
|||||||
s->maps_size -= 1;
|
s->maps_size -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Hashmap* syms_current(Syms* s)
|
static Hashmap* ppsyms_current(PPSyms* s)
|
||||||
{
|
{
|
||||||
assert(s->maps_size > 0);
|
assert(s->maps_size > 0);
|
||||||
return &s->maps[s->maps_size - 1];
|
return &s->maps[s->maps_size - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
static void syms_define(Syms* s, const char* ident, size_t def_idx)
|
static void ppsyms_define(PPSyms* s, const char* ident, size_t def_idx)
|
||||||
{
|
{
|
||||||
Hashmap* m = syms_current(s);
|
Hashmap* m = ppsyms_current(s);
|
||||||
hashmap_set(m, ident, &def_idx);
|
hashmap_set(m, ident, &def_idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t* syms_get(Syms* s, const char* ident)
|
static size_t* ppsyms_get(PPSyms* s, const char* ident)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < s->maps_size; ++i) {
|
for (size_t i = 0; i < s->maps_size; ++i) {
|
||||||
Hashmap* m = &s->maps[s->maps_size - i - 1];
|
Hashmap* m = &s->maps[s->maps_size - i - 1];
|
||||||
@ -114,7 +114,7 @@ struct Preproc {
|
|||||||
Tok curr;
|
Tok curr;
|
||||||
|
|
||||||
ARRAY_FIELD(Def, defs);
|
ARRAY_FIELD(Def, defs);
|
||||||
Syms syms;
|
PPSyms syms;
|
||||||
|
|
||||||
CondStack condstack;
|
CondStack condstack;
|
||||||
|
|
||||||
@ -159,7 +159,7 @@ Preproc* preproc_new(char* filename, char* text, Arena* arena)
|
|||||||
// null-definition at idx 0
|
// null-definition at idx 0
|
||||||
ARRAY_FIELD_PUSH(p, defs, &(Def) { });
|
ARRAY_FIELD_PUSH(p, defs, &(Def) { });
|
||||||
|
|
||||||
syms_init(&p->syms);
|
ppsyms_init(&p->syms);
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
@ -180,7 +180,7 @@ void preproc_free(Preproc* p)
|
|||||||
}
|
}
|
||||||
free(p->defs);
|
free(p->defs);
|
||||||
}
|
}
|
||||||
syms_deinit(&p->syms);
|
ppsyms_deinit(&p->syms);
|
||||||
free(p);
|
free(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -206,7 +206,7 @@ static void step(Preproc* p)
|
|||||||
p->tok_stack_size -= 1;
|
p->tok_stack_size -= 1;
|
||||||
|
|
||||||
if (p->curr.ty == Tok_EndOfMacroInvocation) {
|
if (p->curr.ty == Tok_EndOfMacroInvocation) {
|
||||||
syms_pop_layer(&p->syms);
|
ppsyms_pop_layer(&p->syms);
|
||||||
step(p);
|
step(p);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -217,7 +217,7 @@ static void collect_arg(Preproc* p, size_t def_idx, size_t arg_idx)
|
|||||||
if (arg_idx >= p->defs[def_idx].params_size) {
|
if (arg_idx >= p->defs[def_idx].params_size) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"error: too many arguments for macro on line %d\n",
|
"error: too many arguments for macro on line %d\n",
|
||||||
p->curr.line);
|
p->curr.loc.line);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -248,8 +248,9 @@ static void collect_arg(Preproc* p, size_t def_idx, size_t arg_idx)
|
|||||||
|
|
||||||
if (p->curr.ty != ',' && p->curr.ty != ')') {
|
if (p->curr.ty != ',' && p->curr.ty != ')') {
|
||||||
assert(p->curr.ty == Tok_Eof);
|
assert(p->curr.ty == Tok_Eof);
|
||||||
fprintf(
|
fprintf(stderr,
|
||||||
stderr, "error: expected ',' or ')' on line %d\n", p->curr.line);
|
"error: expected ',' or ')' on line %d\n",
|
||||||
|
p->curr.loc.line);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,7 +261,7 @@ static void collect_arg(Preproc* p, size_t def_idx, size_t arg_idx)
|
|||||||
.toks_size = toks_size,
|
.toks_size = toks_size,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
syms_define(&p->syms, p->defs[def_idx].params[arg_idx], p->defs_size - 1);
|
ppsyms_define(&p->syms, p->defs[def_idx].params[arg_idx], p->defs_size - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define A(B, C) B C
|
#define A(B, C) B C
|
||||||
@ -282,7 +283,7 @@ static void collect_args(Preproc* p, size_t def_idx)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (p->curr.ty != ')') {
|
if (p->curr.ty != ')') {
|
||||||
fprintf(stderr, "error: expected ')' on line %d\n", p->curr.line);
|
fprintf(stderr, "error: expected ')' on line %d\n", p->curr.loc.line);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -290,7 +291,7 @@ static void collect_args(Preproc* p, size_t def_idx)
|
|||||||
if (idx > p->defs[def_idx].params_size) {
|
if (idx > p->defs[def_idx].params_size) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"error: too few arguments for macro on line %d\n",
|
"error: too few arguments for macro on line %d\n",
|
||||||
p->curr.line);
|
p->curr.loc.line);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -299,7 +300,7 @@ static Tok expand_tok(Preproc* p)
|
|||||||
{
|
{
|
||||||
Tok tok = p->curr;
|
Tok tok = p->curr;
|
||||||
size_t* def_idx;
|
size_t* def_idx;
|
||||||
if (tok.ty != Tok_Ident || !(def_idx = syms_get(&p->syms, tok.text))) {
|
if (tok.ty != Tok_Ident || !(def_idx = ppsyms_get(&p->syms, tok.text))) {
|
||||||
step(p);
|
step(p);
|
||||||
return tok;
|
return tok;
|
||||||
}
|
}
|
||||||
@ -308,8 +309,8 @@ static Tok expand_tok(Preproc* p)
|
|||||||
// when seeing the same macro a second time
|
// when seeing the same macro a second time
|
||||||
// in the invocation tree, treat it as a normal token.
|
// in the invocation tree, treat it as a normal token.
|
||||||
// undefine it at this layer.
|
// undefine it at this layer.
|
||||||
syms_push_layer(&p->syms);
|
ppsyms_push_layer(&p->syms);
|
||||||
syms_define(&p->syms, tok.text, 0);
|
ppsyms_define(&p->syms, tok.text, 0);
|
||||||
|
|
||||||
if (p->defs[*def_idx].params) {
|
if (p->defs[*def_idx].params) {
|
||||||
step(p);
|
step(p);
|
||||||
@ -323,8 +324,7 @@ static Tok expand_tok(Preproc* p)
|
|||||||
for (size_t i = 0; i < p->defs[*def_idx].toks_size; ++i) {
|
for (size_t i = 0; i < p->defs[*def_idx].toks_size; ++i) {
|
||||||
Def* def = &p->defs[*def_idx];
|
Def* def = &p->defs[*def_idx];
|
||||||
Tok expanded_tok = def->toks[def->toks_size - i - 1];
|
Tok expanded_tok = def->toks[def->toks_size - i - 1];
|
||||||
expanded_tok.line = tok.line;
|
expanded_tok.loc = tok.loc;
|
||||||
expanded_tok.col = tok.col;
|
|
||||||
ARRAY_FIELD_PUSH(p, tok_stack, &expanded_tok);
|
ARRAY_FIELD_PUSH(p, tok_stack, &expanded_tok);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -338,8 +338,9 @@ static Tok do_define(Preproc* p)
|
|||||||
{
|
{
|
||||||
step(p);
|
step(p);
|
||||||
if (p->curr.ty != Tok_Ident) {
|
if (p->curr.ty != Tok_Ident) {
|
||||||
fprintf(
|
fprintf(stderr,
|
||||||
stderr, "error: expected identifier on line %d\n", p->curr.line);
|
"error: expected identifier on line %d\n",
|
||||||
|
p->curr.loc.line);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
Tok ident_tok = p->curr;
|
Tok ident_tok = p->curr;
|
||||||
@ -374,7 +375,8 @@ static Tok do_define(Preproc* p)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (p->curr.ty != ')') {
|
if (p->curr.ty != ')') {
|
||||||
fprintf(stderr, "error: expected ')' on line %d\n", p->curr.line);
|
fprintf(
|
||||||
|
stderr, "error: expected ')' on line %d\n", p->curr.loc.line);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
step(p);
|
step(p);
|
||||||
@ -402,12 +404,13 @@ static Tok do_define(Preproc* p)
|
|||||||
def.toks_size = toks_size;
|
def.toks_size = toks_size;
|
||||||
|
|
||||||
ARRAY_FIELD_PUSH(p, defs, &def);
|
ARRAY_FIELD_PUSH(p, defs, &def);
|
||||||
syms_define(&p->syms, ident_tok.text, p->defs_size - 1);
|
ppsyms_define(&p->syms, ident_tok.text, p->defs_size - 1);
|
||||||
|
|
||||||
return p->curr;
|
return p->curr;
|
||||||
|
|
||||||
error_expected_identifier:
|
error_expected_identifier:
|
||||||
fprintf(stderr, "error: expected identifier on line %d\n", p->curr.line);
|
fprintf(
|
||||||
|
stderr, "error: expected identifier on line %d\n", p->curr.loc.line);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -416,8 +419,9 @@ static Tok do_undef(Preproc* p)
|
|||||||
step(p);
|
step(p);
|
||||||
|
|
||||||
if (p->curr.ty != Tok_Ident) {
|
if (p->curr.ty != Tok_Ident) {
|
||||||
fprintf(
|
fprintf(stderr,
|
||||||
stderr, "error: expected identifier on line %d\n", p->curr.line);
|
"error: expected identifier on line %d\n",
|
||||||
|
p->curr.loc.line);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
Tok ident_tok = p->curr;
|
Tok ident_tok = p->curr;
|
||||||
@ -425,11 +429,11 @@ static Tok do_undef(Preproc* p)
|
|||||||
if (p->curr.ty != Tok_Eof && p->curr.ty != Tok_Eol) {
|
if (p->curr.ty != Tok_Eof && p->curr.ty != Tok_Eol) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"error: unexpected extra tokens on line %d\n",
|
"error: unexpected extra tokens on line %d\n",
|
||||||
p->curr.line);
|
p->curr.loc.line);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
syms_define(&p->syms, ident_tok.text, 0);
|
ppsyms_define(&p->syms, ident_tok.text, 0);
|
||||||
|
|
||||||
return p->curr;
|
return p->curr;
|
||||||
}
|
}
|
||||||
@ -445,8 +449,9 @@ static Tok do_include(Preproc* p)
|
|||||||
curr_file->lexer.lex_headername = false;
|
curr_file->lexer.lex_headername = false;
|
||||||
|
|
||||||
if (p->curr.ty != Tok_HeaderName) {
|
if (p->curr.ty != Tok_HeaderName) {
|
||||||
fprintf(
|
fprintf(stderr,
|
||||||
stderr, "error: expected header name on line %d\n", p->curr.line);
|
"error: expected header name on line %d\n",
|
||||||
|
p->curr.loc.line);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -456,7 +461,7 @@ static Tok do_include(Preproc* p)
|
|||||||
if (p->curr.ty != Tok_Eof && p->curr.ty != Tok_Eol) {
|
if (p->curr.ty != Tok_Eof && p->curr.ty != Tok_Eol) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"error: unexpected extra tokens on line %d\n",
|
"error: unexpected extra tokens on line %d\n",
|
||||||
p->curr.line);
|
p->curr.loc.line);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -506,12 +511,13 @@ static Tok interpret_directive(Preproc* p);
|
|||||||
|
|
||||||
static Tok do_ifndef(Preproc* p)
|
static Tok do_ifndef(Preproc* p)
|
||||||
{
|
{
|
||||||
int original_line = p->curr.line;
|
int original_line = p->curr.loc.line;
|
||||||
|
|
||||||
step(p);
|
step(p);
|
||||||
if (p->curr.ty != Tok_Ident) {
|
if (p->curr.ty != Tok_Ident) {
|
||||||
fprintf(
|
fprintf(stderr,
|
||||||
stderr, "error: expected identifier on line %d\n", p->curr.line);
|
"error: expected identifier on line %d\n",
|
||||||
|
p->curr.loc.line);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
Tok ident = p->curr;
|
Tok ident = p->curr;
|
||||||
@ -520,11 +526,11 @@ static Tok do_ifndef(Preproc* p)
|
|||||||
if (p->curr.ty != Tok_Eof && p->curr.ty != Tok_Eol) {
|
if (p->curr.ty != Tok_Eof && p->curr.ty != Tok_Eol) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"error: unexpected extra tokens on line %d\n",
|
"error: unexpected extra tokens on line %d\n",
|
||||||
p->curr.line);
|
p->curr.loc.line);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cond = syms_get(&p->syms, ident.text) == nullptr;
|
bool cond = ppsyms_get(&p->syms, ident.text) == nullptr;
|
||||||
|
|
||||||
condstack_push(&p->condstack, cond);
|
condstack_push(&p->condstack, cond);
|
||||||
|
|
||||||
@ -561,7 +567,7 @@ static Tok do_endif(Preproc* p)
|
|||||||
if (p->curr.ty != Tok_Eof && p->curr.ty != Tok_Eol) {
|
if (p->curr.ty != Tok_Eof && p->curr.ty != Tok_Eol) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"error: unexpected extra tokens on line %d\n",
|
"error: unexpected extra tokens on line %d\n",
|
||||||
p->curr.line);
|
p->curr.loc.line);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -576,8 +582,9 @@ static Tok interpret_directive(Preproc* p)
|
|||||||
return p->curr;
|
return p->curr;
|
||||||
|
|
||||||
if (p->curr.ty != Tok_Ident) {
|
if (p->curr.ty != Tok_Ident) {
|
||||||
fprintf(
|
fprintf(stderr,
|
||||||
stderr, "error: expected identifier on line %d\n", p->curr.line);
|
"error: expected identifier on line %d\n",
|
||||||
|
p->curr.loc.line);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -617,7 +624,7 @@ static Tok interpret_directive(Preproc* p)
|
|||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"error: '%s' is not a preprocessor instruction on line %d\n",
|
"error: '%s' is not a preprocessor instruction on line %d\n",
|
||||||
kw.text,
|
kw.text,
|
||||||
kw.line);
|
kw.loc.line);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -659,7 +666,7 @@ Tok tokstream_next(TokStream* s)
|
|||||||
text[0] = '\0';
|
text[0] = '\0';
|
||||||
strncat(text, curr.text, strlen(curr.text) - 1);
|
strncat(text, curr.text, strlen(curr.text) - 1);
|
||||||
strcat(text, next.text + 1);
|
strcat(text, next.text + 1);
|
||||||
s->curr = (Tok) { .ty = Tok_Str, text, curr.line, curr.col };
|
s->curr = (Tok) { .ty = Tok_Str, text, curr.loc };
|
||||||
return tokstream_next(s);
|
return tokstream_next(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
52
syms.c
Normal file
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