work on preproc
This commit is contained in:
parent
52ef4b4754
commit
da32555e6e
70
collection.c
70
collection.c
@ -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);
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
2
lex.c
@ -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
10
main.c
@ -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
19
parse.h
@ -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
|
||||
|
||||
254
preproc.c
254
preproc.c
@ -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**)¶ms,
|
||||
¶ms_cap,
|
||||
¶ms_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**)¶ms,
|
||||
¶ms_cap,
|
||||
¶ms_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);
|
||||
|
||||
if (curr.ty == Tok_Ident) {
|
||||
DefToks* def = hashmap_get(&p->defs, curr.text);
|
||||
if (!def)
|
||||
return curr;
|
||||
|
||||
step(p);
|
||||
p->pasting_toks = def;
|
||||
p->pasting_toks_count = 0;
|
||||
return preproc_next_nl(p);
|
||||
static void collect_arg_toks(Tok** toks, size_t* toks_size)
|
||||
{
|
||||
}
|
||||
|
||||
if (curr.ty == '#') {
|
||||
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 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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
assert(false && "unreachable");
|
||||
}
|
||||
|
||||
return curr;
|
||||
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;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user