#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(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; }