make parser and sema work

This commit is contained in:
sfja 2026-10-20 01:27:50 +02:00
parent 8309384c0b
commit e45e72249f
16 changed files with 709 additions and 580 deletions

View File

@ -1,5 +1,13 @@
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
CFLAGS := -std=c23 -pedantic -Wall -Wextra -g -Werror=switch
# CFLAGS += -fsanitize=address
c_files := $(wildcard *.c)
h_files := $(wildcard *.h)
larpcc: $(c_files) $(h_files)
gcc $(c_files) -o $@ -std=c23 -pedantic -Wall -Wextra -g -Werror=switch

12
ast.h
View File

@ -2,13 +2,9 @@
#define AST_H
#include "collection.h"
#include "diagnostics.h"
#include <stdio.h>
typedef struct {
int line;
int col;
} Loc;
typedef struct AstStmt AstStmt;
typedef struct AstDecl AstDecl;
typedef struct AstDeclar AstDeclar;
@ -19,6 +15,7 @@ typedef struct AstStmtBlock AstStmtBlock;
struct AstStmtBlock {
ARRAY_FIELD(AstStmt*, stmts);
Loc loc;
int id;
};
typedef struct AstDeclBlock AstDeclBlock;
@ -36,6 +33,7 @@ typedef enum {
struct AstStmt {
AstStmtTy ty;
Loc loc;
int id;
union {
AstDecl* decl;
AstExpr* expr;
@ -63,9 +61,11 @@ struct AstDecl {
ARRAY_FIELD(AstDeclar*, declars);
AstStmtBlock* function_body;
Loc loc;
int id;
};
typedef enum {
AstDeclar_Anon,
AstDeclar_Ident,
AstDeclar_Pointer,
AstDeclar_Array,
@ -75,6 +75,7 @@ typedef enum {
struct AstDeclar {
AstDeclarTy ty;
Loc loc;
int id;
AstExpr* init_expr;
union {
char* ident;
@ -102,6 +103,7 @@ typedef enum {
struct AstExpr {
AstExprTy ty;
Loc loc;
int id;
union {
char* ident;
char* str_val;

View File

@ -137,6 +137,10 @@ void ast_decl_print(FILE* f, const AstDecl* node, int depth)
void ast_declar_print(FILE* f, const AstDeclar* node, int depth)
{
switch (node->ty) {
case AstDeclar_Anon: {
fprintf(f, "Declar::Anon %d:%d", node->loc.line, node->loc.col);
return;
}
case AstDeclar_Ident: {
fprintf(
f, "Declar::Ident %d:%d {\n", node->loc.line, node->loc.col);
@ -329,6 +333,7 @@ void ast_declar_visit(AstVisitor* v, AstDeclar* node)
void ast_declar_visit_body(AstVisitor* v, AstDeclar* node)
{
switch (node->ty) {
case AstDeclar_Anon:
case AstDeclar_Ident:
break;
case AstDeclar_Pointer:

View File

@ -240,7 +240,7 @@ struct KeymapEntry {
void keymap_init(Keymap* m, size_t elem_size)
{
size_t entry_size = sizeof(KeymapEntry) + (elem_size + 7ul & ~7ul);
size_t entry_size = sizeof(KeymapEntry) + ((elem_size + 7ul) & ~7ul);
*m = (Keymap) {
ARRAY_FIELD_INIT(entries),

18
diagnostics.c Normal file
View File

@ -0,0 +1,18 @@
#include "diagnostics.h"
#include <stdarg.h>
#include <stdio.h>
void diag_error(Loc loc, const char* fmt, ...)
{
va_list va;
va_start(va, fmt);
fprintf(stderr,
"\x1b[1;97m%s:%d:%d: \x1b[1;91merror: \x1b[0m\n",
loc.file,
loc.line,
loc.col);
vfprintf(stderr, fmt, va);
va_end(va);
}

12
diagnostics.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef DIAGNOSTICS_H
#define DIAGNOSTICS_H
typedef struct {
int line;
int col;
const char* file;
} Loc;
void diag_error(Loc loc, const char* fmt, ...);
#endif

View File

@ -1,6 +1,6 @@
#ifndef NOT_STDIO_H
#define NOT_STDIO_H
int puts(const char* __s);
int puts(const char*);
#endif

296
lex.c
View File

@ -1,296 +0,0 @@
#include "collection.h"
#include "parse.h"
#include <assert.h>
#include <errno.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* read_textfile(const char* filename)
{
FILE* fp = fopen(filename, "r");
if (!fp) {
goto couldnt_read_file;
}
if (fseek(fp, 0, SEEK_END) != 0) {
goto couldnt_read_file;
}
long file_size = ftell(fp);
if (file_size < 0) {
goto couldnt_read_file;
}
if (fseek(fp, 0, SEEK_SET) != 0) {
goto couldnt_read_file;
}
char* buffer = malloc(file_size + 1);
assert(buffer);
if (fread(buffer, sizeof(char), file_size, fp) != (size_t)file_size) {
goto couldnt_read_file;
}
buffer[file_size] = '\0';
return buffer;
couldnt_read_file:
fprintf(stderr,
"error: couldn't read file '%s': %s\n",
filename,
strerror(errno));
return nullptr;
}
const char* tokty_str(TokTy ty)
{
switch (ty) {
case Tok_Eof:
return "Eof";
case Tok_Ident:
return "Ident";
case Tok_Int:
return "Int";
case Tok_Str:
return "Str";
case Tok_Char:
return "Char";
case Tok_Whitespace:
return "Whitespace";
case Tok_HeaderName:
return "HeaderName";
case Tok_Eol:
return "Eol";
case Tok_Semicolon:
return "Semicolon";
case Tok_LParen:
return "LParen";
case Tok_RParen:
return "RParen";
case Tok_LBrace:
return "LBrace";
case Tok_RBrace:
return "RBrace";
case Tok_Asterisk:
return "Asterisk";
case Tok_Hashtag:
return "Hashtag";
case Tok_Comma:
return "Comma";
case Tok_KwInt:
return "KwInt";
case Tok_KwChar:
return "KwChar";
case Tok_KwConst:
return "KwConst";
case Tok_KwVoid:
return "KwVoid";
case Tok_EndOfMacroInvocation:
return "EndOfMacroInvocation";
}
return "<unknown>";
}
void source_iter_init(SourceIter* r, const char* text)
{
*r = (SourceIter) {
.text = text,
.i = 0,
.line = 1,
.col = 1,
};
}
Char source_iter_next(SourceIter* r)
{
char ch = r->text[r->i];
Loc loc = { r->line, r->col };
if (r->text[r->i] != '\0') {
if (ch == '\n') {
r->line += 1;
r->col = 1;
} else {
r->col += 1;
}
r->i += 1;
}
return (Char) { ch, loc };
}
void lsl_iter_init(LslIter* r, SourceIter* source_char_iter)
{
Char curr = source_iter_next(source_char_iter);
*r = (LslIter) {
.source_char_iter = source_char_iter,
.curr = curr,
};
}
Char lsl_iter_next(LslIter* r)
{
Char next = source_iter_next(r->source_char_iter);
if (r->curr.ch == '\\' && next.ch == '\n') {
r->curr = source_iter_next(r->source_char_iter);
return lsl_iter_next(r);
}
Char curr = r->curr;
r->curr = next;
return curr;
}
void lexer_init(Lexer* r, LslIter* lsl_char_iter, Arena* arena)
{
Char curr = lsl_iter_next(lsl_char_iter);
*r = (Lexer) {
.lsl_iter = lsl_char_iter,
.arena = arena,
.curr = curr,
.lex_whitespace = false,
.lex_headername = false,
};
}
static Tok tok(Lexer* l, TokTy ty, const char* text, Loc loc)
{
char* text_dup = arena_alloc(l->arena, strlen(text) + 1);
text_dup[0] = '\0';
strcpy(text_dup, text);
return (Tok) { ty, text_dup, loc };
}
static bool done(Lexer* l)
{
return l->curr.ch == '\0';
}
constexpr size_t max_token_text_len = 64;
static void step(Lexer* l, char text[], size_t* text_len)
{
assert(*text_len < max_token_text_len);
text[*text_len] = l->curr.ch;
*text_len += 1;
l->curr = lsl_iter_next(l->lsl_iter);
}
Tok lexer_next(Lexer* l)
{
Loc loc = l->curr.loc;
char text[max_token_text_len] = "";
size_t text_len = 0;
if (done(l)) {
return tok(l, Tok_Eof, text, loc);
}
bool matched = false;
while (strchr(" \t\r", l->curr.ch)) {
matched = true;
step(l, text, &text_len);
}
if (matched) {
if (l->lex_whitespace) {
return tok(l, Tok_Whitespace, text, loc);
}
return lexer_next(l);
}
while ((l->curr.ch >= 'a' && l->curr.ch <= 'z')
|| (l->curr.ch >= 'A' && l->curr.ch <= 'Z')
|| (matched && l->curr.ch >= '0' && l->curr.ch <= '9')
|| strchr("_", l->curr.ch)) {
matched = true;
step(l, text, &text_len);
}
if (matched) {
return tok(l, Tok_Ident, text, loc);
}
while ((l->curr.ch >= '1' && l->curr.ch <= '9')
|| (matched && l->curr.ch == '0')) {
matched = true;
step(l, text, &text_len);
}
if (matched) {
return tok(l, Tok_Int, text, loc);
}
if (l->lex_headername && (l->curr.ch == '"' || l->curr.ch == '<')) {
char ter = l->curr.ch == '<' ? '>' : '"';
step(l, text, &text_len);
while (l->curr.ch != '\0' && l->curr.ch != '\n' && l->curr.ch != ter) {
step(l, text, &text_len);
}
if (l->curr.ch != ter) {
fprintf(stderr,
"error: malformed header name, expected '%c' on line %d\n",
ter,
l->curr.loc.line);
return lexer_next(l);
}
step(l, text, &text_len);
return tok(l, Tok_HeaderName, text, loc);
}
if (l->curr.ch == '"') {
step(l, text, &text_len);
while (l->curr.ch != '"') {
if (l->curr.ch == '\\') {
step(l, text, &text_len);
if (done(l))
break;
}
step(l, text, &text_len);
}
if (done(l) || l->curr.ch != '"') {
fprintf(stderr,
"error: malformed string literal on line %d\n",
l->curr.loc.line);
return lexer_next(l);
}
step(l, text, &text_len);
return tok(l, Tok_Str, text, loc);
}
if (l->curr.ch == '\'') {
step(l, text, &text_len);
if (l->curr.ch == '\\') {
step(l, text, &text_len);
}
if (!done(l)) {
step(l, text, &text_len);
}
if (done(l) && l->curr.ch != '\'') {
fprintf(stderr,
"error: malformed character literal on line %d\n",
l->curr.loc.line);
return lexer_next(l);
}
step(l, text, &text_len);
return tok(l, Tok_Char, text, loc);
}
if (strchr("\n;(){},*#", l->curr.ch)) {
TokTy ty = (TokTy)l->curr.ch;
step(l, text, &text_len);
return tok(l, ty, text, loc);
}
fprintf(stderr,
"error: illegal character '%c' on line %d\n",
l->curr.ch,
l->curr.loc.line);
step(l, text, &text_len);
return lexer_next(l);
}

13
main.c
View File

@ -1,7 +1,7 @@
#include "ast.h"
#include "collection.h"
#include "parse.h"
#include "resolve.h"
#include "preproc.h"
#include "sema.h"
#include <assert.h>
#include <stddef.h>
@ -36,7 +36,7 @@ int main(int argc, char* argv[])
printf("--- tokens ---\n");
Loc loc = { 1, 1 };
Loc loc = { 1, 1, nullptr };
Tok tok;
while ((tok = tokstream_next(&tokstream)).ty != Tok_Eof) {
// printf("%s\t%s\n", tokty_str(tok.ty), tok.text);
@ -79,15 +79,16 @@ int main(int argc, char* argv[])
printf("--- ast ---\n");
Parser* parser = parser_new(&tokstream, sema, &ast_arena);
Parser parser;
parser_init(&parser, &tokstream, sema, &ast_arena);
// Arena sym_arena;
// arena_init(&sym_arena, 4096);
// Resolver* resolver = resolver_new(&sym_arena);
AstStmt* stmt;
while (!parser_done(parser)) {
stmt = parser_parse_stmt(parser);
while (!parser_done(&parser)) {
stmt = parser_parse_stmt(&parser);
ast_stmt_print(stdout, stmt, 0);
@ -98,7 +99,7 @@ int main(int argc, char* argv[])
// resolver_free(resolver);
parser_free(parser);
parser_deinit(&parser);
preproc_free(preproc);
arena_deinit(&tok_arena);

143
parse.c
View File

@ -9,23 +9,6 @@
#include <stdlib.h>
#include <string.h>
typedef struct {
char ch;
bool is_term;
unsigned short val;
} KwNodeOpt;
typedef struct {
ARRAY_FIELD(KwNodeOpt, opts);
size_t idx;
} KwNode;
typedef struct {
TokStream* tokstream;
Arena arena;
ARRAY_FIELD(KwNode, nodes);
} KwMatcher;
static KwNodeOpt* kwmatcher_create_path(
KwMatcher* m, size_t node_idx, const char* kw)
{
@ -97,7 +80,7 @@ static TokTy kwmatcher_match(KwMatcher* m, const char* kw)
return opt->val;
}
static void kwmatcher_init(KwMatcher* m, TokStream* tokstream)
void kwmatcher_init(KwMatcher* m, TokStream* tokstream)
{
*m = (KwMatcher) {
.tokstream = tokstream,
@ -124,12 +107,12 @@ static void kwmatcher_init(KwMatcher* m, TokStream* tokstream)
}
}
static void kwmatcher_deinit(KwMatcher* m)
void kwmatcher_deinit(KwMatcher* m)
{
arena_deinit(&m->arena);
}
static Tok kwmatcher_next(KwMatcher* m)
Tok kwmatcher_next(KwMatcher* m)
{
Tok tok = tokstream_next(m->tokstream);
if (tok.ty != Tok_Ident)
@ -138,42 +121,30 @@ static Tok kwmatcher_next(KwMatcher* m)
tok.ty = ty;
exit:
printf(" - %-10s %-10s %d:%d\n",
tokty_str(tok.ty),
tok.text,
tok.loc.line,
tok.loc.col);
// printf(" - %-10s %-10s %d:%d\n",
// tokty_str(tok.ty),
// tok.text,
// tok.loc.line,
// tok.loc.col);
return tok;
}
typedef enum : unsigned int {
ParserFlags_ParsingTypedef = 1 << 0,
} ParserFlags;
static AstStmtBlock* parse_stmt_block(Parser* p);
static AstStmt* parse_stmt(Parser* p);
static AstDecl* parse_decl(Parser* p, bool is_param);
static AstDeclar* parse_declar(Parser* p, bool allow_anon);
static AstSpec parse_decl_spec(Parser* p);
static AstExpr* parse_expr(Parser* p);
struct Parser {
KwMatcher kwmatcher;
Sema* sema;
Arena* arena;
Arena sym_arena;
Syms* syms;
Tok curr;
ParserFlags flags;
};
Parser* parser_new(TokStream* tokstream, Sema* sema, Arena* arena)
void parser_init(Parser* p, TokStream* tokstream, Sema* sema, Arena* arena)
{
Parser* p = malloc(sizeof(Parser));
*p = (Parser) {
.kwmatcher = { },
.sema = sema,
.arena = arena,
.sym_arena = { },
.syms = syms_new(),
.old_syms = oldsyms_new(),
.curr = { },
@ -182,15 +153,22 @@ Parser* parser_new(TokStream* tokstream, Sema* sema, Arena* arena)
kwmatcher_init(&p->kwmatcher, tokstream);
p->curr = kwmatcher_next(&p->kwmatcher);
return p;
}
void parser_free(Parser* p)
void parser_deinit(Parser* p)
{
kwmatcher_deinit(&p->kwmatcher);
syms_free(p->syms);
free(p);
oldsyms_free(p->old_syms);
}
AstStmt* parser_parse_stmt(Parser* p)
{
return parse_stmt(p);
}
bool parser_done(Parser* p)
{
return p->curr.ty == Tok_Eof;
}
static void step(Parser* p)
@ -203,6 +181,8 @@ static void step(Parser* p)
{ \
TYPE* val = arena_alloc(p->arena, sizeof(TYPE)); \
*val = init; \
static int ids = 0; \
val->id = ids++; \
POST; \
return val; \
}
@ -214,13 +194,6 @@ DEFINE_NEW(AstExpr, expr, { sema_visit_expr(p->sema, val); })
DEFINE_NEW(AstStmtBlock, stmt_block, { })
static AstStmtBlock* parse_stmt_block(Parser* p);
static AstStmt* parse_stmt(Parser* p);
static AstDecl* parse_decl(Parser* p, bool is_param);
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;
@ -265,7 +238,7 @@ static bool is_defty_ident(Parser* p, Tok tok)
{
if (tok.ty != Tok_Ident)
return false;
OldSym* sym = syms_get(p->syms, tok.text);
OldSym* sym = oldsyms_get(p->old_syms, tok.text);
return sym && sym->ty == OldSym_Typedef;
}
@ -319,7 +292,7 @@ static AstDecl* parse_decl(Parser* p, bool is_param)
ARRAY_VAR(AstDeclar*, declars);
AstDeclar* first = parse_declar(p);
AstDeclar* first = parse_declar(p, is_param);
ARENA_ARRAY_VAR_PUSH(p->arena, declars, &first);
@ -338,7 +311,7 @@ static AstDecl* parse_decl(Parser* p, bool is_param)
while (multi_allowed && p->curr.ty == ',') {
step(p);
AstDeclar* declar = parse_declar(p);
AstDeclar* declar = parse_declar(p, false);
ARENA_ARRAY_VAR_PUSH(p->arena, declars, &declar);
}
@ -356,14 +329,14 @@ static AstDecl* parse_decl(Parser* p, bool is_param)
});
}
static AstDeclar* parse_declar_l1(Parser* p);
static AstDeclar* parse_declar_l2(Parser* p);
static AstDeclar* parse_declar_l3(Parser* p);
static AstDeclar* parse_declar_l4(Parser* p);
static AstDeclar* parse_declar_l1(Parser* p, bool allow_anon);
static AstDeclar* parse_declar_l2(Parser* p, bool allow_anon);
static AstDeclar* parse_declar_l3(Parser* p, bool allow_anon);
static AstDeclar* parse_declar_l4(Parser* p, bool allow_anon);
static AstDeclar* parse_declar(Parser* p)
static AstDeclar* parse_declar(Parser* p, bool allow_anon)
{
AstDeclar* declar = parse_declar_l1(p);
AstDeclar* declar = parse_declar_l1(p, allow_anon);
if (p->curr.ty == '=') {
step(p);
@ -374,7 +347,7 @@ static AstDeclar* parse_declar(Parser* p)
return declar;
}
static AstDeclar* parse_declar_l1(Parser* p)
static AstDeclar* parse_declar_l1(Parser* p, bool allow_anon)
{
Loc loc = p->curr.loc;
@ -383,7 +356,7 @@ static AstDeclar* parse_declar_l1(Parser* p)
AstSpec spec = parse_decl_spec(p);
AstDeclar* declar = parse_declar_l1(p);
AstDeclar* declar = parse_declar_l1(p, allow_anon);
return new_declar(p,
(AstDeclar) {
.ty = AstDeclar_Pointer,
@ -395,14 +368,14 @@ static AstDeclar* parse_declar_l1(Parser* p)
});
}
return parse_declar_l2(p);
return parse_declar_l2(p, allow_anon);
}
static AstDeclar* parse_declar_l2(Parser* p)
static AstDeclar* parse_declar_l2(Parser* p, bool allow_anon)
{
Loc loc = p->curr.loc;
AstDeclar* declar = parse_declar_l3(p);
AstDeclar* declar = parse_declar_l3(p, allow_anon);
while (p->curr.ty == '[') {
step(p);
@ -430,11 +403,11 @@ static AstDeclar* parse_declar_l2(Parser* p)
return declar;
}
static AstDeclar* parse_declar_l3(Parser* p)
static AstDeclar* parse_declar_l3(Parser* p, bool allow_anon)
{
Loc loc = p->curr.loc;
AstDeclar* declar = parse_declar_l4(p);
AstDeclar* declar = parse_declar_l4(p, allow_anon);
if (p->curr.ty == '(') {
step(p);
@ -478,10 +451,18 @@ static AstDeclar* parse_declar_l3(Parser* p)
return declar;
}
static AstDeclar* parse_declar_l4(Parser* p)
static AstDeclar* parse_declar_l4(Parser* p, bool allow_anon)
{
Loc loc = p->curr.loc;
if (allow_anon && (p->curr.ty == ',' || p->curr.ty == ')')) {
return new_declar(p,
(AstDeclar) {
.ty = AstDeclar_Anon,
.loc = loc,
});
}
if (p->curr.ty == Tok_Ident) {
char* ident = arena_strdup(p->arena, p->curr.text);
step(p);
@ -496,7 +477,7 @@ static AstDeclar* parse_declar_l4(Parser* p)
if (p->curr.ty == '(') {
step(p);
AstDeclar* declar = parse_declar_l1(p);
AstDeclar* declar = parse_declar_l1(p, allow_anon);
if (p->curr.ty != ')') {
fprintf(
@ -520,7 +501,7 @@ static AstSpec parse_decl_spec(Parser* p)
while (true) {
switch (p->curr.ty) {
case Tok_Ident: {
OldSym* sym = syms_get(p->syms, p->curr.text);
OldSym* sym = oldsyms_get(p->old_syms, p->curr.text);
if (!sym || sym->ty != OldSym_Typedef)
break;
spec |= AstSpec_DefTy;
@ -686,13 +667,3 @@ static AstExpr* parse_expr_2(Parser* p)
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;
}

119
parse.h
View File

@ -1,116 +1,51 @@
#ifndef PARSE_H
#define PARSE_H
#include "ast.h"
#include "collection.h"
#include "preproc.h"
#include "resolve.h"
#include "sema.h"
#include <stddef.h>
char* read_textfile(const char* filename);
// phases:
// https://en.cppreference.com/c/language/translation_phases
// phase 1 - source chars
typedef struct {
char ch;
Loc loc;
} Char;
bool is_term;
unsigned short val;
} KwNodeOpt;
typedef struct {
const char* text;
size_t i;
int line;
int col;
} SourceIter;
void source_iter_init(SourceIter* r, const char* text);
Char source_iter_next(SourceIter* r);
// phase 2 - logical source lines
ARRAY_FIELD(KwNodeOpt, opts);
size_t idx;
} KwNode;
typedef struct {
SourceIter* source_char_iter;
Char curr;
} LslIter;
TokStream* tokstream;
Arena arena;
ARRAY_FIELD(KwNode, nodes);
} KwMatcher;
void lsl_iter_init(LslIter* r, SourceIter* source_iter);
Char lsl_iter_next(LslIter* r);
void kwmatcher_init(KwMatcher* m, TokStream* tokstream);
void kwmatcher_deinit(KwMatcher* m);
Tok kwmatcher_next(KwMatcher* m);
// phase 3 - preprocessor tokens
typedef enum : unsigned int {
ParserFlags_ParsingTypedef = 1 << 0,
} ParserFlags;
typedef enum {
Tok_Eof,
Tok_Ident,
Tok_Int,
Tok_Str,
Tok_Char,
Tok_Whitespace,
Tok_HeaderName,
Tok_Eol = '\n', // NOTE: has value 10
Tok_Semicolon = ';',
Tok_LParen = '(',
Tok_RParen = ')',
Tok_LBrace = '{',
Tok_RBrace = '}',
Tok_Comma = ',',
Tok_Asterisk = '*',
Tok_Hashtag = '#',
Tok_KwInt = 256,
Tok_KwChar,
Tok_KwConst,
Tok_KwVoid,
// used internally in preprocessor
Tok_EndOfMacroInvocation,
} TokTy;
const char* tokty_str(TokTy ty);
typedef struct {
TokTy ty;
char* text;
Loc loc;
} Tok;
typedef struct {
LslIter* lsl_iter;
typedef struct Parser {
KwMatcher kwmatcher;
Sema* sema;
Arena* arena;
Char curr;
bool lex_whitespace;
bool lex_headername;
} Lexer;
Arena sym_arena;
void lexer_init(Lexer* r, LslIter* lsl_iter, Arena* arena);
Tok lexer_next(Lexer* l);
OldSyms* old_syms;
// phase 4 - preprocessor
typedef struct Preproc Preproc;
Preproc* preproc_new(char* filename, char* text, Arena* arena);
void preproc_free(Preproc* p);
Tok preproc_next(Preproc* p);
// phase 5, 6 - preprocessor cleanup, concat strings
typedef struct {
Preproc* preproc;
Arena* arena;
Tok curr;
} TokStream;
void tokstream_init(TokStream* s, Preproc* preproc, Arena* arena);
Tok tokstream_next(TokStream* s);
ParserFlags flags;
} Parser;
typedef struct Parser Parser;
Parser* parser_new(TokStream* tokstream, Sema* sema, Arena* arena);
void parser_free(Parser* p);
void parser_init(Parser* p, TokStream* tokstream, Sema* sema, Arena* arena);
void parser_deinit(Parser* p);
AstStmt* parser_parse_stmt(Parser* p);
bool parser_done(Parser* p);

372
preproc.c
View File

@ -1,11 +1,301 @@
#include "preproc.h"
#include "collection.h"
#include "parse.h"
#include <assert.h>
#include <errno.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* read_textfile(const char* filename)
{
FILE* fp = fopen(filename, "r");
if (!fp) {
goto couldnt_read_file;
}
if (fseek(fp, 0, SEEK_END) != 0) {
goto couldnt_read_file;
}
long file_size = ftell(fp);
if (file_size < 0) {
goto couldnt_read_file;
}
if (fseek(fp, 0, SEEK_SET) != 0) {
goto couldnt_read_file;
}
char* buffer = malloc(file_size + 1);
assert(buffer);
if (fread(buffer, sizeof(char), file_size, fp) != (size_t)file_size) {
goto couldnt_read_file;
}
buffer[file_size] = '\0';
return buffer;
couldnt_read_file:
fprintf(stderr,
"error: couldn't read file '%s': %s\n",
filename,
strerror(errno));
return nullptr;
}
const char* tokty_str(TokTy ty)
{
switch (ty) {
case Tok_Eof:
return "Eof";
case Tok_Ident:
return "Ident";
case Tok_Int:
return "Int";
case Tok_Str:
return "Str";
case Tok_Char:
return "Char";
case Tok_Whitespace:
return "Whitespace";
case Tok_HeaderName:
return "HeaderName";
case Tok_Eol:
return "Eol";
case Tok_Semicolon:
return "Semicolon";
case Tok_LParen:
return "LParen";
case Tok_RParen:
return "RParen";
case Tok_LBrace:
return "LBrace";
case Tok_RBrace:
return "RBrace";
case Tok_Asterisk:
return "Asterisk";
case Tok_Hashtag:
return "Hashtag";
case Tok_Comma:
return "Comma";
case Tok_KwInt:
return "KwInt";
case Tok_KwChar:
return "KwChar";
case Tok_KwConst:
return "KwConst";
case Tok_KwVoid:
return "KwVoid";
case Tok_EndOfMacroInvocation:
return "EndOfMacroInvocation";
}
return "<unknown>";
}
void source_iter_init(SourceIter* r, const char* filename, const char* text)
{
*r = (SourceIter) {
.filename = filename,
.text = text,
.i = 0,
.line = 1,
.col = 1,
};
}
Char source_iter_next(SourceIter* r)
{
char ch = r->text[r->i];
Loc loc = { r->line, r->col, r->filename };
if (r->text[r->i] != '\0') {
if (ch == '\n') {
r->line += 1;
r->col = 1;
} else {
r->col += 1;
}
r->i += 1;
}
return (Char) { ch, loc };
}
void lsl_iter_init(LslIter* r, SourceIter* source_char_iter)
{
Char curr = source_iter_next(source_char_iter);
*r = (LslIter) {
.source_char_iter = source_char_iter,
.curr = curr,
};
}
Char lsl_iter_next(LslIter* r)
{
Char next = source_iter_next(r->source_char_iter);
if (r->curr.ch == '\\' && next.ch == '\n') {
r->curr = source_iter_next(r->source_char_iter);
return lsl_iter_next(r);
}
Char curr = r->curr;
r->curr = next;
return curr;
}
void lexer_init(Lexer* r, LslIter* lsl_char_iter, Arena* arena)
{
Char curr = lsl_iter_next(lsl_char_iter);
*r = (Lexer) {
.lsl_iter = lsl_char_iter,
.arena = arena,
.curr = curr,
.lex_whitespace = false,
.lex_headername = false,
};
}
static Tok l_tok(Lexer* l, TokTy ty, const char* text, Loc loc)
{
char* text_dup = arena_alloc(l->arena, strlen(text) + 1);
text_dup[0] = '\0';
strcpy(text_dup, text);
return (Tok) { ty, text_dup, loc };
}
static bool l_done(Lexer* l)
{
return l->curr.ch == '\0';
}
constexpr size_t max_token_text_len = 64;
static void l_step(Lexer* l, char text[], size_t* text_len)
{
assert(*text_len < max_token_text_len);
text[*text_len] = l->curr.ch;
*text_len += 1;
l->curr = lsl_iter_next(l->lsl_iter);
}
Tok lexer_next(Lexer* l)
{
Loc loc = l->curr.loc;
char text[max_token_text_len] = "";
size_t text_len = 0;
if (l_done(l)) {
return l_tok(l, Tok_Eof, text, loc);
}
bool matched = false;
while (strchr(" \t\r", l->curr.ch)) {
matched = true;
l_step(l, text, &text_len);
}
if (matched) {
if (l->lex_whitespace) {
return l_tok(l, Tok_Whitespace, text, loc);
}
return lexer_next(l);
}
while ((l->curr.ch >= 'a' && l->curr.ch <= 'z')
|| (l->curr.ch >= 'A' && l->curr.ch <= 'Z')
|| (matched && l->curr.ch >= '0' && l->curr.ch <= '9')
|| strchr("_", l->curr.ch)) {
matched = true;
l_step(l, text, &text_len);
}
if (matched) {
return l_tok(l, Tok_Ident, text, loc);
}
while ((l->curr.ch >= '1' && l->curr.ch <= '9')
|| (matched && l->curr.ch == '0')) {
matched = true;
l_step(l, text, &text_len);
}
if (matched) {
return l_tok(l, Tok_Int, text, loc);
}
if (l->lex_headername && (l->curr.ch == '"' || l->curr.ch == '<')) {
char ter = l->curr.ch == '<' ? '>' : '"';
l_step(l, text, &text_len);
while (l->curr.ch != '\0' && l->curr.ch != '\n' && l->curr.ch != ter) {
l_step(l, text, &text_len);
}
if (l->curr.ch != ter) {
fprintf(stderr,
"error: malformed header name, expected '%c' on line %d\n",
ter,
l->curr.loc.line);
return lexer_next(l);
}
l_step(l, text, &text_len);
return l_tok(l, Tok_HeaderName, text, loc);
}
if (l->curr.ch == '"') {
l_step(l, text, &text_len);
while (l->curr.ch != '"') {
if (l->curr.ch == '\\') {
l_step(l, text, &text_len);
if (l_done(l))
break;
}
l_step(l, text, &text_len);
}
if (l_done(l) || l->curr.ch != '"') {
fprintf(stderr,
"error: malformed string literal on line %d\n",
l->curr.loc.line);
return lexer_next(l);
}
l_step(l, text, &text_len);
return l_tok(l, Tok_Str, text, loc);
}
if (l->curr.ch == '\'') {
l_step(l, text, &text_len);
if (l->curr.ch == '\\') {
l_step(l, text, &text_len);
}
if (!l_done(l)) {
l_step(l, text, &text_len);
}
if (l_done(l) && l->curr.ch != '\'') {
fprintf(stderr,
"error: malformed character literal on line %d\n",
l->curr.loc.line);
return lexer_next(l);
}
l_step(l, text, &text_len);
return l_tok(l, Tok_Char, text, loc);
}
if (strchr("\n;(){},*#", l->curr.ch)) {
TokTy ty = (TokTy)l->curr.ch;
l_step(l, text, &text_len);
return l_tok(l, ty, text, loc);
}
fprintf(stderr,
"error: illegal character '%c' on line %d\n",
l->curr.ch,
l->curr.loc.line);
l_step(l, text, &text_len);
return lexer_next(l);
}
typedef struct {
ARRAY_FIELD(Hashmap, maps);
} PPSyms;
@ -73,7 +363,7 @@ typedef struct {
size_t depth;
} CondStack;
void condstack_push(CondStack* s, bool cond)
static void condstack_push(CondStack* s, bool cond)
{
if (cond) {
s->conds |= 1ul << s->depth;
@ -83,7 +373,7 @@ void condstack_push(CondStack* s, bool cond)
s->depth += 1;
}
bool condstack_pop(CondStack* s)
static bool condstack_pop(CondStack* s)
{
assert(s->depth > 0);
s->depth -= 1;
@ -151,7 +441,7 @@ Preproc* preproc_new(char* filename, char* text, Arena* arena)
}));
File* file = &p->files[0];
source_iter_init(&file->source_iter, text);
source_iter_init(&file->source_iter, filename, text);
lsl_iter_init(&file->lsl_iter, &file->source_iter);
lexer_init(&file->lexer, &file->lsl_iter, p->arena);
p->curr = lexer_next(&file->lexer);
@ -184,7 +474,7 @@ void preproc_free(Preproc* p)
free(p);
}
static void step(Preproc* p)
static void p_step(Preproc* p)
{
p->next_can_be_directive = p->curr.ty == Tok_Eol;
@ -197,7 +487,7 @@ static void step(Preproc* p)
free(curr_file->text);
p->files_size -= 1;
step(p);
p_step(p);
}
return;
@ -207,12 +497,12 @@ static void step(Preproc* p)
if (p->curr.ty == Tok_EndOfMacroInvocation) {
ppsyms_pop_layer(&p->syms);
step(p);
p_step(p);
return;
}
}
static void collect_arg(Preproc* p, size_t def_idx, size_t arg_idx)
static void p_collect_arg(Preproc* p, size_t def_idx, size_t arg_idx)
{
if (arg_idx >= p->defs[def_idx].params_size) {
fprintf(stderr,
@ -243,7 +533,7 @@ static void collect_arg(Preproc* p, size_t def_idx, size_t arg_idx)
(&p->curr),
sizeof(*(&p->curr)));
step(p);
p_step(p);
}
if (p->curr.ty != ',' && p->curr.ty != ')') {
@ -264,21 +554,19 @@ static void collect_arg(Preproc* p, size_t def_idx, size_t arg_idx)
ppsyms_define(&p->syms, p->defs[def_idx].params[arg_idx], p->defs_size - 1);
}
#define A(B, C) B C
static void collect_args(Preproc* p, size_t def_idx)
static void p_collect_args(Preproc* p, size_t def_idx)
{
assert(p->curr.ty == '(');
step(p);
p_step(p);
size_t idx = 0;
if (p->curr.ty != Tok_Eof && p->curr.ty != ')') {
collect_arg(p, def_idx, idx);
p_collect_arg(p, def_idx, idx);
idx += 1;
while (p->curr.ty == ',') {
step(p);
collect_arg(p, def_idx, idx);
p_step(p);
p_collect_arg(p, def_idx, idx);
idx += 1;
}
}
@ -296,12 +584,12 @@ static void collect_args(Preproc* p, size_t def_idx)
}
}
static Tok expand_tok(Preproc* p)
static Tok p_expand_tok(Preproc* p)
{
Tok tok = p->curr;
size_t* def_idx;
if (tok.ty != Tok_Ident || !(def_idx = ppsyms_get(&p->syms, tok.text))) {
step(p);
p_step(p);
return tok;
}
@ -313,11 +601,11 @@ static Tok expand_tok(Preproc* p)
ppsyms_define(&p->syms, tok.text, 0);
if (p->defs[*def_idx].params) {
step(p);
p_step(p);
// function-like macros without arg-lists are ignored.
if (p->curr.ty != '(')
return tok;
collect_args(p, *def_idx);
p_collect_args(p, *def_idx);
}
ARRAY_FIELD_PUSH(p, tok_stack, (&(Tok) { .ty = Tok_EndOfMacroInvocation }));
@ -329,14 +617,14 @@ static Tok expand_tok(Preproc* p)
}
// step into the new invocation
step(p);
p_step(p);
return expand_tok(p);
return p_expand_tok(p);
}
static Tok do_define(Preproc* p)
{
step(p);
p_step(p);
if (p->curr.ty != Tok_Ident) {
fprintf(stderr,
"error: expected identifier on line %d\n",
@ -346,13 +634,13 @@ static Tok do_define(Preproc* p)
Tok ident_tok = p->curr;
p->files[p->files_size - 1].lexer.lex_whitespace = true;
step(p);
p_step(p);
p->files[p->files_size - 1].lexer.lex_whitespace = false;
Def def = { };
if (p->curr.ty == '(') {
step(p);
p_step(p);
ARRAY_VAR(char*, params);
@ -361,16 +649,16 @@ static Tok do_define(Preproc* p)
goto error_expected_identifier;
ARRAY_VAR_PUSH(params, &p->curr.text);
step(p);
p_step(p);
while (p->curr.ty == ',') {
step(p);
p_step(p);
if (p->curr.ty != Tok_Ident)
goto error_expected_identifier;
ARRAY_VAR_PUSH(params, &p->curr.text);
step(p);
p_step(p);
}
}
@ -379,14 +667,14 @@ static Tok do_define(Preproc* p)
stderr, "error: expected ')' on line %d\n", p->curr.loc.line);
exit(1);
}
step(p);
p_step(p);
def.params = params;
def.params_size = params_size;
}
if (p->curr.ty == Tok_Whitespace)
step(p);
p_step(p);
ARRAY_VAR(Tok, toks);
@ -397,7 +685,7 @@ static Tok do_define(Preproc* p)
&toks_size,
(&p->curr),
sizeof(*(&p->curr)));
step(p);
p_step(p);
}
def.toks = toks;
@ -416,7 +704,7 @@ error_expected_identifier:
static Tok do_undef(Preproc* p)
{
step(p);
p_step(p);
if (p->curr.ty != Tok_Ident) {
fprintf(stderr,
@ -445,7 +733,7 @@ static Tok do_include(Preproc* p)
File* curr_file = &p->files[p->files_size - 1];
curr_file->lexer.lex_headername = true;
step(p);
p_step(p);
curr_file->lexer.lex_headername = false;
if (p->curr.ty != Tok_HeaderName) {
@ -456,7 +744,7 @@ static Tok do_include(Preproc* p)
}
Tok headername_tok = p->curr;
step(p);
p_step(p);
if (p->curr.ty != Tok_Eof && p->curr.ty != Tok_Eol) {
fprintf(stderr,
@ -497,7 +785,7 @@ static Tok do_include(Preproc* p)
}));
File* file = &p->files[p->files_size - 1];
source_iter_init(&file->source_iter, text);
source_iter_init(&file->source_iter, filename, text);
lsl_iter_init(&file->lsl_iter, &file->source_iter);
lexer_init(&file->lexer, &file->lsl_iter, p->arena);
p->curr = lexer_next(&file->lexer);
@ -513,7 +801,7 @@ static Tok do_ifndef(Preproc* p)
{
int original_line = p->curr.loc.line;
step(p);
p_step(p);
if (p->curr.ty != Tok_Ident) {
fprintf(stderr,
"error: expected identifier on line %d\n",
@ -521,7 +809,7 @@ static Tok do_ifndef(Preproc* p)
exit(1);
}
Tok ident = p->curr;
step(p);
p_step(p);
if (p->curr.ty != Tok_Eof && p->curr.ty != Tok_Eol) {
fprintf(stderr,
@ -539,10 +827,10 @@ static Tok do_ifndef(Preproc* p)
while (p->curr.ty != Tok_Eof) {
while (p->curr.ty != Tok_Eof
&& (!p->next_can_be_directive || p->curr.ty != '#'))
step(p);
p_step(p);
if (p->curr.ty == Tok_Eof)
break;
step(p);
p_step(p);
if (p->curr.ty != Tok_Ident)
continue;
if (strcmp(p->curr.text, "endif") == 0)
@ -562,7 +850,7 @@ static Tok do_ifndef(Preproc* p)
static Tok do_endif(Preproc* p)
{
step(p);
p_step(p);
if (p->curr.ty != Tok_Eof && p->curr.ty != Tok_Eol) {
fprintf(stderr,
@ -631,10 +919,10 @@ static Tok interpret_directive(Preproc* p)
Tok preproc_next(Preproc* p)
{
if (p->next_can_be_directive && p->curr.ty == '#') {
step(p);
p_step(p);
return interpret_directive(p);
}
return expand_tok(p);
return p_expand_tok(p);
}
static Tok tokstream_next_filtered(TokStream* s)

110
preproc.h Normal file
View File

@ -0,0 +1,110 @@
#ifndef TOKS_H
#define TOKS_H
#include "collection.h"
#include "diagnostics.h"
#include <stddef.h>
char* read_textfile(const char* filename);
// phases:
// https://en.cppreference.com/c/language/translation_phases
// phase 1 - source chars
typedef struct {
char ch;
Loc loc;
} Char;
typedef struct {
const char* filename;
const char* text;
size_t i;
int line;
int col;
} SourceIter;
void source_iter_init(SourceIter* r, const char* filename, const char* text);
Char source_iter_next(SourceIter* r);
// phase 2 - logical source lines
typedef struct {
SourceIter* source_char_iter;
Char curr;
} LslIter;
void lsl_iter_init(LslIter* r, SourceIter* source_iter);
Char lsl_iter_next(LslIter* r);
// phase 3 - preprocessor tokens
typedef enum {
Tok_Eof,
Tok_Ident,
Tok_Int,
Tok_Str,
Tok_Char,
Tok_Whitespace,
Tok_HeaderName,
Tok_Eol = '\n', // NOTE: has value 10
Tok_Semicolon = ';',
Tok_LParen = '(',
Tok_RParen = ')',
Tok_LBrace = '{',
Tok_RBrace = '}',
Tok_Comma = ',',
Tok_Asterisk = '*',
Tok_Hashtag = '#',
Tok_KwInt = 256,
Tok_KwChar,
Tok_KwConst,
Tok_KwVoid,
// used internally in preprocessor
Tok_EndOfMacroInvocation,
} TokTy;
const char* tokty_str(TokTy ty);
typedef struct {
TokTy ty;
char* text;
Loc loc;
} Tok;
typedef struct {
LslIter* lsl_iter;
Arena* arena;
Char curr;
bool lex_whitespace;
bool lex_headername;
} Lexer;
void lexer_init(Lexer* r, LslIter* lsl_iter, Arena* arena);
Tok lexer_next(Lexer* l);
// phase 4 - preprocessor
typedef struct Preproc Preproc;
Preproc* preproc_new(char* filename, char* text, Arena* arena);
void preproc_free(Preproc* p);
Tok preproc_next(Preproc* p);
// phase 5, 6 - preprocessor cleanup, concat strings
typedef struct {
Preproc* preproc;
Arena* arena;
Tok curr;
} TokStream;
void tokstream_init(TokStream* s, Preproc* preproc, Arena* arena);
Tok tokstream_next(TokStream* s);
#endif

View File

@ -5,14 +5,14 @@
#include <stdio.h>
#include <stdlib.h>
struct Syms {
struct OldSyms {
ARRAY_FIELD(Hashmap, maps);
};
Syms* syms_new()
OldSyms* oldsyms_new()
{
Syms* s = malloc(sizeof(Syms));
*s = (Syms) {
OldSyms* s = malloc(sizeof(OldSyms));
*s = (OldSyms) {
ARRAY_FIELD_INIT(maps),
};
@ -22,7 +22,7 @@ Syms* syms_new()
return s;
}
void syms_free(Syms* s)
void oldsyms_free(OldSyms* s)
{
for (size_t i = 0; i < s->maps_size; ++i)
hashmap_deinit(&s->maps[i]);
@ -30,26 +30,26 @@ void syms_free(Syms* s)
free(s);
}
void syms_push_scope(Syms* s)
void oldsyms_push_scope(OldSyms* s)
{
ARRAY_FIELD_PUSH(s, maps, &(Hashmap) { });
hashmap_init(&s->maps[s->maps_size - 1], sizeof(OldSym*));
}
void syms_pop_scope(Syms* s)
void oldsyms_pop_scope(OldSyms* 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, OldSym* sym)
void oldsyms_define(OldSyms* s, const char* ident, OldSym* sym)
{
Hashmap* m = &s->maps[s->maps_size - 1];
hashmap_set(m, ident, &sym);
}
OldSym* syms_get(Syms* s, const char* ident)
OldSym* oldsyms_get(OldSyms* s, const char* ident)
{
OldSym** res;
for (size_t i = 0; i < s->maps_size; ++i)
@ -63,9 +63,9 @@ typedef enum : unsigned int {
} ResolverFlags;
struct Resolver {
Syms* ord_syms;
Syms* tag_syms;
Syms* label_syms;
OldSyms* ord_syms;
OldSyms* tag_syms;
OldSyms* label_syms;
Arena* arena;
@ -75,13 +75,13 @@ struct Resolver {
ResolverFlags flags;
};
Resolver* resolver_new(Arena* arena)
Resolver* oldresolver_new(Arena* arena)
{
Resolver* r = malloc(sizeof(Resolver));
*r = (Resolver) {
.ord_syms = syms_new(),
.tag_syms = syms_new(),
.label_syms = syms_new(),
.ord_syms = oldsyms_new(),
.tag_syms = oldsyms_new(),
.label_syms = oldsyms_new(),
.arena = arena,
@ -96,24 +96,24 @@ Resolver* resolver_new(Arena* arena)
return r;
}
void resolver_free(Resolver* r)
void oldresolver_free(Resolver* r)
{
keymap_deinit(&r->resol_map);
syms_free(r->ord_syms);
syms_free(r->tag_syms);
syms_free(r->label_syms);
oldsyms_free(r->ord_syms);
oldsyms_free(r->tag_syms);
oldsyms_free(r->label_syms);
free(r);
}
static AstVisitorResult visit_stmt_block(AstVisitor* v, AstStmtBlock* node)
{
Resolver* r = v->op;
syms_push_scope(r->ord_syms);
oldsyms_push_scope(r->ord_syms);
ast_stmt_block_visit_body(v, node);
syms_pop_scope(r->ord_syms);
oldsyms_pop_scope(r->ord_syms);
return AstVisitor_Break;
}
@ -154,14 +154,14 @@ static AstVisitorResult visit_decl(AstVisitor* v, AstDecl* node)
ast_declar_visit(v, d->function.declar);
syms_push_scope(r->ord_syms);
oldsyms_push_scope(r->ord_syms);
for (size_t i = 0; i < d->function.params_size; ++i)
ast_decl_visit(v, d->function.params[i]);
ast_stmt_block_visit(v, node->function_body);
syms_pop_scope(r->ord_syms);
oldsyms_pop_scope(r->ord_syms);
return AstVisitor_Break;
}
@ -175,12 +175,12 @@ static AstVisitorResult visit_declar(AstVisitor* v, AstDeclar* node)
if (node->ty == AstDeclar_Function) {
ast_declar_visit(v, node->function.declar);
syms_push_scope(r->ord_syms);
oldsyms_push_scope(r->ord_syms);
for (size_t i = 0; i < node->function.params_size; ++i)
ast_decl_visit(v, node->function.params[i]);
syms_pop_scope(r->ord_syms);
oldsyms_pop_scope(r->ord_syms);
return AstVisitor_Break;
}
@ -195,7 +195,7 @@ static AstVisitorResult visit_declar(AstVisitor* v, AstDeclar* node)
.declar = node,
},
};
syms_define(r->ord_syms, node->ident, sym);
oldsyms_define(r->ord_syms, node->ident, sym);
return AstVisitor_Break;
}
@ -208,7 +208,7 @@ static AstVisitorResult visit_expr(AstVisitor* v, AstExpr* node)
if (node->ty == AstExpr_Ident) {
OldSym* sym = syms_get(r->ord_syms, node->ident);
OldSym* sym = oldsyms_get(r->ord_syms, node->ident);
if (!sym) {
fprintf(stderr,
"error: use of undeclared '%s' on line %d\n",
@ -221,7 +221,7 @@ static AstVisitorResult visit_expr(AstVisitor* v, AstExpr* node)
return AstVisitor_Continue;
}
void resolver_resolve_top_stmt(Resolver* r, AstStmt* stmt)
void oldresolver_resolve_top_stmt(Resolver* r, AstStmt* stmt)
{
if (stmt->ty != AstStmt_Decl) {
fprintf(

View File

@ -19,22 +19,22 @@ typedef struct {
};
} OldSym;
typedef struct Syms Syms;
typedef struct OldSyms OldSyms;
Syms* syms_new();
void syms_free(Syms* s);
OldSyms* oldsyms_new();
void oldsyms_free(OldSyms* s);
void syms_push_scope(Syms* s);
void syms_pop_scope(Syms* s);
void oldsyms_push_scope(OldSyms* s);
void oldsyms_pop_scope(OldSyms* s);
void syms_define(Syms* s, const char* ident, OldSym* sym);
OldSym* syms_get(Syms* s, const char* ident);
void oldsyms_define(OldSyms* s, const char* ident, OldSym* sym);
OldSym* oldsyms_get(OldSyms* s, const char* ident);
typedef struct Resolver Resolver;
Resolver* resolver_new(Arena* arena);
void resolver_free(Resolver* r);
Resolver* oldresolver_new(Arena* arena);
void oldresolver_free(Resolver* r);
void resolver_resolve_top_stmt(Resolver* r, AstStmt* stmt);
void oldresolver_resolve_top_stmt(Resolver* r, AstStmt* stmt);
#endif

93
sema.c
View File

@ -55,9 +55,21 @@ void type_print(FILE* file, const Type* type)
}
if (type->ty == Type_Pointer) {
type_print(file, type->pointer.inner);
fprintf(file, " *");
type_spec_print(file, type->pointer.spec);
type_print(file, type->pointer.inner);
return;
}
if (type->ty == Type_Function) {
type_print(file, type->function.return_type);
fprintf(file, "()(");
for (size_t i = 0; i < type->function.params_size; ++i) {
if (i > 0)
fprintf(file, ", ");
type_print(file, type->function.params[i]);
}
fprintf(file, ")");
return;
}
@ -144,11 +156,16 @@ void sema_scope_leave(Sema* s)
static Sym* get_ord_sym(Sema* s, const char* ident)
{
Sym* sym = nullptr;
Sym** sym = nullptr;
for (size_t i = 0; i < s->ribs_size; ++i)
if ((sym = hashmap_get(&s->ribs[s->ribs_size - i - 1].ord_syms, ident)))
break;
return sym;
return *sym;
}
static void define_ord_sym(Sema* s, const char* ident, Sym* sym)
{
hashmap_set(&s->ribs[s->ribs_size - 1].ord_syms, ident, &sym);
}
static void error_if_multi_spec(
@ -227,6 +244,11 @@ static void check_declar(Sema* s,
const char** out_declar_ident)
{
switch (declar->ty) {
case AstDeclar_Anon: {
*out_declar_type = type;
*out_declar_ident = nullptr;
return;
}
case AstDeclar_Ident: {
*out_declar_type = type;
*out_declar_ident = declar->ident;
@ -284,6 +306,9 @@ static void check_declar(Sema* s,
&s->type_arena, &new_type->function, params, &declar_type);
}
assert(
new_type->function.params_size == declar->function.params_size);
// TODO: handle forward declarations
check_declar(s,
@ -319,7 +344,7 @@ void sema_function_enter(Sema* s, AstSpec spec, AstDeclar* declar)
.type = type,
},
};
hashmap_set(&rib->ord_syms, declar->ident, &sym);
define_ord_sym(s, declar->ident, sym);
sema_scope_enter(s);
@ -335,6 +360,9 @@ void sema_function_enter(Sema* s, AstSpec spec, AstDeclar* declar)
Type* declar_type;
check_declar(s, param_declar, decl_type, &declar_type, &declar_ident);
if (!declar_ident)
continue;
Rib* rib = &s->ribs[s->ribs_size - 1];
error_if_redefinition(&rib->ord_syms, declar->ident, declar->loc);
@ -346,7 +374,7 @@ void sema_function_enter(Sema* s, AstSpec spec, AstDeclar* declar)
.idx = i,
},
};
hashmap_set(&rib->ord_syms, declar_ident, &sym);
define_ord_sym(s, declar_ident, sym);
}
}
@ -387,6 +415,41 @@ void sema_visit_stmt(Sema* s, AstStmt* stmt)
}
}
static bool is_arg_passable_as_param(const Type* arg, const Type* param)
{
// printf("comparing ");
// type_print(stdout, arg);
// printf(" with ");
// type_print(stdout, param);
// printf("\n");
//
if (arg == param)
return true;
if (arg->ty == Type_Pointer && param->ty == Type_Pointer) {
if (!(arg->spec & TypeSpec_Const) && (param->spec & TypeSpec_Const))
return false;
return is_arg_passable_as_param(
arg->pointer.inner, param->pointer.inner);
}
if (arg->ty == Type_Char && arg->ty == param->ty)
return true;
return false;
}
static Type* get_expr_type(Sema* s, const AstExpr* expr)
{
Type** res = keymap_get(&s->expr_types, (size_t)expr);
return res ? *res : nullptr;
}
static void set_expr_type(Sema* s, const AstExpr* expr, Type* type)
{
keymap_set(&s->expr_types, (size_t)expr, &type);
}
void sema_visit_expr(Sema* s, AstExpr* expr)
{
Type* type = nullptr;
@ -431,14 +494,26 @@ void sema_visit_expr(Sema* s, AstExpr* expr)
break;
};
case AstExpr_Call: {
Type* inner_type
= keymap_get(&s->expr_types, (size_t)expr->call.expr);
Type* inner_type = get_expr_type(s, expr->call.expr);
assert(inner_type);
printf("inner_type->ty == %d\n", inner_type->ty);
assert(inner_type->ty == Type_Function);
assert(expr->call.args_size == inner_type->function.params_size);
for (size_t i = 0; i < expr->call.args_size; ++i) {
Type* arg_type = get_expr_type(s, expr->call.args[i]);
Type* param_type = inner_type->function.params[i];
assert(is_arg_passable_as_param(arg_type, param_type));
}
type = inner_type->function.return_type;
break;
}
}
keymap_set(&s->expr_types, (KeymapKey)expr, &type);
// printf(" expr(%d) -> ", expr->id);
// type_print(stdout, type);
// printf("\n");
set_expr_type(s, expr, type);
}