Merge TP_WIDE_STRING_LITERAL into TP_STRING_LITERAL.
[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_wide_character_constant(void)
513 {
514         eat('\'');
515
516         while (true) {
517                 switch (input.c) {
518                 case '\\': {
519                         const utf32 tc = parse_escape_sequence();
520                         obstack_grow_symbol(&symbol_obstack, tc);
521                         break;
522                 }
523
524                 MATCH_NEWLINE(
525                         parse_error("newline while parsing character constant");
526                         break;
527                 )
528
529                 case '\'':
530                         next_char();
531                         goto end_of_wide_char_constant;
532
533                 case EOF:
534                         parse_error("EOF while parsing character constant");
535                         goto end_of_wide_char_constant;
536
537                 default:
538                         obstack_grow_symbol(&symbol_obstack, input.c);
539                         next_char();
540                         break;
541                 }
542         }
543
544 end_of_wide_char_constant:
545         obstack_1grow(&symbol_obstack, '\0');
546         size_t  size = (size_t) obstack_object_size(&symbol_obstack)-1;
547         char   *string = obstack_finish(&symbol_obstack);
548         pp_token.kind          = TP_WIDE_CHARACTER_CONSTANT;
549         pp_token.string.string = make_string(string, size);
550
551         if (size == 0) {
552                 parse_error("empty character constant");
553         }
554 }
555
556 static void parse_character_constant(void)
557 {
558         const unsigned start_linenr = input.position.lineno;
559
560         eat('\'');
561
562         int tc;
563         while (true) {
564                 switch (input.c) {
565                 case '\\':
566                         tc = parse_escape_sequence();
567                         obstack_1grow(&symbol_obstack, (char) tc);
568                         break;
569
570                 MATCH_NEWLINE(
571                         parse_error("newline while parsing character constant");
572                         break;
573                 )
574
575                 case EOF: {
576                         source_position_t source_position;
577                         source_position.input_name = pp_token.base.source_position.input_name;
578                         source_position.lineno     = start_linenr;
579                         errorf(&source_position, "EOF while parsing character constant");
580                         goto end_of_char_constant;
581                 }
582
583                 case '\'':
584                         next_char();
585                         goto end_of_char_constant;
586
587                 default:
588                         obstack_1grow(&symbol_obstack, (char) input.c);
589                         next_char();
590                         break;
591
592                 }
593         }
594
595 end_of_char_constant:;
596         obstack_1grow(&symbol_obstack, '\0');
597         const size_t size   = (size_t)obstack_object_size(&symbol_obstack);
598         char *const  string = obstack_finish(&symbol_obstack);
599
600         pp_token.kind          = TP_CHARACTER_CONSTANT;
601         pp_token.string.string = make_string(string, size);
602
603         if (size == 0) {
604                 parse_error("empty character constant");
605         }
606 }
607
608 #define SYMBOL_CHARS_WITHOUT_E_P \
609         case 'a': \
610         case 'b': \
611         case 'c': \
612         case 'd': \
613         case 'f': \
614         case 'g': \
615         case 'h': \
616         case 'i': \
617         case 'j': \
618         case 'k': \
619         case 'l': \
620         case 'm': \
621         case 'n': \
622         case 'o': \
623         case 'q': \
624         case 'r': \
625         case 's': \
626         case 't': \
627         case 'u': \
628         case 'v': \
629         case 'w': \
630         case 'x': \
631         case 'y': \
632         case 'z': \
633         case 'A': \
634         case 'B': \
635         case 'C': \
636         case 'D': \
637         case 'F': \
638         case 'G': \
639         case 'H': \
640         case 'I': \
641         case 'J': \
642         case 'K': \
643         case 'L': \
644         case 'M': \
645         case 'N': \
646         case 'O': \
647         case 'Q': \
648         case 'R': \
649         case 'S': \
650         case 'T': \
651         case 'U': \
652         case 'V': \
653         case 'W': \
654         case 'X': \
655         case 'Y': \
656         case 'Z': \
657         case '_':
658
659 #define SYMBOL_CHARS \
660         SYMBOL_CHARS_WITHOUT_E_P \
661         case 'e': \
662         case 'p': \
663         case 'E': \
664         case 'P':
665
666 #define DIGITS \
667         case '0':  \
668         case '1':  \
669         case '2':  \
670         case '3':  \
671         case '4':  \
672         case '5':  \
673         case '6':  \
674         case '7':  \
675         case '8':  \
676         case '9':
677
678 /**
679  * returns next final token from a preprocessor macro expansion
680  */
681 static void expand_next(void)
682 {
683         assert(current_expansion != NULL);
684
685         pp_definition_t *definition = current_expansion;
686
687 restart:
688         if (definition->list_len == 0
689                         || definition->expand_pos >= definition->list_len) {
690                 /* we're finished with the current macro, move up 1 level in the
691                  * expansion stack */
692                 pp_definition_t *parent = definition->parent_expansion;
693                 definition->parent_expansion = NULL;
694                 definition->is_expanding     = false;
695
696                 /* it was the outermost expansion, parse normal pptoken */
697                 if (parent == NULL) {
698                         current_expansion = NULL;
699                         next_preprocessing_token();
700                         return;
701                 }
702                 definition        = parent;
703                 current_expansion = definition;
704                 goto restart;
705         }
706         pp_token = definition->token_list[definition->expand_pos];
707         pp_token.base.source_position = expansion_pos;
708         ++definition->expand_pos;
709
710         if (pp_token.kind != TP_IDENTIFIER)
711                 return;
712
713         /* if it was an identifier then we might need to expand again */
714         pp_definition_t *const symbol_definition = pp_token.base.symbol->pp_definition;
715         if (symbol_definition != NULL && !symbol_definition->is_expanding) {
716                 symbol_definition->parent_expansion = definition;
717                 symbol_definition->expand_pos       = 0;
718                 symbol_definition->is_expanding     = true;
719                 definition                          = symbol_definition;
720                 current_expansion                   = definition;
721                 goto restart;
722         }
723 }
724
725 static void skip_line_comment(void)
726 {
727         while (true) {
728                 switch (input.c) {
729                 case EOF:
730                         return;
731
732                 case '\r':
733                 case '\n':
734                         return;
735
736                 default:
737                         next_char();
738                         break;
739                 }
740         }
741 }
742
743 static void skip_multiline_comment(void)
744 {
745         unsigned start_linenr = input.position.lineno;
746         while (true) {
747                 switch (input.c) {
748                 case '/':
749                         next_char();
750                         if (input.c == '*') {
751                                 /* TODO: nested comment, warn here */
752                         }
753                         break;
754                 case '*':
755                         next_char();
756                         if (input.c == '/') {
757                                 if (input.position.lineno != input.output_line)
758                                         info.whitespace = input.position.colno;
759                                 next_char();
760                                 return;
761                         }
762                         break;
763
764                 MATCH_NEWLINE(
765                         break;
766                 )
767
768                 case EOF: {
769                         source_position_t source_position;
770                         source_position.input_name = pp_token.base.source_position.input_name;
771                         source_position.lineno     = start_linenr;
772                         errorf(&source_position, "at end of file while looking for comment end");
773                         return;
774                 }
775
776                 default:
777                         next_char();
778                         break;
779                 }
780         }
781 }
782
783 static void skip_whitespace(void)
784 {
785         while (true) {
786                 switch (input.c) {
787                 case ' ':
788                 case '\t':
789                         next_char();
790                         continue;
791
792                 MATCH_NEWLINE(
793                         info.at_line_begin = true;
794                         return;
795                 )
796
797                 case '/':
798                         next_char();
799                         if (input.c == '/') {
800                                 next_char();
801                                 skip_line_comment();
802                                 continue;
803                         } else if (input.c == '*') {
804                                 next_char();
805                                 skip_multiline_comment();
806                                 continue;
807                         } else {
808                                 put_back(input.c);
809                                 input.c = '/';
810                         }
811                         return;
812                 default:
813                         return;
814                 }
815         }
816 }
817
818 static void eat_pp(preprocessor_token_kind_t const type)
819 {
820         (void) type;
821         assert(pp_token.kind == type);
822         next_preprocessing_token();
823 }
824
825 static void parse_symbol(void)
826 {
827         obstack_1grow(&symbol_obstack, (char) input.c);
828         next_char();
829
830         while (true) {
831                 switch (input.c) {
832                 DIGITS
833                 SYMBOL_CHARS
834                         obstack_1grow(&symbol_obstack, (char) input.c);
835                         next_char();
836                         break;
837
838                 default:
839                         goto end_symbol;
840                 }
841         }
842
843 end_symbol:
844         obstack_1grow(&symbol_obstack, '\0');
845         char *string = obstack_finish(&symbol_obstack);
846
847         /* might be a wide string or character constant ( L"string"/L'c' ) */
848         if (input.c == '"' && string[0] == 'L' && string[1] == '\0') {
849                 obstack_free(&symbol_obstack, string);
850                 parse_string_literal(STRING_ENCODING_WIDE);
851                 return;
852         } else if (input.c == '\'' && string[0] == 'L' && string[1] == '\0') {
853                 obstack_free(&symbol_obstack, string);
854                 parse_wide_character_constant();
855                 return;
856         }
857
858         symbol_t *symbol = symbol_table_insert(string);
859
860         pp_token.kind        = symbol->pp_ID;
861         pp_token.base.symbol = symbol;
862
863         /* we can free the memory from symbol obstack if we already had an entry in
864          * the symbol table */
865         if (symbol->string != string) {
866                 obstack_free(&symbol_obstack, string);
867         }
868 }
869
870 static void parse_number(void)
871 {
872         obstack_1grow(&symbol_obstack, (char) input.c);
873         next_char();
874
875         while (true) {
876                 switch (input.c) {
877                 case '.':
878                 DIGITS
879                 SYMBOL_CHARS_WITHOUT_E_P
880                         obstack_1grow(&symbol_obstack, (char) input.c);
881                         next_char();
882                         break;
883
884                 case 'e':
885                 case 'p':
886                 case 'E':
887                 case 'P':
888                         obstack_1grow(&symbol_obstack, (char) input.c);
889                         next_char();
890                         if (input.c == '+' || input.c == '-') {
891                                 obstack_1grow(&symbol_obstack, (char) input.c);
892                                 next_char();
893                         }
894                         break;
895
896                 default:
897                         goto end_number;
898                 }
899         }
900
901 end_number:
902         obstack_1grow(&symbol_obstack, '\0');
903         size_t  size   = obstack_object_size(&symbol_obstack);
904         char   *string = obstack_finish(&symbol_obstack);
905
906         pp_token.kind          = TP_NUMBER;
907         pp_token.number.number = make_string(string, size);
908 }
909
910
911 #define MAYBE_PROLOG                                       \
912                         next_char();                                   \
913                         while (true) {                                 \
914                                 switch (input.c) {
915
916 #define MAYBE(ch, set_type)                                \
917                                 case ch:                                   \
918                                         next_char();                           \
919                                         pp_token.kind = set_type;              \
920                                         return;
921
922 #define ELSE_CODE(code)                                    \
923                                 default:                                   \
924                                         code                                   \
925                                         return;                                \
926                                 }                                          \
927                         }
928
929 #define ELSE(set_type)                                     \
930                 ELSE_CODE(                                         \
931                         pp_token.kind = set_type;                      \
932                 )
933
934 static void next_preprocessing_token(void)
935 {
936         if (current_expansion != NULL) {
937                 expand_next();
938                 return;
939         }
940
941         info.at_line_begin  = false;
942         info.had_whitespace = false;
943 restart:
944         pp_token.base.source_position = input.position;
945         pp_token.base.symbol          = NULL;
946
947         switch (input.c) {
948         case ' ':
949         case '\t':
950                 ++info.whitespace;
951                 info.had_whitespace = true;
952                 next_char();
953                 goto restart;
954
955         MATCH_NEWLINE(
956                 info.at_line_begin = true;
957                 info.had_whitespace = true;
958                 goto restart;
959         )
960
961         SYMBOL_CHARS
962                 parse_symbol();
963                 return;
964
965         DIGITS
966                 parse_number();
967                 return;
968
969         case '"':
970                 parse_string_literal(STRING_ENCODING_CHAR);
971                 return;
972
973         case '\'':
974                 parse_character_constant();
975                 return;
976
977         case '.':
978                 MAYBE_PROLOG
979                         case '0':
980                         case '1':
981                         case '2':
982                         case '3':
983                         case '4':
984                         case '5':
985                         case '6':
986                         case '7':
987                         case '8':
988                         case '9':
989                                 put_back(input.c);
990                                 input.c = '.';
991                                 parse_number();
992                                 return;
993
994                         case '.':
995                                 MAYBE_PROLOG
996                                 MAYBE('.', TP_DOTDOTDOT)
997                                 ELSE_CODE(
998                                         put_back(input.c);
999                                         input.c = '.';
1000                                         pp_token.kind = '.';
1001                                 )
1002                 ELSE('.')
1003         case '&':
1004                 MAYBE_PROLOG
1005                 MAYBE('&', TP_ANDAND)
1006                 MAYBE('=', TP_ANDEQUAL)
1007                 ELSE('&')
1008         case '*':
1009                 MAYBE_PROLOG
1010                 MAYBE('=', TP_ASTERISKEQUAL)
1011                 ELSE('*')
1012         case '+':
1013                 MAYBE_PROLOG
1014                 MAYBE('+', TP_PLUSPLUS)
1015                 MAYBE('=', TP_PLUSEQUAL)
1016                 ELSE('+')
1017         case '-':
1018                 MAYBE_PROLOG
1019                 MAYBE('>', TP_MINUSGREATER)
1020                 MAYBE('-', TP_MINUSMINUS)
1021                 MAYBE('=', TP_MINUSEQUAL)
1022                 ELSE('-')
1023         case '!':
1024                 MAYBE_PROLOG
1025                 MAYBE('=', TP_EXCLAMATIONMARKEQUAL)
1026                 ELSE('!')
1027         case '/':
1028                 MAYBE_PROLOG
1029                 MAYBE('=', TP_SLASHEQUAL)
1030                         case '*':
1031                                 next_char();
1032                                 info.had_whitespace = true;
1033                                 skip_multiline_comment();
1034                                 goto restart;
1035                         case '/':
1036                                 next_char();
1037                                 info.had_whitespace = true;
1038                                 skip_line_comment();
1039                                 goto restart;
1040                 ELSE('/')
1041         case '%':
1042                 MAYBE_PROLOG
1043                 MAYBE('>', '}')
1044                 MAYBE('=', TP_PERCENTEQUAL)
1045                         case ':':
1046                                 MAYBE_PROLOG
1047                                         case '%':
1048                                                 MAYBE_PROLOG
1049                                                 MAYBE(':', TP_HASHHASH)
1050                                                 ELSE_CODE(
1051                                                         put_back(input.c);
1052                                                         input.c = '%';
1053                                                         pp_token.kind = '#';
1054                                                 )
1055                                 ELSE('#')
1056                 ELSE('%')
1057         case '<':
1058                 MAYBE_PROLOG
1059                 MAYBE(':', '[')
1060                 MAYBE('%', '{')
1061                 MAYBE('=', TP_LESSEQUAL)
1062                         case '<':
1063                                 MAYBE_PROLOG
1064                                 MAYBE('=', TP_LESSLESSEQUAL)
1065                                 ELSE(TP_LESSLESS)
1066                 ELSE('<')
1067         case '>':
1068                 MAYBE_PROLOG
1069                 MAYBE('=', TP_GREATEREQUAL)
1070                         case '>':
1071                                 MAYBE_PROLOG
1072                                 MAYBE('=', TP_GREATERGREATEREQUAL)
1073                                 ELSE(TP_GREATERGREATER)
1074                 ELSE('>')
1075         case '^':
1076                 MAYBE_PROLOG
1077                 MAYBE('=', TP_CARETEQUAL)
1078                 ELSE('^')
1079         case '|':
1080                 MAYBE_PROLOG
1081                 MAYBE('=', TP_PIPEEQUAL)
1082                 MAYBE('|', TP_PIPEPIPE)
1083                 ELSE('|')
1084         case ':':
1085                 MAYBE_PROLOG
1086                 MAYBE('>', ']')
1087                 ELSE(':')
1088         case '=':
1089                 MAYBE_PROLOG
1090                 MAYBE('=', TP_EQUALEQUAL)
1091                 ELSE('=')
1092         case '#':
1093                 MAYBE_PROLOG
1094                 MAYBE('#', TP_HASHHASH)
1095                 ELSE_CODE(
1096                         pp_token.kind = '#';
1097                 )
1098
1099         case '?':
1100         case '[':
1101         case ']':
1102         case '(':
1103         case ')':
1104         case '{':
1105         case '}':
1106         case '~':
1107         case ';':
1108         case ',':
1109         case '\\':
1110                 pp_token.kind = input.c;
1111                 next_char();
1112                 return;
1113
1114         case EOF:
1115                 if (input_stack != NULL) {
1116                         close_input();
1117                         pop_restore_input();
1118                         fputc('\n', out);
1119                         print_line_directive(&input.position, "2");
1120                         goto restart;
1121                 } else {
1122                         pp_token.base.source_position.lineno++;
1123                         info.at_line_begin = true;
1124                         pp_token.kind = TP_EOF;
1125                 }
1126                 return;
1127
1128         default:
1129                 next_char();
1130                 if (!ignore_unknown_chars) {
1131                         errorf(&pp_token.base.source_position,
1132                                "unknown character '%c' found\n", input.c);
1133                         goto restart;
1134                 } else {
1135                         pp_token.kind = input.c;
1136                         return;
1137                 }
1138         }
1139 }
1140
1141 static void print_quoted_string(const char *const string)
1142 {
1143         fputc('"', out);
1144         for (const char *c = string; *c != 0; ++c) {
1145                 switch (*c) {
1146                 case '"': fputs("\\\"", out); break;
1147                 case '\\':  fputs("\\\\", out); break;
1148                 case '\a':  fputs("\\a", out); break;
1149                 case '\b':  fputs("\\b", out); break;
1150                 case '\f':  fputs("\\f", out); break;
1151                 case '\n':  fputs("\\n", out); break;
1152                 case '\r':  fputs("\\r", out); break;
1153                 case '\t':  fputs("\\t", out); break;
1154                 case '\v':  fputs("\\v", out); break;
1155                 case '\?':  fputs("\\?", out); break;
1156                 default:
1157                         if (!isprint(*c)) {
1158                                 fprintf(out, "\\%03o", (unsigned)*c);
1159                                 break;
1160                         }
1161                         fputc(*c, out);
1162                         break;
1163                 }
1164         }
1165         fputc('"', out);
1166 }
1167
1168 static void print_line_directive(const source_position_t *pos, const char *add)
1169 {
1170         fprintf(out, "# %u ", pos->lineno);
1171         print_quoted_string(pos->input_name);
1172         if (add != NULL) {
1173                 fputc(' ', out);
1174                 fputs(add, out);
1175         }
1176
1177         printed_input_name = pos->input_name;
1178         input.output_line  = pos->lineno-1;
1179 }
1180
1181 static bool emit_newlines(void)
1182 {
1183         unsigned delta = pp_token.base.source_position.lineno - input.output_line;
1184         if (delta == 0)
1185                 return false;
1186
1187         if (delta >= 9) {
1188                 fputc('\n', out);
1189                 print_line_directive(&pp_token.base.source_position, NULL);
1190                 fputc('\n', out);
1191         } else {
1192                 for (unsigned i = 0; i < delta; ++i) {
1193                         fputc('\n', out);
1194                 }
1195         }
1196         input.output_line = pp_token.base.source_position.lineno;
1197
1198         for (unsigned i = 0; i < info.whitespace; ++i)
1199                 fputc(' ', out);
1200
1201         return true;
1202 }
1203
1204 static void emit_pp_token(void)
1205 {
1206         if (skip_mode)
1207                 return;
1208
1209         if (!emit_newlines() &&
1210             (info.had_whitespace || tokens_would_paste(last_token, pp_token.kind)))
1211                 fputc(' ', out);
1212
1213         switch (pp_token.kind) {
1214         case TP_IDENTIFIER:
1215                 fputs(pp_token.base.symbol->string, out);
1216                 break;
1217         case TP_NUMBER:
1218                 fputs(pp_token.number.number.begin, out);
1219                 break;
1220
1221         case TP_STRING_LITERAL:
1222                 fputs(get_string_encoding_prefix(pp_token.string.encoding), out);
1223                 fputc('"', out);
1224                 fputs(pp_token.string.string.begin, out);
1225                 fputc('"', out);
1226                 break;
1227         case TP_WIDE_CHARACTER_CONSTANT:
1228                 fputc('L', out);
1229         case TP_CHARACTER_CONSTANT:
1230                 fputc('\'', out);
1231                 fputs(pp_token.string.string.begin, out);
1232                 fputc('\'', out);
1233                 break;
1234         default:
1235                 print_pp_token_kind(out, pp_token.kind);
1236                 break;
1237         }
1238         last_token = pp_token.kind;
1239 }
1240
1241 static void eat_pp_directive(void)
1242 {
1243         while (!info.at_line_begin) {
1244                 next_preprocessing_token();
1245         }
1246 }
1247
1248 static bool strings_equal(const string_t *string1, const string_t *string2)
1249 {
1250         size_t size = string1->size;
1251         if (size != string2->size)
1252                 return false;
1253
1254         const char *c1 = string1->begin;
1255         const char *c2 = string2->begin;
1256         for (size_t i = 0; i < size; ++i, ++c1, ++c2) {
1257                 if (*c1 != *c2)
1258                         return false;
1259         }
1260         return true;
1261 }
1262
1263 static bool pp_tokens_equal(const token_t *token1, const token_t *token2)
1264 {
1265         if (token1->kind != token2->kind)
1266                 return false;
1267
1268         switch (token1->kind) {
1269         case TP_IDENTIFIER:
1270                 return token1->base.symbol == token2->base.symbol;
1271
1272         case TP_NUMBER:
1273         case TP_CHARACTER_CONSTANT:
1274         case TP_STRING_LITERAL:
1275                 return strings_equal(&token1->string.string, &token2->string.string);
1276
1277         default:
1278                 return true;
1279         }
1280 }
1281
1282 static bool pp_definitions_equal(const pp_definition_t *definition1,
1283                                  const pp_definition_t *definition2)
1284 {
1285         if (definition1->list_len != definition2->list_len)
1286                 return false;
1287
1288         size_t         len = definition1->list_len;
1289         const token_t *t1  = definition1->token_list;
1290         const token_t *t2  = definition2->token_list;
1291         for (size_t i = 0; i < len; ++i, ++t1, ++t2) {
1292                 if (!pp_tokens_equal(t1, t2))
1293                         return false;
1294         }
1295         return true;
1296 }
1297
1298 static void parse_define_directive(void)
1299 {
1300         eat_pp(TP_define);
1301         assert(obstack_object_size(&pp_obstack) == 0);
1302
1303         if (pp_token.kind != TP_IDENTIFIER || info.at_line_begin) {
1304                 errorf(&pp_token.base.source_position,
1305                        "expected identifier after #define, got '%t'", &pp_token);
1306                 goto error_out;
1307         }
1308         symbol_t *const symbol = pp_token.base.symbol;
1309
1310         pp_definition_t *new_definition
1311                 = obstack_alloc(&pp_obstack, sizeof(new_definition[0]));
1312         memset(new_definition, 0, sizeof(new_definition[0]));
1313         new_definition->source_position = input.position;
1314
1315         /* this is probably the only place where spaces are significant in the
1316          * lexer (except for the fact that they separate tokens). #define b(x)
1317          * is something else than #define b (x) */
1318         if (input.c == '(') {
1319                 /* eat the '(' */
1320                 next_preprocessing_token();
1321                 /* get next token after '(' */
1322                 next_preprocessing_token();
1323
1324                 while (true) {
1325                         switch (pp_token.kind) {
1326                         case TP_DOTDOTDOT:
1327                                 new_definition->is_variadic = true;
1328                                 next_preprocessing_token();
1329                                 if (pp_token.kind != ')') {
1330                                         errorf(&input.position,
1331                                                         "'...' not at end of macro argument list");
1332                                         goto error_out;
1333                                 }
1334                                 break;
1335                         case TP_IDENTIFIER:
1336                                 obstack_ptr_grow(&pp_obstack, pp_token.base.symbol);
1337                                 next_preprocessing_token();
1338
1339                                 if (pp_token.kind == ',') {
1340                                         next_preprocessing_token();
1341                                         break;
1342                                 }
1343
1344                                 if (pp_token.kind != ')') {
1345                                         errorf(&pp_token.base.source_position,
1346                                                "expected ',' or ')' after identifier, got '%t'",
1347                                                &pp_token);
1348                                         goto error_out;
1349                                 }
1350                                 break;
1351                         case ')':
1352                                 next_preprocessing_token();
1353                                 goto finish_argument_list;
1354                         default:
1355                                 errorf(&pp_token.base.source_position,
1356                                        "expected identifier, '...' or ')' in #define argument list, got '%t'",
1357                                        &pp_token);
1358                                 goto error_out;
1359                         }
1360                 }
1361
1362         finish_argument_list:
1363                 new_definition->has_parameters = true;
1364                 new_definition->n_parameters
1365                         = obstack_object_size(&pp_obstack) / sizeof(new_definition->parameters[0]);
1366                 new_definition->parameters = obstack_finish(&pp_obstack);
1367         } else {
1368                 next_preprocessing_token();
1369         }
1370
1371         /* construct a new pp_definition on the obstack */
1372         assert(obstack_object_size(&pp_obstack) == 0);
1373         size_t list_len = 0;
1374         while (!info.at_line_begin) {
1375                 obstack_grow(&pp_obstack, &pp_token, sizeof(pp_token));
1376                 ++list_len;
1377                 next_preprocessing_token();
1378         }
1379
1380         new_definition->list_len   = list_len;
1381         new_definition->token_list = obstack_finish(&pp_obstack);
1382
1383         pp_definition_t *old_definition = symbol->pp_definition;
1384         if (old_definition != NULL) {
1385                 if (!pp_definitions_equal(old_definition, new_definition)) {
1386                         warningf(WARN_OTHER, &input.position, "multiple definition of macro '%Y' (first defined %P)", symbol, &old_definition->source_position);
1387                 } else {
1388                         /* reuse the old definition */
1389                         obstack_free(&pp_obstack, new_definition);
1390                         new_definition = old_definition;
1391                 }
1392         }
1393
1394         symbol->pp_definition = new_definition;
1395         return;
1396
1397 error_out:
1398         if (obstack_object_size(&pp_obstack) > 0) {
1399                 char *ptr = obstack_finish(&pp_obstack);
1400                 obstack_free(&pp_obstack, ptr);
1401         }
1402         eat_pp_directive();
1403 }
1404
1405 static void parse_undef_directive(void)
1406 {
1407         eat_pp(TP_undef);
1408
1409         if (pp_token.kind != TP_IDENTIFIER) {
1410                 errorf(&input.position,
1411                        "expected identifier after #undef, got '%t'", &pp_token);
1412                 eat_pp_directive();
1413                 return;
1414         }
1415
1416         pp_token.base.symbol->pp_definition = NULL;
1417         next_preprocessing_token();
1418
1419         if (!info.at_line_begin) {
1420                 warningf(WARN_OTHER, &input.position, "extra tokens at end of #undef directive");
1421         }
1422         eat_pp_directive();
1423 }
1424
1425 static void parse_headername(void)
1426 {
1427         const source_position_t start_position = input.position;
1428         string_t                string         = {NULL, 0};
1429         assert(obstack_object_size(&symbol_obstack) == 0);
1430
1431         /* behind an #include we can have the special headername lexems.
1432          * They're only allowed behind an #include so they're not recognized
1433          * by the normal next_preprocessing_token. We handle them as a special
1434          * exception here */
1435         if (info.at_line_begin) {
1436                 parse_error("expected headername after #include");
1437                 goto finish_error;
1438         }
1439
1440         /* check wether we have a "... or <... headername */
1441         switch (input.c) {
1442         case '<':
1443                 next_char();
1444                 while (true) {
1445                         switch (input.c) {
1446                         case EOF:
1447                                 /* fallthrough */
1448                         MATCH_NEWLINE(
1449                                 parse_error("header name without closing '>'");
1450                                 goto finish_error;
1451                         )
1452                         case '>':
1453                                 next_char();
1454                                 goto finished_headername;
1455                         }
1456                         obstack_1grow(&symbol_obstack, (char) input.c);
1457                         next_char();
1458                 }
1459                 /* we should never be here */
1460
1461         case '"':
1462                 next_char();
1463                 while (true) {
1464                         switch (input.c) {
1465                         case EOF:
1466                                 /* fallthrough */
1467                         MATCH_NEWLINE(
1468                                 parse_error("header name without closing '>'");
1469                                 goto finish_error;
1470                         )
1471                         case '"':
1472                                 next_char();
1473                                 goto finished_headername;
1474                         }
1475                         obstack_1grow(&symbol_obstack, (char) input.c);
1476                         next_char();
1477                 }
1478                 /* we should never be here */
1479
1480         default:
1481                 /* TODO: do normal pp_token parsing and concatenate results */
1482                 panic("pp_token concat include not implemented yet");
1483         }
1484
1485 finished_headername:
1486         obstack_1grow(&symbol_obstack, '\0');
1487         const size_t size       = (size_t)obstack_object_size(&symbol_obstack);
1488         char *const  headername = obstack_finish(&symbol_obstack);
1489         string                  = make_string(headername, size);
1490
1491 finish_error:
1492         pp_token.base.source_position = start_position;
1493         pp_token.kind                 = TP_HEADERNAME;
1494         pp_token.string.string        = string;
1495 }
1496
1497 static bool do_include(bool system_include, const char *headername)
1498 {
1499         size_t headername_len = strlen(headername);
1500         if (!system_include) {
1501                 /* put dirname of current input on obstack */
1502                 const char *filename   = input.position.input_name;
1503                 const char *last_slash = strrchr(filename, '/');
1504                 if (last_slash != NULL) {
1505                         size_t len = last_slash - filename;
1506                         obstack_grow(&symbol_obstack, filename, len + 1);
1507                         obstack_grow0(&symbol_obstack, headername, headername_len);
1508                         char *complete_path = obstack_finish(&symbol_obstack);
1509                         headername = identify_string(complete_path);
1510                 }
1511
1512                 FILE *file = fopen(headername, "r");
1513                 if (file != NULL) {
1514                         switch_input(file, headername);
1515                         return true;
1516                 }
1517         }
1518
1519         assert(obstack_object_size(&symbol_obstack) == 0);
1520         /* check searchpath */
1521         for (searchpath_entry_t *entry = searchpath; entry != NULL;
1522              entry = entry->next) {
1523             const char *path = entry->path;
1524             size_t      len  = strlen(path);
1525                 obstack_grow(&symbol_obstack, path, len);
1526                 if (path[len-1] != '/')
1527                         obstack_1grow(&symbol_obstack, '/');
1528                 obstack_grow(&symbol_obstack, headername, headername_len+1);
1529
1530                 char *complete_path = obstack_finish(&symbol_obstack);
1531                 FILE *file          = fopen(complete_path, "r");
1532                 if (file != NULL) {
1533                         const char *filename = identify_string(complete_path);
1534                         switch_input(file, filename);
1535                         return true;
1536                 } else {
1537                         obstack_free(&symbol_obstack, complete_path);
1538                 }
1539         }
1540
1541         return false;
1542 }
1543
1544 /* read till next newline character, only for parse_include_directive(),
1545  * use eat_pp_directive() in all other cases */
1546 static void skip_till_newline(void)
1547 {
1548         /* skip till newline */
1549         while (true) {
1550                 switch (input.c) {
1551                 MATCH_NEWLINE(
1552                         return;
1553                 )
1554                 case EOF:
1555                         return;
1556                 }
1557                 next_char();
1558         }
1559 }
1560
1561 static bool parse_include_directive(void)
1562 {
1563         /* don't eat the TP_include here!
1564          * we need an alternative parsing for the next token */
1565         skip_whitespace();
1566         bool system_include = input.c == '<';
1567         parse_headername();
1568         string_t headername = pp_token.string.string;
1569         if (headername.begin == NULL) {
1570                 eat_pp_directive();
1571                 return false;
1572         }
1573
1574         skip_whitespace();
1575         if (!info.at_line_begin) {
1576                 warningf(WARN_OTHER, &pp_token.base.source_position,
1577                          "extra tokens at end of #include directive");
1578                 skip_till_newline();
1579         }
1580
1581         if (n_inputs > INCLUDE_LIMIT) {
1582                 errorf(&pp_token.base.source_position, "#include nested too deeply");
1583                 /* eat \n or EOF */
1584                 next_preprocessing_token();
1585                 return false;
1586         }
1587
1588         /* switch inputs */
1589         emit_newlines();
1590         push_input();
1591         bool res = do_include(system_include, pp_token.string.string.begin);
1592         if (!res) {
1593                 errorf(&pp_token.base.source_position,
1594                        "failed including '%S': %s", pp_token.string, strerror(errno));
1595                 pop_restore_input();
1596                 return false;
1597         }
1598
1599         return true;
1600 }
1601
1602 static pp_conditional_t *push_conditional(void)
1603 {
1604         pp_conditional_t *conditional
1605                 = obstack_alloc(&pp_obstack, sizeof(*conditional));
1606         memset(conditional, 0, sizeof(*conditional));
1607
1608         conditional->parent = conditional_stack;
1609         conditional_stack   = conditional;
1610
1611         return conditional;
1612 }
1613
1614 static void pop_conditional(void)
1615 {
1616         assert(conditional_stack != NULL);
1617         conditional_stack = conditional_stack->parent;
1618 }
1619
1620 static void check_unclosed_conditionals(void)
1621 {
1622         while (conditional_stack != NULL) {
1623                 pp_conditional_t *conditional = conditional_stack;
1624
1625                 if (conditional->in_else) {
1626                         errorf(&conditional->source_position, "unterminated #else");
1627                 } else {
1628                         errorf(&conditional->source_position, "unterminated condition");
1629                 }
1630                 pop_conditional();
1631         }
1632 }
1633
1634 static void parse_ifdef_ifndef_directive(void)
1635 {
1636         bool is_ifndef = (pp_token.kind == TP_ifndef);
1637         bool condition;
1638         next_preprocessing_token();
1639
1640         if (skip_mode) {
1641                 eat_pp_directive();
1642                 pp_conditional_t *conditional = push_conditional();
1643                 conditional->source_position  = pp_token.base.source_position;
1644                 conditional->skip             = true;
1645                 return;
1646         }
1647
1648         if (pp_token.kind != TP_IDENTIFIER || info.at_line_begin) {
1649                 errorf(&pp_token.base.source_position,
1650                        "expected identifier after #%s, got '%t'",
1651                        is_ifndef ? "ifndef" : "ifdef", &pp_token);
1652                 eat_pp_directive();
1653
1654                 /* just take the true case in the hope to avoid further errors */
1655                 condition = true;
1656         } else {
1657                 /* evaluate wether we are in true or false case */
1658                 condition = !pp_token.base.symbol->pp_definition == is_ifndef;
1659
1660                 next_preprocessing_token();
1661
1662                 if (!info.at_line_begin) {
1663                         errorf(&pp_token.base.source_position,
1664                                "extra tokens at end of #%s",
1665                                is_ifndef ? "ifndef" : "ifdef");
1666                         eat_pp_directive();
1667                 }
1668         }
1669
1670         pp_conditional_t *conditional = push_conditional();
1671         conditional->source_position  = pp_token.base.source_position;
1672         conditional->condition        = condition;
1673
1674         if (!condition) {
1675                 skip_mode = true;
1676         }
1677 }
1678
1679 static void parse_else_directive(void)
1680 {
1681         eat_pp(TP_else);
1682
1683         if (!info.at_line_begin) {
1684                 if (!skip_mode) {
1685                         warningf(WARN_OTHER, &pp_token.base.source_position, "extra tokens at end of #else");
1686                 }
1687                 eat_pp_directive();
1688         }
1689
1690         pp_conditional_t *conditional = conditional_stack;
1691         if (conditional == NULL) {
1692                 errorf(&pp_token.base.source_position, "#else without prior #if");
1693                 return;
1694         }
1695
1696         if (conditional->in_else) {
1697                 errorf(&pp_token.base.source_position,
1698                        "#else after #else (condition started %P)",
1699                        conditional->source_position);
1700                 skip_mode = true;
1701                 return;
1702         }
1703
1704         conditional->in_else = true;
1705         if (!conditional->skip) {
1706                 skip_mode = conditional->condition;
1707         }
1708         conditional->source_position = pp_token.base.source_position;
1709 }
1710
1711 static void parse_endif_directive(void)
1712 {
1713         eat_pp(TP_endif);
1714
1715         if (!info.at_line_begin) {
1716                 if (!skip_mode) {
1717                         warningf(WARN_OTHER, &pp_token.base.source_position, "extra tokens at end of #endif");
1718                 }
1719                 eat_pp_directive();
1720         }
1721
1722         pp_conditional_t *conditional = conditional_stack;
1723         if (conditional == NULL) {
1724                 errorf(&pp_token.base.source_position, "#endif without prior #if");
1725                 return;
1726         }
1727
1728         if (!conditional->skip) {
1729                 skip_mode = false;
1730         }
1731         pop_conditional();
1732 }
1733
1734 static void parse_preprocessing_directive(void)
1735 {
1736         eat_pp('#');
1737
1738         if (info.at_line_begin) {
1739                 /* empty directive */
1740                 return;
1741         }
1742
1743         if (skip_mode) {
1744                 switch (pp_token.kind) {
1745                 case TP_ifdef:
1746                 case TP_ifndef:
1747                         parse_ifdef_ifndef_directive();
1748                         break;
1749                 case TP_else:
1750                         parse_else_directive();
1751                         break;
1752                 case TP_endif:
1753                         parse_endif_directive();
1754                         break;
1755                 default:
1756                         eat_pp_directive();
1757                         break;
1758                 }
1759         } else {
1760                 switch (pp_token.kind) {
1761                 case TP_define:
1762                         parse_define_directive();
1763                         break;
1764                 case TP_undef:
1765                         parse_undef_directive();
1766                         break;
1767                 case TP_ifdef:
1768                 case TP_ifndef:
1769                         parse_ifdef_ifndef_directive();
1770                         break;
1771                 case TP_else:
1772                         parse_else_directive();
1773                         break;
1774                 case TP_endif:
1775                         parse_endif_directive();
1776                         break;
1777                 case TP_include:
1778                         parse_include_directive();
1779                         break;
1780                 default:
1781                         if (info.at_line_begin) {
1782                                 /* the nop directive "#" */
1783                                 break;
1784                         }
1785                         errorf(&pp_token.base.source_position,
1786                                    "invalid preprocessing directive #%t", &pp_token);
1787                         eat_pp_directive();
1788                         break;
1789                 }
1790         }
1791
1792         assert(info.at_line_begin);
1793 }
1794
1795 static void prepend_include_path(const char *path)
1796 {
1797         searchpath_entry_t *entry = OALLOCZ(&config_obstack, searchpath_entry_t);
1798         entry->path = path;
1799         entry->next = searchpath;
1800         searchpath  = entry;
1801 }
1802
1803 static void setup_include_path(void)
1804 {
1805         /* built-in paths */
1806         prepend_include_path("/usr/include");
1807
1808         /* parse environment variable */
1809         const char *cpath = getenv("CPATH");
1810         if (cpath != NULL && *cpath != '\0') {
1811                 const char *begin = cpath;
1812                 const char *c;
1813                 do {
1814                         c = begin;
1815                         while (*c != '\0' && *c != ':')
1816                                 ++c;
1817
1818                         size_t len = c-begin;
1819                         if (len == 0) {
1820                                 /* for gcc compatibility (Matze: I would expect that
1821                                  * nothing happens for an empty entry...) */
1822                                 prepend_include_path(".");
1823                         } else {
1824                                 char *string = obstack_alloc(&config_obstack, len+1);
1825                                 memcpy(string, begin, len);
1826                                 string[len] = '\0';
1827
1828                                 prepend_include_path(string);
1829                         }
1830
1831                         begin = c+1;
1832                         /* skip : */
1833                         if (*begin == ':')
1834                                 ++begin;
1835                 } while(*c != '\0');
1836         }
1837 }
1838
1839 int pptest_main(int argc, char **argv);
1840 int pptest_main(int argc, char **argv)
1841 {
1842         init_symbol_table();
1843         init_tokens();
1844
1845         obstack_init(&config_obstack);
1846         obstack_init(&pp_obstack);
1847         obstack_init(&input_obstack);
1848         strset_init(&stringset);
1849
1850         setup_include_path();
1851
1852         /* simplistic commandline parser */
1853         const char *filename = NULL;
1854         const char *output = NULL;
1855         for (int i = 1; i < argc; ++i) {
1856                 const char *opt = argv[i];
1857                 if (streq(opt, "-I")) {
1858                         prepend_include_path(argv[++i]);
1859                         continue;
1860                 } else if (streq(opt, "-E")) {
1861                         /* ignore */
1862                 } else if (streq(opt, "-o")) {
1863                         output = argv[++i];
1864                         continue;
1865                 } else if (opt[0] == '-') {
1866                         fprintf(stderr, "Unknown option '%s'\n", opt);
1867                 } else {
1868                         if (filename != NULL)
1869                                 fprintf(stderr, "Multiple inputs not supported\n");
1870                         filename = argv[i];
1871                 }
1872         }
1873         if (filename == NULL) {
1874                 fprintf(stderr, "No input specified\n");
1875                 return 1;
1876         }
1877
1878         if (output == NULL) {
1879                 out = stdout;
1880         } else {
1881                 out = fopen(output, "w");
1882                 if (out == NULL) {
1883                         fprintf(stderr, "Couldn't open output '%s'\n", output);
1884                         return 1;
1885                 }
1886         }
1887
1888         /* just here for gcc compatibility */
1889         fprintf(out, "# 1 \"%s\"\n", filename);
1890         fprintf(out, "# 1 \"<built-in>\"\n");
1891         fprintf(out, "# 1 \"<command-line>\"\n");
1892
1893         FILE *file = fopen(filename, "r");
1894         if (file == NULL) {
1895                 fprintf(stderr, "Couldn't open input '%s'\n", filename);
1896                 return 1;
1897         }
1898         switch_input(file, filename);
1899
1900         while (true) {
1901                 if (pp_token.kind == '#' && info.at_line_begin) {
1902                         parse_preprocessing_directive();
1903                         continue;
1904                 } else if (pp_token.kind == TP_EOF) {
1905                         goto end_of_main_loop;
1906                 } else if (pp_token.kind == TP_IDENTIFIER) {
1907                         symbol_t        *const symbol        = pp_token.base.symbol;
1908                         pp_definition_t *const pp_definition = symbol->pp_definition;
1909                         if (pp_definition != NULL && !pp_definition->is_expanding) {
1910                                 expansion_pos = pp_token.base.source_position;
1911                                 if (pp_definition->has_parameters) {
1912                                         source_position_t position = pp_token.base.source_position;
1913                                         add_token_info_t old_info = info;
1914                                         next_preprocessing_token();
1915                                         add_token_info_t new_info = info;
1916
1917                                         /* no opening brace -> no expansion */
1918                                         if (pp_token.kind == '(') {
1919                                                 eat_pp('(');
1920
1921                                                 /* parse arguments (TODO) */
1922                                                 while (pp_token.kind != TP_EOF && pp_token.kind != ')')
1923                                                         next_preprocessing_token();
1924                                         } else {
1925                                                 token_t next_token = pp_token;
1926                                                 /* restore identifier token */
1927                                                 pp_token.kind                 = TP_IDENTIFIER;
1928                                                 pp_token.base.symbol          = symbol;
1929                                                 pp_token.base.source_position = position;
1930                                                 info = old_info;
1931                                                 emit_pp_token();
1932
1933                                                 info = new_info;
1934                                                 pp_token = next_token;
1935                                                 continue;
1936                                         }
1937                                         info = old_info;
1938                                 }
1939                                 pp_definition->expand_pos   = 0;
1940                                 pp_definition->is_expanding = true;
1941                                 current_expansion           = pp_definition;
1942                                 expand_next();
1943                                 continue;
1944                         }
1945                 }
1946
1947                 emit_pp_token();
1948                 next_preprocessing_token();
1949         }
1950 end_of_main_loop:
1951
1952         fputc('\n', out);
1953         check_unclosed_conditionals();
1954         close_input();
1955         if (out != stdout)
1956                 fclose(out);
1957
1958         obstack_free(&input_obstack, NULL);
1959         obstack_free(&pp_obstack, NULL);
1960         obstack_free(&config_obstack, NULL);
1961
1962         strset_destroy(&stringset);
1963
1964         exit_tokens();
1965         exit_symbol_table();
1966
1967         return 0;
1968 }