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