| 1 | /* Preprocess only, using cpplib. |
| 2 | Copyright (C) 1995-2025 Free Software Foundation, Inc. |
| 3 | Written by Per Bothner, 1994-95. |
| 4 | |
| 5 | This program is free software; you can redistribute it and/or modify it |
| 6 | under the terms of the GNU General Public License as published by the |
| 7 | Free Software Foundation; either version 3, or (at your option) any |
| 8 | later version. |
| 9 | |
| 10 | This program is distributed in the hope that it will be useful, |
| 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 13 | GNU General Public License for more details. |
| 14 | |
| 15 | You should have received a copy of the GNU General Public License |
| 16 | along with this program; see the file COPYING3. If not see |
| 17 | <http://www.gnu.org/licenses/>. */ |
| 18 | |
| 19 | #include "config.h" |
| 20 | #include "system.h" |
| 21 | #include "coretypes.h" |
| 22 | #include "c-common.h" /* For flags. */ |
| 23 | #include "../libcpp/internal.h" |
| 24 | #include "langhooks.h" |
| 25 | #include "c-pragma.h" /* For parse_in. */ |
| 26 | #include "file-prefix-map.h" /* remap_macro_filename() */ |
| 27 | |
| 28 | class token_streamer; |
| 29 | |
| 30 | /* Encapsulates state used to convert a stream of tokens into a text |
| 31 | file. */ |
| 32 | static struct |
| 33 | { |
| 34 | FILE *outf; /* Stream to write to. */ |
| 35 | const cpp_token *prev; /* Previous token. */ |
| 36 | const cpp_token *source; /* Source token for spacing. */ |
| 37 | unsigned src_line; /* Line number currently being written. */ |
| 38 | bool printed; /* True if something output at line. */ |
| 39 | bool first_time; /* pp_file_change hasn't been called yet. */ |
| 40 | bool prev_was_system_token; /* True if the previous token was a |
| 41 | system token.*/ |
| 42 | const char *src_file; /* Current source file. */ |
| 43 | token_streamer *streamer; /* Instance of class token_streamer using this |
| 44 | object. */ |
| 45 | } print; |
| 46 | |
| 47 | /* Defined and undefined macros being queued for output with -dU at |
| 48 | the next newline. */ |
| 49 | struct macro_queue |
| 50 | { |
| 51 | struct macro_queue *next; /* Next macro in the list. */ |
| 52 | char *macro; /* The name of the macro if not |
| 53 | defined, the full definition if |
| 54 | defined. */ |
| 55 | }; |
| 56 | static macro_queue *define_queue, *undef_queue; |
| 57 | |
| 58 | /* General output routines. */ |
| 59 | static void scan_translation_unit (cpp_reader *); |
| 60 | static void scan_translation_unit_directives_only (cpp_reader *); |
| 61 | static void scan_translation_unit_trad (cpp_reader *); |
| 62 | static void account_for_newlines (const unsigned char *, size_t); |
| 63 | static int dump_macro (cpp_reader *, cpp_hashnode *, void *); |
| 64 | static void dump_queued_macros (cpp_reader *); |
| 65 | |
| 66 | static bool print_line_1 (location_t, const char*, FILE *); |
| 67 | static bool print_line (location_t, const char *); |
| 68 | static bool maybe_print_line_1 (location_t, FILE *); |
| 69 | static bool maybe_print_line (location_t); |
| 70 | static bool do_line_change (cpp_reader *, const cpp_token *, |
| 71 | location_t, int); |
| 72 | |
| 73 | /* Callback routines for the parser. Most of these are active only |
| 74 | in specific modes. */ |
| 75 | static void cb_line_change (cpp_reader *, const cpp_token *, int); |
| 76 | static void cb_define (cpp_reader *, location_t, cpp_hashnode *); |
| 77 | static void cb_undef (cpp_reader *, location_t, cpp_hashnode *); |
| 78 | static void cb_used_define (cpp_reader *, location_t, cpp_hashnode *); |
| 79 | static void cb_used_undef (cpp_reader *, location_t, cpp_hashnode *); |
| 80 | static void cb_include (cpp_reader *, location_t, const unsigned char *, |
| 81 | const char *, int, const cpp_token **); |
| 82 | static void cb_ident (cpp_reader *, location_t, const cpp_string *); |
| 83 | static void cb_def_pragma (cpp_reader *, location_t); |
| 84 | static void cb_read_pch (cpp_reader *pfile, const char *name, |
| 85 | int fd, const char *orig_name); |
| 86 | |
| 87 | /* Preprocess and output. */ |
| 88 | void |
| 89 | preprocess_file (cpp_reader *pfile) |
| 90 | { |
| 91 | /* A successful cpp_read_main_file guarantees that we can call |
| 92 | cpp_scan_nooutput or cpp_get_token next. */ |
| 93 | if (flag_no_output && pfile->buffer) |
| 94 | { |
| 95 | if (flag_modules) |
| 96 | { |
| 97 | /* For macros from imported headers we need directives_only_cb. */ |
| 98 | scan_translation_unit_directives_only (pfile); |
| 99 | } |
| 100 | else |
| 101 | { |
| 102 | /* Scan -included buffers, then the main file. */ |
| 103 | while (pfile->buffer->prev) |
| 104 | cpp_scan_nooutput (pfile); |
| 105 | cpp_scan_nooutput (pfile); |
| 106 | } |
| 107 | } |
| 108 | else if (cpp_get_options (pfile)->traditional) |
| 109 | scan_translation_unit_trad (pfile); |
| 110 | else if (cpp_get_options (pfile)->directives_only |
| 111 | && !cpp_get_options (pfile)->preprocessed) |
| 112 | scan_translation_unit_directives_only (pfile); |
| 113 | else |
| 114 | scan_translation_unit (pfile); |
| 115 | |
| 116 | /* -dM command line option. Should this be elsewhere? */ |
| 117 | if (flag_dump_macros == 'M') |
| 118 | cpp_forall_identifiers (pfile, dump_macro, NULL); |
| 119 | |
| 120 | /* Flush any pending output. */ |
| 121 | if (print.printed) |
| 122 | putc (c: '\n', stream: print.outf); |
| 123 | } |
| 124 | |
| 125 | /* Don't emit #pragma or #ident directives if we are processing |
| 126 | assembly language; the assembler may choke on them. */ |
| 127 | static bool |
| 128 | should_output_pragmas () |
| 129 | { |
| 130 | return cpp_get_options (parse_in)->lang != CLK_ASM; |
| 131 | } |
| 132 | |
| 133 | /* Set up the callbacks as appropriate. */ |
| 134 | void |
| 135 | init_pp_output (FILE *out_stream) |
| 136 | { |
| 137 | cpp_callbacks *cb = cpp_get_callbacks (parse_in); |
| 138 | |
| 139 | if (!flag_no_output) |
| 140 | { |
| 141 | cb->line_change = cb_line_change; |
| 142 | if (should_output_pragmas ()) |
| 143 | { |
| 144 | cb->ident = cb_ident; |
| 145 | cb->def_pragma = cb_def_pragma; |
| 146 | } |
| 147 | } |
| 148 | |
| 149 | if (flag_dump_includes) |
| 150 | cb->include = cb_include; |
| 151 | |
| 152 | if (flag_pch_preprocess) |
| 153 | { |
| 154 | cb->valid_pch = c_common_valid_pch; |
| 155 | cb->read_pch = cb_read_pch; |
| 156 | } |
| 157 | |
| 158 | if (flag_dump_macros == 'N' || flag_dump_macros == 'D') |
| 159 | { |
| 160 | cb->define = cb_define; |
| 161 | cb->undef = cb_undef; |
| 162 | } |
| 163 | |
| 164 | if (flag_dump_macros == 'U') |
| 165 | { |
| 166 | cb->before_define = dump_queued_macros; |
| 167 | cb->used_define = cb_used_define; |
| 168 | cb->used_undef = cb_used_undef; |
| 169 | } |
| 170 | |
| 171 | cb->has_attribute = c_common_has_attribute; |
| 172 | cb->has_builtin = c_common_has_builtin; |
| 173 | cb->has_feature = c_common_has_feature; |
| 174 | cb->get_source_date_epoch = cb_get_source_date_epoch; |
| 175 | cb->get_suggestion = cb_get_suggestion; |
| 176 | cb->remap_filename = remap_macro_filename; |
| 177 | |
| 178 | /* Initialize the print structure. */ |
| 179 | print.src_line = 1; |
| 180 | print.printed = false; |
| 181 | print.prev = 0; |
| 182 | print.outf = out_stream; |
| 183 | print.first_time = 1; |
| 184 | print.src_file = "" ; |
| 185 | print.prev_was_system_token = false; |
| 186 | print.streamer = nullptr; |
| 187 | } |
| 188 | |
| 189 | // FIXME: Ideally we'd just turn the entirety of the print struct into |
| 190 | // an encapsulated streamer ... |
| 191 | |
| 192 | class token_streamer |
| 193 | { |
| 194 | bool avoid_paste; |
| 195 | bool do_line_adjustments; |
| 196 | bool in_pragma; |
| 197 | |
| 198 | public: |
| 199 | token_streamer (cpp_reader *pfile) |
| 200 | :avoid_paste (false), |
| 201 | do_line_adjustments (cpp_get_options (pfile)->lang != CLK_ASM |
| 202 | && !flag_no_line_commands), |
| 203 | in_pragma (false) |
| 204 | { |
| 205 | gcc_assert (!print.streamer); |
| 206 | print.streamer = this; |
| 207 | } |
| 208 | |
| 209 | void begin_pragma () |
| 210 | { |
| 211 | in_pragma = true; |
| 212 | } |
| 213 | |
| 214 | void stream (cpp_reader *pfile, const cpp_token *tok, location_t); |
| 215 | }; |
| 216 | |
| 217 | void |
| 218 | token_streamer::stream (cpp_reader *pfile, const cpp_token *token, |
| 219 | location_t loc) |
| 220 | { |
| 221 | /* Keep input_location up to date, since it is needed for processing early |
| 222 | pragmas such as #pragma GCC diagnostic. */ |
| 223 | input_location = loc; |
| 224 | |
| 225 | if (token->type == CPP_PADDING) |
| 226 | { |
| 227 | avoid_paste = true; |
| 228 | if (print.source == NULL |
| 229 | || (!(print.source->flags & PREV_WHITE) |
| 230 | && token->val.source == NULL)) |
| 231 | print.source = token->val.source; |
| 232 | return; |
| 233 | } |
| 234 | |
| 235 | if (token->type == CPP_EOF) |
| 236 | return; |
| 237 | |
| 238 | /* Keep track when we move into and out of system locations. */ |
| 239 | const bool is_system_token = in_system_header_at (loc); |
| 240 | const bool system_state_changed |
| 241 | = (is_system_token != print.prev_was_system_token); |
| 242 | print.prev_was_system_token = is_system_token; |
| 243 | |
| 244 | /* Subtle logic to output a space if and only if necessary. */ |
| 245 | bool line_marker_emitted = false; |
| 246 | if (avoid_paste) |
| 247 | { |
| 248 | unsigned src_line = LOCATION_LINE (loc); |
| 249 | |
| 250 | if (print.source == NULL) |
| 251 | print.source = token; |
| 252 | |
| 253 | if (src_line != print.src_line |
| 254 | && do_line_adjustments |
| 255 | && !in_pragma) |
| 256 | { |
| 257 | line_marker_emitted = do_line_change (pfile, token, loc, false); |
| 258 | putc (c: ' ', stream: print.outf); |
| 259 | print.printed = true; |
| 260 | } |
| 261 | else if (print.source->flags & PREV_WHITE |
| 262 | || (print.prev |
| 263 | && cpp_avoid_paste (pfile, print.prev, token)) |
| 264 | || (print.prev == NULL && token->type == CPP_HASH)) |
| 265 | { |
| 266 | putc (c: ' ', stream: print.outf); |
| 267 | print.printed = true; |
| 268 | } |
| 269 | } |
| 270 | else if (token->flags & PREV_WHITE && token->type != CPP_PRAGMA) |
| 271 | { |
| 272 | unsigned src_line = LOCATION_LINE (loc); |
| 273 | |
| 274 | if (src_line != print.src_line |
| 275 | && do_line_adjustments |
| 276 | && !in_pragma) |
| 277 | line_marker_emitted = do_line_change (pfile, token, loc, false); |
| 278 | putc (c: ' ', stream: print.outf); |
| 279 | print.printed = true; |
| 280 | } |
| 281 | |
| 282 | avoid_paste = false; |
| 283 | print.source = NULL; |
| 284 | print.prev = token; |
| 285 | if (token->type == CPP_PRAGMA) |
| 286 | { |
| 287 | in_pragma = true; |
| 288 | if (should_output_pragmas ()) |
| 289 | { |
| 290 | const char *space; |
| 291 | const char *name; |
| 292 | |
| 293 | line_marker_emitted = maybe_print_line (token->src_loc); |
| 294 | fputs (s: "#pragma " , stream: print.outf); |
| 295 | c_pp_lookup_pragma (token->val.pragma, &space, &name); |
| 296 | if (space) |
| 297 | fprintf (stream: print.outf, format: "%s %s" , space, name); |
| 298 | else |
| 299 | fprintf (stream: print.outf, format: "%s" , name); |
| 300 | print.printed = true; |
| 301 | } |
| 302 | if (token->val.pragma >= PRAGMA_FIRST_EXTERNAL) |
| 303 | c_pp_invoke_early_pragma_handler (token->val.pragma); |
| 304 | } |
| 305 | else if (token->type == CPP_PRAGMA_EOL) |
| 306 | { |
| 307 | if (should_output_pragmas ()) |
| 308 | maybe_print_line (UNKNOWN_LOCATION); |
| 309 | in_pragma = false; |
| 310 | } |
| 311 | else if (token->type == CPP_EMBED) |
| 312 | { |
| 313 | char buf[76 + 6]; |
| 314 | maybe_print_line (token->src_loc); |
| 315 | gcc_checking_assert (token->val.str.len != 0); |
| 316 | fputs (s: "#embed \".\" __gnu__::__base64__(" , stream: print.outf); |
| 317 | if (token->val.str.len > 30) |
| 318 | { |
| 319 | fputs (s: " \\\n" , stream: print.outf); |
| 320 | print.src_line++; |
| 321 | } |
| 322 | buf[0] = '"'; |
| 323 | memcpy (dest: buf + 1 + 76, src: "\" \\\n" , n: 5); |
| 324 | unsigned int j = 1; |
| 325 | static const char base64_enc[] = |
| 326 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" ; |
| 327 | for (unsigned i = 0; ; i += 3) |
| 328 | { |
| 329 | unsigned char a = token->val.str.text[i]; |
| 330 | unsigned char b = 0, c = 0; |
| 331 | unsigned int n = token->val.str.len - i; |
| 332 | if (n > 1) |
| 333 | b = token->val.str.text[i + 1]; |
| 334 | if (n > 2) |
| 335 | c = token->val.str.text[i + 2]; |
| 336 | unsigned long v = ((((unsigned long) a) << 16) |
| 337 | | (((unsigned long) b) << 8) |
| 338 | | c); |
| 339 | buf[j++] = base64_enc[(v >> 18) & 63]; |
| 340 | buf[j++] = base64_enc[(v >> 12) & 63]; |
| 341 | buf[j++] = base64_enc[(v >> 6) & 63]; |
| 342 | buf[j++] = base64_enc[v & 63]; |
| 343 | if (j == 76 + 1 || n <= 3) |
| 344 | { |
| 345 | if (n < 3) |
| 346 | { |
| 347 | buf[j - 1] = '='; |
| 348 | if (n == 1) |
| 349 | buf[j - 2] = '='; |
| 350 | } |
| 351 | if (n <= 3) |
| 352 | memcpy (dest: buf + j, src: "\")" , n: 3); |
| 353 | else |
| 354 | print.src_line++; |
| 355 | fputs (s: buf, stream: print.outf); |
| 356 | j = 1; |
| 357 | if (n <= 3) |
| 358 | break; |
| 359 | } |
| 360 | } |
| 361 | print.printed = true; |
| 362 | maybe_print_line (token->src_loc); |
| 363 | return; |
| 364 | } |
| 365 | else |
| 366 | { |
| 367 | if (cpp_get_options (parse_in)->debug) |
| 368 | linemap_dump_location (line_table, token->src_loc, print.outf); |
| 369 | |
| 370 | if (do_line_adjustments |
| 371 | && !in_pragma |
| 372 | && !line_marker_emitted |
| 373 | && system_state_changed |
| 374 | && !is_location_from_builtin_token (loc)) |
| 375 | /* The system-ness of this token is different from the one of |
| 376 | the previous token. Let's emit a line change to mark the |
| 377 | new system-ness before we emit the token. */ |
| 378 | { |
| 379 | line_marker_emitted = do_line_change (pfile, token, loc, false); |
| 380 | } |
| 381 | if (!in_pragma || should_output_pragmas ()) |
| 382 | { |
| 383 | cpp_output_token (token, print.outf); |
| 384 | print.printed = true; |
| 385 | } |
| 386 | } |
| 387 | |
| 388 | /* CPP_COMMENT tokens and raw-string literal tokens can have |
| 389 | embedded new-line characters. Rather than enumerating all the |
| 390 | possible token types just check if token uses val.str union |
| 391 | member. */ |
| 392 | if (cpp_token_val_index (tok: token) == CPP_TOKEN_FLD_STR) |
| 393 | account_for_newlines (token->val.str.text, token->val.str.len); |
| 394 | } |
| 395 | |
| 396 | /* Writes out the preprocessed file, handling spacing and paste |
| 397 | avoidance issues. */ |
| 398 | |
| 399 | static void |
| 400 | scan_translation_unit (cpp_reader *pfile) |
| 401 | { |
| 402 | token_streamer streamer (pfile); |
| 403 | uintptr_t filter = 0; |
| 404 | |
| 405 | if (lang_hooks.preprocess_token) |
| 406 | filter = lang_hooks.preprocess_token (pfile, NULL, filter); |
| 407 | |
| 408 | print.source = NULL; |
| 409 | for (;;) |
| 410 | { |
| 411 | location_t spelling_loc; |
| 412 | const cpp_token *token |
| 413 | = cpp_get_token_with_location (pfile, &spelling_loc); |
| 414 | |
| 415 | streamer.stream (pfile, token, loc: spelling_loc); |
| 416 | if (filter) |
| 417 | { |
| 418 | unsigned flags = lang_hooks.preprocess_token (pfile, token, filter); |
| 419 | if (flags & lang_hooks::PT_begin_pragma) |
| 420 | streamer.begin_pragma (); |
| 421 | } |
| 422 | if (token->type == CPP_EOF) |
| 423 | break; |
| 424 | } |
| 425 | |
| 426 | if (filter) |
| 427 | lang_hooks.preprocess_token (pfile, NULL, filter); |
| 428 | } |
| 429 | |
| 430 | class do_streamer : public token_streamer |
| 431 | { |
| 432 | public: |
| 433 | uintptr_t filter; |
| 434 | |
| 435 | do_streamer (cpp_reader *pfile, uintptr_t filter) |
| 436 | :token_streamer (pfile), filter (filter) |
| 437 | { |
| 438 | } |
| 439 | }; |
| 440 | |
| 441 | static void |
| 442 | directives_only_cb (cpp_reader *pfile, CPP_DO_task task, void *data_, ...) |
| 443 | { |
| 444 | va_list args; |
| 445 | va_start (args, data_); |
| 446 | |
| 447 | do_streamer *streamer = reinterpret_cast <do_streamer *> (data_); |
| 448 | switch (task) |
| 449 | { |
| 450 | default: |
| 451 | gcc_unreachable (); |
| 452 | |
| 453 | case CPP_DO_print: |
| 454 | if (!flag_no_output) |
| 455 | { |
| 456 | print.src_line += va_arg (args, unsigned); |
| 457 | |
| 458 | const void *buf = va_arg (args, const void *); |
| 459 | size_t size = va_arg (args, size_t); |
| 460 | fwrite (ptr: buf, size: 1, n: size, s: print.outf); |
| 461 | } |
| 462 | break; |
| 463 | |
| 464 | case CPP_DO_location: |
| 465 | if (!flag_no_output) |
| 466 | maybe_print_line (va_arg (args, location_t)); |
| 467 | break; |
| 468 | |
| 469 | case CPP_DO_token: |
| 470 | { |
| 471 | const cpp_token *token = va_arg (args, const cpp_token *); |
| 472 | unsigned flags = 0; |
| 473 | if (streamer->filter) |
| 474 | flags = lang_hooks.preprocess_token (pfile, token, streamer->filter); |
| 475 | if (!flag_no_output) |
| 476 | { |
| 477 | location_t spelling_loc = va_arg (args, location_t); |
| 478 | streamer->stream (pfile, token, loc: spelling_loc); |
| 479 | if (flags & lang_hooks::PT_begin_pragma) |
| 480 | streamer->begin_pragma (); |
| 481 | } |
| 482 | } |
| 483 | break; |
| 484 | } |
| 485 | |
| 486 | va_end (args); |
| 487 | } |
| 488 | |
| 489 | /* Writes out the preprocessed file, handling spacing and paste |
| 490 | avoidance issues. */ |
| 491 | static void |
| 492 | scan_translation_unit_directives_only (cpp_reader *pfile) |
| 493 | { |
| 494 | uintptr_t filter = 0; |
| 495 | if (lang_hooks.preprocess_token) |
| 496 | filter = lang_hooks.preprocess_token (pfile, NULL, filter); |
| 497 | do_streamer streamer (pfile, filter); |
| 498 | cpp_directive_only_process (pfile, data: &streamer, cb: directives_only_cb); |
| 499 | if (streamer.filter) |
| 500 | lang_hooks.preprocess_token (pfile, NULL, streamer.filter); |
| 501 | } |
| 502 | |
| 503 | /* Adjust print.src_line for newlines embedded in output. For example, if a raw |
| 504 | string literal contains newlines, then we need to increment our notion of the |
| 505 | current line to keep in sync and avoid outputting a line marker |
| 506 | unnecessarily. If a raw string literal containing newlines is the result of |
| 507 | macro expansion, then we have the opposite problem, where the token takes up |
| 508 | more lines in the output than it did in the input, and hence a line marker is |
| 509 | needed to restore the correct state for subsequent lines. In this case, |
| 510 | incrementing print.src_line still does the job, because it will cause us to |
| 511 | emit the line marker the next time a token is streamed. */ |
| 512 | static void |
| 513 | account_for_newlines (const unsigned char *str, size_t len) |
| 514 | { |
| 515 | while (len--) |
| 516 | if (*str++ == '\n') |
| 517 | print.src_line++; |
| 518 | } |
| 519 | |
| 520 | /* Writes out a traditionally preprocessed file. */ |
| 521 | static void |
| 522 | scan_translation_unit_trad (cpp_reader *pfile) |
| 523 | { |
| 524 | while (_cpp_read_logical_line_trad (pfile)) |
| 525 | { |
| 526 | size_t len = pfile->out.cur - pfile->out.base; |
| 527 | maybe_print_line (pfile->out.first_line); |
| 528 | fwrite (ptr: pfile->out.base, size: 1, n: len, s: print.outf); |
| 529 | print.printed = true; |
| 530 | if (!CPP_OPTION (pfile, discard_comments)) |
| 531 | account_for_newlines (str: pfile->out.base, len); |
| 532 | } |
| 533 | } |
| 534 | |
| 535 | /* If the token read on logical line LINE needs to be output on a |
| 536 | different line to the current one, output the required newlines or |
| 537 | a line marker. If a line marker was emitted, return TRUE otherwise |
| 538 | return FALSE. */ |
| 539 | |
| 540 | static bool |
| 541 | maybe_print_line_1 (location_t src_loc, FILE *stream) |
| 542 | { |
| 543 | bool emitted_line_marker = false; |
| 544 | unsigned src_line = LOCATION_LINE (src_loc); |
| 545 | const char *src_file = LOCATION_FILE (src_loc); |
| 546 | |
| 547 | /* End the previous line of text. */ |
| 548 | if (print.printed) |
| 549 | { |
| 550 | putc (c: '\n', stream: stream); |
| 551 | print.src_line++; |
| 552 | print.printed = false; |
| 553 | } |
| 554 | |
| 555 | if (!flag_no_line_commands |
| 556 | && src_line >= print.src_line |
| 557 | && src_line < print.src_line + 8 |
| 558 | && src_loc != UNKNOWN_LOCATION |
| 559 | && strcmp (s1: src_file, s2: print.src_file) == 0) |
| 560 | { |
| 561 | while (src_line > print.src_line) |
| 562 | { |
| 563 | putc (c: '\n', stream: stream); |
| 564 | print.src_line++; |
| 565 | } |
| 566 | } |
| 567 | else |
| 568 | emitted_line_marker = print_line_1 (src_loc, "" , stream); |
| 569 | |
| 570 | return emitted_line_marker; |
| 571 | } |
| 572 | |
| 573 | /* If the token read on logical line LINE needs to be output on a |
| 574 | different line to the current one, output the required newlines or |
| 575 | a line marker. If a line marker was emitted, return TRUE otherwise |
| 576 | return FALSE. */ |
| 577 | |
| 578 | static bool |
| 579 | maybe_print_line (location_t src_loc) |
| 580 | { |
| 581 | if (cpp_get_options (parse_in)->debug) |
| 582 | linemap_dump_location (line_table, src_loc, |
| 583 | print.outf); |
| 584 | return maybe_print_line_1 (src_loc, stream: print.outf); |
| 585 | } |
| 586 | |
| 587 | /* Output a line marker for logical line LINE. Special flags are "1" |
| 588 | or "2" indicating entering or leaving a file. If the line marker |
| 589 | was effectively emitted, return TRUE otherwise return FALSE. */ |
| 590 | |
| 591 | static bool |
| 592 | print_line_1 (location_t src_loc, const char *special_flags, FILE *stream) |
| 593 | { |
| 594 | bool emitted_line_marker = false; |
| 595 | |
| 596 | /* End any previous line of text. */ |
| 597 | if (print.printed) |
| 598 | putc (c: '\n', stream: stream); |
| 599 | print.printed = false; |
| 600 | |
| 601 | if (src_loc != UNKNOWN_LOCATION && !flag_no_line_commands) |
| 602 | { |
| 603 | const char *file_path = LOCATION_FILE (src_loc); |
| 604 | size_t to_file_len = strlen (s: file_path); |
| 605 | unsigned char *to_file_quoted = |
| 606 | (unsigned char *) alloca (to_file_len * 4 + 1); |
| 607 | |
| 608 | /* cpp_quote_string does not nul-terminate, so we have to do it |
| 609 | ourselves. */ |
| 610 | unsigned char *p = cpp_quote_string (to_file_quoted, |
| 611 | (const unsigned char *) file_path, |
| 612 | to_file_len); |
| 613 | *p = '\0'; |
| 614 | |
| 615 | print.src_line = LOCATION_LINE (src_loc); |
| 616 | print.src_file = file_path; |
| 617 | |
| 618 | fprintf (stream: stream, format: "# %u \"%s\"%s" , |
| 619 | print.src_line, to_file_quoted, special_flags); |
| 620 | |
| 621 | int sysp = in_system_header_at (loc: src_loc); |
| 622 | if (sysp == 2) |
| 623 | fputs (s: " 3 4" , stream: stream); |
| 624 | else if (sysp == 1) |
| 625 | fputs (s: " 3" , stream: stream); |
| 626 | |
| 627 | putc (c: '\n', stream: stream); |
| 628 | emitted_line_marker = true; |
| 629 | } |
| 630 | |
| 631 | return emitted_line_marker; |
| 632 | } |
| 633 | |
| 634 | /* Output a line marker for logical line LINE. Special flags are "1" |
| 635 | or "2" indicating entering or leaving a file. Return TRUE if a |
| 636 | line marker was effectively emitted, FALSE otherwise. */ |
| 637 | |
| 638 | static bool |
| 639 | print_line (location_t src_loc, const char *special_flags) |
| 640 | { |
| 641 | if (cpp_get_options (parse_in)->debug) |
| 642 | linemap_dump_location (line_table, src_loc, |
| 643 | print.outf); |
| 644 | return print_line_1 (src_loc, special_flags, stream: print.outf); |
| 645 | } |
| 646 | |
| 647 | /* Helper function for cb_line_change and scan_translation_unit. |
| 648 | Return TRUE if a line marker is emitted, FALSE otherwise. */ |
| 649 | static bool |
| 650 | do_line_change (cpp_reader *pfile, const cpp_token *token, |
| 651 | location_t src_loc, int parsing_args) |
| 652 | { |
| 653 | bool emitted_line_marker = false; |
| 654 | if (define_queue || undef_queue) |
| 655 | dump_queued_macros (pfile); |
| 656 | |
| 657 | if (token->type == CPP_EOF || parsing_args) |
| 658 | return false; |
| 659 | |
| 660 | emitted_line_marker = maybe_print_line (src_loc); |
| 661 | print.prev = 0; |
| 662 | print.source = 0; |
| 663 | |
| 664 | /* Supply enough spaces to put this token in its original column, |
| 665 | one space per column greater than 2, since scan_translation_unit |
| 666 | will provide a space if PREV_WHITE. Don't bother trying to |
| 667 | reconstruct tabs; we can't get it right in general, and nothing |
| 668 | ought to care. Some things do care; the fault lies with them. |
| 669 | |
| 670 | Also do not output the spaces if this is a CPP_PRAGMA token. In this |
| 671 | case, libcpp has provided the location of the first token after #pragma, |
| 672 | so we would start at the wrong column. */ |
| 673 | if (!CPP_OPTION (pfile, traditional) && token->type != CPP_PRAGMA) |
| 674 | { |
| 675 | int spaces = LOCATION_COLUMN (src_loc) - 2; |
| 676 | print.printed = true; |
| 677 | |
| 678 | while (-- spaces >= 0) |
| 679 | putc (c: ' ', stream: print.outf); |
| 680 | } |
| 681 | |
| 682 | return emitted_line_marker; |
| 683 | } |
| 684 | |
| 685 | /* Called when a line of output is started. TOKEN is the first token |
| 686 | of the line, and at end of file will be CPP_EOF. */ |
| 687 | static void |
| 688 | cb_line_change (cpp_reader *pfile, const cpp_token *token, |
| 689 | int parsing_args) |
| 690 | { |
| 691 | do_line_change (pfile, token, src_loc: token->src_loc, parsing_args); |
| 692 | } |
| 693 | |
| 694 | static void |
| 695 | cb_ident (cpp_reader *pfile ATTRIBUTE_UNUSED, location_t line, |
| 696 | const cpp_string *str) |
| 697 | { |
| 698 | maybe_print_line (src_loc: line); |
| 699 | fprintf (stream: print.outf, format: "#ident %s\n" , str->text); |
| 700 | print.src_line++; |
| 701 | } |
| 702 | |
| 703 | static void |
| 704 | cb_define (cpp_reader *pfile, location_t line, cpp_hashnode *node) |
| 705 | { |
| 706 | const line_map_ordinary *map; |
| 707 | |
| 708 | maybe_print_line (src_loc: line); |
| 709 | fputs (s: "#define " , stream: print.outf); |
| 710 | |
| 711 | /* 'D' is whole definition; 'N' is name only. */ |
| 712 | if (flag_dump_macros == 'D') |
| 713 | fputs (s: (const char *) cpp_macro_definition (pfile, node), |
| 714 | stream: print.outf); |
| 715 | else |
| 716 | fputs (s: (const char *) NODE_NAME (node), stream: print.outf); |
| 717 | |
| 718 | putc (c: '\n', stream: print.outf); |
| 719 | print.printed = false; |
| 720 | linemap_resolve_location (line_table, loc: line, |
| 721 | lrk: LRK_MACRO_DEFINITION_LOCATION, |
| 722 | loc_map: &map); |
| 723 | print.src_line++; |
| 724 | } |
| 725 | |
| 726 | static void |
| 727 | cb_undef (cpp_reader *pfile, location_t line, cpp_hashnode *node) |
| 728 | { |
| 729 | if (lang_hooks.preprocess_undef) |
| 730 | lang_hooks.preprocess_undef (pfile, line, node); |
| 731 | maybe_print_line (src_loc: line); |
| 732 | fprintf (stream: print.outf, format: "#undef %s\n" , NODE_NAME (node)); |
| 733 | print.src_line++; |
| 734 | } |
| 735 | |
| 736 | static void |
| 737 | cb_used_define (cpp_reader *pfile, location_t line ATTRIBUTE_UNUSED, |
| 738 | cpp_hashnode *node) |
| 739 | { |
| 740 | if (cpp_user_macro_p (node)) |
| 741 | { |
| 742 | macro_queue *q; |
| 743 | q = XNEW (macro_queue); |
| 744 | q->macro = xstrdup ((const char *) cpp_macro_definition (pfile, node)); |
| 745 | q->next = define_queue; |
| 746 | define_queue = q; |
| 747 | } |
| 748 | } |
| 749 | |
| 750 | static void |
| 751 | cb_used_undef (cpp_reader *pfile ATTRIBUTE_UNUSED, |
| 752 | location_t line ATTRIBUTE_UNUSED, |
| 753 | cpp_hashnode *node) |
| 754 | { |
| 755 | macro_queue *q; |
| 756 | q = XNEW (macro_queue); |
| 757 | q->macro = xstrdup ((const char *) NODE_NAME (node)); |
| 758 | q->next = undef_queue; |
| 759 | undef_queue = q; |
| 760 | } |
| 761 | |
| 762 | static void |
| 763 | dump_queued_macros (cpp_reader *pfile ATTRIBUTE_UNUSED) |
| 764 | { |
| 765 | macro_queue *q; |
| 766 | |
| 767 | /* End the previous line of text. */ |
| 768 | if (print.printed) |
| 769 | { |
| 770 | putc (c: '\n', stream: print.outf); |
| 771 | print.src_line++; |
| 772 | print.printed = false; |
| 773 | } |
| 774 | |
| 775 | for (q = define_queue; q;) |
| 776 | { |
| 777 | macro_queue *oq; |
| 778 | fputs (s: "#define " , stream: print.outf); |
| 779 | fputs (s: q->macro, stream: print.outf); |
| 780 | putc (c: '\n', stream: print.outf); |
| 781 | print.printed = false; |
| 782 | print.src_line++; |
| 783 | oq = q; |
| 784 | q = q->next; |
| 785 | free (ptr: oq->macro); |
| 786 | free (ptr: oq); |
| 787 | } |
| 788 | define_queue = NULL; |
| 789 | for (q = undef_queue; q;) |
| 790 | { |
| 791 | macro_queue *oq; |
| 792 | fprintf (stream: print.outf, format: "#undef %s\n" , q->macro); |
| 793 | print.src_line++; |
| 794 | oq = q; |
| 795 | q = q->next; |
| 796 | free (ptr: oq->macro); |
| 797 | free (ptr: oq); |
| 798 | } |
| 799 | undef_queue = NULL; |
| 800 | } |
| 801 | |
| 802 | static void |
| 803 | cb_include (cpp_reader *pfile ATTRIBUTE_UNUSED, location_t line, |
| 804 | const unsigned char *dir, const char *, int angle_brackets, |
| 805 | const cpp_token **) |
| 806 | { |
| 807 | maybe_print_line (src_loc: line); |
| 808 | if (angle_brackets) |
| 809 | fprintf (stream: print.outf, format: "#%s <%s>" , dir, header); |
| 810 | else |
| 811 | fprintf (stream: print.outf, format: "#%s \"%s\"" , dir, header); |
| 812 | |
| 813 | if (comments != NULL) |
| 814 | { |
| 815 | while (*comments != NULL) |
| 816 | { |
| 817 | if ((*comments)->flags & PREV_WHITE) |
| 818 | putc (c: ' ', stream: print.outf); |
| 819 | cpp_output_token (*comments, print.outf); |
| 820 | ++comments; |
| 821 | } |
| 822 | } |
| 823 | |
| 824 | putc (c: '\n', stream: print.outf); |
| 825 | print.printed = false; |
| 826 | print.src_line++; |
| 827 | } |
| 828 | |
| 829 | /* Callback called when -fworking-director and -E to emit working |
| 830 | directory in cpp output file. */ |
| 831 | |
| 832 | void |
| 833 | pp_dir_change (cpp_reader *pfile ATTRIBUTE_UNUSED, const char *dir) |
| 834 | { |
| 835 | size_t to_file_len = strlen (s: dir); |
| 836 | unsigned char *to_file_quoted = |
| 837 | (unsigned char *) alloca (to_file_len * 4 + 1); |
| 838 | unsigned char *p; |
| 839 | |
| 840 | /* cpp_quote_string does not nul-terminate, so we have to do it ourselves. */ |
| 841 | p = cpp_quote_string (to_file_quoted, (const unsigned char *) dir, to_file_len); |
| 842 | *p = '\0'; |
| 843 | fprintf (stream: print.outf, format: "# 1 \"%s//\"\n" , to_file_quoted); |
| 844 | } |
| 845 | |
| 846 | /* The file name, line number or system header flags have changed, as |
| 847 | described in MAP. */ |
| 848 | |
| 849 | void |
| 850 | pp_file_change (const line_map_ordinary *map) |
| 851 | { |
| 852 | const char *flags = "" ; |
| 853 | |
| 854 | if (flag_no_line_commands) |
| 855 | return; |
| 856 | |
| 857 | if (map != NULL) |
| 858 | { |
| 859 | input_location = map->start_location; |
| 860 | if (print.first_time) |
| 861 | { |
| 862 | /* Avoid printing foo.i when the main file is foo.c. */ |
| 863 | if (!cpp_get_options (parse_in)->preprocessed) |
| 864 | print_line (src_loc: map->start_location, special_flags: flags); |
| 865 | print.first_time = 0; |
| 866 | } |
| 867 | else |
| 868 | { |
| 869 | /* Bring current file to correct line when entering a new file. */ |
| 870 | if (map->reason == LC_ENTER) |
| 871 | { |
| 872 | maybe_print_line (src_loc: linemap_included_from (ord_map: map)); |
| 873 | flags = " 1" ; |
| 874 | } |
| 875 | else if (map->reason == LC_LEAVE) |
| 876 | flags = " 2" ; |
| 877 | print_line (src_loc: map->start_location, special_flags: flags); |
| 878 | } |
| 879 | } |
| 880 | } |
| 881 | |
| 882 | /* Copy a #pragma directive to the preprocessed output. */ |
| 883 | static void |
| 884 | cb_def_pragma (cpp_reader *pfile, location_t line) |
| 885 | { |
| 886 | maybe_print_line (src_loc: line); |
| 887 | fputs (s: "#pragma " , stream: print.outf); |
| 888 | cpp_output_line (pfile, print.outf); |
| 889 | print.printed = false; |
| 890 | print.src_line++; |
| 891 | } |
| 892 | |
| 893 | /* Stream a token as if we had seen it directly ourselves; needed |
| 894 | in case a token was lexed externally, e.g. while processing a |
| 895 | pragma. */ |
| 896 | void |
| 897 | c_pp_stream_token (cpp_reader *pfile, const cpp_token *tok, location_t loc) |
| 898 | { |
| 899 | gcc_assert (print.streamer); |
| 900 | print.streamer->stream (pfile, token: tok, loc); |
| 901 | } |
| 902 | |
| 903 | /* Dump out the hash table. */ |
| 904 | static int |
| 905 | dump_macro (cpp_reader *pfile, cpp_hashnode *node, void *v ATTRIBUTE_UNUSED) |
| 906 | { |
| 907 | if (cpp_user_macro_p (node)) |
| 908 | { |
| 909 | fputs (s: "#define " , stream: print.outf); |
| 910 | fputs (s: (const char *) cpp_macro_definition (pfile, node), |
| 911 | stream: print.outf); |
| 912 | putc (c: '\n', stream: print.outf); |
| 913 | print.printed = false; |
| 914 | print.src_line++; |
| 915 | } |
| 916 | |
| 917 | return 1; |
| 918 | } |
| 919 | |
| 920 | /* Load in the PCH file NAME, open on FD. It was originally searched for |
| 921 | by ORIG_NAME. Also, print out a #include command so that the PCH |
| 922 | file can be loaded when the preprocessed output is compiled. */ |
| 923 | |
| 924 | static void |
| 925 | cb_read_pch (cpp_reader *pfile, const char *name, |
| 926 | int fd, const char *orig_name ATTRIBUTE_UNUSED) |
| 927 | { |
| 928 | c_common_read_pch (pfile, name, fd, orig: orig_name); |
| 929 | |
| 930 | fprintf (stream: print.outf, format: "#pragma GCC pch_preprocess \"%s\"\n" , name); |
| 931 | print.src_line++; |
| 932 | |
| 933 | /* The process of reading the PCH has destroyed the frontend parser, |
| 934 | so ask the frontend to reinitialize it, in case we need it to |
| 935 | process any #pragma directives encountered while preprocessing. */ |
| 936 | c_init_preprocess (); |
| 937 | } |
| 938 | |