make parser and sema work
This commit is contained in:
parent
8309384c0b
commit
e45e72249f
12
Makefile
12
Makefile
@ -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
12
ast.h
@ -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;
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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
18
diagnostics.c
Normal 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
12
diagnostics.h
Normal 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
|
||||
@ -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
296
lex.c
@ -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
13
main.c
@ -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
143
parse.c
@ -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
119
parse.h
@ -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
372
preproc.c
@ -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
110
preproc.h
Normal 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
|
||||
58
resolve.c
58
resolve.c
@ -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(
|
||||
|
||||
20
resolve.h
20
resolve.h
@ -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
93
sema.c
@ -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);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user