#include "collection.h" #include "parse.h" #include #include #include #include #include struct DefToks { Tok* toks; size_t toks_cap; size_t toks_size; }; void preproc_init(Preproc* p, Lexer* lexer) { Tok curr = lexer_next(lexer); *p = (Preproc) { .lexer = lexer, .curr = curr, .deftoks = nullptr, .deftoks_cap = 0, .deftoks_size = 0, .defs = { }, .pasting_toks = nullptr, .pasting_toks_count = 0, }; hashmap_init(&p->defs); } void preproc_deinit(Preproc* p) { if (p->deftoks) { for (size_t i = 0; i < p->deftoks_size; ++i) { free(p->deftoks[i].toks); } free(p->deftoks); } hashmap_deinit(&p->defs); } static void step(Preproc* p) { p->curr = lexer_next(p->lexer); } static Tok p_define(Preproc* p) { 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; } static Tok p_undef(Preproc* p) { 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; } static Tok p_include(Preproc* p) { 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"); } static Tok preproc_next_nl(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); } Tok tok = p->pasting_toks->toks[p->pasting_toks_count]; p->pasting_toks_count += 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); } if (curr.ty == '#') { Tok kw = p->curr; if (strcmp(kw.text, "define") == 0) { return p_define(p); } else if (strcmp(kw.text, "undef") == 0) { return p_undef(p); } else if (strcmp(kw.text, "include") == 0) { return p_include(p); } 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 curr; } Tok preproc_next(Preproc* p) { Tok tok; while ((tok = preproc_next_nl(p)).ty == Tok_Eol || tok.ty == Tok_Whitespace) { } return tok; }