kit

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

pp_priv.h (10012B)


      1 /* pp_priv.h — shared types, helpers, and cross-module forward declarations
      2  * for the preprocessor split (pp.c / pp_expand.c / pp_directive.c).
      3  * NOT part of the public API; included only within lang/cpp/pp/. */
      4 
      5 #ifndef KIT_PP_PRIV_H
      6 #define KIT_PP_PRIV_H
      7 
      8 #include <stdlib.h>
      9 #include <string.h>
     10 
     11 #include "cpp_support.h"
     12 #include "pp/pp.h"
     13 
     14 /* ============================================================
     15  * Internal token kinds
     16  * ============================================================ */
     17 
     18 /* Outside the range used by the lexer (TOK_KW_LAST = 0x1000). */
     19 #define TOK_PP_PARAM ((u16)0x1100)
     20 #define TOK_PP_PLACEMARKER ((u16)0x1101) /* empty-arg substitution marker */
     21 
     22 /* ============================================================
     23  * Types
     24  * ============================================================ */
     25 
     26 typedef struct Macro {
     27   Sym name;
     28   SrcLoc def_loc;
     29   u8 is_func;
     30   u8 is_variadic;
     31   u8 pad[2];
     32   u32 n_params;
     33   Sym* params; /* parameter names                              */
     34   Tok* body;   /* body tokens; TOK_PP_PARAM kind + v.punct=idx */
     35   u32 body_len;
     36 } Macro;
     37 
     38 typedef u32 HidesetId;
     39 #define HS_EMPTY 0u
     40 
     41 typedef struct Hideset {
     42   u32 n;
     43   Sym names[1]; /* flexible; allocated with extra trailing slots */
     44 } Hideset;
     45 
     46 typedef enum { SRC_LEX = 1, SRC_BUF = 2 } SrcKind;
     47 
     48 typedef struct TokSrc {
     49   u8 kind;
     50   /* When set on a SRC_BUF: src_next_raw returns TOK_EOF when this is
     51    * the top source and it's exhausted, instead of popping. The caller
     52    * (e.g. argument pre-expansion) explicitly pops the scope when done.
     53    * This bounds expansion to a single argument's token stream. */
     54   u8 scope_top;
     55   u8 pad[2];
     56   /* SRC_LEX */
     57   Lexer* lex;
     58   /* SRC_BUF */
     59   Tok* toks;
     60   HidesetId* hs;
     61   u32 i;
     62   u32 n;
     63   /* #line state (SRC_LEX only). line_delta is added to every emitted
     64    * token's loc.line on its way out so __LINE__ and the output cursor
     65    * see user-visible numbering. file_override is the Sym (without
     66    * surrounding quotes) used by __FILE__ when set. */
     67   i32 line_delta;
     68   Sym file_override;
     69 } TokSrc;
     70 
     71 typedef enum IfState {
     72   IF_INCLUDE = 1,   /* group active, emit code                       */
     73   IF_SEEK_TRUE = 2, /* skip, looking for the first true elif/else    */
     74   IF_DONE = 3,      /* skip, already had a true branch               */
     75 } IfState;
     76 
     77 typedef struct IfFrame {
     78   u8 state;
     79   u8 has_else;
     80   u8 pad[2];
     81   SrcLoc loc;
     82 } IfFrame;
     83 
     84 /* MacroMap = Sym -> Macro*. Generated open-addressed hashmap with
     85  * deletion (#undef). See core/hashmap.h. */
     86 #include <kit/support/hashmap.h>
     87 static inline u32 macro_hash_(Sym s) { return kit_hash_u32((u32)s); }
     88 KIT_HASHMAP_DEFINE(MacroMap, Sym, Macro*, macro_hash_);
     89 
     90 /* ============================================================
     91  * Pp struct (definition shared across all three TUs)
     92  * ============================================================ */
     93 
     94 struct Pp {
     95   Compiler* c;
     96   Pool* pool;
     97 
     98   /* Source stack — top of stack is sources[nsources-1]. */
     99   TokSrc* sources;
    100   u32 nsources;
    101   u32 sources_cap;
    102 
    103   /* Macro table (open-addressed; key = Sym, value = Macro*). */
    104   MacroMap mtab;
    105 
    106   /* Conditional inclusion stack (#if / #ifdef / #ifndef → #endif). */
    107   IfFrame* ifstk;
    108   u32 ifstk_n;
    109   u32 ifstk_cap;
    110 
    111   /* Hideset table. Element 0 reserved as HS_EMPTY. */
    112   Hideset** hsets;
    113   u32 hsets_n;
    114   u32 hsets_cap;
    115 
    116   /* Include directories (stage 9). */
    117   struct {
    118     const char* path;
    119     u8 system;
    120   }* inc_dirs;
    121   u32 ninc_dirs;
    122   u32 inc_dirs_cap;
    123 
    124   /* Current #pragma pack maximum field alignment. 0 means natural. */
    125   u32 pack_align;
    126   u32 pack_stack[16];
    127   u32 pack_stack_n;
    128 
    129   /* Internal arena: macro bodies, hidesets, expansion buffers, file
    130    * data for #include. Lives until pp_free. */
    131   KitArena* arena;
    132 
    133   /* Cached interned identifiers used for directive recognition. */
    134   Sym sym_define;
    135   Sym sym_undef;
    136   Sym sym_include;
    137   Sym sym_if;
    138   Sym sym_ifdef;
    139   Sym sym_ifndef;
    140   Sym sym_elif;
    141   Sym sym_else;
    142   Sym sym_endif;
    143   Sym sym_line;
    144   Sym sym_pragma;
    145   Sym sym_error;
    146   Sym sym_warning;
    147   Sym sym_embed;
    148   Sym sym_defined;
    149   Sym sym_va_args;
    150   Sym sym_line__; /* __LINE__   */
    151   Sym sym_file__; /* __FILE__   */
    152   Sym sym_date__; /* __DATE__   */
    153   Sym sym_time__; /* __TIME__   */
    154   Sym sym_stdc__; /* __STDC__   */
    155   Sym sym_stdc_hosted__;
    156   Sym sym_stdc_version__;
    157   Sym sym__pragma;   /* _Pragma operator */
    158   Sym sym_pragma_kw; /* "pragma" — for synthesized #pragma */
    159 
    160   /* Pre-formatted "Mmm dd yyyy" / "hh:mm:ss" string spellings for
    161    * __DATE__ and __TIME__, derived from SOURCE_DATE_EPOCH (or
    162    * time(NULL) if unset). */
    163   Sym val_date_str;
    164   Sym val_time_str;
    165 
    166   /* Defined-operator handling during #if expansion.
    167    *
    168    * The first prepass in eval_if_expr replaces `defined X` / `defined
    169    * (X)` literally found in the directive line, but `defined()` can
    170    * also come from macro bodies (mingw's intrin-impl.h uses
    171    * `defined(__INTRINSIC_DEFINED_ ## name)` inside a #define).  When
    172    * the expander processes such a body, the identifier inside
    173    * `defined(...)` must NOT be macro-expanded — otherwise an empty
    174    * macro X would turn `defined(X)` into `defined()` and the
    175    * post-expansion prepass would reject it.
    176    *
    177    * This pair of fields tracks the state across `pp_next_raw` calls
    178    * within `expand_for_if`:
    179    *   in_if_expansion: 1 inside an #if's expand_arg_to_eof call
    180    *   defined_skip:    0 normally; 1 after emitting `defined`
    181    *                    (consume one IDENT before clearing); 2 after
    182    *                    emitting `defined (` (waiting for IDENT then
    183    *                    `)`).
    184    * The expander uses these to mark the operand IDENT TF_NO_EXPAND
    185    * before the macro-expansion check at the head of pp_next_raw. */
    186   u8 in_if_expansion;
    187   u8 defined_skip;
    188 };
    189 
    190 /* ============================================================
    191  * Allocation helpers (defined in pp.c, used everywhere)
    192  * ============================================================ */
    193 
    194 static inline Heap* pp_heap(Pp* pp) {
    195   return kit_compiler_context(pp->c)->heap;
    196 }
    197 
    198 static inline void* pp_xrealloc(Pp* pp, void* p, size_t old_n, size_t new_n,
    199                                 size_t align) {
    200   Heap* h = pp_heap(pp);
    201   void* q = h->realloc(h, p, old_n, new_n, align);
    202   if (!q) compiler_panic(pp->c, (SrcLoc){0, 0, 0}, "pp: out of memory");
    203   return q;
    204 }
    205 
    206 static inline void pp_xfree(Pp* pp, void* p, size_t n) {
    207   if (p) pp_heap(pp)->free(pp_heap(pp), p, n);
    208 }
    209 
    210 /* ============================================================
    211  * Token-vector helpers
    212  * ============================================================ */
    213 
    214 typedef struct TokVec {
    215   Tok* data;
    216   u32 n;
    217   u32 cap;
    218 } TokVec;
    219 
    220 typedef struct HsVec {
    221   HidesetId* data;
    222   u32 n;
    223   u32 cap;
    224 } HsVec;
    225 
    226 static inline void tv_grow(Pp* pp, TokVec* v, u32 want) {
    227   u32 nc;
    228   if (v->cap >= want) return;
    229   nc = v->cap ? v->cap * 2 : 8;
    230   while (nc < want) nc *= 2;
    231   {
    232     Tok* nb = arena_array(pp->arena, Tok, nc);
    233     if (v->n) memcpy(nb, v->data, sizeof(Tok) * v->n);
    234     v->data = nb;
    235     v->cap = nc;
    236   }
    237 }
    238 
    239 static inline void tv_push(Pp* pp, TokVec* v, Tok t) {
    240   tv_grow(pp, v, v->n + 1);
    241   v->data[v->n++] = t;
    242 }
    243 
    244 static inline void hsv_grow(Pp* pp, HsVec* v, u32 want) {
    245   u32 nc;
    246   if (v->cap >= want) return;
    247   nc = v->cap ? v->cap * 2 : 8;
    248   while (nc < want) nc *= 2;
    249   {
    250     HidesetId* nb = arena_array(pp->arena, HidesetId, nc);
    251     if (v->n) memcpy(nb, v->data, sizeof(HidesetId) * v->n);
    252     v->data = nb;
    253     v->cap = nc;
    254   }
    255 }
    256 
    257 static inline void hsv_push(Pp* pp, HsVec* v, HidesetId hs) {
    258   hsv_grow(pp, v, v->n + 1);
    259   v->data[v->n++] = hs;
    260 }
    261 
    262 /* Growable char buffer (arena-backed). */
    263 typedef struct CharBuf {
    264   char* data;
    265   u32 len;
    266   u32 cap;
    267 } CharBuf;
    268 
    269 static inline void cb_append(Pp* pp, CharBuf* b, const char* s, u32 n) {
    270   if (b->len + n > b->cap) {
    271     u32 nc = b->cap ? b->cap * 2 : 64;
    272     while (nc < b->len + n) nc *= 2;
    273     {
    274       char* nb = (char*)arena_alloc(pp->arena, nc, 1);
    275       if (b->len) memcpy(nb, b->data, b->len);
    276       b->data = nb;
    277       b->cap = nc;
    278     }
    279   }
    280   if (n) memcpy(b->data + b->len, s, n);
    281   b->len += n;
    282 }
    283 
    284 static inline void cb_putc(Pp* pp, CharBuf* b, char c) {
    285   cb_append(pp, b, &c, 1);
    286 }
    287 
    288 /* ============================================================
    289  * Cross-module forward declarations
    290  * ============================================================ */
    291 
    292 /* --- pp.c (source stack) → pp_expand.c, pp_directive.c --- */
    293 Tok src_next_raw(Pp* pp, HidesetId* hs_out, u8* src_kind_out);
    294 void src_push(Pp* pp, TokSrc s);
    295 void src_pop(Pp* pp);
    296 void push_buf(Pp* pp, Tok* toks, HidesetId* hs, u32 n);
    297 
    298 /* pp_next_raw is the mutual-recursion entry: expand_arg_to_eof calls it,
    299  * and pp_next_raw drives directives and expansion. Declared non-static so
    300  * pp_expand.c can call it without a forward decl each time. */
    301 Tok pp_next_raw(Pp* pp);
    302 
    303 /* --- pp_expand.c → pp.c, pp_directive.c --- */
    304 HidesetId hs_add(Pp* pp, HidesetId id, Sym s);
    305 int hs_contains(Pp* pp, HidesetId id, Sym s);
    306 Macro* mt_get(Pp* pp, Sym name);
    307 void mt_put(Pp* pp, Sym name, Macro* m);
    308 void mt_del(Pp* pp, Sym name);
    309 void expand_arg_to_eof(Pp* pp, Tok* in, HidesetId* hs, u32 nin, TokVec* out);
    310 
    311 /* --- pp_directive.c → pp_expand.c --- */
    312 i64 eval_if_expr(Pp* pp, const Tok* line, u32 n, SrcLoc loc);
    313 void process_directive(Pp* pp, SrcLoc hash_loc);
    314 
    315 /* --- pp_directive.c internal helpers called from pp_expand.c --- */
    316 void emit_pragma_line(Pp* pp, const Tok* line, u32 n, SrcLoc loc);
    317 int peek_for_invoke_paren(Pp* pp, int* ws_has_space_out);
    318 int try_expand_pragma_op(Pp* pp, const Tok* invoke);
    319 
    320 /* --- pp_directive.c: read_directive_line (used by pp.c/pp_define) --- */
    321 void read_directive_line(Pp* pp, Tok** out_toks, u32* out_n);
    322 
    323 /* --- pp_expand.c: do_define / do_undef (used by pp.c/pp_define) --- */
    324 void do_define(Pp* pp, const Tok* line, u32 n);
    325 void do_undef(Pp* pp, const Tok* line, u32 n);
    326 
    327 /* --- pp_directive.c helpers needed by pp_expand.c (_Pragma) --- */
    328 TokSrc* current_lex_src(Pp* pp);
    329 
    330 #endif /* KIT_PP_PRIV_H */