larpcc/preproc.c
2026-09-17 00:27:20 +02:00

159 lines
4.5 KiB
C

#include "collection.h"
#include "parse.h"
#include <assert.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct DefToks {
Tok* toks;
size_t toks_cap;
size_t toks_size;
};
void preproc_init(Preproc* p, Lexer* lexer)
{
Tok curr = lexer_next(p->lexer);
*p = (Preproc) {
.lexer = lexer,
.curr = curr,
.deftoks = nullptr,
.deftoks_cap = 0,
.deftoks_size = 0,
.defs = { },
};
hashmap_init(&p->defs);
}
void preproc_deinit(Preproc* p)
{
if (p->deftoks) {
free(p->deftoks);
}
hashmap_deinit(&p->defs);
}
static void step(Preproc* p)
{
p->curr = lexer_next(p->lexer);
}
Tok preproc_next(Preproc* p)
{
if (p->curr.ty == '#') {
step(p);
Tok kw = p->curr;
if (strcmp(kw.text, "define") == 0) {
step(p);
if (p->curr.ty != Tok_Ident) {
fprintf(stderr,
"error: expected identifier on line %d\n",
p->curr.line);
exit(1);
}
Tok ident_tok = p->curr;
p->lexer->lex_whitespace = true;
step(p);
p->lexer->lex_whitespace = false;
if (p->curr.ty == '(') {
// function-like macro
assert(false && "not implemented");
}
DefToks toks = { };
while (p->curr.ty != Tok_Eof && p->curr.ty != Tok_Eol) {
array_push((void**)&toks.toks,
&toks.toks_cap,
&toks.toks_size,
&p->curr,
sizeof(p->curr));
step(p);
}
array_push((void**)&p->deftoks,
&p->deftoks_cap,
&p->deftoks_size,
&toks,
sizeof(toks));
DefToks* deftoks = &p->deftoks[p->deftoks_size - 1];
hashmap_set(&p->defs, ident_tok.text, deftoks);
return p->curr;
} else if (strcmp(kw.text, "undef") == 0) {
step(p);
if (p->curr.ty != Tok_Ident) {
fprintf(stderr,
"error: expected identifier on line %d\n",
p->curr.line);
exit(1);
}
Tok ident_tok = p->curr;
if (p->curr.ty != Tok_Eof && p->curr.ty != Tok_Eol) {
fprintf(stderr,
"error: unexpected extra tokens on line %d\n",
p->curr.line);
exit(1);
}
hashmap_set(&p->defs, ident_tok.text, nullptr);
return p->curr;
} else if (strcmp(kw.text, "include") == 0) {
p->lexer->lex_headername = true;
step(p);
p->lexer->lex_headername = false;
if (p->curr.ty != Tok_HeaderName) {
fprintf(stderr,
"error: expected header name line %d\n",
p->curr.line);
exit(1);
}
assert(false && "not implemented");
} else if (strcmp(kw.text, "if") == 0) {
assert(false && "not implemented");
} else if (strcmp(kw.text, "ifdef") == 0) {
assert(false && "not implemented");
} else if (strcmp(kw.text, "ifndef") == 0) {
assert(false && "not implemented");
} else if (strcmp(kw.text, "else") == 0) {
assert(false && "not implemented");
} else if (strcmp(kw.text, "elif") == 0) {
assert(false && "not implemented");
} else if (strcmp(kw.text, "elifdef") == 0) {
assert(false && "not implemented");
} else if (strcmp(kw.text, "elifndef") == 0) {
assert(false && "not implemented");
} else if (strcmp(kw.text, "endif") == 0) {
assert(false && "not implemented");
} else if (strcmp(kw.text, "line") == 0) {
assert(false && "not implemented");
} else if (strcmp(kw.text, "embed") == 0) {
assert(false && "not implemented");
} else if (strcmp(kw.text, "error") == 0) {
assert(false && "not implemented");
} else if (strcmp(kw.text, "warning") == 0) {
assert(false && "not implemented");
} else if (strcmp(kw.text, "pragma") == 0) {
fprintf(stderr,
"error: '%s' is not a preprocessor instruction on line %d\n",
kw.text,
kw.line);
exit(1);
}
}
return p->curr;
}