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 */