preprocessor: scanning for :: token was missing
[cparser] / preprocessor.c
1 #include <config.h>
2
3 #include <assert.h>
4 #include <errno.h>
5 #include <string.h>
6 #include <stdbool.h>
7 #include <ctype.h>
8
9 #include "token_t.h"
10 #include "symbol_t.h"
11 #include "adt/util.h"
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"
18 #include "input.h"
19
20 #define MAX_PUTBACK 3
21 #define INCLUDE_LIMIT 199  /* 199 is for gcc "compatibility" */
22
23 struct pp_argument_t {
24         size_t   list_len;
25         token_t *token_list;
26 };
27
28 struct pp_definition_t {
29         symbol_t          *symbol;
30         source_position_t  source_position;
31         pp_definition_t   *parent_expansion;
32         size_t             expand_pos;
33         bool               is_variadic    : 1;
34         bool               is_expanding   : 1;
35         bool               has_parameters : 1;
36         size_t             n_parameters;
37         symbol_t          *parameters;
38
39         /* replacement */
40         size_t             list_len;
41         token_t           *token_list;
42
43 };
44
45 typedef struct pp_conditional_t pp_conditional_t;
46 struct pp_conditional_t {
47         source_position_t  source_position;
48         bool               condition;
49         bool               in_else;
50         bool               skip; /**< conditional in skip mode (then+else gets skipped) */
51         pp_conditional_t  *parent;
52 };
53
54 typedef struct pp_input_t pp_input_t;
55 struct pp_input_t {
56         FILE              *file;
57         input_t           *input;
58         utf32              c;
59         utf32              buf[1024+MAX_PUTBACK];
60         const utf32       *bufend;
61         const utf32       *bufpos;
62         source_position_t  position;
63         pp_input_t        *parent;
64         unsigned           output_line;
65 };
66
67 /** additional info about the current token */
68 typedef struct add_token_info_t {
69         /** whitespace from beginning of line to the token */
70         unsigned whitespace;
71         /** there has been any whitespace before the token */
72         bool     had_whitespace;
73         /** the token is at the beginning of the line */
74         bool     at_line_begin;
75 } add_token_info_t;
76
77 typedef struct searchpath_entry_t searchpath_entry_t;
78 struct searchpath_entry_t {
79         const char         *path;
80         searchpath_entry_t *next;
81 };
82
83 static pp_input_t      input;
84
85 static pp_input_t     *input_stack;
86 static unsigned        n_inputs;
87 static struct obstack  input_obstack;
88
89 static pp_conditional_t *conditional_stack;
90
91 static token_t           pp_token;
92 static bool              resolve_escape_sequences = false;
93 static bool              error_on_unknown_chars   = true;
94 static bool              skip_mode;
95 static FILE             *out;
96 static struct obstack    pp_obstack;
97 static struct obstack    config_obstack;
98 static const char       *printed_input_name = NULL;
99 static source_position_t expansion_pos;
100 static pp_definition_t  *current_expansion  = NULL;
101 static strset_t          stringset;
102 static token_kind_t      last_token;
103
104 static searchpath_entry_t *searchpath;
105
106 static add_token_info_t  info;
107
108 static inline void next_char(void);
109 static void next_preprocessing_token(void);
110 static void print_line_directive(const source_position_t *pos, const char *add);
111
112 static symbol_t *symbol_colongreater;
113 static symbol_t *symbol_lesscolon;
114 static symbol_t *symbol_lesspercent;
115 static symbol_t *symbol_percentcolon;
116 static symbol_t *symbol_percentcolonpercentcolon;
117 static symbol_t *symbol_percentgreater;
118
119 static void init_symbols(void)
120 {
121         symbol_colongreater             = symbol_table_insert(":>");
122         symbol_lesscolon                = symbol_table_insert("<:");
123         symbol_lesspercent              = symbol_table_insert("<%");
124         symbol_percentcolon             = symbol_table_insert("%:");
125         symbol_percentcolonpercentcolon = symbol_table_insert("%:%:");
126         symbol_percentgreater           = symbol_table_insert("%>");
127 }
128
129 static void switch_input(FILE *file, const char *filename)
130 {
131         input.file                = file;
132         input.input               = input_from_stream(file, NULL);
133         input.bufend              = NULL;
134         input.bufpos              = NULL;
135         input.output_line         = 0;
136         input.position.input_name = filename;
137         input.position.lineno     = 1;
138
139         /* indicate that we're at a new input */
140         print_line_directive(&input.position, input_stack != NULL ? "1" : NULL);
141
142         /* place a virtual '\n' so we realize we're at line begin */
143         input.position.lineno = 0;
144         input.c               = '\n';
145         next_preprocessing_token();
146 }
147
148 static void close_input(void)
149 {
150         input_free(input.input);
151         assert(input.file != NULL);
152
153         fclose(input.file);
154         input.input  = NULL;
155         input.file   = NULL;
156         input.bufend = NULL;
157         input.bufpos = NULL;
158         input.c      = EOF;
159 }
160
161 static void push_input(void)
162 {
163         pp_input_t *saved_input
164                 = obstack_alloc(&input_obstack, sizeof(*saved_input));
165
166         memcpy(saved_input, &input, sizeof(*saved_input));
167
168         /* adjust buffer positions */
169         if (input.bufpos != NULL)
170                 saved_input->bufpos = saved_input->buf + (input.bufpos - input.buf);
171         if (input.bufend != NULL)
172                 saved_input->bufend = saved_input->buf + (input.bufend - input.buf);
173
174         saved_input->parent = input_stack;
175         input_stack         = saved_input;
176         ++n_inputs;
177 }
178
179 static void pop_restore_input(void)
180 {
181         assert(n_inputs > 0);
182         assert(input_stack != NULL);
183
184         pp_input_t *saved_input = input_stack;
185
186         memcpy(&input, saved_input, sizeof(input));
187         input.parent = NULL;
188
189         /* adjust buffer positions */
190         if (saved_input->bufpos != NULL)
191                 input.bufpos = input.buf + (saved_input->bufpos - saved_input->buf);
192         if (saved_input->bufend != NULL)
193                 input.bufend = input.buf + (saved_input->bufend - saved_input->buf);
194
195         input_stack = saved_input->parent;
196         obstack_free(&input_obstack, saved_input);
197         --n_inputs;
198 }
199
200 /**
201  * Prints a parse error message at the current token.
202  *
203  * @param msg   the error message
204  */
205 static void parse_error(const char *msg)
206 {
207         errorf(&pp_token.base.source_position,  "%s", msg);
208 }
209
210 static inline void next_real_char(void)
211 {
212         assert(input.bufpos <= input.bufend);
213         if (input.bufpos >= input.bufend) {
214                 size_t const n = decode(input.input, input.buf + MAX_PUTBACK, lengthof(input.buf) - MAX_PUTBACK);
215                 if (n == 0) {
216                         input.c = EOF;
217                         return;
218                 }
219                 input.bufpos = input.buf + MAX_PUTBACK;
220                 input.bufend = input.bufpos + n;
221         }
222         input.c = *input.bufpos++;
223         ++input.position.colno;
224 }
225
226 /**
227  * Put a character back into the buffer.
228  *
229  * @param pc  the character to put back
230  */
231 static inline void put_back(utf32 const pc)
232 {
233         assert(input.bufpos > input.buf);
234         *(--input.bufpos - input.buf + input.buf) = (char) pc;
235         --input.position.colno;
236 }
237
238 #define NEWLINE \
239         '\r': \
240                 next_char(); \
241                 if (input.c == '\n') { \
242         case '\n': \
243                         next_char(); \
244                 } \
245                 info.whitespace = 0; \
246                 ++input.position.lineno; \
247                 input.position.colno = 1; \
248                 goto newline; \
249                 newline // Let it look like an ordinary case label.
250
251 #define eat(c_type) (assert(input.c == c_type), next_char())
252
253 static void maybe_concat_lines(void)
254 {
255         eat('\\');
256
257         switch (input.c) {
258         case NEWLINE:
259                 return;
260
261         default:
262                 break;
263         }
264
265         put_back(input.c);
266         input.c = '\\';
267 }
268
269 /**
270  * Set c to the next input character, ie.
271  * after expanding trigraphs.
272  */
273 static inline void next_char(void)
274 {
275         next_real_char();
276
277         /* filter trigraphs and concatenated lines */
278         if (UNLIKELY(input.c == '\\')) {
279                 maybe_concat_lines();
280                 goto end_of_next_char;
281         }
282
283         if (LIKELY(input.c != '?'))
284                 goto end_of_next_char;
285
286         next_real_char();
287         if (LIKELY(input.c != '?')) {
288                 put_back(input.c);
289                 input.c = '?';
290                 goto end_of_next_char;
291         }
292
293         next_real_char();
294         switch (input.c) {
295         case '=': input.c = '#'; break;
296         case '(': input.c = '['; break;
297         case '/': input.c = '\\'; maybe_concat_lines(); break;
298         case ')': input.c = ']'; break;
299         case '\'': input.c = '^'; break;
300         case '<': input.c = '{'; break;
301         case '!': input.c = '|'; break;
302         case '>': input.c = '}'; break;
303         case '-': input.c = '~'; break;
304         default:
305                 put_back(input.c);
306                 put_back('?');
307                 input.c = '?';
308                 break;
309         }
310
311 end_of_next_char:;
312 #ifdef DEBUG_CHARS
313         printf("nchar '%c'\n", input.c);
314 #endif
315 }
316
317
318
319 /**
320  * Returns true if the given char is a octal digit.
321  *
322  * @param char  the character to check
323  */
324 static inline bool is_octal_digit(int chr)
325 {
326         switch (chr) {
327         case '0':
328         case '1':
329         case '2':
330         case '3':
331         case '4':
332         case '5':
333         case '6':
334         case '7':
335                 return true;
336         default:
337                 return false;
338         }
339 }
340
341 /**
342  * Returns the value of a digit.
343  * The only portable way to do it ...
344  */
345 static int digit_value(int digit)
346 {
347         switch (digit) {
348         case '0': return 0;
349         case '1': return 1;
350         case '2': return 2;
351         case '3': return 3;
352         case '4': return 4;
353         case '5': return 5;
354         case '6': return 6;
355         case '7': return 7;
356         case '8': return 8;
357         case '9': return 9;
358         case 'a':
359         case 'A': return 10;
360         case 'b':
361         case 'B': return 11;
362         case 'c':
363         case 'C': return 12;
364         case 'd':
365         case 'D': return 13;
366         case 'e':
367         case 'E': return 14;
368         case 'f':
369         case 'F': return 15;
370         default:
371                 panic("wrong character given");
372         }
373 }
374
375 /**
376  * Parses an octal character sequence.
377  *
378  * @param first_digit  the already read first digit
379  */
380 static utf32 parse_octal_sequence(const utf32 first_digit)
381 {
382         assert(is_octal_digit(first_digit));
383         utf32 value = digit_value(first_digit);
384         if (!is_octal_digit(input.c)) return value;
385         value = 8 * value + digit_value(input.c);
386         next_char();
387         if (!is_octal_digit(input.c)) return value;
388         value = 8 * value + digit_value(input.c);
389         next_char();
390         return value;
391
392 }
393
394 /**
395  * Parses a hex character sequence.
396  */
397 static utf32 parse_hex_sequence(void)
398 {
399         utf32 value = 0;
400         while (isxdigit(input.c)) {
401                 value = 16 * value + digit_value(input.c);
402                 next_char();
403         }
404         return value;
405 }
406
407 /**
408  * Parse an escape sequence.
409  */
410 static utf32 parse_escape_sequence(void)
411 {
412         eat('\\');
413
414         utf32 const ec = input.c;
415         next_char();
416
417         switch (ec) {
418         case '"':  return '"';
419         case '\'': return '\'';
420         case '\\': return '\\';
421         case '?': return '\?';
422         case 'a': return '\a';
423         case 'b': return '\b';
424         case 'f': return '\f';
425         case 'n': return '\n';
426         case 'r': return '\r';
427         case 't': return '\t';
428         case 'v': return '\v';
429         case 'x':
430                 return parse_hex_sequence();
431         case '0':
432         case '1':
433         case '2':
434         case '3':
435         case '4':
436         case '5':
437         case '6':
438         case '7':
439                 return parse_octal_sequence(ec);
440         case EOF:
441                 parse_error("reached end of file while parsing escape sequence");
442                 return EOF;
443         /* \E is not documented, but handled, by GCC.  It is acceptable according
444          * to Â§6.11.4, whereas \e is not. */
445         case 'E':
446         case 'e':
447                 if (c_mode & _GNUC)
448                         return 27;   /* hopefully 27 is ALWAYS the code for ESCAPE */
449                 break;
450         case 'u':
451         case 'U':
452                 parse_error("universal character parsing not implemented yet");
453                 return EOF;
454         default:
455                 break;
456         }
457         /* Â§6.4.4.4:8 footnote 64 */
458         parse_error("unknown escape sequence");
459         return EOF;
460 }
461
462 static const char *identify_string(char *string)
463 {
464         const char *result = strset_insert(&stringset, string);
465         if (result != string) {
466                 obstack_free(&symbol_obstack, string);
467         }
468         return result;
469 }
470
471 static string_t sym_make_string(string_encoding_t const enc)
472 {
473         obstack_1grow(&symbol_obstack, '\0');
474         size_t      const len    = obstack_object_size(&symbol_obstack) - 1;
475         char       *const string = obstack_finish(&symbol_obstack);
476         char const *const result = identify_string(string);
477         return (string_t){ result, len, enc };
478 }
479
480 static void parse_string(utf32 const delimiter, token_kind_t const kind,
481                          string_encoding_t const enc,
482                          char const *const context)
483 {
484         const unsigned start_linenr = input.position.lineno;
485
486         eat(delimiter);
487
488         while (true) {
489                 switch (input.c) {
490                 case '\\': {
491                         if (resolve_escape_sequences) {
492                                 utf32 const tc = parse_escape_sequence();
493                                 if (enc == STRING_ENCODING_CHAR) {
494                                         if (tc >= 0x100) {
495                                                 warningf(WARN_OTHER, &pp_token.base.source_position, "escape sequence out of range");
496                                         }
497                                         obstack_1grow(&symbol_obstack, tc);
498                                 } else {
499                                         obstack_grow_utf8(&symbol_obstack, tc);
500                                 }
501                         } else {
502                                 obstack_1grow(&symbol_obstack, (char)input.c);
503                                 next_char();
504                                 obstack_1grow(&symbol_obstack, (char)input.c);
505                                 next_char();
506                         }
507                         break;
508                 }
509
510                 case NEWLINE:
511                         errorf(&pp_token.base.source_position, "newline while parsing %s", context);
512                         break;
513
514                 case EOF: {
515                         source_position_t source_position;
516                         source_position.input_name = pp_token.base.source_position.input_name;
517                         source_position.lineno     = start_linenr;
518                         errorf(&source_position, "EOF while parsing %s", context);
519                         goto end_of_string;
520                 }
521
522                 default:
523                         if (input.c == delimiter) {
524                                 next_char();
525                                 goto end_of_string;
526                         } else {
527                                 obstack_grow_utf8(&symbol_obstack, input.c);
528                                 next_char();
529                                 break;
530                         }
531                 }
532         }
533
534 end_of_string:
535         pp_token.kind           = kind;
536         pp_token.literal.string = sym_make_string(enc);
537 }
538
539 static void parse_string_literal(string_encoding_t const enc)
540 {
541         parse_string('"', T_STRING_LITERAL, enc, "string literal");
542 }
543
544 static void parse_character_constant(string_encoding_t const enc)
545 {
546         parse_string('\'', T_CHARACTER_CONSTANT, enc, "character constant");
547         if (pp_token.literal.string.size == 0) {
548                 parse_error("empty character constant");
549         }
550 }
551
552 #define SYMBOL_CASES_WITHOUT_E_P \
553              'a': \
554         case 'b': \
555         case 'c': \
556         case 'd': \
557         case 'f': \
558         case 'g': \
559         case 'h': \
560         case 'i': \
561         case 'j': \
562         case 'k': \
563         case 'l': \
564         case 'm': \
565         case 'n': \
566         case 'o': \
567         case 'q': \
568         case 'r': \
569         case 's': \
570         case 't': \
571         case 'u': \
572         case 'v': \
573         case 'w': \
574         case 'x': \
575         case 'y': \
576         case 'z': \
577         case 'A': \
578         case 'B': \
579         case 'C': \
580         case 'D': \
581         case 'F': \
582         case 'G': \
583         case 'H': \
584         case 'I': \
585         case 'J': \
586         case 'K': \
587         case 'L': \
588         case 'M': \
589         case 'N': \
590         case 'O': \
591         case 'Q': \
592         case 'R': \
593         case 'S': \
594         case 'T': \
595         case 'U': \
596         case 'V': \
597         case 'W': \
598         case 'X': \
599         case 'Y': \
600         case 'Z': \
601         case '_'
602
603 #define SYMBOL_CASES \
604              SYMBOL_CASES_WITHOUT_E_P: \
605         case 'e': \
606         case 'p': \
607         case 'E': \
608         case 'P'
609
610 #define DIGIT_CASES \
611              '0':  \
612         case '1':  \
613         case '2':  \
614         case '3':  \
615         case '4':  \
616         case '5':  \
617         case '6':  \
618         case '7':  \
619         case '8':  \
620         case '9'
621
622 static inline void set_punctuator(token_kind_t const kind)
623 {
624         pp_token.kind        = kind;
625         pp_token.base.symbol = token_symbols[kind];
626 }
627
628 static inline void set_digraph(token_kind_t const kind, symbol_t *const symbol)
629 {
630         pp_token.kind        = kind;
631         pp_token.base.symbol = symbol;
632 }
633
634 /**
635  * returns next final token from a preprocessor macro expansion
636  */
637 static void expand_next(void)
638 {
639         assert(current_expansion != NULL);
640
641         pp_definition_t *definition = current_expansion;
642
643 restart:
644         if (definition->list_len == 0
645                         || definition->expand_pos >= definition->list_len) {
646                 /* we're finished with the current macro, move up 1 level in the
647                  * expansion stack */
648                 pp_definition_t *parent = definition->parent_expansion;
649                 definition->parent_expansion = NULL;
650                 definition->is_expanding     = false;
651
652                 /* it was the outermost expansion, parse normal pptoken */
653                 if (parent == NULL) {
654                         current_expansion = NULL;
655                         next_preprocessing_token();
656                         return;
657                 }
658                 definition        = parent;
659                 current_expansion = definition;
660                 goto restart;
661         }
662         pp_token = definition->token_list[definition->expand_pos];
663         pp_token.base.source_position = expansion_pos;
664         ++definition->expand_pos;
665
666         if (pp_token.kind != T_IDENTIFIER)
667                 return;
668
669         /* if it was an identifier then we might need to expand again */
670         pp_definition_t *const symbol_definition = pp_token.base.symbol->pp_definition;
671         if (symbol_definition != NULL && !symbol_definition->is_expanding) {
672                 symbol_definition->parent_expansion = definition;
673                 symbol_definition->expand_pos       = 0;
674                 symbol_definition->is_expanding     = true;
675                 definition                          = symbol_definition;
676                 current_expansion                   = definition;
677                 goto restart;
678         }
679 }
680
681 static void skip_line_comment(void)
682 {
683         while (true) {
684                 switch (input.c) {
685                 case EOF:
686                         return;
687
688                 case '\r':
689                 case '\n':
690                         return;
691
692                 default:
693                         next_char();
694                         break;
695                 }
696         }
697 }
698
699 static void skip_multiline_comment(void)
700 {
701         unsigned start_linenr = input.position.lineno;
702         while (true) {
703                 switch (input.c) {
704                 case '/':
705                         next_char();
706                         if (input.c == '*') {
707                                 /* TODO: nested comment, warn here */
708                         }
709                         break;
710                 case '*':
711                         next_char();
712                         if (input.c == '/') {
713                                 if (input.position.lineno != input.output_line)
714                                         info.whitespace = input.position.colno;
715                                 next_char();
716                                 return;
717                         }
718                         break;
719
720                 case NEWLINE:
721                         break;
722
723                 case EOF: {
724                         source_position_t source_position;
725                         source_position.input_name = pp_token.base.source_position.input_name;
726                         source_position.lineno     = start_linenr;
727                         errorf(&source_position, "at end of file while looking for comment end");
728                         return;
729                 }
730
731                 default:
732                         next_char();
733                         break;
734                 }
735         }
736 }
737
738 static void skip_whitespace(void)
739 {
740         while (true) {
741                 switch (input.c) {
742                 case ' ':
743                 case '\t':
744                         next_char();
745                         continue;
746
747                 case NEWLINE:
748                         info.at_line_begin = true;
749                         return;
750
751                 case '/':
752                         next_char();
753                         if (input.c == '/') {
754                                 next_char();
755                                 skip_line_comment();
756                                 continue;
757                         } else if (input.c == '*') {
758                                 next_char();
759                                 skip_multiline_comment();
760                                 continue;
761                         } else {
762                                 put_back(input.c);
763                                 input.c = '/';
764                         }
765                         return;
766                 default:
767                         return;
768                 }
769         }
770 }
771
772 static inline void eat_pp(pp_token_kind_t const kind)
773 {
774         assert(pp_token.base.symbol->pp_ID == kind);
775         (void) kind;
776         next_preprocessing_token();
777 }
778
779 static inline void eat_token(token_kind_t const kind)
780 {
781         assert(pp_token.kind == kind);
782         (void)kind;
783         next_preprocessing_token();
784 }
785
786 static void parse_symbol(void)
787 {
788         obstack_1grow(&symbol_obstack, (char) input.c);
789         next_char();
790
791         while (true) {
792                 switch (input.c) {
793                 case DIGIT_CASES:
794                 case SYMBOL_CASES:
795                         obstack_1grow(&symbol_obstack, (char) input.c);
796                         next_char();
797                         break;
798
799                 default:
800                         goto end_symbol;
801                 }
802         }
803
804 end_symbol:
805         obstack_1grow(&symbol_obstack, '\0');
806         char *string = obstack_finish(&symbol_obstack);
807
808         /* might be a wide string or character constant ( L"string"/L'c' ) */
809         if (input.c == '"' && string[0] == 'L' && string[1] == '\0') {
810                 obstack_free(&symbol_obstack, string);
811                 parse_string_literal(STRING_ENCODING_WIDE);
812                 return;
813         } else if (input.c == '\'' && string[0] == 'L' && string[1] == '\0') {
814                 obstack_free(&symbol_obstack, string);
815                 parse_character_constant(STRING_ENCODING_WIDE);
816                 return;
817         }
818
819         symbol_t *symbol = symbol_table_insert(string);
820
821         pp_token.kind        = symbol->ID;
822         pp_token.base.symbol = symbol;
823
824         /* we can free the memory from symbol obstack if we already had an entry in
825          * the symbol table */
826         if (symbol->string != string) {
827                 obstack_free(&symbol_obstack, string);
828         }
829 }
830
831 static void parse_number(void)
832 {
833         obstack_1grow(&symbol_obstack, (char) input.c);
834         next_char();
835
836         while (true) {
837                 switch (input.c) {
838                 case '.':
839                 case DIGIT_CASES:
840                 case SYMBOL_CASES_WITHOUT_E_P:
841                         obstack_1grow(&symbol_obstack, (char) input.c);
842                         next_char();
843                         break;
844
845                 case 'e':
846                 case 'p':
847                 case 'E':
848                 case 'P':
849                         obstack_1grow(&symbol_obstack, (char) input.c);
850                         next_char();
851                         if (input.c == '+' || input.c == '-') {
852                                 obstack_1grow(&symbol_obstack, (char) input.c);
853                                 next_char();
854                         }
855                         break;
856
857                 default:
858                         goto end_number;
859                 }
860         }
861
862 end_number:
863         pp_token.kind           = T_NUMBER;
864         pp_token.literal.string = sym_make_string(STRING_ENCODING_CHAR);
865 }
866
867 #define MAYBE_PROLOG \
868         next_char(); \
869         switch (input.c) {
870
871 #define MAYBE(ch, kind) \
872         case ch: \
873                 next_char(); \
874                 set_punctuator(kind); \
875                 return;
876
877 #define MAYBE_DIGRAPH(ch, kind, symbol) \
878         case ch: \
879                 next_char(); \
880                 set_digraph(kind, symbol); \
881                 return;
882
883 #define ELSE_CODE(code) \
884         default: \
885                 code \
886                 return; \
887         }
888
889 #define ELSE(kind) ELSE_CODE(set_punctuator(kind);)
890
891 static void next_preprocessing_token(void)
892 {
893         if (current_expansion != NULL) {
894                 expand_next();
895                 return;
896         }
897
898         info.at_line_begin  = false;
899         info.had_whitespace = false;
900 restart:
901         pp_token.base.source_position = input.position;
902         pp_token.base.symbol          = NULL;
903
904         switch (input.c) {
905         case ' ':
906         case '\t':
907                 ++info.whitespace;
908                 info.had_whitespace = true;
909                 next_char();
910                 goto restart;
911
912         case NEWLINE:
913                 info.at_line_begin = true;
914                 info.had_whitespace = true;
915                 goto restart;
916
917         case SYMBOL_CASES:
918                 parse_symbol();
919                 return;
920
921         case DIGIT_CASES:
922                 parse_number();
923                 return;
924
925         case '"':
926                 parse_string_literal(STRING_ENCODING_CHAR);
927                 return;
928
929         case '\'':
930                 parse_character_constant(STRING_ENCODING_CHAR);
931                 return;
932
933         case '.':
934                 MAYBE_PROLOG
935                         case '0':
936                         case '1':
937                         case '2':
938                         case '3':
939                         case '4':
940                         case '5':
941                         case '6':
942                         case '7':
943                         case '8':
944                         case '9':
945                                 put_back(input.c);
946                                 input.c = '.';
947                                 parse_number();
948                                 return;
949
950                         case '.':
951                                 MAYBE_PROLOG
952                                 MAYBE('.', T_DOTDOTDOT)
953                                 ELSE_CODE(
954                                         put_back(input.c);
955                                         input.c = '.';
956                                         set_punctuator('.');
957                                 )
958                 ELSE('.')
959         case '&':
960                 MAYBE_PROLOG
961                 MAYBE('&', T_ANDAND)
962                 MAYBE('=', T_ANDEQUAL)
963                 ELSE('&')
964         case '*':
965                 MAYBE_PROLOG
966                 MAYBE('=', T_ASTERISKEQUAL)
967                 ELSE('*')
968         case '+':
969                 MAYBE_PROLOG
970                 MAYBE('+', T_PLUSPLUS)
971                 MAYBE('=', T_PLUSEQUAL)
972                 ELSE('+')
973         case '-':
974                 MAYBE_PROLOG
975                 MAYBE('>', T_MINUSGREATER)
976                 MAYBE('-', T_MINUSMINUS)
977                 MAYBE('=', T_MINUSEQUAL)
978                 ELSE('-')
979         case '!':
980                 MAYBE_PROLOG
981                 MAYBE('=', T_EXCLAMATIONMARKEQUAL)
982                 ELSE('!')
983         case '/':
984                 MAYBE_PROLOG
985                 MAYBE('=', T_SLASHEQUAL)
986                 case '*':
987                         next_char();
988                         info.had_whitespace = true;
989                         skip_multiline_comment();
990                         goto restart;
991                 case '/':
992                         next_char();
993                         info.had_whitespace = true;
994                         skip_line_comment();
995                         goto restart;
996                 ELSE('/')
997         case '%':
998                 MAYBE_PROLOG
999                 MAYBE_DIGRAPH('>', '}', symbol_percentgreater)
1000                 MAYBE('=', T_PERCENTEQUAL)
1001                 case ':':
1002                         MAYBE_PROLOG
1003                         case '%':
1004                                 MAYBE_PROLOG
1005                                 MAYBE_DIGRAPH(':', T_HASHHASH, symbol_percentcolonpercentcolon)
1006                                 ELSE_CODE(
1007                                         put_back(input.c);
1008                                         input.c = '%';
1009                                         goto digraph_percentcolon;
1010                                 )
1011                         ELSE_CODE(
1012 digraph_percentcolon:
1013                                 set_digraph('#', symbol_percentcolon);
1014                         )
1015                 ELSE('%')
1016         case '<':
1017                 MAYBE_PROLOG
1018                 MAYBE_DIGRAPH(':', '[', symbol_lesscolon)
1019                 MAYBE_DIGRAPH('%', '{', symbol_lesspercent)
1020                 MAYBE('=', T_LESSEQUAL)
1021                 case '<':
1022                         MAYBE_PROLOG
1023                         MAYBE('=', T_LESSLESSEQUAL)
1024                         ELSE(T_LESSLESS)
1025                 ELSE('<')
1026         case '>':
1027                 MAYBE_PROLOG
1028                 MAYBE('=', T_GREATEREQUAL)
1029                 case '>':
1030                         MAYBE_PROLOG
1031                         MAYBE('=', T_GREATERGREATEREQUAL)
1032                         ELSE(T_GREATERGREATER)
1033                 ELSE('>')
1034         case '^':
1035                 MAYBE_PROLOG
1036                 MAYBE('=', T_CARETEQUAL)
1037                 ELSE('^')
1038         case '|':
1039                 MAYBE_PROLOG
1040                 MAYBE('=', T_PIPEEQUAL)
1041                 MAYBE('|', T_PIPEPIPE)
1042                 ELSE('|')
1043         case ':':
1044                 MAYBE_PROLOG
1045                 MAYBE_DIGRAPH('>', ']', symbol_colongreater)
1046                 case ':':
1047                         if (c_mode & _CXX) {
1048                                 next_char();
1049                                 set_punctuator(T_COLONCOLON);
1050                                 return;
1051                         }
1052                         /* FALLTHROUGH */
1053                 ELSE(':')
1054         case '=':
1055                 MAYBE_PROLOG
1056                 MAYBE('=', T_EQUALEQUAL)
1057                 ELSE('=')
1058         case '#':
1059                 MAYBE_PROLOG
1060                 MAYBE('#', T_HASHHASH)
1061                 ELSE('#')
1062
1063         case '?':
1064         case '[':
1065         case ']':
1066         case '(':
1067         case ')':
1068         case '{':
1069         case '}':
1070         case '~':
1071         case ';':
1072         case ',':
1073                 set_punctuator(input.c);
1074                 next_char();
1075                 return;
1076
1077         case EOF:
1078                 if (input_stack != NULL) {
1079                         close_input();
1080                         pop_restore_input();
1081                         fputc('\n', out);
1082                         print_line_directive(&input.position, "2");
1083                         goto restart;
1084                 } else {
1085                         pp_token.base.source_position.lineno++;
1086                         info.at_line_begin = true;
1087                         set_punctuator(T_EOF);
1088                 }
1089                 return;
1090
1091         default:
1092                 if (error_on_unknown_chars) {
1093                         errorf(&pp_token.base.source_position,
1094                                "unknown character '%lc' found\n", input.c);
1095                         next_char();
1096                         goto restart;
1097                 } else {
1098                         assert(obstack_object_size(&symbol_obstack) == 0);
1099                         obstack_grow_utf8(&symbol_obstack, input.c);
1100                         obstack_1grow(&symbol_obstack, '\0');
1101                         char     *const string = obstack_finish(&symbol_obstack);
1102                         symbol_t *const symbol = symbol_table_insert(string);
1103                         if (symbol->string != string)
1104                                 obstack_free(&symbol_obstack, string);
1105
1106                         pp_token.kind        = T_UNKNOWN_CHAR;
1107                         pp_token.base.symbol = symbol;
1108                         next_char();
1109                         return;
1110                 }
1111         }
1112 }
1113
1114 static void print_quoted_string(const char *const string)
1115 {
1116         fputc('"', out);
1117         for (const char *c = string; *c != 0; ++c) {
1118                 switch (*c) {
1119                 case '"': fputs("\\\"", out); break;
1120                 case '\\':  fputs("\\\\", out); break;
1121                 case '\a':  fputs("\\a", out); break;
1122                 case '\b':  fputs("\\b", out); break;
1123                 case '\f':  fputs("\\f", out); break;
1124                 case '\n':  fputs("\\n", out); break;
1125                 case '\r':  fputs("\\r", out); break;
1126                 case '\t':  fputs("\\t", out); break;
1127                 case '\v':  fputs("\\v", out); break;
1128                 case '\?':  fputs("\\?", out); break;
1129                 default:
1130                         if (!isprint(*c)) {
1131                                 fprintf(out, "\\%03o", (unsigned)*c);
1132                                 break;
1133                         }
1134                         fputc(*c, out);
1135                         break;
1136                 }
1137         }
1138         fputc('"', out);
1139 }
1140
1141 static void print_line_directive(const source_position_t *pos, const char *add)
1142 {
1143         fprintf(out, "# %u ", pos->lineno);
1144         print_quoted_string(pos->input_name);
1145         if (add != NULL) {
1146                 fputc(' ', out);
1147                 fputs(add, out);
1148         }
1149
1150         printed_input_name = pos->input_name;
1151         input.output_line  = pos->lineno-1;
1152 }
1153
1154 static bool emit_newlines(void)
1155 {
1156         unsigned delta = pp_token.base.source_position.lineno - input.output_line;
1157         if (delta == 0)
1158                 return false;
1159
1160         if (delta >= 9) {
1161                 fputc('\n', out);
1162                 print_line_directive(&pp_token.base.source_position, NULL);
1163                 fputc('\n', out);
1164         } else {
1165                 for (unsigned i = 0; i < delta; ++i) {
1166                         fputc('\n', out);
1167                 }
1168         }
1169         input.output_line = pp_token.base.source_position.lineno;
1170
1171         for (unsigned i = 0; i < info.whitespace; ++i)
1172                 fputc(' ', out);
1173
1174         return true;
1175 }
1176
1177 static void emit_pp_token(void)
1178 {
1179         if (skip_mode)
1180                 return;
1181
1182         if (!emit_newlines() &&
1183             (info.had_whitespace || tokens_would_paste(last_token, pp_token.kind)))
1184                 fputc(' ', out);
1185
1186         switch (pp_token.kind) {
1187         case T_NUMBER:
1188                 fputs(pp_token.literal.string.begin, out);
1189                 break;
1190
1191         case T_STRING_LITERAL:
1192                 fputs(get_string_encoding_prefix(pp_token.literal.string.encoding), out);
1193                 fputc('"', out);
1194                 fputs(pp_token.literal.string.begin, out);
1195                 fputc('"', out);
1196                 break;
1197
1198         case T_CHARACTER_CONSTANT:
1199                 fputs(get_string_encoding_prefix(pp_token.literal.string.encoding), out);
1200                 fputc('\'', out);
1201                 fputs(pp_token.literal.string.begin, out);
1202                 fputc('\'', out);
1203                 break;
1204
1205         default:
1206                 fputs(pp_token.base.symbol->string, out);
1207                 break;
1208         }
1209         last_token = pp_token.kind;
1210 }
1211
1212 static void eat_pp_directive(void)
1213 {
1214         while (!info.at_line_begin) {
1215                 next_preprocessing_token();
1216         }
1217 }
1218
1219 static bool strings_equal(const string_t *string1, const string_t *string2)
1220 {
1221         size_t size = string1->size;
1222         if (size != string2->size)
1223                 return false;
1224
1225         const char *c1 = string1->begin;
1226         const char *c2 = string2->begin;
1227         for (size_t i = 0; i < size; ++i, ++c1, ++c2) {
1228                 if (*c1 != *c2)
1229                         return false;
1230         }
1231         return true;
1232 }
1233
1234 static bool pp_tokens_equal(const token_t *token1, const token_t *token2)
1235 {
1236         if (token1->kind != token2->kind)
1237                 return false;
1238
1239         switch (token1->kind) {
1240         case T_NUMBER:
1241         case T_CHARACTER_CONSTANT:
1242         case T_STRING_LITERAL:
1243                 return strings_equal(&token1->literal.string, &token2->literal.string);
1244
1245         default:
1246                 return token1->base.symbol == token2->base.symbol;
1247         }
1248 }
1249
1250 static bool pp_definitions_equal(const pp_definition_t *definition1,
1251                                  const pp_definition_t *definition2)
1252 {
1253         if (definition1->list_len != definition2->list_len)
1254                 return false;
1255
1256         size_t         len = definition1->list_len;
1257         const token_t *t1  = definition1->token_list;
1258         const token_t *t2  = definition2->token_list;
1259         for (size_t i = 0; i < len; ++i, ++t1, ++t2) {
1260                 if (!pp_tokens_equal(t1, t2))
1261                         return false;
1262         }
1263         return true;
1264 }
1265
1266 static void parse_define_directive(void)
1267 {
1268         eat_pp(TP_define);
1269         if (skip_mode) {
1270                 eat_pp_directive();
1271                 return;
1272         }
1273
1274         assert(obstack_object_size(&pp_obstack) == 0);
1275
1276         if (pp_token.kind != T_IDENTIFIER || info.at_line_begin) {
1277                 errorf(&pp_token.base.source_position,
1278                        "expected identifier after #define, got %K", &pp_token);
1279                 goto error_out;
1280         }
1281         symbol_t *const symbol = pp_token.base.symbol;
1282
1283         pp_definition_t *new_definition
1284                 = obstack_alloc(&pp_obstack, sizeof(new_definition[0]));
1285         memset(new_definition, 0, sizeof(new_definition[0]));
1286         new_definition->source_position = input.position;
1287
1288         /* this is probably the only place where spaces are significant in the
1289          * lexer (except for the fact that they separate tokens). #define b(x)
1290          * is something else than #define b (x) */
1291         if (input.c == '(') {
1292                 eat_token(T_IDENTIFIER);
1293                 eat_token('(');
1294
1295                 while (true) {
1296                         switch (pp_token.kind) {
1297                         case T_DOTDOTDOT:
1298                                 new_definition->is_variadic = true;
1299                                 eat_token(T_DOTDOTDOT);
1300                                 if (pp_token.kind != ')') {
1301                                         errorf(&input.position,
1302                                                         "'...' not at end of macro argument list");
1303                                         goto error_out;
1304                                 }
1305                                 break;
1306
1307                         case T_IDENTIFIER:
1308                                 obstack_ptr_grow(&pp_obstack, pp_token.base.symbol);
1309                                 eat_token(T_IDENTIFIER);
1310
1311                                 if (pp_token.kind == ',') {
1312                                         eat_token(',');
1313                                         break;
1314                                 }
1315
1316                                 if (pp_token.kind != ')') {
1317                                         errorf(&pp_token.base.source_position,
1318                                                "expected ',' or ')' after identifier, got %K",
1319                                                &pp_token);
1320                                         goto error_out;
1321                                 }
1322                                 break;
1323
1324                         case ')':
1325                                 eat_token(')');
1326                                 goto finish_argument_list;
1327
1328                         default:
1329                                 errorf(&pp_token.base.source_position,
1330                                        "expected identifier, '...' or ')' in #define argument list, got %K",
1331                                        &pp_token);
1332                                 goto error_out;
1333                         }
1334                 }
1335
1336         finish_argument_list:
1337                 new_definition->has_parameters = true;
1338                 new_definition->n_parameters
1339                         = obstack_object_size(&pp_obstack) / sizeof(new_definition->parameters[0]);
1340                 new_definition->parameters = obstack_finish(&pp_obstack);
1341         } else {
1342                 eat_token(T_IDENTIFIER);
1343         }
1344
1345         /* construct a new pp_definition on the obstack */
1346         assert(obstack_object_size(&pp_obstack) == 0);
1347         size_t list_len = 0;
1348         while (!info.at_line_begin) {
1349                 obstack_grow(&pp_obstack, &pp_token, sizeof(pp_token));
1350                 ++list_len;
1351                 next_preprocessing_token();
1352         }
1353
1354         new_definition->list_len   = list_len;
1355         new_definition->token_list = obstack_finish(&pp_obstack);
1356
1357         pp_definition_t *old_definition = symbol->pp_definition;
1358         if (old_definition != NULL) {
1359                 if (!pp_definitions_equal(old_definition, new_definition)) {
1360                         warningf(WARN_OTHER, &input.position, "multiple definition of macro '%Y' (first defined %P)", symbol, &old_definition->source_position);
1361                 } else {
1362                         /* reuse the old definition */
1363                         obstack_free(&pp_obstack, new_definition);
1364                         new_definition = old_definition;
1365                 }
1366         }
1367
1368         symbol->pp_definition = new_definition;
1369         return;
1370
1371 error_out:
1372         if (obstack_object_size(&pp_obstack) > 0) {
1373                 char *ptr = obstack_finish(&pp_obstack);
1374                 obstack_free(&pp_obstack, ptr);
1375         }
1376         eat_pp_directive();
1377 }
1378
1379 static void parse_undef_directive(void)
1380 {
1381         eat_pp(TP_undef);
1382         if (skip_mode) {
1383                 eat_pp_directive();
1384                 return;
1385         }
1386
1387         if (pp_token.kind != T_IDENTIFIER) {
1388                 errorf(&input.position,
1389                        "expected identifier after #undef, got %K", &pp_token);
1390                 eat_pp_directive();
1391                 return;
1392         }
1393
1394         pp_token.base.symbol->pp_definition = NULL;
1395         eat_token(T_IDENTIFIER);
1396
1397         if (!info.at_line_begin) {
1398                 warningf(WARN_OTHER, &input.position, "extra tokens at end of #undef directive");
1399         }
1400         eat_pp_directive();
1401 }
1402
1403 /** behind an #include we can have the special headername lexems.
1404  * They're only allowed behind an #include so they're not recognized
1405  * by the normal next_preprocessing_token. We handle them as a special
1406  * exception here */
1407 static void parse_headername(void)
1408 {
1409         const source_position_t start_position = input.position;
1410         string_t                string         = { NULL, 0, STRING_ENCODING_CHAR };
1411         assert(obstack_object_size(&symbol_obstack) == 0);
1412
1413         if (info.at_line_begin) {
1414                 parse_error("expected headername after #include");
1415                 goto finish_error;
1416         }
1417
1418         /* check wether we have a "... or <... headername */
1419         switch (input.c) {
1420         {
1421                 utf32 delimiter;
1422         case '<': delimiter = '>'; goto parse_name;
1423         case '"': delimiter = '"'; goto parse_name;
1424 parse_name:
1425                 next_char();
1426                 while (true) {
1427                         switch (input.c) {
1428                         case NEWLINE:
1429                         case EOF:
1430                                 errorf(&pp_token.base.source_position, "header name without closing '%c'", (char)delimiter);
1431                                 goto finish_error;
1432
1433                         default:
1434                                 if (input.c == delimiter) {
1435                                         next_char();
1436                                         goto finished_headername;
1437                                 } else {
1438                                         obstack_1grow(&symbol_obstack, (char)input.c);
1439                                         next_char();
1440                                 }
1441                                 break;
1442                         }
1443                 }
1444                 /* we should never be here */
1445         }
1446
1447         default:
1448                 /* TODO: do normal pp_token parsing and concatenate results */
1449                 panic("pp_token concat include not implemented yet");
1450         }
1451
1452 finished_headername:
1453         string = sym_make_string(STRING_ENCODING_CHAR);
1454
1455 finish_error:
1456         pp_token.base.source_position = start_position;
1457         pp_token.kind                 = T_HEADERNAME;
1458         pp_token.literal.string       = string;
1459 }
1460
1461 static bool do_include(bool system_include, const char *headername)
1462 {
1463         size_t headername_len = strlen(headername);
1464         if (!system_include) {
1465                 /* put dirname of current input on obstack */
1466                 const char *filename   = input.position.input_name;
1467                 const char *last_slash = strrchr(filename, '/');
1468                 if (last_slash != NULL) {
1469                         size_t len = last_slash - filename;
1470                         obstack_grow(&symbol_obstack, filename, len + 1);
1471                         obstack_grow0(&symbol_obstack, headername, headername_len);
1472                         char *complete_path = obstack_finish(&symbol_obstack);
1473                         headername = identify_string(complete_path);
1474                 }
1475
1476                 FILE *file = fopen(headername, "r");
1477                 if (file != NULL) {
1478                         switch_input(file, headername);
1479                         return true;
1480                 }
1481         }
1482
1483         assert(obstack_object_size(&symbol_obstack) == 0);
1484         /* check searchpath */
1485         for (searchpath_entry_t *entry = searchpath; entry != NULL;
1486              entry = entry->next) {
1487             const char *path = entry->path;
1488             size_t      len  = strlen(path);
1489                 obstack_grow(&symbol_obstack, path, len);
1490                 if (path[len-1] != '/')
1491                         obstack_1grow(&symbol_obstack, '/');
1492                 obstack_grow(&symbol_obstack, headername, headername_len+1);
1493
1494                 char *complete_path = obstack_finish(&symbol_obstack);
1495                 FILE *file          = fopen(complete_path, "r");
1496                 if (file != NULL) {
1497                         const char *filename = identify_string(complete_path);
1498                         switch_input(file, filename);
1499                         return true;
1500                 } else {
1501                         obstack_free(&symbol_obstack, complete_path);
1502                 }
1503         }
1504
1505         return false;
1506 }
1507
1508 /* read till next newline character, only for parse_include_directive(),
1509  * use eat_pp_directive() in all other cases */
1510 static void skip_till_newline(void)
1511 {
1512         /* skip till newline */
1513         while (true) {
1514                 switch (input.c) {
1515                 case NEWLINE:
1516                 case EOF:
1517                         return;
1518                 }
1519                 next_char();
1520         }
1521 }
1522
1523 static void parse_include_directive(void)
1524 {
1525         if (skip_mode) {
1526                 eat_pp_directive();
1527                 return;
1528         }
1529
1530         /* don't eat the TP_include here!
1531          * we need an alternative parsing for the next token */
1532         skip_whitespace();
1533         bool system_include = input.c == '<';
1534         parse_headername();
1535         string_t headername = pp_token.literal.string;
1536         if (headername.begin == NULL) {
1537                 eat_pp_directive();
1538                 return;
1539         }
1540
1541         skip_whitespace();
1542         if (!info.at_line_begin) {
1543                 warningf(WARN_OTHER, &pp_token.base.source_position,
1544                          "extra tokens at end of #include directive");
1545                 skip_till_newline();
1546         }
1547
1548         if (n_inputs > INCLUDE_LIMIT) {
1549                 errorf(&pp_token.base.source_position, "#include nested too deeply");
1550                 /* eat \n or EOF */
1551                 next_preprocessing_token();
1552                 return;
1553         }
1554
1555         /* switch inputs */
1556         emit_newlines();
1557         push_input();
1558         bool res = do_include(system_include, pp_token.literal.string.begin);
1559         if (!res) {
1560                 errorf(&pp_token.base.source_position, "failed including '%S': %s", &pp_token.literal, strerror(errno));
1561                 pop_restore_input();
1562         }
1563 }
1564
1565 static pp_conditional_t *push_conditional(void)
1566 {
1567         pp_conditional_t *conditional
1568                 = obstack_alloc(&pp_obstack, sizeof(*conditional));
1569         memset(conditional, 0, sizeof(*conditional));
1570
1571         conditional->parent = conditional_stack;
1572         conditional_stack   = conditional;
1573
1574         return conditional;
1575 }
1576
1577 static void pop_conditional(void)
1578 {
1579         assert(conditional_stack != NULL);
1580         conditional_stack = conditional_stack->parent;
1581 }
1582
1583 static void check_unclosed_conditionals(void)
1584 {
1585         while (conditional_stack != NULL) {
1586                 pp_conditional_t *conditional = conditional_stack;
1587
1588                 if (conditional->in_else) {
1589                         errorf(&conditional->source_position, "unterminated #else");
1590                 } else {
1591                         errorf(&conditional->source_position, "unterminated condition");
1592                 }
1593                 pop_conditional();
1594         }
1595 }
1596
1597 static void parse_ifdef_ifndef_directive(bool const is_ifdef)
1598 {
1599         bool condition;
1600         eat_pp(is_ifdef ? TP_ifdef : TP_ifndef);
1601
1602         if (skip_mode) {
1603                 eat_pp_directive();
1604                 pp_conditional_t *conditional = push_conditional();
1605                 conditional->source_position  = pp_token.base.source_position;
1606                 conditional->skip             = true;
1607                 return;
1608         }
1609
1610         if (pp_token.kind != T_IDENTIFIER || info.at_line_begin) {
1611                 errorf(&pp_token.base.source_position,
1612                        "expected identifier after #%s, got %K",
1613                        is_ifdef ? "ifdef" : "ifndef", &pp_token);
1614                 eat_pp_directive();
1615
1616                 /* just take the true case in the hope to avoid further errors */
1617                 condition = true;
1618         } else {
1619                 /* evaluate wether we are in true or false case */
1620                 condition = (bool)pp_token.base.symbol->pp_definition == is_ifdef;
1621                 eat_token(T_IDENTIFIER);
1622
1623                 if (!info.at_line_begin) {
1624                         errorf(&pp_token.base.source_position,
1625                                "extra tokens at end of #%s",
1626                                is_ifdef ? "ifdef" : "ifndef");
1627                         eat_pp_directive();
1628                 }
1629         }
1630
1631         pp_conditional_t *conditional = push_conditional();
1632         conditional->source_position  = pp_token.base.source_position;
1633         conditional->condition        = condition;
1634
1635         if (!condition) {
1636                 skip_mode = true;
1637         }
1638 }
1639
1640 static void parse_else_directive(void)
1641 {
1642         eat_pp(TP_else);
1643
1644         if (!info.at_line_begin) {
1645                 if (!skip_mode) {
1646                         warningf(WARN_OTHER, &pp_token.base.source_position, "extra tokens at end of #else");
1647                 }
1648                 eat_pp_directive();
1649         }
1650
1651         pp_conditional_t *conditional = conditional_stack;
1652         if (conditional == NULL) {
1653                 errorf(&pp_token.base.source_position, "#else without prior #if");
1654                 return;
1655         }
1656
1657         if (conditional->in_else) {
1658                 errorf(&pp_token.base.source_position,
1659                        "#else after #else (condition started %P)",
1660                        &conditional->source_position);
1661                 skip_mode = true;
1662                 return;
1663         }
1664
1665         conditional->in_else = true;
1666         if (!conditional->skip) {
1667                 skip_mode = conditional->condition;
1668         }
1669         conditional->source_position = pp_token.base.source_position;
1670 }
1671
1672 static void parse_endif_directive(void)
1673 {
1674         eat_pp(TP_endif);
1675
1676         if (!info.at_line_begin) {
1677                 if (!skip_mode) {
1678                         warningf(WARN_OTHER, &pp_token.base.source_position, "extra tokens at end of #endif");
1679                 }
1680                 eat_pp_directive();
1681         }
1682
1683         pp_conditional_t *conditional = conditional_stack;
1684         if (conditional == NULL) {
1685                 errorf(&pp_token.base.source_position, "#endif without prior #if");
1686                 return;
1687         }
1688
1689         if (!conditional->skip) {
1690                 skip_mode = false;
1691         }
1692         pop_conditional();
1693 }
1694
1695 static void parse_preprocessing_directive(void)
1696 {
1697         eat_token('#');
1698
1699         if (info.at_line_begin) {
1700                 /* empty directive */
1701                 return;
1702         }
1703
1704         if (pp_token.base.symbol) {
1705                 switch (pp_token.base.symbol->pp_ID) {
1706                 case TP_define:  parse_define_directive();            break;
1707                 case TP_else:    parse_else_directive();              break;
1708                 case TP_endif:   parse_endif_directive();             break;
1709                 case TP_ifdef:   parse_ifdef_ifndef_directive(true);  break;
1710                 case TP_ifndef:  parse_ifdef_ifndef_directive(false); break;
1711                 case TP_include: parse_include_directive();           break;
1712                 case TP_undef:   parse_undef_directive();             break;
1713                 default:         goto skip;
1714                 }
1715         } else {
1716 skip:
1717                 if (!skip_mode) {
1718                         errorf(&pp_token.base.source_position, "invalid preprocessing directive #%K", &pp_token);
1719                 }
1720                 eat_pp_directive();
1721         }
1722
1723         assert(info.at_line_begin);
1724 }
1725
1726 static void prepend_include_path(const char *path)
1727 {
1728         searchpath_entry_t *entry = OALLOCZ(&config_obstack, searchpath_entry_t);
1729         entry->path = path;
1730         entry->next = searchpath;
1731         searchpath  = entry;
1732 }
1733
1734 static void setup_include_path(void)
1735 {
1736         /* built-in paths */
1737         prepend_include_path("/usr/include");
1738
1739         /* parse environment variable */
1740         const char *cpath = getenv("CPATH");
1741         if (cpath != NULL && *cpath != '\0') {
1742                 const char *begin = cpath;
1743                 const char *c;
1744                 do {
1745                         c = begin;
1746                         while (*c != '\0' && *c != ':')
1747                                 ++c;
1748
1749                         size_t len = c-begin;
1750                         if (len == 0) {
1751                                 /* for gcc compatibility (Matze: I would expect that
1752                                  * nothing happens for an empty entry...) */
1753                                 prepend_include_path(".");
1754                         } else {
1755                                 char *string = obstack_alloc(&config_obstack, len+1);
1756                                 memcpy(string, begin, len);
1757                                 string[len] = '\0';
1758
1759                                 prepend_include_path(string);
1760                         }
1761
1762                         begin = c+1;
1763                         /* skip : */
1764                         if (*begin == ':')
1765                                 ++begin;
1766                 } while(*c != '\0');
1767         }
1768 }
1769
1770 int pptest_main(int argc, char **argv);
1771 int pptest_main(int argc, char **argv)
1772 {
1773         init_symbol_table();
1774         init_tokens();
1775         init_symbols();
1776
1777         obstack_init(&config_obstack);
1778         obstack_init(&pp_obstack);
1779         obstack_init(&input_obstack);
1780         strset_init(&stringset);
1781
1782         error_on_unknown_chars = false;
1783
1784         setup_include_path();
1785
1786         /* simplistic commandline parser */
1787         const char *filename = NULL;
1788         const char *output = NULL;
1789         for (int i = 1; i < argc; ++i) {
1790                 const char *opt = argv[i];
1791                 if (streq(opt, "-I")) {
1792                         prepend_include_path(argv[++i]);
1793                         continue;
1794                 } else if (streq(opt, "-E")) {
1795                         /* ignore */
1796                 } else if (streq(opt, "-o")) {
1797                         output = argv[++i];
1798                         continue;
1799                 } else if (opt[0] == '-') {
1800                         fprintf(stderr, "Unknown option '%s'\n", opt);
1801                 } else {
1802                         if (filename != NULL)
1803                                 fprintf(stderr, "Multiple inputs not supported\n");
1804                         filename = argv[i];
1805                 }
1806         }
1807         if (filename == NULL) {
1808                 fprintf(stderr, "No input specified\n");
1809                 return 1;
1810         }
1811
1812         if (output == NULL) {
1813                 out = stdout;
1814         } else {
1815                 out = fopen(output, "w");
1816                 if (out == NULL) {
1817                         fprintf(stderr, "Couldn't open output '%s'\n", output);
1818                         return 1;
1819                 }
1820         }
1821
1822         /* just here for gcc compatibility */
1823         fprintf(out, "# 1 \"%s\"\n", filename);
1824         fprintf(out, "# 1 \"<built-in>\"\n");
1825         fprintf(out, "# 1 \"<command-line>\"\n");
1826
1827         FILE *file = fopen(filename, "r");
1828         if (file == NULL) {
1829                 fprintf(stderr, "Couldn't open input '%s'\n", filename);
1830                 return 1;
1831         }
1832         switch_input(file, filename);
1833
1834         while (true) {
1835                 if (pp_token.kind == '#' && info.at_line_begin) {
1836                         parse_preprocessing_directive();
1837                         continue;
1838                 } else if (pp_token.kind == T_EOF) {
1839                         goto end_of_main_loop;
1840                 } else if (pp_token.kind == T_IDENTIFIER) {
1841                         symbol_t        *const symbol        = pp_token.base.symbol;
1842                         pp_definition_t *const pp_definition = symbol->pp_definition;
1843                         if (pp_definition != NULL && !pp_definition->is_expanding) {
1844                                 expansion_pos = pp_token.base.source_position;
1845                                 if (pp_definition->has_parameters) {
1846                                         source_position_t position = pp_token.base.source_position;
1847                                         add_token_info_t old_info = info;
1848                                         eat_token(T_IDENTIFIER);
1849                                         add_token_info_t new_info = info;
1850
1851                                         /* no opening brace -> no expansion */
1852                                         if (pp_token.kind == '(') {
1853                                                 eat_token('(');
1854
1855                                                 /* parse arguments (TODO) */
1856                                                 while (pp_token.kind != T_EOF && pp_token.kind != ')')
1857                                                         next_preprocessing_token();
1858                                         } else {
1859                                                 token_t next_token = pp_token;
1860                                                 /* restore identifier token */
1861                                                 pp_token.kind                 = T_IDENTIFIER;
1862                                                 pp_token.base.symbol          = symbol;
1863                                                 pp_token.base.source_position = position;
1864                                                 info = old_info;
1865                                                 emit_pp_token();
1866
1867                                                 info = new_info;
1868                                                 pp_token = next_token;
1869                                                 continue;
1870                                         }
1871                                         info = old_info;
1872                                 }
1873                                 pp_definition->expand_pos   = 0;
1874                                 pp_definition->is_expanding = true;
1875                                 current_expansion           = pp_definition;
1876                                 expand_next();
1877                                 continue;
1878                         }
1879                 }
1880
1881                 emit_pp_token();
1882                 next_preprocessing_token();
1883         }
1884 end_of_main_loop:
1885
1886         fputc('\n', out);
1887         check_unclosed_conditionals();
1888         close_input();
1889         if (out != stdout)
1890                 fclose(out);
1891
1892         obstack_free(&input_obstack, NULL);
1893         obstack_free(&pp_obstack, NULL);
1894         obstack_free(&config_obstack, NULL);
1895
1896         strset_destroy(&stringset);
1897
1898         exit_tokens();
1899         exit_symbol_table();
1900
1901         return 0;
1902 }