add sema
This commit is contained in:
parent
48587d47de
commit
d43dc3539d
2
Makefile
2
Makefile
@ -1,5 +1,5 @@
|
||||
|
||||
larpcc: main.c lex.c preproc.c collection.c parse.c ast_print.c resolve.c
|
||||
larpcc: main.c lex.c preproc.c collection.c parse.c ast_print.c resolve.c sema.c
|
||||
gcc $^ -o $@ -std=c23 -pedantic -Wall -Wextra -g -fsanitize=address -Werror=switch
|
||||
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
#include "not_stdio.h"
|
||||
|
||||
int main()
|
||||
int main(void)
|
||||
{
|
||||
puts("hello world");
|
||||
}
|
||||
|
||||
2
lex.c
2
lex.c
@ -86,6 +86,8 @@ const char* tokty_str(TokTy ty)
|
||||
return "KwChar";
|
||||
case Tok_KwConst:
|
||||
return "KwConst";
|
||||
case Tok_KwVoid:
|
||||
return "KwVoid";
|
||||
case Tok_EndOfMacroInvocation:
|
||||
return "EndOfMacroInvocation";
|
||||
}
|
||||
|
||||
21
main.c
21
main.c
@ -2,6 +2,7 @@
|
||||
#include "collection.h"
|
||||
#include "parse.h"
|
||||
#include "resolve.h"
|
||||
#include "sema.h"
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
@ -71,16 +72,18 @@ int main(int argc, char* argv[])
|
||||
TokStream tokstream;
|
||||
tokstream_init(&tokstream, preproc, &tok_arena);
|
||||
|
||||
Sema* sema = sema_new();
|
||||
|
||||
Arena ast_arena;
|
||||
arena_init(&ast_arena, 4096);
|
||||
|
||||
printf("--- ast ---\n");
|
||||
|
||||
Parser* parser = parser_new(&tokstream, &ast_arena);
|
||||
Parser* parser = parser_new(&tokstream, sema, &ast_arena);
|
||||
|
||||
Arena sym_arena;
|
||||
arena_init(&sym_arena, 4096);
|
||||
Resolver* resolver = resolver_new(&sym_arena);
|
||||
// Arena sym_arena;
|
||||
// arena_init(&sym_arena, 4096);
|
||||
// Resolver* resolver = resolver_new(&sym_arena);
|
||||
|
||||
AstStmt* stmt;
|
||||
while (!parser_done(parser)) {
|
||||
@ -90,16 +93,18 @@ int main(int argc, char* argv[])
|
||||
|
||||
printf("\n");
|
||||
|
||||
resolver_resolve_top_stmt(resolver, stmt);
|
||||
// resolver_resolve_top_stmt(resolver, stmt);
|
||||
}
|
||||
|
||||
resolver_free(resolver);
|
||||
// resolver_free(resolver);
|
||||
|
||||
parser_free(parser);
|
||||
|
||||
preproc_free(preproc);
|
||||
arena_deinit(&tok_arena);
|
||||
|
||||
arena_deinit(&ast_arena);
|
||||
arena_deinit(&sym_arena);
|
||||
// arena_deinit(&sym_arena);
|
||||
|
||||
sema_free(sema);
|
||||
}
|
||||
}
|
||||
|
||||
35
parse.c
35
parse.c
@ -2,6 +2,7 @@
|
||||
#include "ast.h"
|
||||
#include "collection.h"
|
||||
#include "resolve.h"
|
||||
#include "sema.h"
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
@ -115,6 +116,7 @@ static void kwmatcher_init(KwMatcher* m, TokStream* tokstream)
|
||||
{ Tok_KwInt, "int" },
|
||||
{ Tok_KwChar, "char" },
|
||||
{ Tok_KwConst, "const" },
|
||||
{ Tok_KwVoid, "void" },
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < sizeof(kws) / sizeof(kws[0]); ++i) {
|
||||
@ -150,6 +152,7 @@ typedef enum : unsigned int {
|
||||
|
||||
struct Parser {
|
||||
KwMatcher kwmatcher;
|
||||
Sema* sema;
|
||||
Arena* arena;
|
||||
Arena sym_arena;
|
||||
|
||||
@ -160,12 +163,13 @@ struct Parser {
|
||||
ParserFlags flags;
|
||||
};
|
||||
|
||||
Parser* parser_new(TokStream* tokstream, Arena* arena)
|
||||
Parser* parser_new(TokStream* tokstream, Sema* sema, Arena* arena)
|
||||
{
|
||||
Parser* p = malloc(sizeof(Parser));
|
||||
|
||||
*p = (Parser) {
|
||||
.kwmatcher = { },
|
||||
.sema = sema,
|
||||
.arena = arena,
|
||||
.sym_arena = { },
|
||||
|
||||
@ -194,20 +198,21 @@ static void step(Parser* p)
|
||||
p->curr = kwmatcher_next(&p->kwmatcher);
|
||||
}
|
||||
|
||||
#define DEFINE_NEW(TYPE, FN_NAME) \
|
||||
#define DEFINE_NEW(TYPE, FN_NAME, POST) \
|
||||
[[maybe_unused]] static TYPE* new_##FN_NAME(Parser* p, TYPE init) \
|
||||
{ \
|
||||
TYPE* val = arena_alloc(p->arena, sizeof(TYPE)); \
|
||||
*val = init; \
|
||||
POST; \
|
||||
return val; \
|
||||
}
|
||||
|
||||
DEFINE_NEW(AstStmt, stmt)
|
||||
DEFINE_NEW(AstDecl, decl)
|
||||
DEFINE_NEW(AstDeclar, declar)
|
||||
DEFINE_NEW(AstExpr, expr)
|
||||
DEFINE_NEW(AstStmt, stmt, { sema_visit_stmt(p->sema, val); })
|
||||
DEFINE_NEW(AstDecl, decl, { })
|
||||
DEFINE_NEW(AstDeclar, declar, { })
|
||||
DEFINE_NEW(AstExpr, expr, { sema_visit_expr(p->sema, val); })
|
||||
|
||||
DEFINE_NEW(AstStmtBlock, stmt_block)
|
||||
DEFINE_NEW(AstStmtBlock, stmt_block, { })
|
||||
|
||||
static AstStmtBlock* parse_stmt_block(Parser* p);
|
||||
static AstStmt* parse_stmt(Parser* p);
|
||||
@ -260,8 +265,8 @@ static bool is_defty_ident(Parser* p, Tok tok)
|
||||
{
|
||||
if (tok.ty != Tok_Ident)
|
||||
return false;
|
||||
Sym* sym = syms_get(p->syms, tok.text);
|
||||
return sym && sym->ty == Sym_Typedef;
|
||||
OldSym* sym = syms_get(p->syms, tok.text);
|
||||
return sym && sym->ty == OldSym_Typedef;
|
||||
}
|
||||
|
||||
static AstStmt* parse_stmt(Parser* p)
|
||||
@ -322,7 +327,11 @@ static AstDecl* parse_decl(Parser* p, bool is_param)
|
||||
bool multi_allowed = !is_param;
|
||||
|
||||
if (!is_param && first->ty == AstDeclar_Function && p->curr.ty == '{') {
|
||||
|
||||
sema_function_enter(p->sema, declars[0]);
|
||||
function_body = parse_stmt_block(p);
|
||||
sema_function_leave(p->sema);
|
||||
|
||||
multi_allowed = false;
|
||||
}
|
||||
|
||||
@ -432,7 +441,9 @@ static AstDeclar* parse_declar_l3(Parser* p)
|
||||
|
||||
ARRAY_VAR(AstDecl*, params);
|
||||
|
||||
if (p->curr.ty != Tok_Eof && p->curr.ty != ')') {
|
||||
if (p->curr.ty == Tok_KwVoid) {
|
||||
step(p);
|
||||
} else if (p->curr.ty != Tok_Eof && p->curr.ty != ')') {
|
||||
AstDecl* d = parse_decl(p, true);
|
||||
ARENA_ARRAY_VAR_PUSH(p->arena, params, &d);
|
||||
|
||||
@ -509,8 +520,8 @@ static AstSpec parse_decl_spec(Parser* p)
|
||||
while (true) {
|
||||
switch (p->curr.ty) {
|
||||
case Tok_Ident: {
|
||||
Sym* sym = syms_get(p->syms, p->curr.text);
|
||||
if (!sym || sym->ty != Sym_Typedef)
|
||||
OldSym* sym = syms_get(p->syms, p->curr.text);
|
||||
if (!sym || sym->ty != OldSym_Typedef)
|
||||
break;
|
||||
spec |= AstSpec_DefTy;
|
||||
step(p);
|
||||
|
||||
8
parse.h
8
parse.h
@ -3,6 +3,7 @@
|
||||
|
||||
#include "ast.h"
|
||||
#include "collection.h"
|
||||
#include "sema.h"
|
||||
#include <stddef.h>
|
||||
|
||||
char* read_textfile(const char* filename);
|
||||
@ -47,6 +48,7 @@ typedef enum {
|
||||
Tok_Char,
|
||||
Tok_Whitespace,
|
||||
Tok_HeaderName,
|
||||
|
||||
Tok_Eol = '\n', // NOTE: has value 10
|
||||
Tok_Semicolon = ';',
|
||||
Tok_LParen = '(',
|
||||
@ -57,12 +59,14 @@ typedef enum {
|
||||
Tok_Asterisk = '*',
|
||||
Tok_Hashtag = '#',
|
||||
|
||||
Tok_KwInt,
|
||||
Tok_KwInt = 256,
|
||||
Tok_KwChar,
|
||||
Tok_KwConst,
|
||||
Tok_KwVoid,
|
||||
|
||||
// used internally in preprocessor
|
||||
Tok_EndOfMacroInvocation,
|
||||
|
||||
} TokTy;
|
||||
|
||||
const char* tokty_str(TokTy ty);
|
||||
@ -105,7 +109,7 @@ Tok tokstream_next(TokStream* s);
|
||||
|
||||
typedef struct Parser Parser;
|
||||
|
||||
Parser* parser_new(TokStream* tokstream, Arena* arena);
|
||||
Parser* parser_new(TokStream* tokstream, Sema* sema, Arena* arena);
|
||||
void parser_free(Parser* p);
|
||||
AstStmt* parser_parse_stmt(Parser* p);
|
||||
bool parser_done(Parser* p);
|
||||
|
||||
62
resolve.c
62
resolve.c
@ -17,7 +17,7 @@ Syms* syms_new()
|
||||
};
|
||||
|
||||
ARRAY_FIELD_PUSH(s, maps, &(Hashmap) { });
|
||||
hashmap_init(&s->maps[0], sizeof(Sym*));
|
||||
hashmap_init(&s->maps[0], sizeof(OldSym*));
|
||||
|
||||
return s;
|
||||
}
|
||||
@ -33,7 +33,7 @@ void syms_free(Syms* s)
|
||||
void syms_push_scope(Syms* s)
|
||||
{
|
||||
ARRAY_FIELD_PUSH(s, maps, &(Hashmap) { });
|
||||
hashmap_init(&s->maps[s->maps_size - 1], sizeof(Sym*));
|
||||
hashmap_init(&s->maps[s->maps_size - 1], sizeof(OldSym*));
|
||||
}
|
||||
|
||||
void syms_pop_scope(Syms* s)
|
||||
@ -43,60 +43,21 @@ void syms_pop_scope(Syms* s)
|
||||
s->maps_size -= 1;
|
||||
}
|
||||
|
||||
void syms_define(Syms* s, const char* ident, Sym* sym)
|
||||
void syms_define(Syms* s, const char* ident, OldSym* sym)
|
||||
{
|
||||
Hashmap* m = &s->maps[s->maps_size - 1];
|
||||
hashmap_set(m, ident, &sym);
|
||||
}
|
||||
|
||||
Sym* syms_get(Syms* s, const char* ident)
|
||||
OldSym* syms_get(Syms* s, const char* ident)
|
||||
{
|
||||
Sym** res;
|
||||
OldSym** res;
|
||||
for (size_t i = 0; i < s->maps_size; ++i)
|
||||
if ((res = hashmap_get(&s->maps[s->maps_size - i - 1], ident)))
|
||||
return *res;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void print_sym(Sym* s)
|
||||
{
|
||||
switch (s->ty) {
|
||||
case Sym_Typedef:
|
||||
printf("Typedef");
|
||||
break;
|
||||
case Sym_Declarator:
|
||||
printf("Declarator");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
struct SymPrinter {
|
||||
int depth;
|
||||
};
|
||||
|
||||
static void print_sym_hashmap(void* self, const char* key, void* val)
|
||||
{
|
||||
struct SymPrinter* p = self;
|
||||
Sym* sym = *(Sym**)val;
|
||||
|
||||
printf(" ");
|
||||
for (int i = 0; i < p->depth; ++i)
|
||||
printf(" ");
|
||||
printf("'%s' -> ", key);
|
||||
print_sym(sym);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void syms_print(Syms* s)
|
||||
{
|
||||
for (size_t i = 0; i < s->maps_size; ++i) {
|
||||
struct SymPrinter p = {
|
||||
.depth = i,
|
||||
};
|
||||
hashmap_for_each(&s->maps[i], print_sym_hashmap, &p);
|
||||
}
|
||||
}
|
||||
|
||||
typedef enum : unsigned int {
|
||||
ResolverFlags_InTypedef,
|
||||
} ResolverFlags;
|
||||
@ -130,7 +91,7 @@ Resolver* resolver_new(Arena* arena)
|
||||
.flags = 0,
|
||||
};
|
||||
|
||||
keymap_init(&r->resol_map, sizeof(Sym*));
|
||||
keymap_init(&r->resol_map, sizeof(OldSym*));
|
||||
|
||||
return r;
|
||||
}
|
||||
@ -226,9 +187,9 @@ static AstVisitorResult visit_declar(AstVisitor* v, AstDeclar* node)
|
||||
if (node->ty == AstDeclar_Ident) {
|
||||
assert(r->current_decl_stmt);
|
||||
|
||||
Sym* sym = arena_alloc(r->arena, sizeof(Sym));
|
||||
*sym = (Sym) {
|
||||
.ty = Sym_Declarator,
|
||||
OldSym* sym = arena_alloc(r->arena, sizeof(OldSym));
|
||||
*sym = (OldSym) {
|
||||
.ty = OldSym_Declarator,
|
||||
.declarator = {
|
||||
.stmt = r->current_decl_stmt,
|
||||
.declar = node,
|
||||
@ -247,15 +208,12 @@ static AstVisitorResult visit_expr(AstVisitor* v, AstExpr* node)
|
||||
|
||||
if (node->ty == AstExpr_Ident) {
|
||||
|
||||
Sym* sym = syms_get(r->ord_syms, node->ident);
|
||||
OldSym* sym = syms_get(r->ord_syms, node->ident);
|
||||
if (!sym) {
|
||||
fprintf(stderr,
|
||||
"error: use of undeclared '%s' on line %d\n",
|
||||
node->ident,
|
||||
node->loc.line);
|
||||
|
||||
syms_print(r->ord_syms);
|
||||
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
14
resolve.h
14
resolve.h
@ -5,19 +5,19 @@
|
||||
#include "collection.h"
|
||||
|
||||
typedef enum {
|
||||
Sym_Typedef,
|
||||
Sym_Declarator,
|
||||
} SymTy;
|
||||
OldSym_Typedef,
|
||||
OldSym_Declarator,
|
||||
} OldSymTy;
|
||||
|
||||
typedef struct {
|
||||
SymTy ty;
|
||||
OldSymTy ty;
|
||||
union {
|
||||
struct {
|
||||
AstStmt* stmt;
|
||||
AstDeclar* declar;
|
||||
} declarator;
|
||||
};
|
||||
} Sym;
|
||||
} OldSym;
|
||||
|
||||
typedef struct Syms Syms;
|
||||
|
||||
@ -27,8 +27,8 @@ 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);
|
||||
void syms_define(Syms* s, const char* ident, OldSym* sym);
|
||||
OldSym* syms_get(Syms* s, const char* ident);
|
||||
|
||||
typedef struct Resolver Resolver;
|
||||
|
||||
|
||||
106
sema.c
Normal file
106
sema.c
Normal file
@ -0,0 +1,106 @@
|
||||
#include "sema.h"
|
||||
#include "ast.h"
|
||||
#include "collection.h"
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct {
|
||||
Hashmap ord_syms;
|
||||
Hashmap tag_syms;
|
||||
} Rib;
|
||||
|
||||
static void rib_init(Rib* r)
|
||||
{
|
||||
*r = (Rib) {
|
||||
.ord_syms = { },
|
||||
.tag_syms = { },
|
||||
};
|
||||
hashmap_init(&r->ord_syms, sizeof(Sym*));
|
||||
hashmap_init(&r->tag_syms, sizeof(Sym*));
|
||||
}
|
||||
|
||||
static void rib_deinit(Rib* r)
|
||||
{
|
||||
hashmap_deinit(&r->ord_syms);
|
||||
hashmap_deinit(&r->tag_syms);
|
||||
}
|
||||
|
||||
struct Sema {
|
||||
Arena sym_arena;
|
||||
ARRAY_FIELD(Rib, ribs);
|
||||
Hashmap labels;
|
||||
};
|
||||
|
||||
Sema* sema_new(void)
|
||||
{
|
||||
Sema* s = malloc(sizeof(Sema));
|
||||
*s = (Sema) {
|
||||
.sym_arena = { },
|
||||
ARRAY_FIELD_INIT(ribs),
|
||||
.labels = { },
|
||||
};
|
||||
|
||||
arena_init(&s->sym_arena, 1024);
|
||||
|
||||
ARRAY_FIELD_PUSH(s, ribs, (&(Rib) { }));
|
||||
rib_init(&s->ribs[0]);
|
||||
|
||||
hashmap_init(&s->labels, sizeof(LabelSym*));
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void sema_free(Sema* s)
|
||||
{
|
||||
arena_deinit(&s->sym_arena);
|
||||
for (size_t i = 0; i < s->ribs_size; ++i)
|
||||
rib_deinit(&s->ribs[i]);
|
||||
if (s->ribs)
|
||||
free(s->ribs);
|
||||
hashmap_deinit(&s->labels);
|
||||
free(s);
|
||||
}
|
||||
|
||||
void sema_scope_enter(Sema* s)
|
||||
{
|
||||
ARRAY_FIELD_PUSH(s, ribs, (&(Rib) { }));
|
||||
rib_init(&s->ribs[s->ribs_size - 1]);
|
||||
}
|
||||
|
||||
void sema_scope_leave(Sema* s)
|
||||
{
|
||||
assert(s->ribs_size > 0);
|
||||
rib_deinit(&s->ribs[s->ribs_size - 1]);
|
||||
s->ribs_size -= 1;
|
||||
}
|
||||
|
||||
void sema_function_enter(Sema* s, AstDeclar* declar)
|
||||
{
|
||||
assert(declar->ty == AstDeclar_Function);
|
||||
|
||||
// clear label map
|
||||
hashmap_deinit(&s->labels);
|
||||
hashmap_init(&s->labels, sizeof(LabelSym*));
|
||||
|
||||
sema_scope_enter(s);
|
||||
|
||||
for (size_t i = 0; i < declar->function.params_size; ++i) { }
|
||||
}
|
||||
|
||||
void sema_function_leave(Sema* s)
|
||||
{
|
||||
sema_scope_leave(s);
|
||||
}
|
||||
|
||||
void sema_visit_function_declar(Sema* s, AstDeclar* declar)
|
||||
{
|
||||
}
|
||||
|
||||
void sema_visit_stmt(Sema* s, AstStmt* stmt)
|
||||
{
|
||||
if (stmt->ty == AstStmt_Decl) { }
|
||||
}
|
||||
|
||||
void sema_visit_expr(Sema* s, AstExpr* expr)
|
||||
{
|
||||
}
|
||||
31
sema.h
Normal file
31
sema.h
Normal file
@ -0,0 +1,31 @@
|
||||
#ifndef SEMA_H
|
||||
#define SEMA_H
|
||||
|
||||
#include "ast.h"
|
||||
typedef enum {
|
||||
Sym_Declar,
|
||||
} SymTy;
|
||||
|
||||
typedef struct {
|
||||
SymTy ty;
|
||||
} Sym;
|
||||
|
||||
typedef struct {
|
||||
int _;
|
||||
} LabelSym;
|
||||
|
||||
typedef struct Sema Sema;
|
||||
|
||||
Sema* sema_new(void);
|
||||
void sema_free(Sema* s);
|
||||
|
||||
void sema_scope_enter(Sema* s);
|
||||
void sema_scope_leave(Sema* s);
|
||||
|
||||
void sema_function_enter(Sema* s, AstDeclar* declar);
|
||||
void sema_function_leave(Sema* s);
|
||||
|
||||
void sema_visit_stmt(Sema* s, AstStmt* stmt);
|
||||
void sema_visit_expr(Sema* s, AstExpr* expr);
|
||||
|
||||
#endif
|
||||
Loading…
x
Reference in New Issue
Block a user