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