7 #include "lang_features.h"
8 #include "diagnostic.h"
9 #include "string_rep.h"
19 #define INCLUDE_LIMIT 199 /* 199 is for gcc "compatibility" */
21 struct pp_definition_t {
23 source_position_t source_position;
24 pp_definition_t *parent_expansion;
27 bool is_expanding : 1;
28 bool has_arguments : 1;
32 token_t *replacement_list;
35 typedef struct pp_conditional_t pp_conditional_t;
36 struct pp_conditional_t {
37 source_position_t source_position;
40 bool skip; /**< conditional in skip mode (then+else gets skipped) */
41 pp_conditional_t *parent;
44 typedef struct pp_input_t pp_input_t;
48 char buf[1024+MAX_PUTBACK];
51 source_position_t position;
59 static pp_input_t *input_stack;
60 static unsigned n_inputs;
61 static struct obstack input_obstack;
63 static pp_conditional_t *conditional_stack;
66 static bool resolve_escape_sequences = false;
67 static bool do_print_spaces = true;
68 static bool do_expansions;
69 static bool skip_mode;
71 static struct obstack pp_obstack;
72 static unsigned counted_newlines;
73 static unsigned counted_spaces;
74 static const char *printed_input_name = NULL;
75 static pp_definition_t *current_expansion = NULL;
77 static inline void next_char(void);
78 static void next_preprocessing_token(void);
79 static void print_line_directive(const source_position_t *pos, const char *add);
80 static void print_spaces(void);
82 static bool open_input(const char *filename)
84 FILE *file = fopen(filename, "r");
91 input.had_non_space = false;
92 input.position.input_name = filename;
93 input.position.linenr = 1;
95 /* indicate that we're at a new input */
96 print_line_directive(&input.position, input_stack != NULL ? "1" : NULL);
101 /* read first char and first token */
103 next_preprocessing_token();
108 static void close_input(void)
110 /* ensure we have a newline at EOF */
111 if (input.had_non_space) {
115 assert(input.file != NULL);
124 static void push_input(void)
126 pp_input_t *saved_input
127 = obstack_alloc(&input_obstack, sizeof(*saved_input));
129 memcpy(saved_input, &input, sizeof(*saved_input));
131 /* adjust buffer positions */
132 if (input.bufpos != NULL)
133 saved_input->bufpos = saved_input->buf + (input.bufpos - input.buf);
134 if (input.bufend != NULL)
135 saved_input->bufend = saved_input->buf + (input.bufend - input.buf);
137 saved_input->parent = input_stack;
138 input_stack = saved_input;
142 static void pop_restore_input(void)
144 assert(n_inputs > 0);
145 assert(input_stack != NULL);
147 pp_input_t *saved_input = input_stack;
149 memcpy(&input, saved_input, sizeof(input));
152 /* adjust buffer positions */
153 if (saved_input->bufpos != NULL)
154 input.bufpos = input.buf + (saved_input->bufpos - saved_input->buf);
155 if (saved_input->bufend != NULL)
156 input.bufend = input.buf + (saved_input->bufend - saved_input->buf);
158 input_stack = saved_input->parent;
159 obstack_free(&input_obstack, saved_input);
164 * Prints a parse error message at the current token.
166 * @param msg the error message
168 static void parse_error(const char *msg)
170 errorf(&pp_token.source_position, "%s", msg);
173 static inline void next_real_char(void)
175 assert(input.bufpos <= input.bufend);
176 if (input.bufpos >= input.bufend) {
177 size_t s = fread(input.buf + MAX_PUTBACK, 1,
178 sizeof(input.buf) - MAX_PUTBACK, input.file);
183 input.bufpos = input.buf + MAX_PUTBACK;
184 input.bufend = input.buf + MAX_PUTBACK + s;
186 CC = *input.bufpos++;
190 * Put a character back into the buffer.
192 * @param pc the character to put back
194 static inline void put_back(int pc)
196 assert(input.bufpos > input.buf);
197 *(--input.bufpos - input.buf + input.buf) = (char) pc;
200 printf("putback '%c'\n", pc);
204 #define MATCH_NEWLINE(code) \
210 ++input.position.linenr; \
214 ++input.position.linenr; \
217 #define eat(c_type) do { assert(CC == c_type); next_char(); } while(0)
219 static void maybe_concat_lines(void)
224 MATCH_NEWLINE(return;)
235 * Set c to the next input character, ie.
236 * after expanding trigraphs.
238 static inline void next_char(void)
242 /* filter trigraphs and concatenated lines */
243 if(UNLIKELY(CC == '\\')) {
244 maybe_concat_lines();
245 goto end_of_next_char;
248 if(LIKELY(CC != '?'))
249 goto end_of_next_char;
252 if(LIKELY(CC != '?')) {
255 goto end_of_next_char;
260 case '=': CC = '#'; break;
261 case '(': CC = '['; break;
262 case '/': CC = '\\'; maybe_concat_lines(); break;
263 case ')': CC = ']'; break;
264 case '\'': CC = '^'; break;
265 case '<': CC = '{'; break;
266 case '!': CC = '|'; break;
267 case '>': CC = '}'; break;
268 case '-': CC = '~'; break;
278 printf("nchar '%c'\n", CC);
285 * Returns true if the given char is a octal digit.
287 * @param char the character to check
289 static inline bool is_octal_digit(int chr)
307 * Returns the value of a digit.
308 * The only portable way to do it ...
310 static int digit_value(int digit) {
335 panic("wrong character given");
340 * Parses an octal character sequence.
342 * @param first_digit the already read first digit
344 static int parse_octal_sequence(const int first_digit)
346 assert(is_octal_digit(first_digit));
347 int value = digit_value(first_digit);
348 if (!is_octal_digit(CC)) return value;
349 value = 8 * value + digit_value(CC);
351 if (!is_octal_digit(CC)) return value;
352 value = 8 * value + digit_value(CC);
356 return (signed char) value;
358 return (unsigned char) value;
363 * Parses a hex character sequence.
365 static int parse_hex_sequence(void)
368 while(isxdigit(CC)) {
369 value = 16 * value + digit_value(CC);
374 return (signed char) value;
376 return (unsigned char) value;
381 * Parse an escape sequence.
383 static int parse_escape_sequence(void)
391 case '"': return '"';
392 case '\'': return '\'';
393 case '\\': return '\\';
394 case '?': return '\?';
395 case 'a': return '\a';
396 case 'b': return '\b';
397 case 'f': return '\f';
398 case 'n': return '\n';
399 case 'r': return '\r';
400 case 't': return '\t';
401 case 'v': return '\v';
403 return parse_hex_sequence();
412 return parse_octal_sequence(ec);
414 parse_error("reached end of file while parsing escape sequence");
417 parse_error("unknown escape sequence");
422 static void parse_string_literal(void)
424 const unsigned start_linenr = input.position.linenr;
432 if(resolve_escape_sequences) {
433 tc = parse_escape_sequence();
434 obstack_1grow(&symbol_obstack, (char) tc);
436 obstack_1grow(&symbol_obstack, (char) CC);
438 obstack_1grow(&symbol_obstack, (char) CC);
444 source_position_t source_position;
445 source_position.input_name = pp_token.source_position.input_name;
446 source_position.linenr = start_linenr;
447 errorf(&source_position, "string has no end");
448 pp_token.type = TP_ERROR;
457 obstack_1grow(&symbol_obstack, (char) CC);
464 /* add finishing 0 to the string */
465 obstack_1grow(&symbol_obstack, '\0');
466 const size_t size = (size_t)obstack_object_size(&symbol_obstack);
467 const char *const string = obstack_finish(&symbol_obstack);
469 #if 0 /* TODO hash */
470 /* check if there is already a copy of the string */
471 result = strset_insert(&stringset, string);
472 if(result != string) {
473 obstack_free(&symbol_obstack, string);
476 const char *const result = string;
479 pp_token.type = TP_STRING_LITERAL;
480 pp_token.v.string.begin = result;
481 pp_token.v.string.size = size;
484 static void parse_wide_character_constant(void)
492 found_char = parse_escape_sequence();
496 parse_error("newline while parsing character constant");
502 goto end_of_wide_char_constant;
505 parse_error("EOF while parsing character constant");
506 pp_token.type = TP_ERROR;
510 if(found_char != 0) {
511 parse_error("more than 1 characters in character "
513 goto end_of_wide_char_constant;
522 end_of_wide_char_constant:
523 pp_token.type = TP_WIDE_CHARACTER_CONSTANT;
527 static void parse_wide_string_literal(void)
529 const unsigned start_linenr = input.position.linenr;
537 wchar_rep_t tc = parse_escape_sequence();
538 obstack_grow(&symbol_obstack, &tc, sizeof(tc));
543 source_position_t source_position;
544 source_position.input_name = pp_token.source_position.input_name;
545 source_position.linenr = start_linenr;
546 errorf(&source_position, "string has no end");
547 pp_token.type = TP_ERROR;
557 obstack_grow(&symbol_obstack, &tc, sizeof(tc));
565 /* add finishing 0 to the string */
566 static const wchar_rep_t nul = L'\0';
567 obstack_grow(&symbol_obstack, &nul, sizeof(nul));
570 = (size_t)obstack_object_size(&symbol_obstack) / sizeof(wchar_rep_t);
571 const wchar_rep_t *const string = obstack_finish(&symbol_obstack);
573 #if 0 /* TODO hash */
574 /* check if there is already a copy of the string */
575 const wchar_rep_t *const result = strset_insert(&stringset, string);
576 if(result != string) {
577 obstack_free(&symbol_obstack, string);
580 const wchar_rep_t *const result = string;
583 pp_token.type = TP_WIDE_STRING_LITERAL;
584 pp_token.v.wide_string.begin = result;
585 pp_token.v.wide_string.size = size;
588 static void parse_character_constant(void)
590 const unsigned start_linenr = input.position.linenr;
598 tc = parse_escape_sequence();
599 obstack_1grow(&symbol_obstack, (char) tc);
603 parse_error("newline while parsing character constant");
608 source_position_t source_position;
609 source_position.input_name = pp_token.source_position.input_name;
610 source_position.linenr = start_linenr;
611 errorf(&source_position, "EOF while parsing character constant");
612 pp_token.type = TP_ERROR;
618 goto end_of_char_constant;
621 obstack_1grow(&symbol_obstack, (char) CC);
628 end_of_char_constant:;
629 const size_t size = (size_t)obstack_object_size(&symbol_obstack);
630 const char *const string = obstack_finish(&symbol_obstack);
632 pp_token.type = TP_CHARACTER_CONSTANT;
633 pp_token.v.string.begin = string;
634 pp_token.v.string.size = size;
637 #define SYMBOL_CHARS_WITHOUT_E_P \
688 #define SYMBOL_CHARS \
689 SYMBOL_CHARS_WITHOUT_E_P \
708 * returns next final token from a preprocessor macro expansion
710 static void expand_next(void)
712 assert(current_expansion != NULL);
714 pp_definition_t *definition = current_expansion;
717 if(definition->list_len == 0
718 || definition->expand_pos >= definition->list_len) {
719 /* we're finished with the current macro, move up 1 level in the
721 pp_definition_t *parent = definition->parent_expansion;
722 definition->parent_expansion = NULL;
723 definition->is_expanding = false;
725 /* it was the outermost expansion, parse normal pptoken */
727 current_expansion = NULL;
728 next_preprocessing_token();
732 current_expansion = definition;
735 pp_token = definition->replacement_list[definition->expand_pos];
736 ++definition->expand_pos;
738 if(pp_token.type != TP_IDENTIFIER)
741 /* if it was an identifier then we might need to expand again */
742 pp_definition_t *symbol_definition = pp_token.v.symbol->pp_definition;
743 if(symbol_definition != NULL && !symbol_definition->is_expanding) {
744 symbol_definition->parent_expansion = definition;
745 symbol_definition->expand_pos = 0;
746 symbol_definition->is_expanding = true;
747 definition = symbol_definition;
748 current_expansion = definition;
753 static void parse_symbol(void)
755 obstack_1grow(&symbol_obstack, (char) CC);
762 obstack_1grow(&symbol_obstack, (char) CC);
772 obstack_1grow(&symbol_obstack, '\0');
773 char *string = obstack_finish(&symbol_obstack);
775 /* might be a wide string or character constant ( L"string"/L'c' ) */
776 if(CC == '"' && string[0] == 'L' && string[1] == '\0') {
777 obstack_free(&symbol_obstack, string);
778 parse_wide_string_literal();
780 } else if(CC == '\'' && string[0] == 'L' && string[1] == '\0') {
781 obstack_free(&symbol_obstack, string);
782 parse_wide_character_constant();
786 symbol_t *symbol = symbol_table_insert(string);
788 pp_token.type = symbol->pp_ID;
789 pp_token.v.symbol = symbol;
791 /* we can free the memory from symbol obstack if we already had an entry in
792 * the symbol table */
793 if(symbol->string != string) {
794 obstack_free(&symbol_obstack, string);
797 pp_definition_t *pp_definition = symbol->pp_definition;
798 if(do_expansions && pp_definition != NULL) {
799 pp_definition->expand_pos = 0;
800 pp_definition->is_expanding = true,
801 current_expansion = pp_definition;
806 static void parse_number(void)
808 obstack_1grow(&symbol_obstack, (char) CC);
815 SYMBOL_CHARS_WITHOUT_E_P
816 obstack_1grow(&symbol_obstack, (char) CC);
824 obstack_1grow(&symbol_obstack, (char) CC);
826 if(CC == '+' || CC == '-') {
827 obstack_1grow(&symbol_obstack, (char) CC);
838 obstack_1grow(&symbol_obstack, '\0');
839 size_t size = obstack_object_size(&symbol_obstack);
840 char *string = obstack_finish(&symbol_obstack);
842 pp_token.type = TP_NUMBER;
843 pp_token.v.string.begin = string;
844 pp_token.v.string.size = size;
847 static void skip_multiline_comment(void)
852 unsigned start_linenr = input.position.linenr;
858 /* TODO: nested comment, warn here */
870 if(do_print_spaces) {
878 source_position_t source_position;
879 source_position.input_name = pp_token.source_position.input_name;
880 source_position.linenr = start_linenr;
881 errorf(&source_position, "at end of file while looking for comment end");
892 static void skip_line_comment(void)
915 #define MAYBE_PROLOG \
920 #define MAYBE(ch, set_type) \
923 pp_token.type = set_type; \
926 #define ELSE_CODE(code) \
930 } /* end of while(1) */ \
933 #define ELSE(set_type) \
935 pp_token.type = set_type; \
939 static void next_preprocessing_token(void)
941 if(current_expansion != NULL) {
946 pp_token.source_position = input.position;
960 pp_token.type = '\n';
973 parse_string_literal();
977 parse_character_constant();
999 MAYBE('.', TP_DOTDOTDOT)
1003 pp_token.type = '.';
1009 MAYBE('&', TP_ANDAND)
1010 MAYBE('=', TP_ANDEQUAL)
1014 MAYBE('=', TP_ASTERISKEQUAL)
1018 MAYBE('+', TP_PLUSPLUS)
1019 MAYBE('=', TP_PLUSEQUAL)
1023 MAYBE('>', TP_MINUSGREATER)
1024 MAYBE('-', TP_MINUSMINUS)
1025 MAYBE('=', TP_MINUSEQUAL)
1029 MAYBE('=', TP_EXCLAMATIONMARKEQUAL)
1033 MAYBE('=', TP_SLASHEQUAL)
1036 skip_multiline_comment();
1040 skip_line_comment();
1046 MAYBE('=', TP_PERCENTEQUAL)
1051 MAYBE(':', TP_HASHHASH)
1055 pp_token.type = '#';
1064 MAYBE('=', TP_LESSEQUAL)
1067 MAYBE('=', TP_LESSLESSEQUAL)
1072 MAYBE('=', TP_GREATEREQUAL)
1075 MAYBE('=', TP_GREATERGREATEREQUAL)
1076 ELSE(TP_GREATERGREATER)
1080 MAYBE('=', TP_CARETEQUAL)
1084 MAYBE('=', TP_PIPEEQUAL)
1085 MAYBE('|', TP_PIPEPIPE)
1093 MAYBE('=', TP_EQUALEQUAL)
1097 MAYBE('#', TP_HASHHASH)
1116 if (input_stack != NULL) {
1118 pop_restore_input();
1119 counted_newlines = 0;
1121 /* hack to output correct line number */
1122 print_line_directive(&input.position, "2");
1123 next_preprocessing_token();
1125 pp_token.type = TP_EOF;
1131 errorf(&pp_token.source_position, "unknown character '%c' found\n", CC);
1132 pp_token.type = TP_ERROR;
1137 static void print_quoted_string(const char *const string)
1140 for (const char *c = string; *c != 0; ++c) {
1142 case '"': fputs("\\\"", out); break;
1143 case '\\': fputs("\\\\", out); break;
1144 case '\a': fputs("\\a", out); break;
1145 case '\b': fputs("\\b", out); break;
1146 case '\f': fputs("\\f", out); break;
1147 case '\n': fputs("\\n", out); break;
1148 case '\r': fputs("\\r", out); break;
1149 case '\t': fputs("\\t", out); break;
1150 case '\v': fputs("\\v", out); break;
1151 case '\?': fputs("\\?", out); break;
1154 fprintf(out, "\\%03o", *c);
1164 static void print_line_directive(const source_position_t *pos, const char *add)
1166 fprintf(out, "# %d ", pos->linenr);
1167 print_quoted_string(pos->input_name);
1174 printed_input_name = pos->input_name;
1177 static void print_spaces(void)
1179 if (counted_newlines >= 8) {
1180 if (input.had_non_space) {
1183 print_line_directive(&pp_token.source_position, NULL);
1184 counted_newlines = 0;
1186 for (unsigned i = 0; i < counted_newlines; ++i)
1188 counted_newlines = 0;
1190 for (unsigned i = 0; i < counted_spaces; ++i)
1195 static void emit_pp_token(void)
1200 if (pp_token.type != '\n') {
1202 input.had_non_space = true;
1205 switch(pp_token.type) {
1207 fputs(pp_token.v.symbol->string, out);
1210 fputs(pp_token.v.string.begin, out);
1212 case TP_STRING_LITERAL:
1214 fputs(pp_token.v.string.begin, out);
1220 print_pp_token_type(out, pp_token.type);
1225 static void eat_pp(preprocessor_token_type_t type)
1228 assert(pp_token.type == type);
1229 next_preprocessing_token();
1232 static void eat_pp_directive(void)
1234 while(pp_token.type != '\n' && pp_token.type != TP_EOF) {
1235 next_preprocessing_token();
1239 static bool strings_equal(const string_t *string1, const string_t *string2)
1241 size_t size = string1->size;
1242 if(size != string2->size)
1245 const char *c1 = string1->begin;
1246 const char *c2 = string2->begin;
1247 for(size_t i = 0; i < size; ++i, ++c1, ++c2) {
1254 static bool wide_strings_equal(const wide_string_t *string1,
1255 const wide_string_t *string2)
1257 size_t size = string1->size;
1258 if(size != string2->size)
1261 const wchar_rep_t *c1 = string1->begin;
1262 const wchar_rep_t *c2 = string2->begin;
1263 for(size_t i = 0; i < size; ++i, ++c1, ++c2) {
1270 static bool pp_tokens_equal(const token_t *token1, const token_t *token2)
1272 if(token1->type != token2->type)
1275 switch(token1->type) {
1280 return token1->v.symbol == token2->v.symbol;
1282 case TP_CHARACTER_CONSTANT:
1283 case TP_STRING_LITERAL:
1284 return strings_equal(&token1->v.string, &token2->v.string);
1286 case TP_WIDE_CHARACTER_CONSTANT:
1287 case TP_WIDE_STRING_LITERAL:
1288 return wide_strings_equal(&token1->v.wide_string,
1289 &token2->v.wide_string);
1295 static bool pp_definitions_equal(const pp_definition_t *definition1,
1296 const pp_definition_t *definition2)
1298 if(definition1->list_len != definition2->list_len)
1301 size_t len = definition1->list_len;
1302 const token_t *t1 = definition1->replacement_list;
1303 const token_t *t2 = definition2->replacement_list;
1304 for(size_t i = 0; i < len; ++i, ++t1, ++t2) {
1305 if(!pp_tokens_equal(t1, t2))
1311 static void parse_define_directive(void)
1314 assert(obstack_object_size(&pp_obstack) == 0);
1316 if (pp_token.type != TP_IDENTIFIER) {
1317 errorf(&pp_token.source_position,
1318 "expected identifier after #define, got '%t'", &pp_token);
1321 symbol_t *symbol = pp_token.v.symbol;
1323 pp_definition_t *new_definition
1324 = obstack_alloc(&pp_obstack, sizeof(new_definition[0]));
1325 memset(new_definition, 0, sizeof(new_definition[0]));
1326 new_definition->source_position = input.position;
1328 /* this is probably the only place where spaces are significant in the
1329 * lexer (except for the fact that they separate tokens). #define b(x)
1330 * is something else than #define b (x) */
1333 next_preprocessing_token();
1334 /* get next token after '(' */
1335 next_preprocessing_token();
1338 switch (pp_token.type) {
1340 new_definition->is_variadic = true;
1341 next_preprocessing_token();
1342 if (pp_token.type != ')') {
1343 errorf(&input.position,
1344 "'...' not at end of macro argument list");
1349 obstack_ptr_grow(&pp_obstack, pp_token.v.symbol);
1350 next_preprocessing_token();
1352 if (pp_token.type == ',') {
1353 next_preprocessing_token();
1357 if (pp_token.type != ')') {
1358 errorf(&pp_token.source_position,
1359 "expected ',' or ')' after identifier, got '%t'",
1365 goto finish_argument_list;
1367 errorf(&pp_token.source_position,
1368 "expected identifier, '...' or ')' in #define argument list, got '%t'",
1374 finish_argument_list:
1375 new_definition->has_arguments = true;
1376 new_definition->n_arguments
1377 = obstack_object_size(&pp_obstack) / sizeof(new_definition->arguments[0]);
1378 new_definition->arguments = obstack_finish(&pp_obstack);
1380 next_preprocessing_token();
1383 /* construct a new pp_definition on the obstack */
1384 assert(obstack_object_size(&pp_obstack) == 0);
1385 size_t list_len = 0;
1386 while (pp_token.type != '\n' && pp_token.type != TP_EOF) {
1387 obstack_grow(&pp_obstack, &pp_token, sizeof(pp_token));
1389 next_preprocessing_token();
1392 new_definition->list_len = list_len;
1393 new_definition->replacement_list = obstack_finish(&pp_obstack);
1395 pp_definition_t *old_definition = symbol->pp_definition;
1396 if (old_definition != NULL) {
1397 if (!pp_definitions_equal(old_definition, new_definition)) {
1398 warningf(&input.position, "multiple definition of macro '%Y' (first defined %P)",
1399 symbol, &old_definition->source_position);
1401 /* reuse the old definition */
1402 obstack_free(&pp_obstack, new_definition);
1403 new_definition = old_definition;
1407 symbol->pp_definition = new_definition;
1411 if (obstack_object_size(&pp_obstack) > 0) {
1412 char *ptr = obstack_finish(&pp_obstack);
1413 obstack_free(&pp_obstack, ptr);
1418 static void parse_undef_directive(void)
1422 if(pp_token.type != TP_IDENTIFIER) {
1423 errorf(&input.position,
1424 "expected identifier after #undef, got '%t'", &pp_token);
1429 symbol_t *symbol = pp_token.v.symbol;
1430 symbol->pp_definition = NULL;
1431 next_preprocessing_token();
1433 if(pp_token.type != '\n') {
1434 warningf(&input.position, "extra tokens at end of #undef directive");
1436 /* eat until '\n' */
1440 /* skip spaces advancing at the start of the next preprocessing token */
1441 static void skip_spaces(void)
1455 skip_line_comment();
1457 } else if (CC == '*') {
1459 skip_multiline_comment();
1472 static const char *parse_headername(void)
1474 /* behind an #include we can have the special headername lexems.
1475 * They're only allowed behind an #include so they're not recognized
1476 * by the normal next_preprocessing_token. We handle them as a special
1479 /* skip spaces so we reach start of next preprocessing token */
1482 assert(obstack_object_size(&input_obstack) == 0);
1484 /* check wether we have a "... or <... headername */
1487 /* for now until we have proper searchpath handling */
1488 obstack_1grow(&input_obstack, '.');
1489 obstack_1grow(&input_obstack, '/');
1497 parse_error("header name without closing '>'");
1502 goto finished_headername;
1504 obstack_1grow(&input_obstack, (char) CC);
1507 /* we should never be here */
1510 /* for now until we have proper searchpath handling */
1511 obstack_1grow(&input_obstack, '.');
1512 obstack_1grow(&input_obstack, '/');
1520 parse_error("header name without closing '>'");
1525 goto finished_headername;
1527 obstack_1grow(&input_obstack, (char) CC);
1530 /* we should never be here */
1533 /* TODO: do normale pp_token parsing and concatenate results */
1534 panic("pp_token concat include not implemented yet");
1537 finished_headername:
1538 obstack_1grow(&input_obstack, '\0');
1539 char *headername = obstack_finish(&input_obstack);
1541 /* TODO: iterate search-path to find the file */
1543 next_preprocessing_token();
1548 static bool parse_include_directive(void)
1550 /* don't eat the TP_include here!
1551 * we need an alternative parsing for the next token */
1555 const char *headername = parse_headername();
1556 if (headername == NULL) {
1561 if (pp_token.type != '\n' && pp_token.type != TP_EOF) {
1562 warningf(&pp_token.source_position,
1563 "extra tokens at end of #include directive");
1567 if (n_inputs > INCLUDE_LIMIT) {
1568 errorf(&pp_token.source_position, "#include nested too deeply");
1570 next_preprocessing_token();
1574 /* we have to reenable space counting and macro expansion here,
1575 * because it is still disabled in directive parsing,
1576 * but we will trigger a preprocessing token reading of the new file
1577 * now and need expansions/space counting */
1578 do_print_spaces = true;
1579 do_expansions = true;
1583 bool res = open_input(headername);
1585 errorf(&pp_token.source_position,
1586 "failed including '%s': %s", headername, strerror(errno));
1587 pop_restore_input();
1594 static pp_conditional_t *push_conditional(void)
1596 pp_conditional_t *conditional
1597 = obstack_alloc(&pp_obstack, sizeof(*conditional));
1598 memset(conditional, 0, sizeof(*conditional));
1600 conditional->parent = conditional_stack;
1601 conditional_stack = conditional;
1606 static void pop_conditional(void)
1608 assert(conditional_stack != NULL);
1609 conditional_stack = conditional_stack->parent;
1612 static void check_unclosed_conditionals(void)
1614 while (conditional_stack != NULL) {
1615 pp_conditional_t *conditional = conditional_stack;
1617 if (conditional->in_else) {
1618 errorf(&conditional->source_position, "unterminated #else");
1620 errorf(&conditional->source_position, "unterminated condition");
1626 static void parse_ifdef_ifndef_directive(void)
1628 bool is_ifndef = (pp_token.type == TP_ifndef);
1630 next_preprocessing_token();
1634 pp_conditional_t *conditional = push_conditional();
1635 conditional->source_position = pp_token.source_position;
1636 conditional->skip = true;
1640 if (pp_token.type != TP_IDENTIFIER) {
1641 errorf(&pp_token.source_position,
1642 "expected identifier after #%s, got '%t'",
1643 is_ifndef ? "ifndef" : "ifdef", &pp_token);
1646 /* just take the true case in the hope to avoid further errors */
1649 symbol_t *symbol = pp_token.v.symbol;
1650 pp_definition_t *pp_definition = symbol->pp_definition;
1651 next_preprocessing_token();
1653 if (pp_token.type != '\n') {
1654 errorf(&pp_token.source_position,
1655 "extra tokens at end of #%s",
1656 is_ifndef ? "ifndef" : "ifdef");
1660 /* evaluate wether we are in true or false case */
1661 condition = is_ifndef ? pp_definition == NULL : pp_definition != NULL;
1664 pp_conditional_t *conditional = push_conditional();
1665 conditional->source_position = pp_token.source_position;
1666 conditional->condition = condition;
1673 static void parse_else_directive(void)
1677 if (pp_token.type != '\n') {
1679 warningf(&pp_token.source_position, "extra tokens at end of #else");
1684 pp_conditional_t *conditional = conditional_stack;
1685 if (conditional == NULL) {
1686 errorf(&pp_token.source_position, "#else without prior #if");
1690 if (conditional->in_else) {
1691 errorf(&pp_token.source_position,
1692 "#else after #else (condition started %P)",
1693 conditional->source_position);
1698 conditional->in_else = true;
1699 if (!conditional->skip) {
1700 skip_mode = conditional->condition;
1702 conditional->source_position = pp_token.source_position;
1705 static void parse_endif_directive(void)
1709 if (pp_token.type != '\n') {
1711 warningf(&pp_token.source_position,
1712 "extra tokens at end of #endif");
1717 pp_conditional_t *conditional = conditional_stack;
1718 if (conditional == NULL) {
1719 errorf(&pp_token.source_position, "#endif without prior #if");
1723 if (!conditional->skip) {
1729 static void parse_preprocessing_directive(void)
1731 do_print_spaces = false;
1732 do_expansions = false;
1736 switch(pp_token.type) {
1739 parse_ifdef_ifndef_directive();
1742 parse_else_directive();
1745 parse_endif_directive();
1752 switch(pp_token.type) {
1754 parse_define_directive();
1757 parse_undef_directive();
1761 parse_ifdef_ifndef_directive();
1764 parse_else_directive();
1767 parse_endif_directive();
1770 bool in_new_source = parse_include_directive();
1771 /* no need to do anything if source file switched */
1777 /* the nop directive */
1780 errorf(&pp_token.source_position,
1781 "invalid preprocessing directive #%t", &pp_token);
1787 do_print_spaces = true;
1788 do_expansions = true;
1791 assert(pp_token.type == '\n' || pp_token.type == TP_EOF);
1792 next_preprocessing_token();
1795 #define GCC_COMPAT_MODE
1797 int pptest_main(int argc, char **argv);
1798 int pptest_main(int argc, char **argv)
1800 init_symbol_table();
1803 obstack_init(&pp_obstack);
1804 obstack_init(&input_obstack);
1806 const char *filename = "t.c";
1812 #ifdef GCC_COMPAT_MODE
1813 /* this is here so we can directly compare "gcc -E" output and our output */
1814 fprintf(out, "# 1 \"%s\"\n", filename);
1815 fputs("# 1 \"<built-in>\"\n", out);
1816 fputs("# 1 \"<command-line>\"\n", out);
1819 bool ok = open_input(filename);
1823 /* we're at a line begin */
1824 if(pp_token.type == '#') {
1825 parse_preprocessing_directive();
1827 /* parse+emit a line */
1828 while(pp_token.type != '\n') {
1829 if(pp_token.type == TP_EOF)
1830 goto end_of_main_loop;
1832 next_preprocessing_token();
1835 next_preprocessing_token();
1840 check_unclosed_conditionals();
1843 obstack_free(&input_obstack, NULL);
1844 obstack_free(&pp_obstack, NULL);
1847 exit_symbol_table();