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