12 #include "adt/error.h"
13 #include "adt/strutil.h"
14 #include "adt/strset.h"
15 #include "lang_features.h"
16 #include "diagnostic.h"
17 #include "string_rep.h"
21 #define INCLUDE_LIMIT 199 /* 199 is for gcc "compatibility" */
23 typedef struct saved_token_t {
28 typedef struct whitespace_info_t {
29 /** current token had whitespace in front of it */
31 /** current token is at the beginning of a line.
32 * => a "#" at line begin starts a preprocessing directive. */
34 /** number of spaces before the first token in a line */
35 unsigned whitespace_at_line_begin;
38 struct pp_definition_t {
40 source_position_t source_position;
41 pp_definition_t *parent_expansion;
43 whitespace_info_t expand_info;
45 bool is_expanding : 1;
46 bool has_parameters : 1;
47 bool is_parameter : 1;
48 pp_definition_t *function_definition;
50 pp_definition_t *parameters;
54 saved_token_t *token_list;
57 typedef struct pp_conditional_t pp_conditional_t;
58 struct pp_conditional_t {
59 source_position_t source_position;
62 /** conditional in skip mode (then+else gets skipped) */
64 pp_conditional_t *parent;
67 typedef struct pp_input_t pp_input_t;
72 utf32 buf[1024+MAX_PUTBACK];
75 source_position_t position;
80 typedef struct searchpath_entry_t searchpath_entry_t;
81 struct searchpath_entry_t {
83 searchpath_entry_t *next;
86 static pp_input_t input;
88 static pp_input_t *input_stack;
89 static unsigned n_inputs;
90 static struct obstack input_obstack;
92 static pp_conditional_t *conditional_stack;
94 static token_t pp_token;
95 static bool resolve_escape_sequences = false;
96 static bool error_on_unknown_chars = true;
97 static bool skip_mode;
99 static struct obstack pp_obstack;
100 static struct obstack config_obstack;
101 static const char *printed_input_name = NULL;
102 static source_position_t expansion_pos;
103 static pp_definition_t *current_expansion = NULL;
104 static pp_definition_t *current_call = NULL;
105 static pp_definition_t *current_argument = NULL;
106 static pp_definition_t *argument_expanding = NULL;
107 static unsigned argument_brace_count;
108 static strset_t stringset;
109 static token_kind_t last_token;
111 static searchpath_entry_t *searchpath;
113 static whitespace_info_t next_info; /* valid if had_whitespace is true */
114 static whitespace_info_t info;
116 static inline void next_char(void);
117 static void next_input_token(void);
118 static void print_line_directive(const source_position_t *pos, const char *add);
120 static symbol_t *symbol_colongreater;
121 static symbol_t *symbol_lesscolon;
122 static symbol_t *symbol_lesspercent;
123 static symbol_t *symbol_percentcolon;
124 static symbol_t *symbol_percentcolonpercentcolon;
125 static symbol_t *symbol_percentgreater;
127 extern bool allow_dollar_in_symbol;
129 static void init_symbols(void)
131 symbol_colongreater = symbol_table_insert(":>");
132 symbol_lesscolon = symbol_table_insert("<:");
133 symbol_lesspercent = symbol_table_insert("<%");
134 symbol_percentcolon = symbol_table_insert("%:");
135 symbol_percentcolonpercentcolon = symbol_table_insert("%:%:");
136 symbol_percentgreater = symbol_table_insert("%>");
139 static void switch_input(FILE *file, const char *filename)
142 input.input = input_from_stream(file, NULL);
145 input.output_line = 0;
146 input.position.input_name = filename;
147 input.position.lineno = 1;
149 /* indicate that we're at a new input */
150 print_line_directive(&input.position, input_stack != NULL ? "1" : NULL);
152 /* place a virtual '\n' so we realize we're at line begin */
153 input.position.lineno = 0;
157 static void close_input(void)
159 input_free(input.input);
160 assert(input.file != NULL);
170 static void push_input(void)
172 pp_input_t *saved_input
173 = obstack_alloc(&input_obstack, sizeof(*saved_input));
175 memcpy(saved_input, &input, sizeof(*saved_input));
177 /* adjust buffer positions */
178 if (input.bufpos != NULL)
179 saved_input->bufpos = saved_input->buf + (input.bufpos - input.buf);
180 if (input.bufend != NULL)
181 saved_input->bufend = saved_input->buf + (input.bufend - input.buf);
183 saved_input->parent = input_stack;
184 input_stack = saved_input;
188 static void pop_restore_input(void)
190 assert(n_inputs > 0);
191 assert(input_stack != NULL);
193 pp_input_t *saved_input = input_stack;
195 memcpy(&input, saved_input, sizeof(input));
198 /* adjust buffer positions */
199 if (saved_input->bufpos != NULL)
200 input.bufpos = input.buf + (saved_input->bufpos - saved_input->buf);
201 if (saved_input->bufend != NULL)
202 input.bufend = input.buf + (saved_input->bufend - saved_input->buf);
204 input_stack = saved_input->parent;
205 obstack_free(&input_obstack, saved_input);
210 * Prints a parse error message at the current token.
212 * @param msg the error message
214 static void parse_error(const char *msg)
216 errorf(&pp_token.base.source_position, "%s", msg);
219 static inline void next_real_char(void)
221 assert(input.bufpos <= input.bufend);
222 if (input.bufpos >= input.bufend) {
223 size_t const n = decode(input.input, input.buf + MAX_PUTBACK, lengthof(input.buf) - MAX_PUTBACK);
228 input.bufpos = input.buf + MAX_PUTBACK;
229 input.bufend = input.bufpos + n;
231 input.c = *input.bufpos++;
232 ++input.position.colno;
236 * Put a character back into the buffer.
238 * @param pc the character to put back
240 static inline void put_back(utf32 const pc)
242 assert(input.bufpos > input.buf);
243 *(--input.bufpos - input.buf + input.buf) = (char) pc;
244 --input.position.colno;
250 if (input.c == '\n') { \
254 ++input.position.lineno; \
255 input.position.colno = 1; \
257 newline // Let it look like an ordinary case label.
259 #define eat(c_type) (assert(input.c == c_type), next_char())
261 static void maybe_concat_lines(void)
267 info.whitespace_at_line_begin = 0;
279 * Set c to the next input character, ie.
280 * after expanding trigraphs.
282 static inline void next_char(void)
286 /* filter trigraphs and concatenated lines */
287 if (UNLIKELY(input.c == '\\')) {
288 maybe_concat_lines();
289 goto end_of_next_char;
292 if (LIKELY(input.c != '?'))
293 goto end_of_next_char;
296 if (LIKELY(input.c != '?')) {
299 goto end_of_next_char;
304 case '=': input.c = '#'; break;
305 case '(': input.c = '['; break;
306 case '/': input.c = '\\'; maybe_concat_lines(); break;
307 case ')': input.c = ']'; break;
308 case '\'': input.c = '^'; break;
309 case '<': input.c = '{'; break;
310 case '!': input.c = '|'; break;
311 case '>': input.c = '}'; break;
312 case '-': input.c = '~'; break;
322 printf("nchar '%c'\n", input.c);
329 * Returns true if the given char is a octal digit.
331 * @param char the character to check
333 static inline bool is_octal_digit(int chr)
351 * Returns the value of a digit.
352 * The only portable way to do it ...
354 static int digit_value(int digit)
380 panic("wrong character given");
385 * Parses an octal character sequence.
387 * @param first_digit the already read first digit
389 static utf32 parse_octal_sequence(const utf32 first_digit)
391 assert(is_octal_digit(first_digit));
392 utf32 value = digit_value(first_digit);
393 if (!is_octal_digit(input.c)) return value;
394 value = 8 * value + digit_value(input.c);
396 if (!is_octal_digit(input.c)) return value;
397 value = 8 * value + digit_value(input.c);
404 * Parses a hex character sequence.
406 static utf32 parse_hex_sequence(void)
409 while (isxdigit(input.c)) {
410 value = 16 * value + digit_value(input.c);
416 static bool is_universal_char_valid(utf32 const v)
419 if (v < 0xA0U && v != 0x24 && v != 0x40 && v != 0x60)
421 if (0xD800 <= v && v <= 0xDFFF)
426 static utf32 parse_universal_char(unsigned const n_digits)
429 for (unsigned k = n_digits; k != 0; --k) {
430 if (isxdigit(input.c)) {
431 v = 16 * v + digit_value(input.c);
432 if (!resolve_escape_sequences)
433 obstack_1grow(&symbol_obstack, input.c);
436 errorf(&input.position,
437 "short universal character name, expected %u more digits",
442 if (!is_universal_char_valid(v)) {
443 errorf(&input.position,
444 "\\%c%0*X is not a valid universal character name",
445 n_digits == 4 ? 'u' : 'U', (int)n_digits, v);
450 static bool is_universal_char_valid_identifier(utf32 const v)
453 if ( v == 0x000A8) return true;
454 if ( v == 0x000AA) return true;
455 if ( v == 0x000AD) return true;
456 if ( v == 0x000AF) return true;
457 if (0x000B2 <= v && v <= 0x000B5) return true;
458 if (0x000B7 <= v && v <= 0x000BA) return true;
459 if (0x000BC <= v && v <= 0x000BE) return true;
460 if (0x000C0 <= v && v <= 0x000D6) return true;
461 if (0x000D8 <= v && v <= 0x000F6) return true;
462 if (0x000F8 <= v && v <= 0x000FF) return true;
463 if (0x00100 <= v && v <= 0x0167F) return true;
464 if (0x01681 <= v && v <= 0x0180D) return true;
465 if (0x0180F <= v && v <= 0x01FFF) return true;
466 if (0x0200B <= v && v <= 0x0200D) return true;
467 if (0x0202A <= v && v <= 0x0202E) return true;
468 if (0x0203F <= v && v <= 0x02040) return true;
469 if ( v == 0x02054) return true;
470 if (0x02060 <= v && v <= 0x0206F) return true;
471 if (0x02070 <= v && v <= 0x0218F) return true;
472 if (0x02460 <= v && v <= 0x024FF) return true;
473 if (0x02776 <= v && v <= 0x02793) return true;
474 if (0x02C00 <= v && v <= 0x02DFF) return true;
475 if (0x02E80 <= v && v <= 0x02FFF) return true;
476 if (0x03004 <= v && v <= 0x03007) return true;
477 if (0x03021 <= v && v <= 0x0302F) return true;
478 if (0x03031 <= v && v <= 0x0303F) return true;
479 if (0x03040 <= v && v <= 0x0D7FF) return true;
480 if (0x0F900 <= v && v <= 0x0FD3D) return true;
481 if (0x0FD40 <= v && v <= 0x0FDCF) return true;
482 if (0x0FDF0 <= v && v <= 0x0FE44) return true;
483 if (0x0FE47 <= v && v <= 0x0FFFD) return true;
484 if (0x10000 <= v && v <= 0x1FFFD) return true;
485 if (0x20000 <= v && v <= 0x2FFFD) return true;
486 if (0x30000 <= v && v <= 0x3FFFD) return true;
487 if (0x40000 <= v && v <= 0x4FFFD) return true;
488 if (0x50000 <= v && v <= 0x5FFFD) return true;
489 if (0x60000 <= v && v <= 0x6FFFD) return true;
490 if (0x70000 <= v && v <= 0x7FFFD) return true;
491 if (0x80000 <= v && v <= 0x8FFFD) return true;
492 if (0x90000 <= v && v <= 0x9FFFD) return true;
493 if (0xA0000 <= v && v <= 0xAFFFD) return true;
494 if (0xB0000 <= v && v <= 0xBFFFD) return true;
495 if (0xC0000 <= v && v <= 0xCFFFD) return true;
496 if (0xD0000 <= v && v <= 0xDFFFD) return true;
497 if (0xE0000 <= v && v <= 0xEFFFD) return true;
501 static bool is_universal_char_valid_identifier_start(utf32 const v)
504 if (0x0300 <= v && v <= 0x036F) return false;
505 if (0x1DC0 <= v && v <= 0x1DFF) return false;
506 if (0x20D0 <= v && v <= 0x20FF) return false;
507 if (0xFE20 <= v && v <= 0xFE2F) return false;
512 * Parse an escape sequence.
514 static utf32 parse_escape_sequence(void)
518 utf32 const ec = input.c;
522 case '"': return '"';
523 case '\'': return '\'';
524 case '\\': return '\\';
525 case '?': return '\?';
526 case 'a': return '\a';
527 case 'b': return '\b';
528 case 'f': return '\f';
529 case 'n': return '\n';
530 case 'r': return '\r';
531 case 't': return '\t';
532 case 'v': return '\v';
534 return parse_hex_sequence();
543 return parse_octal_sequence(ec);
545 parse_error("reached end of file while parsing escape sequence");
547 /* \E is not documented, but handled, by GCC. It is acceptable according
548 * to §6.11.4, whereas \e is not. */
552 return 27; /* hopefully 27 is ALWAYS the code for ESCAPE */
555 case 'U': return parse_universal_char(8);
556 case 'u': return parse_universal_char(4);
561 /* §6.4.4.4:8 footnote 64 */
562 parse_error("unknown escape sequence");
566 static const char *identify_string(char *string)
568 const char *result = strset_insert(&stringset, string);
569 if (result != string) {
570 obstack_free(&symbol_obstack, string);
575 static string_t sym_make_string(string_encoding_t const enc)
577 obstack_1grow(&symbol_obstack, '\0');
578 size_t const len = obstack_object_size(&symbol_obstack) - 1;
579 char *const string = obstack_finish(&symbol_obstack);
580 char const *const result = identify_string(string);
581 return (string_t){ result, len, enc };
584 static void parse_string(utf32 const delimiter, token_kind_t const kind,
585 string_encoding_t const enc,
586 char const *const context)
588 const unsigned start_linenr = input.position.lineno;
595 if (resolve_escape_sequences) {
596 utf32 const tc = parse_escape_sequence();
597 if (enc == STRING_ENCODING_CHAR) {
599 warningf(WARN_OTHER, &pp_token.base.source_position, "escape sequence out of range");
601 obstack_1grow(&symbol_obstack, tc);
603 obstack_grow_utf8(&symbol_obstack, tc);
606 obstack_1grow(&symbol_obstack, (char)input.c);
608 obstack_1grow(&symbol_obstack, (char)input.c);
615 errorf(&pp_token.base.source_position, "newline while parsing %s", context);
619 source_position_t source_position;
620 source_position.input_name = pp_token.base.source_position.input_name;
621 source_position.lineno = start_linenr;
622 errorf(&source_position, "EOF while parsing %s", context);
627 if (input.c == delimiter) {
631 obstack_grow_utf8(&symbol_obstack, input.c);
639 pp_token.kind = kind;
640 pp_token.literal.string = sym_make_string(enc);
643 static void parse_string_literal(string_encoding_t const enc)
645 parse_string('"', T_STRING_LITERAL, enc, "string literal");
648 static void parse_character_constant(string_encoding_t const enc)
650 parse_string('\'', T_CHARACTER_CONSTANT, enc, "character constant");
651 if (pp_token.literal.string.size == 0) {
652 parse_error("empty character constant");
656 #define SYMBOL_CASES_WITHOUT_E_P \
657 '$': if (!allow_dollar_in_symbol) goto dollar_sign; \
708 #define SYMBOL_CASES \
709 SYMBOL_CASES_WITHOUT_E_P: \
715 #define DIGIT_CASES \
727 static void start_expanding(pp_definition_t *definition)
729 definition->parent_expansion = current_expansion;
730 definition->expand_pos = 0;
731 definition->is_expanding = true;
732 if (definition->list_len > 0) {
733 definition->token_list[0].had_whitespace
734 = info.had_whitespace;
736 current_expansion = definition;
739 static void finished_expanding(pp_definition_t *definition)
741 assert(definition->is_expanding);
742 pp_definition_t *parent = definition->parent_expansion;
743 definition->parent_expansion = NULL;
744 definition->is_expanding = false;
746 /* stop further expanding once we expanded a parameter used in a
748 if (definition == argument_expanding)
749 argument_expanding = NULL;
751 assert(current_expansion == definition);
752 current_expansion = parent;
755 static inline void set_punctuator(token_kind_t const kind)
757 pp_token.kind = kind;
758 pp_token.base.symbol = token_symbols[kind];
761 static inline void set_digraph(token_kind_t const kind, symbol_t *const symbol)
763 pp_token.kind = kind;
764 pp_token.base.symbol = symbol;
768 * returns next final token from a preprocessor macro expansion
770 static bool expand_next(void)
772 if (current_expansion == NULL)
776 size_t pos = current_expansion->expand_pos;
777 if (pos >= current_expansion->list_len) {
778 finished_expanding(current_expansion);
779 /* it was the outermost expansion, parse pptoken normally */
780 if (current_expansion == NULL) {
785 const saved_token_t *saved = ¤t_expansion->token_list[pos++];
786 pp_token = saved->token;
788 if (current_expansion->expand_pos > 0)
789 info.had_whitespace = saved->had_whitespace;
790 pp_token.base.source_position = expansion_pos;
791 ++current_expansion->expand_pos;
797 * Returns the next token kind found when continuing the current expansions
798 * without starting new sub-expansions.
800 static token_kind_t peek_expansion(void)
802 pp_definition_t *expansion = current_expansion;
803 while (expansion != NULL && expansion->expand_pos >= expansion->list_len) {
804 expansion = expansion->parent_expansion;
806 if (expansion == NULL)
808 return expansion->token_list[expansion->expand_pos].token.kind;
811 static void skip_line_comment(void)
813 info.had_whitespace = true;
830 static void skip_multiline_comment(void)
832 info.had_whitespace = true;
834 unsigned start_linenr = input.position.lineno;
839 if (input.c == '*') {
840 /* TODO: nested comment, warn here */
845 if (input.c == '/') {
846 if (input.position.lineno != input.output_line)
847 info.whitespace_at_line_begin = input.position.colno;
857 source_position_t source_position;
858 source_position.input_name = pp_token.base.source_position.input_name;
859 source_position.lineno = start_linenr;
860 errorf(&source_position, "at end of file while looking for comment end");
871 static bool skip_till_newline(bool stop_at_non_whitespace)
883 if (input.c == '/') {
887 } else if (input.c == '*') {
889 skip_multiline_comment();
901 if (stop_at_non_whitespace)
910 static void skip_whitespace(void)
916 ++info.whitespace_at_line_begin;
917 info.had_whitespace = true;
922 info.at_line_begin = true;
923 info.had_whitespace = true;
924 info.whitespace_at_line_begin = 0;
929 if (input.c == '/') {
933 } else if (input.c == '*') {
935 skip_multiline_comment();
949 static inline void eat_pp(pp_token_kind_t const kind)
951 assert(pp_token.base.symbol->pp_ID == kind);
956 static inline void eat_token(token_kind_t const kind)
958 assert(pp_token.kind == kind);
963 static void parse_symbol(void)
965 assert(obstack_object_size(&symbol_obstack) == 0);
970 obstack_1grow(&symbol_obstack, (char) input.c);
979 case 'U': n = 8; goto universal;
980 case 'u': n = 4; goto universal;
982 if (!resolve_escape_sequences) {
983 obstack_1grow(&symbol_obstack, '\\');
984 obstack_1grow(&symbol_obstack, input.c);
987 utf32 const v = parse_universal_char(n);
988 if (!is_universal_char_valid_identifier(v)) {
989 if (is_universal_char_valid(v)) {
990 errorf(&input.position,
991 "universal character \\%c%0*X is not valid in an identifier",
992 n == 4 ? 'u' : 'U', (int)n, v);
994 } else if (obstack_object_size(&symbol_obstack) == 0 && !is_universal_char_valid_identifier_start(v)) {
995 errorf(&input.position,
996 "universal character \\%c%0*X is not valid as start of an identifier",
997 n == 4 ? 'u' : 'U', (int)n, v);
998 } else if (resolve_escape_sequences) {
999 obstack_grow_utf8(&symbol_obstack, v);
1017 obstack_1grow(&symbol_obstack, '\0');
1018 char *string = obstack_finish(&symbol_obstack);
1020 /* might be a wide string or character constant ( L"string"/L'c' ) */
1021 if (input.c == '"' && string[0] == 'L' && string[1] == '\0') {
1022 obstack_free(&symbol_obstack, string);
1023 parse_string_literal(STRING_ENCODING_WIDE);
1025 } else if (input.c == '\'' && string[0] == 'L' && string[1] == '\0') {
1026 obstack_free(&symbol_obstack, string);
1027 parse_character_constant(STRING_ENCODING_WIDE);
1031 symbol_t *symbol = symbol_table_insert(string);
1033 pp_token.kind = symbol->ID;
1034 pp_token.base.symbol = symbol;
1036 /* we can free the memory from symbol obstack if we already had an entry in
1037 * the symbol table */
1038 if (symbol->string != string) {
1039 obstack_free(&symbol_obstack, string);
1043 static void parse_number(void)
1045 obstack_1grow(&symbol_obstack, (char) input.c);
1052 case SYMBOL_CASES_WITHOUT_E_P:
1053 obstack_1grow(&symbol_obstack, (char) input.c);
1061 obstack_1grow(&symbol_obstack, (char) input.c);
1063 if (input.c == '+' || input.c == '-') {
1064 obstack_1grow(&symbol_obstack, (char) input.c);
1076 pp_token.kind = T_NUMBER;
1077 pp_token.literal.string = sym_make_string(STRING_ENCODING_CHAR);
1080 #define MAYBE_PROLOG \
1084 #define MAYBE(ch, kind) \
1087 set_punctuator(kind); \
1090 #define MAYBE_DIGRAPH(ch, kind, symbol) \
1093 set_digraph(kind, symbol); \
1096 #define ELSE_CODE(code) \
1102 #define ELSE(kind) ELSE_CODE(set_punctuator(kind);)
1104 /** identifies and returns the next preprocessing token contained in the
1105 * input stream. No macro expansion is performed. */
1106 static void next_input_token(void)
1108 if (next_info.had_whitespace) {
1110 next_info.had_whitespace = false;
1112 info.at_line_begin = false;
1113 info.had_whitespace = false;
1116 pp_token.base.source_position = input.position;
1117 pp_token.base.symbol = NULL;
1122 info.whitespace_at_line_begin++;
1123 info.had_whitespace = true;
1128 info.at_line_begin = true;
1129 info.had_whitespace = true;
1130 info.whitespace_at_line_begin = 0;
1142 parse_string_literal(STRING_ENCODING_CHAR);
1146 parse_character_constant(STRING_ENCODING_CHAR);
1168 MAYBE('.', T_DOTDOTDOT)
1172 set_punctuator('.');
1177 MAYBE('&', T_ANDAND)
1178 MAYBE('=', T_ANDEQUAL)
1182 MAYBE('=', T_ASTERISKEQUAL)
1186 MAYBE('+', T_PLUSPLUS)
1187 MAYBE('=', T_PLUSEQUAL)
1191 MAYBE('>', T_MINUSGREATER)
1192 MAYBE('-', T_MINUSMINUS)
1193 MAYBE('=', T_MINUSEQUAL)
1197 MAYBE('=', T_EXCLAMATIONMARKEQUAL)
1201 MAYBE('=', T_SLASHEQUAL)
1204 skip_multiline_comment();
1208 skip_line_comment();
1213 MAYBE_DIGRAPH('>', '}', symbol_percentgreater)
1214 MAYBE('=', T_PERCENTEQUAL)
1219 MAYBE_DIGRAPH(':', T_HASHHASH, symbol_percentcolonpercentcolon)
1223 goto digraph_percentcolon;
1226 digraph_percentcolon:
1227 set_digraph('#', symbol_percentcolon);
1232 MAYBE_DIGRAPH(':', '[', symbol_lesscolon)
1233 MAYBE_DIGRAPH('%', '{', symbol_lesspercent)
1234 MAYBE('=', T_LESSEQUAL)
1237 MAYBE('=', T_LESSLESSEQUAL)
1242 MAYBE('=', T_GREATEREQUAL)
1245 MAYBE('=', T_GREATERGREATEREQUAL)
1246 ELSE(T_GREATERGREATER)
1250 MAYBE('=', T_CARETEQUAL)
1254 MAYBE('=', T_PIPEEQUAL)
1255 MAYBE('|', T_PIPEPIPE)
1259 MAYBE_DIGRAPH('>', ']', symbol_colongreater)
1261 if (c_mode & _CXX) {
1263 set_punctuator(T_COLONCOLON);
1270 MAYBE('=', T_EQUALEQUAL)
1274 MAYBE('#', T_HASHHASH)
1287 set_punctuator(input.c);
1292 if (input_stack != NULL) {
1294 pop_restore_input();
1296 if (input.c == (utf32)EOF)
1297 --input.position.lineno;
1298 print_line_directive(&input.position, "2");
1301 info.at_line_begin = true;
1302 set_punctuator(T_EOF);
1308 int next_c = input.c;
1311 if (next_c == 'U' || next_c == 'u') {
1318 if (error_on_unknown_chars) {
1319 errorf(&pp_token.base.source_position,
1320 "unknown character '%lc' found\n", input.c);
1324 assert(obstack_object_size(&symbol_obstack) == 0);
1325 obstack_grow_utf8(&symbol_obstack, input.c);
1326 obstack_1grow(&symbol_obstack, '\0');
1327 char *const string = obstack_finish(&symbol_obstack);
1328 symbol_t *const symbol = symbol_table_insert(string);
1329 if (symbol->string != string)
1330 obstack_free(&symbol_obstack, string);
1332 pp_token.kind = T_UNKNOWN_CHAR;
1333 pp_token.base.symbol = symbol;
1340 static void print_quoted_string(const char *const string)
1343 for (const char *c = string; *c != 0; ++c) {
1345 case '"': fputs("\\\"", out); break;
1346 case '\\': fputs("\\\\", out); break;
1347 case '\a': fputs("\\a", out); break;
1348 case '\b': fputs("\\b", out); break;
1349 case '\f': fputs("\\f", out); break;
1350 case '\n': fputs("\\n", out); break;
1351 case '\r': fputs("\\r", out); break;
1352 case '\t': fputs("\\t", out); break;
1353 case '\v': fputs("\\v", out); break;
1354 case '\?': fputs("\\?", out); break;
1357 fprintf(out, "\\%03o", (unsigned)*c);
1367 static void print_line_directive(const source_position_t *pos, const char *add)
1369 fprintf(out, "# %u ", pos->lineno);
1370 print_quoted_string(pos->input_name);
1376 printed_input_name = pos->input_name;
1377 input.output_line = pos->lineno-1;
1380 static bool emit_newlines(void)
1382 unsigned delta = pp_token.base.source_position.lineno - input.output_line;
1388 print_line_directive(&pp_token.base.source_position, NULL);
1391 for (unsigned i = 0; i < delta; ++i) {
1395 input.output_line = pp_token.base.source_position.lineno;
1397 for (unsigned i = 0; i < info.whitespace_at_line_begin; ++i)
1403 static void emit_pp_token(void)
1405 if (!emit_newlines() &&
1406 (info.had_whitespace || tokens_would_paste(last_token, pp_token.kind)))
1409 switch (pp_token.kind) {
1411 fputs(pp_token.literal.string.begin, out);
1414 case T_STRING_LITERAL:
1415 fputs(get_string_encoding_prefix(pp_token.literal.string.encoding), out);
1417 fputs(pp_token.literal.string.begin, out);
1421 case T_CHARACTER_CONSTANT:
1422 fputs(get_string_encoding_prefix(pp_token.literal.string.encoding), out);
1424 fputs(pp_token.literal.string.begin, out);
1428 case T_MACRO_PARAMETER:
1429 panic("macro parameter not expanded");
1432 fputs(pp_token.base.symbol->string, out);
1435 last_token = pp_token.kind;
1438 static void eat_pp_directive(void)
1440 while (!info.at_line_begin) {
1445 static bool strings_equal(const string_t *string1, const string_t *string2)
1447 size_t size = string1->size;
1448 if (size != string2->size)
1451 const char *c1 = string1->begin;
1452 const char *c2 = string2->begin;
1453 for (size_t i = 0; i < size; ++i, ++c1, ++c2) {
1460 static bool pp_tokens_equal(const token_t *token1, const token_t *token2)
1462 if (token1->kind != token2->kind)
1465 switch (token1->kind) {
1467 case T_CHARACTER_CONSTANT:
1468 case T_STRING_LITERAL:
1469 return strings_equal(&token1->literal.string, &token2->literal.string);
1471 case T_MACRO_PARAMETER:
1472 return token1->macro_parameter.def->symbol
1473 == token2->macro_parameter.def->symbol;
1476 return token1->base.symbol == token2->base.symbol;
1480 static bool pp_definitions_equal(const pp_definition_t *definition1,
1481 const pp_definition_t *definition2)
1483 if (definition1->list_len != definition2->list_len)
1486 size_t len = definition1->list_len;
1487 const saved_token_t *t1 = definition1->token_list;
1488 const saved_token_t *t2 = definition2->token_list;
1489 for (size_t i = 0; i < len; ++i, ++t1, ++t2) {
1490 if (!pp_tokens_equal(&t1->token, &t2->token))
1496 static void parse_define_directive(void)
1504 assert(obstack_object_size(&pp_obstack) == 0);
1506 if (pp_token.kind != T_IDENTIFIER || info.at_line_begin) {
1507 errorf(&pp_token.base.source_position,
1508 "expected identifier after #define, got %K", &pp_token);
1511 symbol_t *const symbol = pp_token.base.symbol;
1513 pp_definition_t *new_definition
1514 = obstack_alloc(&pp_obstack, sizeof(new_definition[0]));
1515 memset(new_definition, 0, sizeof(new_definition[0]));
1516 new_definition->symbol = symbol;
1517 new_definition->source_position = input.position;
1519 /* this is probably the only place where spaces are significant in the
1520 * lexer (except for the fact that they separate tokens). #define b(x)
1521 * is something else than #define b (x) */
1522 if (input.c == '(') {
1523 eat_token(T_IDENTIFIER);
1527 switch (pp_token.kind) {
1529 new_definition->is_variadic = true;
1530 eat_token(T_DOTDOTDOT);
1531 if (pp_token.kind != ')') {
1532 errorf(&input.position,
1533 "'...' not at end of macro argument list");
1538 case T_IDENTIFIER: {
1539 pp_definition_t parameter;
1540 memset(¶meter, 0, sizeof(parameter));
1541 parameter.source_position = pp_token.base.source_position;
1542 parameter.symbol = pp_token.base.symbol;
1543 parameter.is_parameter = true;
1544 obstack_grow(&pp_obstack, ¶meter, sizeof(parameter));
1545 eat_token(T_IDENTIFIER);
1547 if (pp_token.kind == ',') {
1552 if (pp_token.kind != ')') {
1553 errorf(&pp_token.base.source_position,
1554 "expected ',' or ')' after identifier, got %K",
1563 goto finish_argument_list;
1566 errorf(&pp_token.base.source_position,
1567 "expected identifier, '...' or ')' in #define argument list, got %K",
1573 finish_argument_list:
1574 new_definition->has_parameters = true;
1575 size_t size = obstack_object_size(&pp_obstack);
1576 new_definition->n_parameters
1577 = size / sizeof(new_definition->parameters[0]);
1578 new_definition->parameters = obstack_finish(&pp_obstack);
1579 for (size_t i = 0; i < new_definition->n_parameters; ++i) {
1580 pp_definition_t *param = &new_definition->parameters[i];
1581 symbol_t *symbol = param->symbol;
1582 pp_definition_t *previous = symbol->pp_definition;
1583 if (previous != NULL
1584 && previous->function_definition == new_definition) {
1585 errorf(¶m->source_position,
1586 "duplicate macro parameter '%Y'", symbol);
1587 param->symbol = sym_anonymous;
1590 param->parent_expansion = previous;
1591 param->function_definition = new_definition;
1592 symbol->pp_definition = param;
1595 eat_token(T_IDENTIFIER);
1598 /* construct token list */
1599 assert(obstack_object_size(&pp_obstack) == 0);
1600 while (!info.at_line_begin) {
1601 if (pp_token.kind == T_IDENTIFIER) {
1602 const symbol_t *symbol = pp_token.base.symbol;
1603 pp_definition_t *definition = symbol->pp_definition;
1604 if (definition != NULL
1605 && definition->function_definition == new_definition) {
1606 pp_token.kind = T_MACRO_PARAMETER;
1607 pp_token.macro_parameter.def = definition;
1610 saved_token_t saved_token;
1611 saved_token.token = pp_token;
1612 saved_token.had_whitespace = info.had_whitespace;
1613 obstack_grow(&pp_obstack, &saved_token, sizeof(saved_token));
1617 new_definition->list_len = obstack_object_size(&pp_obstack)
1618 / sizeof(new_definition->token_list[0]);
1619 new_definition->token_list = obstack_finish(&pp_obstack);
1621 if (new_definition->has_parameters) {
1622 for (size_t i = 0; i < new_definition->n_parameters; ++i) {
1623 pp_definition_t *param = &new_definition->parameters[i];
1624 symbol_t *symbol = param->symbol;
1625 if (symbol == sym_anonymous)
1627 assert(symbol->pp_definition == param);
1628 assert(param->function_definition == new_definition);
1629 symbol->pp_definition = param->parent_expansion;
1630 param->parent_expansion = NULL;
1634 pp_definition_t *old_definition = symbol->pp_definition;
1635 if (old_definition != NULL) {
1636 if (!pp_definitions_equal(old_definition, new_definition)) {
1637 warningf(WARN_OTHER, &input.position, "multiple definition of macro '%Y' (first defined %P)", symbol, &old_definition->source_position);
1639 /* reuse the old definition */
1640 obstack_free(&pp_obstack, new_definition);
1641 new_definition = old_definition;
1645 symbol->pp_definition = new_definition;
1649 if (obstack_object_size(&pp_obstack) > 0) {
1650 char *ptr = obstack_finish(&pp_obstack);
1651 obstack_free(&pp_obstack, ptr);
1656 static void parse_undef_directive(void)
1664 if (pp_token.kind != T_IDENTIFIER) {
1665 errorf(&input.position,
1666 "expected identifier after #undef, got %K", &pp_token);
1671 pp_token.base.symbol->pp_definition = NULL;
1672 eat_token(T_IDENTIFIER);
1674 if (!info.at_line_begin) {
1675 warningf(WARN_OTHER, &input.position, "extra tokens at end of #undef directive");
1680 /** behind an #include we can have the special headername lexems.
1681 * They're only allowed behind an #include so they're not recognized
1682 * by the normal next_preprocessing_token. We handle them as a special
1684 static void parse_headername(void)
1686 const source_position_t start_position = input.position;
1687 string_t string = { NULL, 0, STRING_ENCODING_CHAR };
1688 assert(obstack_object_size(&symbol_obstack) == 0);
1690 if (info.at_line_begin) {
1691 parse_error("expected headername after #include");
1695 /* check wether we have a "... or <... headername */
1699 case '<': delimiter = '>'; goto parse_name;
1700 case '"': delimiter = '"'; goto parse_name;
1707 errorf(&pp_token.base.source_position, "header name without closing '%c'", (char)delimiter);
1711 if (input.c == delimiter) {
1713 goto finished_headername;
1715 obstack_1grow(&symbol_obstack, (char)input.c);
1721 /* we should never be here */
1725 /* TODO: do normal pp_token parsing and concatenate results */
1726 panic("pp_token concat include not implemented yet");
1729 finished_headername:
1730 string = sym_make_string(STRING_ENCODING_CHAR);
1733 pp_token.base.source_position = start_position;
1734 pp_token.kind = T_HEADERNAME;
1735 pp_token.literal.string = string;
1738 static bool do_include(bool system_include, const char *headername)
1740 size_t headername_len = strlen(headername);
1741 if (!system_include) {
1742 /* put dirname of current input on obstack */
1743 const char *filename = input.position.input_name;
1744 const char *last_slash = strrchr(filename, '/');
1745 if (last_slash != NULL) {
1746 size_t len = last_slash - filename;
1747 obstack_grow(&symbol_obstack, filename, len + 1);
1748 obstack_grow0(&symbol_obstack, headername, headername_len);
1749 char *complete_path = obstack_finish(&symbol_obstack);
1750 headername = identify_string(complete_path);
1753 FILE *file = fopen(headername, "r");
1755 switch_input(file, headername);
1760 assert(obstack_object_size(&symbol_obstack) == 0);
1761 /* check searchpath */
1762 for (searchpath_entry_t *entry = searchpath; entry != NULL;
1763 entry = entry->next) {
1764 const char *path = entry->path;
1765 size_t len = strlen(path);
1766 obstack_grow(&symbol_obstack, path, len);
1767 if (path[len-1] != '/')
1768 obstack_1grow(&symbol_obstack, '/');
1769 obstack_grow(&symbol_obstack, headername, headername_len+1);
1771 char *complete_path = obstack_finish(&symbol_obstack);
1772 FILE *file = fopen(complete_path, "r");
1774 const char *filename = identify_string(complete_path);
1775 switch_input(file, filename);
1778 obstack_free(&symbol_obstack, complete_path);
1785 static void parse_include_directive(void)
1792 /* don't eat the TP_include here!
1793 * we need an alternative parsing for the next token */
1794 skip_till_newline(true);
1795 bool system_include = input.c == '<';
1797 string_t headername = pp_token.literal.string;
1798 if (headername.begin == NULL) {
1803 bool had_nonwhitespace = skip_till_newline(false);
1804 if (had_nonwhitespace) {
1805 warningf(WARN_OTHER, &pp_token.base.source_position,
1806 "extra tokens at end of #include directive");
1809 if (n_inputs > INCLUDE_LIMIT) {
1810 errorf(&pp_token.base.source_position, "#include nested too deeply");
1817 info.whitespace_at_line_begin = 0;
1818 info.had_whitespace = false;
1819 info.at_line_begin = true;
1822 bool res = do_include(system_include, pp_token.literal.string.begin);
1826 errorf(&pp_token.base.source_position, "failed including '%S': %s", &pp_token.literal.string, strerror(errno));
1827 pop_restore_input();
1831 static pp_conditional_t *push_conditional(void)
1833 pp_conditional_t *conditional
1834 = obstack_alloc(&pp_obstack, sizeof(*conditional));
1835 memset(conditional, 0, sizeof(*conditional));
1837 conditional->parent = conditional_stack;
1838 conditional_stack = conditional;
1843 static void pop_conditional(void)
1845 assert(conditional_stack != NULL);
1846 conditional_stack = conditional_stack->parent;
1849 static void check_unclosed_conditionals(void)
1851 while (conditional_stack != NULL) {
1852 pp_conditional_t *conditional = conditional_stack;
1854 if (conditional->in_else) {
1855 errorf(&conditional->source_position, "unterminated #else");
1857 errorf(&conditional->source_position, "unterminated condition");
1863 static void parse_ifdef_ifndef_directive(bool const is_ifdef)
1866 eat_pp(is_ifdef ? TP_ifdef : TP_ifndef);
1870 pp_conditional_t *conditional = push_conditional();
1871 conditional->source_position = pp_token.base.source_position;
1872 conditional->skip = true;
1876 if (pp_token.kind != T_IDENTIFIER || info.at_line_begin) {
1877 errorf(&pp_token.base.source_position,
1878 "expected identifier after #%s, got %K",
1879 is_ifdef ? "ifdef" : "ifndef", &pp_token);
1882 /* just take the true case in the hope to avoid further errors */
1885 /* evaluate wether we are in true or false case */
1886 condition = (bool)pp_token.base.symbol->pp_definition == is_ifdef;
1887 eat_token(T_IDENTIFIER);
1889 if (!info.at_line_begin) {
1890 errorf(&pp_token.base.source_position,
1891 "extra tokens at end of #%s",
1892 is_ifdef ? "ifdef" : "ifndef");
1897 pp_conditional_t *conditional = push_conditional();
1898 conditional->source_position = pp_token.base.source_position;
1899 conditional->condition = condition;
1906 static void parse_else_directive(void)
1910 if (!info.at_line_begin) {
1912 warningf(WARN_OTHER, &pp_token.base.source_position, "extra tokens at end of #else");
1917 pp_conditional_t *conditional = conditional_stack;
1918 if (conditional == NULL) {
1919 errorf(&pp_token.base.source_position, "#else without prior #if");
1923 if (conditional->in_else) {
1924 errorf(&pp_token.base.source_position,
1925 "#else after #else (condition started %P)",
1926 &conditional->source_position);
1931 conditional->in_else = true;
1932 if (!conditional->skip) {
1933 skip_mode = conditional->condition;
1935 conditional->source_position = pp_token.base.source_position;
1938 static void parse_endif_directive(void)
1942 if (!info.at_line_begin) {
1944 warningf(WARN_OTHER, &pp_token.base.source_position, "extra tokens at end of #endif");
1949 pp_conditional_t *conditional = conditional_stack;
1950 if (conditional == NULL) {
1951 errorf(&pp_token.base.source_position, "#endif without prior #if");
1955 if (!conditional->skip) {
1961 typedef enum stdc_pragma_kind_t {
1965 STDC_CX_LIMITED_RANGE
1966 } stdc_pragma_kind_t;
1968 typedef enum stdc_pragma_value_kind_t {
1973 } stdc_pragma_value_kind_t;
1975 static void parse_pragma_directive(void)
1979 if (pp_token.kind != T_IDENTIFIER) {
1980 warningf(WARN_UNKNOWN_PRAGMAS, &pp_token.base.source_position,
1981 "expected identifier after #pragma");
1986 stdc_pragma_kind_t kind = STDC_UNKNOWN;
1987 if (pp_token.base.symbol->pp_ID == TP_STDC && c_mode & _C99) {
1991 switch (pp_token.base.symbol->pp_ID) {
1992 case TP_FP_CONTRACT: kind = STDC_FP_CONTRACT; break;
1993 case TP_FENV_ACCESS: kind = STDC_FENV_ACCESS; break;
1994 case TP_CX_LIMITED_RANGE: kind = STDC_CX_LIMITED_RANGE; break;
1997 if (kind != STDC_UNKNOWN) {
1999 stdc_pragma_value_kind_t value;
2000 switch (pp_token.base.symbol->pp_ID) {
2001 case TP_ON: value = STDC_VALUE_ON; break;
2002 case TP_OFF: value = STDC_VALUE_OFF; break;
2003 case TP_DEFAULT: value = STDC_VALUE_DEFAULT; break;
2004 default: value = STDC_VALUE_UNKNOWN; break;
2006 if (value == STDC_VALUE_UNKNOWN) {
2007 kind = STDC_UNKNOWN;
2008 errorf(&pp_token.base.source_position, "bad STDC pragma argument");
2013 if (kind == STDC_UNKNOWN) {
2014 warningf(WARN_UNKNOWN_PRAGMAS, &pp_token.base.source_position,
2015 "encountered unknown #pragma");
2019 static void parse_line_directive(void)
2021 if (pp_token.kind != T_NUMBER) {
2023 parse_error("expected integer");
2026 long const line = strtol(pp_token.literal.string.begin, &end, 0);
2028 /* use offset -1 as this is about the next line */
2029 input.position.lineno = line - 1;
2030 /* force output of line */
2031 input.output_line = input.position.lineno - 20;
2034 errorf(&input.position, "'%S' is not a valid line number",
2035 &pp_token.literal.string);
2040 if (pp_token.kind == T_STRING_LITERAL
2041 && pp_token.literal.string.encoding == STRING_ENCODING_CHAR) {
2042 input.position.input_name = pp_token.literal.string.begin;
2043 input.position.is_system_header = false;
2046 /* attempt to parse numeric flags as outputted by gcc preprocessor */
2047 while (pp_token.kind == T_NUMBER) {
2049 * 1 - indicates start of a new file
2050 * 2 - indicates return from a file
2051 * 3 - indicates system header
2052 * 4 - indicates implicit extern "C" in C++ mode
2054 * currently we're only interested in "3"
2056 if (streq(pp_token.literal.string.begin, "3")) {
2057 input.position.is_system_header = true;
2066 static void parse_preprocessing_directive(void)
2070 if (info.at_line_begin) {
2071 /* empty directive */
2075 if (pp_token.base.symbol) {
2076 switch (pp_token.base.symbol->pp_ID) {
2077 case TP_define: parse_define_directive(); break;
2078 case TP_else: parse_else_directive(); break;
2079 case TP_endif: parse_endif_directive(); break;
2080 case TP_ifdef: parse_ifdef_ifndef_directive(true); break;
2081 case TP_ifndef: parse_ifdef_ifndef_directive(false); break;
2082 case TP_include: parse_include_directive(); break;
2083 case TP_line: next_input_token(); goto line_directive;
2084 case TP_pragma: parse_pragma_directive(); break;
2085 case TP_undef: parse_undef_directive(); break;
2088 } else if (pp_token.kind == T_NUMBER) {
2090 parse_line_directive();
2094 errorf(&pp_token.base.source_position, "invalid preprocessing directive #%K", &pp_token);
2099 assert(info.at_line_begin);
2102 static void finish_current_argument(void)
2104 if (current_argument == NULL)
2106 size_t size = obstack_object_size(&pp_obstack);
2107 current_argument->list_len = size/sizeof(current_argument->token_list[0]);
2108 current_argument->token_list = obstack_finish(&pp_obstack);
2111 static void next_preprocessing_token(void)
2114 if (!expand_next()) {
2117 while (pp_token.kind == '#' && info.at_line_begin) {
2118 parse_preprocessing_directive();
2120 } while (skip_mode && pp_token.kind != T_EOF);
2123 const token_kind_t kind = pp_token.kind;
2124 if (current_call == NULL || argument_expanding != NULL) {
2125 if (kind == T_IDENTIFIER) {
2126 symbol_t *const symbol = pp_token.base.symbol;
2127 pp_definition_t *const pp_definition = symbol->pp_definition;
2128 if (pp_definition != NULL && !pp_definition->is_expanding) {
2129 if (pp_definition->has_parameters) {
2131 /* check if next token is a '(' */
2132 whitespace_info_t old_info = info;
2133 token_kind_t next_token = peek_expansion();
2134 if (next_token == T_EOF) {
2135 info.at_line_begin = false;
2136 info.had_whitespace = false;
2138 if (input.c == '(') {
2143 if (next_token == '(') {
2144 if (current_expansion == NULL)
2145 expansion_pos = pp_token.base.source_position;
2146 next_preprocessing_token();
2147 assert(pp_token.kind == '(');
2149 pp_definition->parent_expansion = current_expansion;
2150 current_call = pp_definition;
2151 current_call->expand_pos = 0;
2152 current_call->expand_info = old_info;
2153 if (current_call->n_parameters > 0) {
2154 current_argument = ¤t_call->parameters[0];
2155 assert(argument_brace_count == 0);
2159 /* skip_whitespaces() skipped newlines and whitespace,
2160 * remember results for next token */
2166 if (current_expansion == NULL)
2167 expansion_pos = pp_token.base.source_position;
2168 start_expanding(pp_definition);
2172 } else if (kind == T_MACRO_PARAMETER) {
2173 assert(current_expansion != NULL);
2174 start_expanding(pp_token.macro_parameter.def);
2179 if (current_call != NULL) {
2180 /* current_call != NULL */
2182 ++argument_brace_count;
2183 } else if (kind == ')') {
2184 if (argument_brace_count > 0) {
2185 --argument_brace_count;
2187 finish_current_argument();
2188 assert(kind == ')');
2189 start_expanding(current_call);
2190 info = current_call->expand_info;
2191 current_call = NULL;
2192 current_argument = NULL;
2195 } else if (kind == ',' && argument_brace_count == 0) {
2196 finish_current_argument();
2197 current_call->expand_pos++;
2198 if (current_call->expand_pos >= current_call->n_parameters) {
2199 errorf(&pp_token.base.source_position,
2200 "too many arguments passed for macro '%Y'",
2201 current_call->symbol);
2202 current_argument = NULL;
2205 = ¤t_call->parameters[current_call->expand_pos];
2208 } else if (kind == T_MACRO_PARAMETER) {
2209 /* parameters have to be fully expanded before being used as
2210 * parameters for another macro-call */
2211 assert(current_expansion != NULL);
2212 pp_definition_t *argument = pp_token.macro_parameter.def;
2213 argument_expanding = argument;
2214 start_expanding(argument);
2216 } else if (kind == T_EOF) {
2217 errorf(&expansion_pos,
2218 "reached end of file while parsing arguments for '%Y'",
2219 current_call->symbol);
2222 if (current_argument != NULL) {
2223 saved_token_t saved;
2224 saved.token = pp_token;
2225 saved.had_whitespace = info.had_whitespace;
2226 obstack_grow(&pp_obstack, &saved, sizeof(saved));
2233 static void prepend_include_path(const char *path)
2235 searchpath_entry_t *entry = OALLOCZ(&config_obstack, searchpath_entry_t);
2237 entry->next = searchpath;
2241 static void setup_include_path(void)
2243 /* built-in paths */
2244 prepend_include_path("/usr/include");
2246 /* parse environment variable */
2247 const char *cpath = getenv("CPATH");
2248 if (cpath != NULL && *cpath != '\0') {
2249 const char *begin = cpath;
2253 while (*c != '\0' && *c != ':')
2256 size_t len = c-begin;
2258 /* for gcc compatibility (Matze: I would expect that
2259 * nothing happens for an empty entry...) */
2260 prepend_include_path(".");
2262 char *string = obstack_alloc(&config_obstack, len+1);
2263 memcpy(string, begin, len);
2266 prepend_include_path(string);
2273 } while(*c != '\0');
2277 int pptest_main(int argc, char **argv);
2278 int pptest_main(int argc, char **argv)
2280 init_symbol_table();
2284 obstack_init(&config_obstack);
2285 obstack_init(&pp_obstack);
2286 obstack_init(&input_obstack);
2287 strset_init(&stringset);
2289 error_on_unknown_chars = false;
2291 setup_include_path();
2293 /* simplistic commandline parser */
2294 const char *filename = NULL;
2295 const char *output = NULL;
2296 for (int i = 1; i < argc; ++i) {
2297 const char *opt = argv[i];
2298 if (streq(opt, "-I")) {
2299 prepend_include_path(argv[++i]);
2301 } else if (streq(opt, "-E")) {
2303 } else if (streq(opt, "-o")) {
2306 } else if (opt[0] == '-') {
2307 fprintf(stderr, "Unknown option '%s'\n", opt);
2309 if (filename != NULL)
2310 fprintf(stderr, "Multiple inputs not supported\n");
2314 if (filename == NULL) {
2315 fprintf(stderr, "No input specified\n");
2319 if (output == NULL) {
2322 out = fopen(output, "w");
2324 fprintf(stderr, "Couldn't open output '%s'\n", output);
2329 /* just here for gcc compatibility */
2330 fprintf(out, "# 1 \"%s\"\n", filename);
2331 fprintf(out, "# 1 \"<built-in>\"\n");
2332 fprintf(out, "# 1 \"<command-line>\"\n");
2334 FILE *file = fopen(filename, "r");
2336 fprintf(stderr, "Couldn't open input '%s'\n", filename);
2339 switch_input(file, filename);
2342 next_preprocessing_token();
2343 if (pp_token.kind == T_EOF)
2349 check_unclosed_conditionals();
2354 obstack_free(&input_obstack, NULL);
2355 obstack_free(&pp_obstack, NULL);
2356 obstack_free(&config_obstack, NULL);
2358 strset_destroy(&stringset);
2361 exit_symbol_table();