kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

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 }