work on preproc

This commit is contained in:
sfja 2026-09-20 02:22:28 +02:00
parent 52ef4b4754
commit da32555e6e
7 changed files with 335 additions and 103 deletions

View File

@ -4,24 +4,55 @@
#include <stdlib.h>
#include <string.h>
void array_push(
void** data, size_t* capacity, size_t* size, void* elem, size_t elem_size)
static void array_push_generic(void** data,
size_t* capacity,
size_t* size,
void* elem,
size_t elem_size,
void* alloc_fn(void*, size_t),
void* realloc_fn(void*, void*, size_t),
void* allocator)
{
if (!*capacity) {
*capacity = 4;
}
if (!*data) {
*data = malloc(*capacity * elem_size);
*data = alloc_fn(allocator, *capacity * elem_size);
*size = 0;
}
if (*size >= *capacity) {
*capacity *= 2;
*data = realloc(*data, *capacity * elem_size);
*data = realloc_fn(allocator, *data, *capacity * elem_size);
}
memcpy((unsigned char*)*data + *size * elem_size, elem, elem_size);
*size += 1;
}
static void* malloc_wrap(void* self, size_t size)
{
(void)self;
return malloc(size);
}
static void* realloc_wrap(void* self, void* p, size_t size)
{
(void)self;
return realloc(p, size);
}
void array_push(
void** data, size_t* capacity, size_t* size, void* elem, size_t elem_size)
{
array_push_generic(data,
capacity,
size,
elem,
elem_size,
malloc_wrap,
realloc_wrap,
nullptr);
}
static void push_kwpair(Hashmap* m, KwPair* pair)
{
array_push((void**)&m->entries,
@ -134,3 +165,34 @@ void* arena_alloc(Arena* a, size_t size)
return ptr;
}
static void* arena_alloc_wrap(void* self, size_t size)
{
Arena* a = self;
return arena_alloc(a, size);
}
static void* arena_realloc_wrap(void* self, void* p, size_t size)
{
Arena* a = self;
void* new_buf = arena_alloc(a, size);
memcpy(new_buf, p, size);
return new_buf;
}
void arena_array_push(Arena* arena,
void** data,
size_t* capacity,
size_t* size,
void* elem,
size_t elem_size)
{
array_push_generic(data,
capacity,
size,
elem,
elem_size,
arena_alloc_wrap,
arena_realloc_wrap,
arena);
}

View File

@ -40,4 +40,11 @@ void arena_init(Arena* a, size_t bucket_cap);
void arena_deinit(Arena* a);
void* arena_alloc(Arena* a, size_t size);
void arena_array_push(Arena* arena,
void** data,
size_t* capacity,
size_t* size,
void* elem,
size_t elem_size);
#endif

View File

@ -1,8 +1,8 @@
int puts(const char* __s);
#define PUTS puts
#define PUTS(A, B) puts(A, B)
int main()
{
PUTS("hello");
PUTS("hello", "world");
}

2
lex.c
View File

@ -232,7 +232,7 @@ Tok lexer_next(Lexer* l)
return tok(l, Tok_Char, text, line, col);
}
if (strchr("\n;(){}*#", l->curr.ch)) {
if (strchr("\n;(){},*#", l->curr.ch)) {
TokTy ty = (TokTy)l->curr.ch;
step(l, text, &text_len);
return tok(l, ty, text, line, col);

10
main.c
View File

@ -57,7 +57,7 @@ int main(int argc, char* argv[])
return EXIT_FAILURE;
}
printf("%s\n", text);
printf("text:\n%s\n", text);
SourceIter source_chars;
source_iter_init(&source_chars, text);
@ -74,10 +74,14 @@ int main(int argc, char* argv[])
Preproc preproc;
preproc_init(&preproc, &lexer);
printf("tokens:\n");
Tok tok;
while ((tok = preproc_next(&preproc)).ty != Tok_Eof) {
printf("%s\t%s\n", tokty_str(tok.ty), tok.text);
while ((tok = preproc_next_with_newline(&preproc)).ty != Tok_Eof) {
// printf("%s\t%s\n", tokty_str(tok.ty), tok.text);
printf("%s ", tok.text);
}
fputs("\n", stdout);
preproc_deinit(&preproc);
free(text);

19
parse.h
View File

@ -51,6 +51,7 @@ typedef enum {
Tok_RParen = ')',
Tok_LBrace = '{',
Tok_RBrace = '}',
Tok_Comma = ',',
Tok_Asterisk = '*',
Tok_Hashtag = '#',
} TokTy;
@ -77,23 +78,27 @@ Tok lexer_next(Lexer* l);
// phase 4 - preprocessor
typedef struct DefToks DefToks;
typedef struct MacroDef MacroDef;
typedef struct MacroInv MacroInv;
typedef struct {
Lexer* lexer;
Tok curr;
DefToks* deftoks;
size_t deftoks_cap;
size_t deftoks_size;
Hashmap defs;
MacroDef* defs;
size_t defs_cap;
size_t defs_size;
Hashmap def_map;
DefToks* pasting_toks;
size_t pasting_toks_count;
Arena arg_arena;
MacroInv* macro_invs;
size_t macro_invs_cap;
size_t macro_invs_size;
} Preproc;
void preproc_init(Preproc* p, Lexer* lexer);
void preproc_deinit(Preproc* p);
Tok preproc_next_with_newline(Preproc* p);
Tok preproc_next(Preproc* p);
#endif

250
preproc.c
View File

@ -6,12 +6,26 @@
#include <stdlib.h>
#include <string.h>
struct DefToks {
struct MacroDef {
Tok* toks;
size_t toks_cap;
size_t toks_size;
char** params;
size_t params_size;
};
struct MacroInv {
MacroDef* def;
size_t tok_idx;
Hashmap arg_map;
};
typedef struct {
Tok* toks;
size_t toks_size;
} MacroArg;
void preproc_init(Preproc* p, Lexer* lexer)
{
Tok curr = lexer_next(lexer);
@ -19,26 +33,35 @@ void preproc_init(Preproc* p, Lexer* lexer)
*p = (Preproc) {
.lexer = lexer,
.curr = curr,
.deftoks = nullptr,
.deftoks_cap = 0,
.deftoks_size = 0,
.defs = { },
.pasting_toks = nullptr,
.pasting_toks_count = 0,
.defs = nullptr,
.defs_cap = 0,
.defs_size = 0,
.def_map = { },
.arg_arena = { },
.macro_invs = nullptr,
.macro_invs_cap = 0,
.macro_invs_size = 0,
};
hashmap_init(&p->defs);
hashmap_init(&p->def_map);
arena_init(&p->arg_arena, 512);
}
void preproc_deinit(Preproc* p)
{
if (p->deftoks) {
for (size_t i = 0; i < p->deftoks_size; ++i) {
free(p->deftoks[i].toks);
if (p->defs) {
for (size_t i = 0; i < p->defs_size; ++i) {
free(p->defs[i].toks);
if (p->defs[i].params) {
free(p->defs[i].params);
}
free(p->deftoks);
}
hashmap_deinit(&p->defs);
free(p->defs);
}
hashmap_deinit(&p->def_map);
arena_deinit(&p->arg_arena);
}
static void step(Preproc* p)
@ -60,30 +83,69 @@ static Tok p_define(Preproc* p)
step(p);
p->lexer->lex_whitespace = false;
MacroDef def = { };
if (p->curr.ty == '(') {
// function-like macro
assert(false && "not implemented");
step(p);
char** params = nullptr;
size_t params_cap = 0;
size_t params_size = 0;
if (p->curr.ty != Tok_Eof && p->curr.ty != ')') {
if (p->curr.ty != Tok_Ident) {
fprintf(stderr,
"error: expected identifier on line %d\n",
p->curr.line);
exit(1);
}
array_push((void**)&params,
&params_cap,
&params_size,
p->curr.text,
sizeof(p->curr.text));
while (p->curr.ty == ',') {
step(p);
if (p->curr.ty != Tok_Ident) {
fprintf(stderr,
"error: expected identifier on line %d\n",
p->curr.line);
exit(1);
}
array_push((void**)&params,
&params_cap,
&params_size,
p->curr.text,
sizeof(p->curr.text));
}
}
DefToks toks = { };
if (p->curr.ty == Tok_Eof || p->curr.ty == ')') {
fprintf(stderr, "error: expected ')' on line %d\n", p->curr.line);
exit(1);
}
step(p);
def.params = params;
def.params_size = params_size;
}
while (p->curr.ty != Tok_Eof && p->curr.ty != Tok_Eol) {
array_push((void**)&toks.toks,
&toks.toks_cap,
&toks.toks_size,
array_push((void**)&def.toks,
&def.toks_cap,
&def.toks_size,
&p->curr,
sizeof(p->curr));
step(p);
}
array_push((void**)&p->deftoks,
&p->deftoks_cap,
&p->deftoks_size,
&toks,
sizeof(toks));
array_push(
(void**)&p->defs, &p->defs_cap, &p->defs_size, &def, sizeof(def));
DefToks* deftoks = &p->deftoks[p->deftoks_size - 1];
hashmap_set(&p->defs, ident_tok.text, deftoks);
MacroDef* deftoks = &p->defs[p->defs_size - 1];
hashmap_set(&p->def_map, ident_tok.text, deftoks);
return p->curr;
}
@ -106,7 +168,7 @@ static Tok p_undef(Preproc* p)
exit(1);
}
hashmap_set(&p->defs, ident_tok.text, nullptr);
hashmap_set(&p->def_map, ident_tok.text, nullptr);
return p->curr;
}
@ -125,35 +187,94 @@ static Tok p_include(Preproc* p)
assert(false && "not implemented");
}
static Tok preproc_next_nl(Preproc* p)
static Tok p_paste_macro_body(Preproc* p)
{
if (p->pasting_toks) {
if (p->pasting_toks_count >= p->pasting_toks->toks_size) {
p->pasting_toks = nullptr;
p->pasting_toks_count = 0;
return preproc_next_nl(p);
MacroInv* inv = &p->macro_invs[p->macro_invs_size - 1];
if (inv->tok_idx >= inv->def->toks_size) {
p->macro_invs_size -= 1;
return preproc_next_with_newline(p);
}
Tok tok = p->pasting_toks->toks[p->pasting_toks_count];
p->pasting_toks_count += 1;
Tok tok = inv->def->toks[inv->tok_idx];
inv->tok_idx += 1;
return tok;
}
}
Tok curr = p->curr;
step(p);
static void collect_arg_toks(Tok** toks, size_t* toks_size)
{
}
if (curr.ty == Tok_Ident) {
DefToks* def = hashmap_get(&p->defs, curr.text);
struct arg_def {
Tok* toks;
size_t toks_size;
};
static Tok p_detect_macro(Preproc* p, Tok head)
{
MacroDef* def = hashmap_get(&p->def_map, head.text);
if (!def)
return curr;
return head;
MacroInv inv = {
.def = def,
.tok_idx = 0,
.arg_map = { },
};
hashmap_init(&inv.arg_map);
array_push(
(void**)&p->macro_invs, &p->defs_cap, &p->defs_size, &inv, sizeof(inv));
if (!def->params)
return preproc_next_with_newline(p);
if (p->curr.ty != '(')
return head;
step(p);
p->pasting_toks = def;
p->pasting_toks_count = 0;
return preproc_next_nl(p);
struct arg_def* arg_defs;
size_t arg_defs_cap = 0;
size_t arg_defs_size = 0;
size_t arg_idx = 0;
bool first = true;
while ((first && (p->curr.ty != Tok_Eof && p->curr.ty != ')'))
|| p->curr.ty != ',') {
first = false;
if (arg_idx + 1 >= def->params_size) {
fprintf(stderr,
"error: too many arguments for macro line %d\n",
p->curr.line);
exit(1);
}
if (curr.ty == '#') {
Tok* toks;
size_t toks_size;
collect_arg_toks(&toks, &toks_size);
arena_array_push(&p->arg_arena,
(void**)&arg_defs,
&arg_defs_cap,
&arg_defs_size,
&(struct arg_def) { toks, toks_size },
sizeof(struct arg_def));
hashmap_set(
&inv.arg_map, def->params[arg_idx], &arg_defs[arg_defs_size - 1]);
arg_idx += 1;
}
return preproc_next_with_newline(p);
}
static Tok p_interpret_directive(Preproc* p)
{
Tok kw = p->curr;
if (strcmp(kw.text, "define") == 0) {
@ -193,15 +314,48 @@ static Tok preproc_next_nl(Preproc* p)
kw.line);
exit(1);
}
}
return curr;
assert(false && "unreachable");
}
static Tok replace_candidate_tok(Preproc* p, Tok tok, size_t inv_idx)
{
if (inv_idx == 0)
return tok;
MacroInv* inv = &p->macro_invs[inv_idx];
if (tok.ty != Tok_Ident)
return tok;
MacroArg* arg = hashmap_get(&inv->arg_map, tok.text);
if (!arg)
return replace_candidate_tok(p, tok, inv_idx - 1);
}
static Tok expand_tok(Preproc* p, Tok tok)
{
if (p->macro_invs_size == 0)
return tok;
MacroInv* inv = &p->macro_invs[p->macro_invs_size - 1];
if (inv->tok_idx >= inv->def->toks_size) {
p->macro_invs_size -= 1;
return expand_tok(p, tok);
}
}
Tok preproc_next_with_newline(Preproc* p)
{
Tok tok = p->curr;
step(p);
if (tok.ty == '#')
return p_interpret_directive(p);
return expand_tok(p, tok);
}
Tok preproc_next(Preproc* p)
{
Tok tok;
while ((tok = preproc_next_nl(p)).ty == Tok_Eol
while ((tok = preproc_next_with_newline(p)).ty == Tok_Eol
|| tok.ty == Tok_Whitespace) { }
return tok;
}