cpp.c (2715B)
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 Pp* pp; 56 SourceSpec spec; 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 pp = pp_new(c); 71 if (!pp) compiler_panic(c, cpp_no_loc(), "C preprocessor out of memory"); 72 cpp_apply_options(pp, opts); 73 /* -E / cpp: NOT parser-feed — newlines surface for text reconstruction. */ 74 memset(&spec, 0, sizeof(spec)); 75 spec.name = kit_slice_cstr(r->name.s); 76 spec.bytes = input->s; 77 spec.len = (u32)input->len; 78 spec.flags = SRC_PRIMARY; 79 pp_push_source(pp, &spec); 80 pp_emit_text(pp, out); 81 pp_free(pp); 82 return KIT_OK; 83 } 84 85 KitStatus kit_cpp_preprocess(KitCompiler* c, const KitPreprocessOptions* opts, 86 KitSlice name, const KitSlice* input, 87 KitWriter* out) { 88 CppRun r; 89 r.opts = opts; 90 r.name = name; 91 r.input = input; 92 r.out = out; 93 return kit_frontend_run(c, cpp_preprocess_body, &r); 94 }