159 lines
4.5 KiB
C
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;
|
|
}
|