This commit is contained in:
sfja 2026-10-03 02:14:26 +02:00
parent 48587d47de
commit d43dc3539d
10 changed files with 200 additions and 83 deletions

View File

@ -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

View File

@ -1,6 +1,6 @@
#include "not_stdio.h"
int main()
int main(void)
{
puts("hello world");
}

2
lex.c
View File

@ -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
View File

@ -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
View File

@ -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);

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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
View 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
View 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