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