cpp.c (2573B)
1 /* cpp.c — public entry point for the kit C preprocessor. 2 * 3 * kit_cpp_preprocess() runs the preprocessor under the standard 4 * frontend panic boundary and writes the resulting token stream as 5 * text to the caller's writer. This is the implementation behind 6 * `kit cpp` and `kit cc -E`; the full C frontend reuses it too. */ 7 8 #include <kit/preprocess.h> 9 10 #include "cpp_support.h" 11 #include "lex/lex.h" 12 #include "pp/pp.h" 13 14 static SrcLoc cpp_no_loc(void) { 15 SrcLoc loc; 16 loc.file_id = 0; 17 loc.line = 0; 18 loc.col = 0; 19 return loc; 20 } 21 22 static _Noreturn void cpp_bad_options(Compiler* c, const char* msg) { 23 compiler_panic(c, cpp_no_loc(), "bad preprocess options: %.*s", 24 KIT_SLICE_ARG(kit_slice_cstr(msg))); 25 } 26 27 static void cpp_apply_options(Pp* pp, const KitPreprocessOptions* opts) { 28 u32 i; 29 30 for (i = 0; i < opts->ninclude_dirs; ++i) { 31 pp_add_include_dir(pp, opts->include_dirs[i], 0); 32 } 33 for (i = 0; i < opts->nsystem_include_dirs; ++i) { 34 pp_add_include_dir(pp, opts->system_include_dirs[i], 1); 35 } 36 for (i = 0; i < opts->ndefines; ++i) { 37 const char* body = 38 opts->defines[i].body.len ? opts->defines[i].body.s : "1"; 39 pp_define(pp, opts->defines[i].name.s, body); 40 } 41 for (i = 0; i < opts->nundefines; ++i) { 42 pp_undef(pp, opts->undefines[i].s); 43 } 44 } 45 46 typedef struct CppRun { 47 const KitPreprocessOptions* opts; 48 KitSlice name; 49 const KitSlice* input; 50 KitWriter* out; 51 } CppRun; 52 53 static KitStatus cpp_preprocess_body(KitCompiler* c, void* user) { 54 CppRun* r = (CppRun*)user; 55 Lexer* lex; 56 Pp* pp; 57 58 const KitPreprocessOptions* opts = r->opts; 59 const KitSlice* input = r->input; 60 KitWriter* out = r->out; 61 62 if (!opts || !input || !out) { 63 cpp_bad_options(c, "preprocess args missing"); 64 } 65 if (!r->name.s) cpp_bad_options(c, "input name is NULL"); 66 if (!input->data && input->len != 0) { 67 cpp_bad_options(c, "input data is NULL but len > 0"); 68 } 69 70 lex = lex_open_mem(c, r->name.s, input->s, input->len); 71 if (lex) lex_skip_shebang(lex); 72 pp = pp_new(c); 73 if (!lex || !pp) 74 compiler_panic(c, cpp_no_loc(), "C preprocessor out of memory"); 75 cpp_apply_options(pp, opts); 76 pp_push_input(pp, lex); 77 pp_emit_text(pp, out); 78 pp_free(pp); 79 return KIT_OK; 80 } 81 82 KitStatus kit_cpp_preprocess(KitCompiler* c, const KitPreprocessOptions* opts, 83 KitSlice name, const KitSlice* input, 84 KitWriter* out) { 85 CppRun r; 86 r.opts = opts; 87 r.name = name; 88 r.input = input; 89 r.out = out; 90 return kit_frontend_run(c, cpp_preprocess_body, &r); 91 }