always set symbol for non-literal tokens
[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                 ELSE(':')
1047         case '=':
1048                 MAYBE_PROLOG
1049                 MAYBE('=', T_EQUALEQUAL)
1050                 ELSE('=')
1051         case '#':
1052                 MAYBE_PROLOG
1053                 MAYBE('#', T_HASHHASH)
1054                 ELSE('#')
1055
1056         case '?':
1057         case '[':
1058         case ']':
1059         case '(':
1060         case ')':
1061         case '{':
1062         case '}':
1063         case '~':
1064         case ';':
1065         case ',':
1066                 set_punctuator(input.c);
1067                 next_char();
1068                 return;
1069
1070         case EOF:
1071                 if (input_stack != NULL) {
1072                         close_input();
1073                         pop_restore_input();
1074                         fputc('\n', out);
1075                         print_line_directive(&input.position, "2");
1076                         goto restart;
1077                 } else {
1078                         pp_token.base.source_position.lineno++;
1079                         info.at_line_begin = true;
1080                         set_punctuator(T_EOF);
1081                 }
1082                 return;
1083
1084         default:
1085                 if (error_on_unknown_chars) {
1086                         errorf(&pp_token.base.source_position,
1087                                "unknown character '%lc' found\n", input.c);
1088                         next_char();
1089                         goto restart;
1090                 } else {
1091                         assert(obstack_object_size(&symbol_obstack) == 0);
1092                         obstack_grow_utf8(&symbol_obstack, input.c);
1093                         obstack_1grow(&symbol_obstack, '\0');
1094                         char     *const string = obstack_finish(&symbol_obstack);
1095                         symbol_t *const symbol = symbol_table_insert(string);
1096                         if (symbol->string != string)
1097                                 obstack_free(&symbol_obstack, string);
1098
1099                         pp_token.kind        = T_UNKNOWN_CHAR;
1100                         pp_token.base.symbol = symbol;
1101                         next_char();
1102                         return;
1103                 }
1104         }
1105 }
1106
1107 static void print_quoted_string(const char *const string)
1108 {
1109         fputc('"', out);
1110         for (const char *c = string; *c != 0; ++c) {
1111                 switch (*c) {
1112                 case '"': fputs("\\\"", out); break;
1113                 case '\\':  fputs("\\\\", out); break;
1114                 case '\a':  fputs("\\a", out); break;
1115                 case '\b':  fputs("\\b", out); break;
1116                 case '\f':  fputs("\\f", out); break;
1117                 case '\n':  fputs("\\n", out); break;
1118                 case '\r':  fputs("\\r", out); break;
1119                 case '\t':  fputs("\\t", out); break;
1120                 case '\v':  fputs("\\v", out); break;
1121                 case '\?':  fputs("\\?", out); break;
1122                 default:
1123                         if (!isprint(*c)) {
1124                                 fprintf(out, "\\%03o", (unsigned)*c);
1125                                 break;
1126                         }
1127                         fputc(*c, out);
1128                         break;
1129                 }
1130         }
1131         fputc('"', out);
1132 }
1133
1134 static void print_line_directive(const source_position_t *pos, const char *add)
1135 {
1136         fprintf(out, "# %u ", pos->lineno);
1137         print_quoted_string(pos->input_name);
1138         if (add != NULL) {
1139                 fputc(' ', out);
1140                 fputs(add, out);
1141         }
1142
1143         printed_input_name = pos->input_name;
1144         input.output_line  = pos->lineno-1;
1145 }
1146
1147 static bool emit_newlines(void)
1148 {
1149         unsigned delta = pp_token.base.source_position.lineno - input.output_line;
1150         if (delta == 0)
1151                 return false;
1152
1153         if (delta >= 9) {
1154                 fputc('\n', out);
1155                 print_line_directive(&pp_token.base.source_position, NULL);
1156                 fputc('\n', out);
1157         } else {
1158                 for (unsigned i = 0; i < delta; ++i) {
1159                         fputc('\n', out);
1160                 }
1161         }
1162         input.output_line = pp_token.base.source_position.lineno;
1163
1164         for (unsigned i = 0; i < info.whitespace; ++i)
1165                 fputc(' ', out);
1166
1167         return true;
1168 }
1169
1170 static void emit_pp_token(void)
1171 {
1172         if (skip_mode)
1173                 return;
1174
1175         if (!emit_newlines() &&
1176             (info.had_whitespace || tokens_would_paste(last_token, pp_token.kind)))
1177                 fputc(' ', out);
1178
1179         switch (pp_token.kind) {
1180         case T_NUMBER:
1181                 fputs(pp_token.literal.string.begin, out);
1182                 break;
1183
1184         case T_STRING_LITERAL:
1185                 fputs(get_string_encoding_prefix(pp_token.literal.string.encoding), out);
1186                 fputc('"', out);
1187                 fputs(pp_token.literal.string.begin, out);
1188                 fputc('"', out);
1189                 break;
1190
1191         case T_CHARACTER_CONSTANT:
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         default:
1199                 fputs(pp_token.base.symbol->string, out);
1200                 break;
1201         }
1202         last_token = pp_token.kind;
1203 }
1204
1205 static void eat_pp_directive(void)
1206 {
1207         while (!info.at_line_begin) {
1208                 next_preprocessing_token();
1209         }
1210 }
1211
1212 static bool strings_equal(const string_t *string1, const string_t *string2)
1213 {
1214         size_t size = string1->size;
1215         if (size != string2->size)
1216                 return false;
1217
1218         const char *c1 = string1->begin;
1219         const char *c2 = string2->begin;
1220         for (size_t i = 0; i < size; ++i, ++c1, ++c2) {
1221                 if (*c1 != *c2)
1222                         return false;
1223         }
1224         return true;
1225 }
1226
1227 static bool pp_tokens_equal(const token_t *token1, const token_t *token2)
1228 {
1229         if (token1->kind != token2->kind)
1230                 return false;
1231
1232         switch (token1->kind) {
1233         case T_NUMBER:
1234         case T_CHARACTER_CONSTANT:
1235         case T_STRING_LITERAL:
1236                 return strings_equal(&token1->literal.string, &token2->literal.string);
1237
1238         default:
1239                 return token1->base.symbol == token2->base.symbol;
1240         }
1241 }
1242
1243 static bool pp_definitions_equal(const pp_definition_t *definition1,
1244                                  const pp_definition_t *definition2)
1245 {
1246         if (definition1->list_len != definition2->list_len)
1247                 return false;
1248
1249         size_t         len = definition1->list_len;
1250         const token_t *t1  = definition1->token_list;
1251         const token_t *t2  = definition2->token_list;
1252         for (size_t i = 0; i < len; ++i, ++t1, ++t2) {
1253                 if (!pp_tokens_equal(t1, t2))
1254                         return false;
1255         }
1256         return true;
1257 }
1258
1259 static void parse_define_directive(void)
1260 {
1261         eat_pp(TP_define);
1262         if (skip_mode) {
1263                 eat_pp_directive();
1264                 return;
1265         }
1266
1267         assert(obstack_object_size(&pp_obstack) == 0);
1268
1269         if (pp_token.kind != T_IDENTIFIER || info.at_line_begin) {
1270                 errorf(&pp_token.base.source_position,
1271                        "expected identifier after #define, got %K", &pp_token);
1272                 goto error_out;
1273         }
1274         symbol_t *const symbol = pp_token.base.symbol;
1275
1276         pp_definition_t *new_definition
1277                 = obstack_alloc(&pp_obstack, sizeof(new_definition[0]));
1278         memset(new_definition, 0, sizeof(new_definition[0]));
1279         new_definition->source_position = input.position;
1280
1281         /* this is probably the only place where spaces are significant in the
1282          * lexer (except for the fact that they separate tokens). #define b(x)
1283          * is something else than #define b (x) */
1284         if (input.c == '(') {
1285                 eat_token(T_IDENTIFIER);
1286                 eat_token('(');
1287
1288                 while (true) {
1289                         switch (pp_token.kind) {
1290                         case T_DOTDOTDOT:
1291                                 new_definition->is_variadic = true;
1292                                 eat_token(T_DOTDOTDOT);
1293                                 if (pp_token.kind != ')') {
1294                                         errorf(&input.position,
1295                                                         "'...' not at end of macro argument list");
1296                                         goto error_out;
1297                                 }
1298                                 break;
1299
1300                         case T_IDENTIFIER:
1301                                 obstack_ptr_grow(&pp_obstack, pp_token.base.symbol);
1302                                 eat_token(T_IDENTIFIER);
1303
1304                                 if (pp_token.kind == ',') {
1305                                         eat_token(',');
1306                                         break;
1307                                 }
1308
1309                                 if (pp_token.kind != ')') {
1310                                         errorf(&pp_token.base.source_position,
1311                                                "expected ',' or ')' after identifier, got %K",
1312                                                &pp_token);
1313                                         goto error_out;
1314                                 }
1315                                 break;
1316
1317                         case ')':
1318                                 eat_token(')');
1319                                 goto finish_argument_list;
1320
1321                         default:
1322                                 errorf(&pp_token.base.source_position,
1323                                        "expected identifier, '...' or ')' in #define argument list, got %K",
1324                                        &pp_token);
1325                                 goto error_out;
1326                         }
1327                 }
1328
1329         finish_argument_list:
1330                 new_definition->has_parameters = true;
1331                 new_definition->n_parameters
1332                         = obstack_object_size(&pp_obstack) / sizeof(new_definition->parameters[0]);
1333                 new_definition->parameters = obstack_finish(&pp_obstack);
1334         } else {
1335                 eat_token(T_IDENTIFIER);
1336         }
1337
1338         /* construct a new pp_definition on the obstack */
1339         assert(obstack_object_size(&pp_obstack) == 0);
1340         size_t list_len = 0;
1341         while (!info.at_line_begin) {
1342                 obstack_grow(&pp_obstack, &pp_token, sizeof(pp_token));
1343                 ++list_len;
1344                 next_preprocessing_token();
1345         }
1346
1347         new_definition->list_len   = list_len;
1348         new_definition->token_list = obstack_finish(&pp_obstack);
1349
1350         pp_definition_t *old_definition = symbol->pp_definition;
1351         if (old_definition != NULL) {
1352                 if (!pp_definitions_equal(old_definition, new_definition)) {
1353                         warningf(WARN_OTHER, &input.position, "multiple definition of macro '%Y' (first defined %P)", symbol, &old_definition->source_position);
1354                 } else {
1355                         /* reuse the old definition */
1356                         obstack_free(&pp_obstack, new_definition);
1357                         new_definition = old_definition;
1358                 }
1359         }
1360
1361         symbol->pp_definition = new_definition;
1362         return;
1363
1364 error_out:
1365         if (obstack_object_size(&pp_obstack) > 0) {
1366                 char *ptr = obstack_finish(&pp_obstack);
1367                 obstack_free(&pp_obstack, ptr);
1368         }
1369         eat_pp_directive();
1370 }
1371
1372 static void parse_undef_directive(void)
1373 {
1374         eat_pp(TP_undef);
1375         if (skip_mode) {
1376                 eat_pp_directive();
1377                 return;
1378         }
1379
1380         if (pp_token.kind != T_IDENTIFIER) {
1381                 errorf(&input.position,
1382                        "expected identifier after #undef, got %K", &pp_token);
1383                 eat_pp_directive();
1384                 return;
1385         }
1386
1387         pp_token.base.symbol->pp_definition = NULL;
1388         eat_token(T_IDENTIFIER);
1389
1390         if (!info.at_line_begin) {
1391                 warningf(WARN_OTHER, &input.position, "extra tokens at end of #undef directive");
1392         }
1393         eat_pp_directive();
1394 }
1395
1396 /** behind an #include we can have the special headername lexems.
1397  * They're only allowed behind an #include so they're not recognized
1398  * by the normal next_preprocessing_token. We handle them as a special
1399  * exception here */
1400 static void parse_headername(void)
1401 {
1402         const source_position_t start_position = input.position;
1403         string_t                string         = { NULL, 0, STRING_ENCODING_CHAR };
1404         assert(obstack_object_size(&symbol_obstack) == 0);
1405
1406         if (info.at_line_begin) {
1407                 parse_error("expected headername after #include");
1408                 goto finish_error;
1409         }
1410
1411         /* check wether we have a "... or <... headername */
1412         switch (input.c) {
1413         {
1414                 utf32 delimiter;
1415         case '<': delimiter = '>'; goto parse_name;
1416         case '"': delimiter = '"'; goto parse_name;
1417 parse_name:
1418                 next_char();
1419                 while (true) {
1420                         switch (input.c) {
1421                         case NEWLINE:
1422                         case EOF:
1423                                 errorf(&pp_token.base.source_position, "header name without closing '%c'", (char)delimiter);
1424                                 goto finish_error;
1425
1426                         default:
1427                                 if (input.c == delimiter) {
1428                                         next_char();
1429                                         goto finished_headername;
1430                                 } else {
1431                                         obstack_1grow(&symbol_obstack, (char)input.c);
1432                                         next_char();
1433                                 }
1434                                 break;
1435                         }
1436                 }
1437                 /* we should never be here */
1438         }
1439
1440         default:
1441                 /* TODO: do normal pp_token parsing and concatenate results */
1442                 panic("pp_token concat include not implemented yet");
1443         }
1444
1445 finished_headername:
1446         string = sym_make_string(STRING_ENCODING_CHAR);
1447
1448 finish_error:
1449         pp_token.base.source_position = start_position;
1450         pp_token.kind                 = T_HEADERNAME;
1451         pp_token.literal.string       = string;
1452 }
1453
1454 static bool do_include(bool system_include, const char *headername)
1455 {
1456         size_t headername_len = strlen(headername);
1457         if (!system_include) {
1458                 /* put dirname of current input on obstack */
1459                 const char *filename   = input.position.input_name;
1460                 const char *last_slash = strrchr(filename, '/');
1461                 if (last_slash != NULL) {
1462                         size_t len = last_slash - filename;
1463                         obstack_grow(&symbol_obstack, filename, len + 1);
1464                         obstack_grow0(&symbol_obstack, headername, headername_len);
1465                         char *complete_path = obstack_finish(&symbol_obstack);
1466                         headername = identify_string(complete_path);
1467                 }
1468
1469                 FILE *file = fopen(headername, "r");
1470                 if (file != NULL) {
1471                         switch_input(file, headername);
1472                         return true;
1473                 }
1474         }
1475
1476         assert(obstack_object_size(&symbol_obstack) == 0);
1477         /* check searchpath */
1478         for (searchpath_entry_t *entry = searchpath; entry != NULL;
1479              entry = entry->next) {
1480             const char *path = entry->path;
1481             size_t      len  = strlen(path);
1482                 obstack_grow(&symbol_obstack, path, len);
1483                 if (path[len-1] != '/')
1484                         obstack_1grow(&symbol_obstack, '/');
1485                 obstack_grow(&symbol_obstack, headername, headername_len+1);
1486
1487                 char *complete_path = obstack_finish(&symbol_obstack);
1488                 FILE *file          = fopen(complete_path, "r");
1489                 if (file != NULL) {
1490                         const char *filename = identify_string(complete_path);
1491                         switch_input(file, filename);
1492                         return true;
1493                 } else {
1494                         obstack_free(&symbol_obstack, complete_path);
1495                 }
1496         }
1497
1498         return false;
1499 }
1500
1501 /* read till next newline character, only for parse_include_directive(),
1502  * use eat_pp_directive() in all other cases */
1503 static void skip_till_newline(void)
1504 {
1505         /* skip till newline */
1506         while (true) {
1507                 switch (input.c) {
1508                 case NEWLINE:
1509                 case EOF:
1510                         return;
1511                 }
1512                 next_char();
1513         }
1514 }
1515
1516 static void parse_include_directive(void)
1517 {
1518         if (skip_mode) {
1519                 eat_pp_directive();
1520                 return;
1521         }
1522
1523         /* don't eat the TP_include here!
1524          * we need an alternative parsing for the next token */
1525         skip_whitespace();
1526         bool system_include = input.c == '<';
1527         parse_headername();
1528         string_t headername = pp_token.literal.string;
1529         if (headername.begin == NULL) {
1530                 eat_pp_directive();
1531                 return;
1532         }
1533
1534         skip_whitespace();
1535         if (!info.at_line_begin) {
1536                 warningf(WARN_OTHER, &pp_token.base.source_position,
1537                          "extra tokens at end of #include directive");
1538                 skip_till_newline();
1539         }
1540
1541         if (n_inputs > INCLUDE_LIMIT) {
1542                 errorf(&pp_token.base.source_position, "#include nested too deeply");
1543                 /* eat \n or EOF */
1544                 next_preprocessing_token();
1545                 return;
1546         }
1547
1548         /* switch inputs */
1549         emit_newlines();
1550         push_input();
1551         bool res = do_include(system_include, pp_token.literal.string.begin);
1552         if (!res) {
1553                 errorf(&pp_token.base.source_position, "failed including '%S': %s", &pp_token.literal, strerror(errno));
1554                 pop_restore_input();
1555         }
1556 }
1557
1558 static pp_conditional_t *push_conditional(void)
1559 {
1560         pp_conditional_t *conditional
1561                 = obstack_alloc(&pp_obstack, sizeof(*conditional));
1562         memset(conditional, 0, sizeof(*conditional));
1563
1564         conditional->parent = conditional_stack;
1565         conditional_stack   = conditional;
1566
1567         return conditional;
1568 }
1569
1570 static void pop_conditional(void)
1571 {
1572         assert(conditional_stack != NULL);
1573         conditional_stack = conditional_stack->parent;
1574 }
1575
1576 static void check_unclosed_conditionals(void)
1577 {
1578         while (conditional_stack != NULL) {
1579                 pp_conditional_t *conditional = conditional_stack;
1580
1581                 if (conditional->in_else) {
1582                         errorf(&conditional->source_position, "unterminated #else");
1583                 } else {
1584                         errorf(&conditional->source_position, "unterminated condition");
1585                 }
1586                 pop_conditional();
1587         }
1588 }
1589
1590 static void parse_ifdef_ifndef_directive(bool const is_ifdef)
1591 {
1592         bool condition;
1593         eat_pp(is_ifdef ? TP_ifdef : TP_ifndef);
1594
1595         if (skip_mode) {
1596                 eat_pp_directive();
1597                 pp_conditional_t *conditional = push_conditional();
1598                 conditional->source_position  = pp_token.base.source_position;
1599                 conditional->skip             = true;
1600                 return;
1601         }
1602
1603         if (pp_token.kind != T_IDENTIFIER || info.at_line_begin) {
1604                 errorf(&pp_token.base.source_position,
1605                        "expected identifier after #%s, got %K",
1606                        is_ifdef ? "ifdef" : "ifndef", &pp_token);
1607                 eat_pp_directive();
1608
1609                 /* just take the true case in the hope to avoid further errors */
1610                 condition = true;
1611         } else {
1612                 /* evaluate wether we are in true or false case */
1613                 condition = (bool)pp_token.base.symbol->pp_definition == is_ifdef;
1614                 eat_token(T_IDENTIFIER);
1615
1616                 if (!info.at_line_begin) {
1617                         errorf(&pp_token.base.source_position,
1618                                "extra tokens at end of #%s",
1619                                is_ifdef ? "ifdef" : "ifndef");
1620                         eat_pp_directive();
1621                 }
1622         }
1623
1624         pp_conditional_t *conditional = push_conditional();
1625         conditional->source_position  = pp_token.base.source_position;
1626         conditional->condition        = condition;
1627
1628         if (!condition) {
1629                 skip_mode = true;
1630         }
1631 }
1632
1633 static void parse_else_directive(void)
1634 {
1635         eat_pp(TP_else);
1636
1637         if (!info.at_line_begin) {
1638                 if (!skip_mode) {
1639                         warningf(WARN_OTHER, &pp_token.base.source_position, "extra tokens at end of #else");
1640                 }
1641                 eat_pp_directive();
1642         }
1643
1644         pp_conditional_t *conditional = conditional_stack;
1645         if (conditional == NULL) {
1646                 errorf(&pp_token.base.source_position, "#else without prior #if");
1647                 return;
1648         }
1649
1650         if (conditional->in_else) {
1651                 errorf(&pp_token.base.source_position,
1652                        "#else after #else (condition started %P)",
1653                        &conditional->source_position);
1654                 skip_mode = true;
1655                 return;
1656         }
1657
1658         conditional->in_else = true;
1659         if (!conditional->skip) {
1660                 skip_mode = conditional->condition;
1661         }
1662         conditional->source_position = pp_token.base.source_position;
1663 }
1664
1665 static void parse_endif_directive(void)
1666 {
1667         eat_pp(TP_endif);
1668
1669         if (!info.at_line_begin) {
1670                 if (!skip_mode) {
1671                         warningf(WARN_OTHER, &pp_token.base.source_position, "extra tokens at end of #endif");
1672                 }
1673                 eat_pp_directive();
1674         }
1675
1676         pp_conditional_t *conditional = conditional_stack;
1677         if (conditional == NULL) {
1678                 errorf(&pp_token.base.source_position, "#endif without prior #if");
1679                 return;
1680         }
1681
1682         if (!conditional->skip) {
1683                 skip_mode = false;
1684         }
1685         pop_conditional();
1686 }
1687
1688 static void parse_preprocessing_directive(void)
1689 {
1690         eat_token('#');
1691
1692         if (info.at_line_begin) {
1693                 /* empty directive */
1694                 return;
1695         }
1696
1697         if (pp_token.base.symbol) {
1698                 switch (pp_token.base.symbol->pp_ID) {
1699                 case TP_define:  parse_define_directive();            break;
1700                 case TP_else:    parse_else_directive();              break;
1701                 case TP_endif:   parse_endif_directive();             break;
1702                 case TP_ifdef:   parse_ifdef_ifndef_directive(true);  break;
1703                 case TP_ifndef:  parse_ifdef_ifndef_directive(false); break;
1704                 case TP_include: parse_include_directive();           break;
1705                 case TP_undef:   parse_undef_directive();             break;
1706                 default:         goto skip;
1707                 }
1708         } else {
1709 skip:
1710                 if (!skip_mode) {
1711                         errorf(&pp_token.base.source_position, "invalid preprocessing directive #%K", &pp_token);
1712                 }
1713                 eat_pp_directive();
1714         }
1715
1716         assert(info.at_line_begin);
1717 }
1718
1719 static void prepend_include_path(const char *path)
1720 {
1721         searchpath_entry_t *entry = OALLOCZ(&config_obstack, searchpath_entry_t);
1722         entry->path = path;
1723         entry->next = searchpath;
1724         searchpath  = entry;
1725 }
1726
1727 static void setup_include_path(void)
1728 {
1729         /* built-in paths */
1730         prepend_include_path("/usr/include");
1731
1732         /* parse environment variable */
1733         const char *cpath = getenv("CPATH");
1734         if (cpath != NULL && *cpath != '\0') {
1735                 const char *begin = cpath;
1736                 const char *c;
1737                 do {
1738                         c = begin;
1739                         while (*c != '\0' && *c != ':')
1740                                 ++c;
1741
1742                         size_t len = c-begin;
1743                         if (len == 0) {
1744                                 /* for gcc compatibility (Matze: I would expect that
1745                                  * nothing happens for an empty entry...) */
1746                                 prepend_include_path(".");
1747                         } else {
1748                                 char *string = obstack_alloc(&config_obstack, len+1);
1749                                 memcpy(string, begin, len);
1750                                 string[len] = '\0';
1751
1752                                 prepend_include_path(string);
1753                         }
1754
1755                         begin = c+1;
1756                         /* skip : */
1757                         if (*begin == ':')
1758                                 ++begin;
1759                 } while(*c != '\0');
1760         }
1761 }
1762
1763 int pptest_main(int argc, char **argv);
1764 int pptest_main(int argc, char **argv)
1765 {
1766         init_symbol_table();
1767         init_tokens();
1768         init_symbols();
1769
1770         obstack_init(&config_obstack);
1771         obstack_init(&pp_obstack);
1772         obstack_init(&input_obstack);
1773         strset_init(&stringset);
1774
1775         error_on_unknown_chars = false;
1776
1777         setup_include_path();
1778
1779         /* simplistic commandline parser */
1780         const char *filename = NULL;
1781         const char *output = NULL;
1782         for (int i = 1; i < argc; ++i) {
1783                 const char *opt = argv[i];
1784                 if (streq(opt, "-I")) {
1785                         prepend_include_path(argv[++i]);
1786                         continue;
1787                 } else if (streq(opt, "-E")) {
1788                         /* ignore */
1789                 } else if (streq(opt, "-o")) {
1790                         output = argv[++i];
1791                         continue;
1792                 } else if (opt[0] == '-') {
1793                         fprintf(stderr, "Unknown option '%s'\n", opt);
1794                 } else {
1795                         if (filename != NULL)
1796                                 fprintf(stderr, "Multiple inputs not supported\n");
1797                         filename = argv[i];
1798                 }
1799         }
1800         if (filename == NULL) {
1801                 fprintf(stderr, "No input specified\n");
1802                 return 1;
1803         }
1804
1805         if (output == NULL) {
1806                 out = stdout;
1807         } else {
1808                 out = fopen(output, "w");
1809                 if (out == NULL) {
1810                         fprintf(stderr, "Couldn't open output '%s'\n", output);
1811                         return 1;
1812                 }
1813         }
1814
1815         /* just here for gcc compatibility */
1816         fprintf(out, "# 1 \"%s\"\n", filename);
1817         fprintf(out, "# 1 \"<built-in>\"\n");
1818         fprintf(out, "# 1 \"<command-line>\"\n");
1819
1820         FILE *file = fopen(filename, "r");
1821         if (file == NULL) {
1822                 fprintf(stderr, "Couldn't open input '%s'\n", filename);
1823                 return 1;
1824         }
1825         switch_input(file, filename);
1826
1827         while (true) {
1828                 if (pp_token.kind == '#' && info.at_line_begin) {
1829                         parse_preprocessing_directive();
1830                         continue;
1831                 } else if (pp_token.kind == T_EOF) {
1832                         goto end_of_main_loop;
1833                 } else if (pp_token.kind == T_IDENTIFIER) {
1834                         symbol_t        *const symbol        = pp_token.base.symbol;
1835                         pp_definition_t *const pp_definition = symbol->pp_definition;
1836                         if (pp_definition != NULL && !pp_definition->is_expanding) {
1837                                 expansion_pos = pp_token.base.source_position;
1838                                 if (pp_definition->has_parameters) {
1839                                         source_position_t position = pp_token.base.source_position;
1840                                         add_token_info_t old_info = info;
1841                                         eat_token(T_IDENTIFIER);
1842                                         add_token_info_t new_info = info;
1843
1844                                         /* no opening brace -> no expansion */
1845                                         if (pp_token.kind == '(') {
1846                                                 eat_token('(');
1847
1848                                                 /* parse arguments (TODO) */
1849                                                 while (pp_token.kind != T_EOF && pp_token.kind != ')')
1850                                                         next_preprocessing_token();
1851                                         } else {
1852                                                 token_t next_token = pp_token;
1853                                                 /* restore identifier token */
1854                                                 pp_token.kind                 = T_IDENTIFIER;
1855                                                 pp_token.base.symbol          = symbol;
1856                                                 pp_token.base.source_position = position;
1857                                                 info = old_info;
1858                                                 emit_pp_token();
1859
1860                                                 info = new_info;
1861                                                 pp_token = next_token;
1862                                                 continue;
1863                                         }
1864                                         info = old_info;
1865                                 }
1866                                 pp_definition->expand_pos   = 0;
1867                                 pp_definition->is_expanding = true;
1868                                 current_expansion           = pp_definition;
1869                                 expand_next();
1870                                 continue;
1871                         }
1872                 }
1873
1874                 emit_pp_token();
1875                 next_preprocessing_token();
1876         }
1877 end_of_main_loop:
1878
1879         fputc('\n', out);
1880         check_unclosed_conditionals();
1881         close_input();
1882         if (out != stdout)
1883                 fclose(out);
1884
1885         obstack_free(&input_obstack, NULL);
1886         obstack_free(&pp_obstack, NULL);
1887         obstack_free(&config_obstack, NULL);
1888
1889         strset_destroy(&stringset);
1890
1891         exit_tokens();
1892         exit_symbol_table();
1893
1894         return 0;
1895 }