cc528eb6ffcc3e16225fd7877201bff4ae4d101f
[cparser] / lexer.c
1 /*
2  * This file is part of cparser.
3  * Copyright (C) 2007-2009 Matthias Braun <matze@braunis.de>
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
18  * 02111-1307, USA.
19  */
20 #include <config.h>
21
22 #include "input.h"
23 #include "diagnostic.h"
24 #include "lexer.h"
25 #include "symbol_t.h"
26 #include "token_t.h"
27 #include "symbol_table_t.h"
28 #include "adt/error.h"
29 #include "adt/strset.h"
30 #include "adt/util.h"
31 #include "types.h"
32 #include "type_t.h"
33 #include "target_architecture.h"
34 #include "parser.h"
35 #include "warning.h"
36 #include "lang_features.h"
37
38 #include <assert.h>
39 #include <errno.h>
40 #include <string.h>
41 #include <stdbool.h>
42 #include <ctype.h>
43
44 #ifndef _WIN32
45 #include <strings.h>
46 #endif
47
48 #define MAX_PUTBACK 16    // 3 would be enough, but 16 gives a nicer alignment
49 #define BUF_SIZE    1024
50
51 static input_t           *input;
52 static utf32              input_buf[BUF_SIZE + MAX_PUTBACK];
53 static const utf32       *bufpos;
54 static const utf32       *bufend;
55 static utf32              c;
56 static source_position_t  lexer_pos;
57 token_t                   lexer_token;
58 static symbol_t          *symbol_L;
59 static strset_t           stringset;
60 static char              *encoding;
61 bool                      allow_dollar_in_symbol = true;
62
63 /**
64  * Prints a parse error message at the current token.
65  *
66  * @param msg   the error message
67  */
68 static void parse_error(const char *msg)
69 {
70         errorf(&lexer_pos, "%s", msg);
71 }
72
73 /**
74  * Prints an internal error message at the current token.
75  *
76  * @param msg   the error message
77  */
78 static NORETURN internal_error(const char *msg)
79 {
80         internal_errorf(&lexer_pos, "%s", msg);
81 }
82
83 static inline void next_real_char(void)
84 {
85         assert(bufpos <= bufend);
86         if (bufpos >= bufend) {
87                 size_t n = decode(input, input_buf+MAX_PUTBACK, BUF_SIZE);
88                 if (n == 0) {
89                         c = EOF;
90                         return;
91                 }
92                 bufpos = input_buf + MAX_PUTBACK;
93                 bufend = bufpos + n;
94         }
95         c = *bufpos++;
96         ++lexer_pos.colno;
97 }
98
99 /**
100  * Put a character back into the buffer.
101  *
102  * @param pc  the character to put back
103  */
104 static inline void put_back(utf32 const pc)
105 {
106         *(--bufpos - input_buf + input_buf) = pc;
107         --lexer_pos.colno;
108 }
109
110 static inline void next_char(void);
111
112 #define MATCH_NEWLINE(code)  \
113         case '\r':               \
114                 next_char();         \
115                 if (c == '\n') {     \
116         case '\n':               \
117                         next_char();     \
118                 }                    \
119                 lexer_pos.lineno++;  \
120                 lexer_pos.colno = 1; \
121                 code
122
123 #define eat(c_type) (assert(c == c_type), next_char())
124
125 static void maybe_concat_lines(void)
126 {
127         eat('\\');
128
129         switch (c) {
130         MATCH_NEWLINE(return;)
131
132         default:
133                 break;
134         }
135
136         put_back(c);
137         c = '\\';
138 }
139
140 /**
141  * Set c to the next input character, ie.
142  * after expanding trigraphs.
143  */
144 static inline void next_char(void)
145 {
146         next_real_char();
147
148         /* filter trigraphs */
149         if (UNLIKELY(c == '\\')) {
150                 maybe_concat_lines();
151                 return;
152         }
153
154         if (LIKELY(c != '?'))
155                 return;
156
157         next_real_char();
158         if (LIKELY(c != '?')) {
159                 put_back(c);
160                 c = '?';
161                 return;
162         }
163
164         next_real_char();
165         switch (c) {
166         case '=': c = '#'; break;
167         case '(': c = '['; break;
168         case '/': c = '\\'; maybe_concat_lines(); break;
169         case ')': c = ']'; break;
170         case '\'': c = '^'; break;
171         case '<': c = '{'; break;
172         case '!': c = '|'; break;
173         case '>': c = '}'; break;
174         case '-': c = '~'; break;
175         default:
176                 put_back(c);
177                 put_back('?');
178                 c = '?';
179                 break;
180         }
181 }
182
183 #define SYMBOL_CHARS  \
184         case '$': if (!allow_dollar_in_symbol) goto dollar_sign; \
185         case 'a':         \
186         case 'b':         \
187         case 'c':         \
188         case 'd':         \
189         case 'e':         \
190         case 'f':         \
191         case 'g':         \
192         case 'h':         \
193         case 'i':         \
194         case 'j':         \
195         case 'k':         \
196         case 'l':         \
197         case 'm':         \
198         case 'n':         \
199         case 'o':         \
200         case 'p':         \
201         case 'q':         \
202         case 'r':         \
203         case 's':         \
204         case 't':         \
205         case 'u':         \
206         case 'v':         \
207         case 'w':         \
208         case 'x':         \
209         case 'y':         \
210         case 'z':         \
211         case 'A':         \
212         case 'B':         \
213         case 'C':         \
214         case 'D':         \
215         case 'E':         \
216         case 'F':         \
217         case 'G':         \
218         case 'H':         \
219         case 'I':         \
220         case 'J':         \
221         case 'K':         \
222         case 'L':         \
223         case 'M':         \
224         case 'N':         \
225         case 'O':         \
226         case 'P':         \
227         case 'Q':         \
228         case 'R':         \
229         case 'S':         \
230         case 'T':         \
231         case 'U':         \
232         case 'V':         \
233         case 'W':         \
234         case 'X':         \
235         case 'Y':         \
236         case 'Z':         \
237         case '_':
238
239 #define DIGITS        \
240         case '0':         \
241         case '1':         \
242         case '2':         \
243         case '3':         \
244         case '4':         \
245         case '5':         \
246         case '6':         \
247         case '7':         \
248         case '8':         \
249         case '9':
250
251 /**
252  * Read a symbol from the input and build
253  * the lexer_token.
254  */
255 static void parse_symbol(void)
256 {
257         obstack_1grow(&symbol_obstack, (char) c);
258         next_char();
259
260         while (true) {
261                 switch (c) {
262                 DIGITS
263                 SYMBOL_CHARS
264                         obstack_1grow(&symbol_obstack, (char) c);
265                         next_char();
266                         break;
267
268                 default:
269 dollar_sign:
270                         goto end_symbol;
271                 }
272         }
273
274 end_symbol:
275         obstack_1grow(&symbol_obstack, '\0');
276
277         char     *string = obstack_finish(&symbol_obstack);
278         symbol_t *symbol = symbol_table_insert(string);
279
280         lexer_token.type   = symbol->ID;
281         lexer_token.symbol = symbol;
282
283         if (symbol->string != string) {
284                 obstack_free(&symbol_obstack, string);
285         }
286 }
287
288 /**
289  * parse suffixes like 'LU' or 'f' after numbers
290  */
291 static void parse_number_suffix(void)
292 {
293         assert(obstack_object_size(&symbol_obstack) == 0);
294         while (true) {
295                 switch (c) {
296                 SYMBOL_CHARS
297                         obstack_1grow(&symbol_obstack, (char) c);
298                         next_char();
299                         break;
300                 default:
301                 dollar_sign:
302                         goto finish_suffix;
303                 }
304         }
305 finish_suffix:
306         if (obstack_object_size(&symbol_obstack) == 0) {
307                 lexer_token.symbol = NULL;
308                 return;
309         }
310
311         obstack_1grow(&symbol_obstack, '\0');
312         char     *string = obstack_finish(&symbol_obstack);
313         symbol_t *symbol = symbol_table_insert(string);
314
315         if (symbol->string != string) {
316                 obstack_free(&symbol_obstack, string);
317         }
318         lexer_token.symbol = symbol;
319 }
320
321 static string_t identify_string(char *string, size_t len)
322 {
323         /* TODO hash */
324 #if 0
325         const char *result = strset_insert(&stringset, concat);
326         if (result != concat) {
327                 obstack_free(&symbol_obstack, concat);
328         }
329 #else
330         const char *result = string;
331 #endif
332         return (string_t) {result, len};
333 }
334
335 /**
336  * Parses a hex number including hex floats and set the
337  * lexer_token.
338  */
339 static void parse_number_hex(void)
340 {
341         bool is_float   = false;
342         bool has_digits = false;
343
344         assert(obstack_object_size(&symbol_obstack) == 0);
345         while (isxdigit(c)) {
346                 has_digits = true;
347                 obstack_1grow(&symbol_obstack, (char) c);
348                 next_char();
349         }
350
351         if (c == '.') {
352                 is_float = true;
353                 obstack_1grow(&symbol_obstack, (char) c);
354                 next_char();
355
356                 while (isxdigit(c)) {
357                         has_digits = true;
358                         obstack_1grow(&symbol_obstack, (char) c);
359                         next_char();
360                 }
361         }
362         if (c == 'p' || c == 'P') {
363                 is_float = true;
364                 obstack_1grow(&symbol_obstack, (char) c);
365                 next_char();
366
367                 if (c == '-' || c == '+') {
368                         obstack_1grow(&symbol_obstack, (char) c);
369                         next_char();
370                 }
371
372                 while (isxdigit(c)) {
373                         obstack_1grow(&symbol_obstack, (char) c);
374                         next_char();
375                 }
376         } else if (is_float) {
377                 errorf(&lexer_token.source_position,
378                        "hexadecimal floatingpoint constant requires an exponent");
379         }
380         obstack_1grow(&symbol_obstack, '\0');
381
382         size_t  size   = obstack_object_size(&symbol_obstack) - 1;
383         char   *string = obstack_finish(&symbol_obstack);
384         lexer_token.literal = identify_string(string, size);
385
386         lexer_token.type    =
387                 is_float ? T_FLOATINGPOINT_HEXADECIMAL : T_INTEGER_HEXADECIMAL;
388
389         if (!has_digits) {
390                 errorf(&lexer_token.source_position, "invalid number literal '0x%S'",
391                        &lexer_token.literal);
392                 lexer_token.literal.begin = "0";
393                 lexer_token.literal.size  = 1;
394         }
395
396         parse_number_suffix();
397 }
398
399 /**
400  * Returns true if the given char is a octal digit.
401  *
402  * @param char  the character to check
403  */
404 static bool is_octal_digit(utf32 chr)
405 {
406         return '0' <= chr && chr <= '7';
407 }
408
409 /**
410  * Parses a number and sets the lexer_token.
411  */
412 static void parse_number(void)
413 {
414         bool is_float   = false;
415         bool has_digits = false;
416
417         assert(obstack_object_size(&symbol_obstack) == 0);
418         if (c == '0') {
419                 next_char();
420                 if (c == 'x' || c == 'X') {
421                         next_char();
422                         parse_number_hex();
423                         return;
424                 } else {
425                         has_digits = true;
426                 }
427                 obstack_1grow(&symbol_obstack, '0');
428         }
429
430         while (isdigit(c)) {
431                 has_digits = true;
432                 obstack_1grow(&symbol_obstack, (char) c);
433                 next_char();
434         }
435
436         if (c == '.') {
437                 is_float = true;
438                 obstack_1grow(&symbol_obstack, '.');
439                 next_char();
440
441                 while (isdigit(c)) {
442                         has_digits = true;
443                         obstack_1grow(&symbol_obstack, (char) c);
444                         next_char();
445                 }
446         }
447         if (c == 'e' || c == 'E') {
448                 is_float = true;
449                 obstack_1grow(&symbol_obstack, 'e');
450                 next_char();
451
452                 if (c == '-' || c == '+') {
453                         obstack_1grow(&symbol_obstack, (char) c);
454                         next_char();
455                 }
456
457                 while (isdigit(c)) {
458                         obstack_1grow(&symbol_obstack, (char) c);
459                         next_char();
460                 }
461         }
462
463         obstack_1grow(&symbol_obstack, '\0');
464         size_t  size   = obstack_object_size(&symbol_obstack) - 1;
465         char   *string = obstack_finish(&symbol_obstack);
466         lexer_token.literal = identify_string(string, size);
467
468         /* is it an octal number? */
469         if (is_float) {
470                 lexer_token.type = T_FLOATINGPOINT;
471         } else if (string[0] == '0') {
472                 lexer_token.type = T_INTEGER_OCTAL;
473
474                 /* check for invalid octal digits */
475                 for (size_t i= 0; i < size; ++i) {
476                         char t = string[i];
477                         if (t >= '8')
478                                 errorf(&lexer_token.source_position,
479                                        "invalid digit '%c' in octal number", t);
480                 }
481         } else {
482                 lexer_token.type = T_INTEGER;
483         }
484
485         if (!has_digits) {
486                 errorf(&lexer_token.source_position, "invalid number literal '%S'",
487                        &lexer_token.literal);
488         }
489
490         parse_number_suffix();
491 }
492
493 /**
494  * Returns the value of a digit.
495  * The only portable way to do it ...
496  */
497 static int digit_value(utf32 const digit)
498 {
499         switch (digit) {
500         case '0': return 0;
501         case '1': return 1;
502         case '2': return 2;
503         case '3': return 3;
504         case '4': return 4;
505         case '5': return 5;
506         case '6': return 6;
507         case '7': return 7;
508         case '8': return 8;
509         case '9': return 9;
510         case 'a':
511         case 'A': return 10;
512         case 'b':
513         case 'B': return 11;
514         case 'c':
515         case 'C': return 12;
516         case 'd':
517         case 'D': return 13;
518         case 'e':
519         case 'E': return 14;
520         case 'f':
521         case 'F': return 15;
522         default:
523                 internal_error("wrong character given");
524         }
525 }
526
527 /**
528  * Parses an octal character sequence.
529  *
530  * @param first_digit  the already read first digit
531  */
532 static utf32 parse_octal_sequence(utf32 const first_digit)
533 {
534         assert(is_octal_digit(first_digit));
535         utf32 value = digit_value(first_digit);
536         if (!is_octal_digit(c)) return value;
537         value = 8 * value + digit_value(c);
538         next_char();
539         if (!is_octal_digit(c)) return value;
540         value = 8 * value + digit_value(c);
541         next_char();
542         return value;
543 }
544
545 /**
546  * Parses a hex character sequence.
547  */
548 static utf32 parse_hex_sequence(void)
549 {
550         utf32 value = 0;
551         while (isxdigit(c)) {
552                 value = 16 * value + digit_value(c);
553                 next_char();
554         }
555         return value;
556 }
557
558 /**
559  * Parse an escape sequence.
560  */
561 static utf32 parse_escape_sequence(void)
562 {
563         eat('\\');
564
565         utf32 const ec = c;
566         next_char();
567
568         switch (ec) {
569         case '"':  return '"';
570         case '\'': return '\'';
571         case '\\': return '\\';
572         case '?': return '\?';
573         case 'a': return '\a';
574         case 'b': return '\b';
575         case 'f': return '\f';
576         case 'n': return '\n';
577         case 'r': return '\r';
578         case 't': return '\t';
579         case 'v': return '\v';
580         case 'x':
581                 return parse_hex_sequence();
582         case '0':
583         case '1':
584         case '2':
585         case '3':
586         case '4':
587         case '5':
588         case '6':
589         case '7':
590                 return parse_octal_sequence(ec);
591         case EOF:
592                 parse_error("reached end of file while parsing escape sequence");
593                 return EOF;
594         /* \E is not documented, but handled, by GCC.  It is acceptable according
595          * to Â§6.11.4, whereas \e is not. */
596         case 'E':
597         case 'e':
598                 if (c_mode & _GNUC)
599                         return 27;   /* hopefully 27 is ALWAYS the code for ESCAPE */
600                 break;
601         case 'u':
602         case 'U':
603                 parse_error("universal character parsing not implemented yet");
604                 return EOF;
605         default:
606                 break;
607         }
608         /* Â§6.4.4.4:8 footnote 64 */
609         parse_error("unknown escape sequence");
610         return EOF;
611 }
612
613 /**
614  * Concatenate two strings.
615  */
616 string_t concat_strings(const string_t *const s1, const string_t *const s2)
617 {
618         const size_t len1 = s1->size - 1;
619         const size_t len2 = s2->size - 1;
620
621         char *const concat = obstack_alloc(&symbol_obstack, len1 + len2 + 1);
622         memcpy(concat, s1->begin, len1);
623         memcpy(concat + len1, s2->begin, len2 + 1);
624
625         return identify_string(concat, len1 + len2 + 1);
626 }
627
628 string_t make_string(const char *string)
629 {
630         size_t      len   = strlen(string) + 1;
631         char *const space = obstack_alloc(&symbol_obstack, len);
632         memcpy(space, string, len);
633
634         return identify_string(space, len);
635 }
636
637 static void grow_symbol(utf32 const tc)
638 {
639         struct obstack *const o  = &symbol_obstack;
640         if (tc < 0x80U) {
641                 obstack_1grow(o, tc);
642         } else if (tc < 0x800) {
643                 obstack_1grow(o, 0xC0 | (tc >> 6));
644                 obstack_1grow(o, 0x80 | (tc & 0x3F));
645         } else if (tc < 0x10000) {
646                 obstack_1grow(o, 0xE0 | ( tc >> 12));
647                 obstack_1grow(o, 0x80 | ((tc >>  6) & 0x3F));
648                 obstack_1grow(o, 0x80 | ( tc        & 0x3F));
649         } else {
650                 obstack_1grow(o, 0xF0 | ( tc >> 18));
651                 obstack_1grow(o, 0x80 | ((tc >> 12) & 0x3F));
652                 obstack_1grow(o, 0x80 | ((tc >>  6) & 0x3F));
653                 obstack_1grow(o, 0x80 | ( tc        & 0x3F));
654         }
655 }
656
657 /**
658  * Parse a string literal and set lexer_token.
659  */
660 static void parse_string_literal(void)
661 {
662         eat('"');
663
664         while (true) {
665                 switch (c) {
666                 case '\\': {
667                         utf32 const tc = parse_escape_sequence();
668                         if (tc >= 0x100) {
669                                 warningf(WARN_OTHER, &lexer_pos, "escape sequence out of range");
670                         }
671                         obstack_1grow(&symbol_obstack, tc);
672                         break;
673                 }
674
675                 case EOF: {
676                         errorf(&lexer_token.source_position, "string has no end");
677                         lexer_token.type = T_ERROR;
678                         return;
679                 }
680
681                 case '"':
682                         next_char();
683                         goto end_of_string;
684
685                 default:
686                         grow_symbol(c);
687                         next_char();
688                         break;
689                 }
690         }
691
692 end_of_string:
693
694         /* TODO: concatenate multiple strings separated by whitespace... */
695
696         /* add finishing 0 to the string */
697         obstack_1grow(&symbol_obstack, '\0');
698         const size_t  size   = (size_t)obstack_object_size(&symbol_obstack);
699         char         *string = obstack_finish(&symbol_obstack);
700
701         lexer_token.type    = T_STRING_LITERAL;
702         lexer_token.literal = identify_string(string, size);
703 }
704
705 /**
706  * Parse a wide character constant and set lexer_token.
707  */
708 static void parse_wide_character_constant(void)
709 {
710         eat('\'');
711
712         while (true) {
713                 switch (c) {
714                 case '\\': {
715                         const utf32 tc = parse_escape_sequence();
716                         grow_symbol(tc);
717                         break;
718                 }
719
720                 MATCH_NEWLINE(
721                         parse_error("newline while parsing character constant");
722                         break;
723                 )
724
725                 case '\'':
726                         next_char();
727                         goto end_of_wide_char_constant;
728
729                 case EOF: {
730                         errorf(&lexer_token.source_position, "EOF while parsing character constant");
731                         lexer_token.type = T_ERROR;
732                         return;
733                 }
734
735                 default:
736                         grow_symbol(c);
737                         next_char();
738                         break;
739                 }
740         }
741
742 end_of_wide_char_constant:;
743         obstack_1grow(&symbol_obstack, '\0');
744         size_t  size   = (size_t) obstack_object_size(&symbol_obstack) - 1;
745         char   *string = obstack_finish(&symbol_obstack);
746
747         lexer_token.type     = T_WIDE_CHARACTER_CONSTANT;
748         lexer_token.literal  = identify_string(string, size);
749
750         if (size == 0) {
751                 errorf(&lexer_token.source_position, "empty character constant");
752         }
753 }
754
755 /**
756  * Parse a wide string literal and set lexer_token.
757  */
758 static void parse_wide_string_literal(void)
759 {
760         parse_string_literal();
761         if (lexer_token.type == T_STRING_LITERAL)
762                 lexer_token.type = T_WIDE_STRING_LITERAL;
763 }
764
765 /**
766  * Parse a character constant and set lexer_token.
767  */
768 static void parse_character_constant(void)
769 {
770         eat('\'');
771
772         while (true) {
773                 switch (c) {
774                 case '\\': {
775                         utf32 const tc = parse_escape_sequence();
776                         if (tc >= 0x100) {
777                                 warningf(WARN_OTHER, &lexer_pos, "escape sequence out of range");
778                         }
779                         obstack_1grow(&symbol_obstack, tc);
780                         break;
781                 }
782
783                 MATCH_NEWLINE(
784                         parse_error("newline while parsing character constant");
785                         break;
786                 )
787
788                 case '\'':
789                         next_char();
790                         goto end_of_char_constant;
791
792                 case EOF: {
793                         errorf(&lexer_token.source_position, "EOF while parsing character constant");
794                         lexer_token.type = T_ERROR;
795                         return;
796                 }
797
798                 default:
799                         grow_symbol(c);
800                         next_char();
801                         break;
802
803                 }
804         }
805
806 end_of_char_constant:;
807         obstack_1grow(&symbol_obstack, '\0');
808         const size_t        size   = (size_t)obstack_object_size(&symbol_obstack)-1;
809         char         *const string = obstack_finish(&symbol_obstack);
810
811         lexer_token.type    = T_CHARACTER_CONSTANT;
812         lexer_token.literal = identify_string(string, size);
813
814         if (size == 0) {
815                 errorf(&lexer_token.source_position, "empty character constant");
816         }
817 }
818
819 /**
820  * Skip a multiline comment.
821  */
822 static void skip_multiline_comment(void)
823 {
824         while (true) {
825                 switch (c) {
826                 case '/':
827                         next_char();
828                         if (c == '*') {
829                                 /* nested comment, warn here */
830                                 warningf(WARN_COMMENT, &lexer_pos, "'/*' within comment");
831                         }
832                         break;
833                 case '*':
834                         next_char();
835                         if (c == '/') {
836                                 next_char();
837                                 return;
838                         }
839                         break;
840
841                 MATCH_NEWLINE(break;)
842
843                 case EOF: {
844                         errorf(&lexer_token.source_position, "at end of file while looking for comment end");
845                         return;
846                 }
847
848                 default:
849                         next_char();
850                         break;
851                 }
852         }
853 }
854
855 /**
856  * Skip a single line comment.
857  */
858 static void skip_line_comment(void)
859 {
860         while (true) {
861                 switch (c) {
862                 case EOF:
863                         return;
864
865                 case '\n':
866                 case '\r':
867                         return;
868
869                 case '\\':
870                         next_char();
871                         if (c == '\n' || c == '\r') {
872                                 warningf(WARN_COMMENT, &lexer_pos, "multi-line comment");
873                                 return;
874                         }
875                         break;
876
877                 default:
878                         next_char();
879                         break;
880                 }
881         }
882 }
883
884 /** The current preprocessor token. */
885 static token_t pp_token;
886
887 /**
888  * Read the next preprocessor token.
889  */
890 static inline void next_pp_token(void)
891 {
892         lexer_next_preprocessing_token();
893         pp_token = lexer_token;
894 }
895
896 /**
897  * Eat all preprocessor tokens until newline.
898  */
899 static void eat_until_newline(void)
900 {
901         while (pp_token.type != '\n' && pp_token.type != T_EOF) {
902                 next_pp_token();
903         }
904 }
905
906 /**
907  * Handle the define directive.
908  */
909 static void define_directive(void)
910 {
911         lexer_next_preprocessing_token();
912         if (lexer_token.type != T_IDENTIFIER) {
913                 parse_error("expected identifier after #define\n");
914                 eat_until_newline();
915         }
916 }
917
918 /**
919  * Handle the ifdef directive.
920  */
921 static void ifdef_directive(int is_ifndef)
922 {
923         (void) is_ifndef;
924         lexer_next_preprocessing_token();
925         //expect_identifier();
926         //extect_newline();
927 }
928
929 /**
930  * Handle the endif directive.
931  */
932 static void endif_directive(void)
933 {
934         //expect_newline();
935 }
936
937 /**
938  * Parse the line directive.
939  */
940 static void parse_line_directive(void)
941 {
942         if (pp_token.type != T_INTEGER) {
943                 parse_error("expected integer");
944         } else {
945                 /* use offset -1 as this is about the next line */
946                 lexer_pos.lineno = atoi(pp_token.literal.begin) - 1;
947                 next_pp_token();
948         }
949         if (pp_token.type == T_STRING_LITERAL) {
950                 lexer_pos.input_name = pp_token.literal.begin;
951                 next_pp_token();
952         }
953
954         eat_until_newline();
955 }
956
957 /**
958  * STDC pragmas.
959  */
960 typedef enum stdc_pragma_kind_t {
961         STDC_UNKNOWN,
962         STDC_FP_CONTRACT,
963         STDC_FENV_ACCESS,
964         STDC_CX_LIMITED_RANGE
965 } stdc_pragma_kind_t;
966
967 /**
968  * STDC pragma values.
969  */
970 typedef enum stdc_pragma_value_kind_t {
971         STDC_VALUE_UNKNOWN,
972         STDC_VALUE_ON,
973         STDC_VALUE_OFF,
974         STDC_VALUE_DEFAULT
975 } stdc_pragma_value_kind_t;
976
977 /**
978  * Parse a pragma directive.
979  */
980 static void parse_pragma(void)
981 {
982         bool unknown_pragma = true;
983
984         next_pp_token();
985         if (pp_token.symbol->pp_ID == TP_STDC) {
986                 stdc_pragma_kind_t kind = STDC_UNKNOWN;
987                 /* a STDC pragma */
988                 if (c_mode & _C99) {
989                         next_pp_token();
990
991                         switch (pp_token.symbol->pp_ID) {
992                         case TP_FP_CONTRACT:
993                                 kind = STDC_FP_CONTRACT;
994                                 break;
995                         case TP_FENV_ACCESS:
996                                 kind = STDC_FENV_ACCESS;
997                                 break;
998                         case TP_CX_LIMITED_RANGE:
999                                 kind = STDC_CX_LIMITED_RANGE;
1000                                 break;
1001                         default:
1002                                 break;
1003                         }
1004                         if (kind != STDC_UNKNOWN) {
1005                                 stdc_pragma_value_kind_t value = STDC_VALUE_UNKNOWN;
1006                                 next_pp_token();
1007                                 switch (pp_token.symbol->pp_ID) {
1008                                 case TP_ON:
1009                                         value = STDC_VALUE_ON;
1010                                         break;
1011                                 case TP_OFF:
1012                                         value = STDC_VALUE_OFF;
1013                                         break;
1014                                 case TP_DEFAULT:
1015                                         value = STDC_VALUE_DEFAULT;
1016                                         break;
1017                                 default:
1018                                         break;
1019                                 }
1020                                 if (value != STDC_VALUE_UNKNOWN) {
1021                                         unknown_pragma = false;
1022                                 } else {
1023                                         errorf(&pp_token.source_position, "bad STDC pragma argument");
1024                                 }
1025                         }
1026                 }
1027         } else {
1028                 unknown_pragma = true;
1029         }
1030         eat_until_newline();
1031         if (unknown_pragma) {
1032                 warningf(WARN_UNKNOWN_PRAGMAS, &pp_token.source_position, "encountered unknown #pragma");
1033         }
1034 }
1035
1036 /**
1037  * Parse a preprocessor non-null directive.
1038  */
1039 static void parse_preprocessor_identifier(void)
1040 {
1041         assert(pp_token.type == T_IDENTIFIER);
1042         symbol_t *symbol = pp_token.symbol;
1043
1044         switch (symbol->pp_ID) {
1045         case TP_include:
1046                 printf("include - enable header name parsing!\n");
1047                 break;
1048         case TP_define:
1049                 define_directive();
1050                 break;
1051         case TP_ifdef:
1052                 ifdef_directive(0);
1053                 break;
1054         case TP_ifndef:
1055                 ifdef_directive(1);
1056                 break;
1057         case TP_endif:
1058                 endif_directive();
1059                 break;
1060         case TP_line:
1061                 next_pp_token();
1062                 parse_line_directive();
1063                 break;
1064         case TP_if:
1065         case TP_else:
1066         case TP_elif:
1067         case TP_undef:
1068         case TP_error:
1069                 /* TODO; output the rest of the line */
1070                 parse_error("#error directive: ");
1071                 break;
1072         case TP_pragma:
1073                 parse_pragma();
1074                 break;
1075         }
1076 }
1077
1078 /**
1079  * Parse a preprocessor directive.
1080  */
1081 static void parse_preprocessor_directive(void)
1082 {
1083         next_pp_token();
1084
1085         switch (pp_token.type) {
1086         case T_IDENTIFIER:
1087                 parse_preprocessor_identifier();
1088                 break;
1089         case T_INTEGER:
1090                 parse_line_directive();
1091                 break;
1092         case '\n':
1093                 /* NULL directive, see Â§6.10.7 */
1094                 break;
1095         default:
1096                 parse_error("invalid preprocessor directive");
1097                 eat_until_newline();
1098                 break;
1099         }
1100 }
1101
1102 #define MAYBE_PROLOG                                       \
1103                         next_char();                                   \
1104                         while (true) {                                 \
1105                                 switch (c) {
1106
1107 #define MAYBE(ch, set_type)                                \
1108                                 case ch:                                   \
1109                                         next_char();                           \
1110                                         lexer_token.type = set_type;           \
1111                                         return;
1112
1113 /* must use this as last thing */
1114 #define MAYBE_MODE(ch, set_type, mode)                     \
1115                                 case ch:                                   \
1116                                         if (c_mode & mode) {                   \
1117                                                 next_char();                       \
1118                                                 lexer_token.type = set_type;       \
1119                                                 return;                            \
1120                                         }                                      \
1121                                         /* fallthrough */
1122
1123 #define ELSE_CODE(code)                                    \
1124                                 default:                                   \
1125                                         code                                   \
1126                                         return;                                \
1127                                 }                                          \
1128                         } /* end of while (true) */                    \
1129
1130 #define ELSE(set_type)                                     \
1131                 ELSE_CODE(                                         \
1132                         lexer_token.type = set_type;                   \
1133                 )
1134
1135 void lexer_next_preprocessing_token(void)
1136 {
1137         while (true) {
1138                 lexer_token.source_position = lexer_pos;
1139
1140                 switch (c) {
1141                 case ' ':
1142                 case '\t':
1143                         next_char();
1144                         break;
1145
1146                 MATCH_NEWLINE(
1147                         lexer_token.type = '\n';
1148                         return;
1149                 )
1150
1151                 SYMBOL_CHARS
1152                         parse_symbol();
1153                         /* might be a wide string ( L"string" ) */
1154                         if (lexer_token.symbol == symbol_L) {
1155                                 switch (c) {
1156                                         case '"':  parse_wide_string_literal();     break;
1157                                         case '\'': parse_wide_character_constant(); break;
1158                                 }
1159                         }
1160                         return;
1161
1162                 DIGITS
1163                         parse_number();
1164                         return;
1165
1166                 case '"':
1167                         parse_string_literal();
1168                         return;
1169
1170                 case '\'':
1171                         parse_character_constant();
1172                         return;
1173
1174                 case '.':
1175                         MAYBE_PROLOG
1176                                 DIGITS
1177                                         put_back(c);
1178                                         c = '.';
1179                                         parse_number();
1180                                         return;
1181
1182                                 case '.':
1183                                         MAYBE_PROLOG
1184                                         MAYBE('.', T_DOTDOTDOT)
1185                                         ELSE_CODE(
1186                                                 put_back(c);
1187                                                 c = '.';
1188                                                 lexer_token.type = '.';
1189                                         )
1190                         ELSE('.')
1191                 case '&':
1192                         MAYBE_PROLOG
1193                         MAYBE('&', T_ANDAND)
1194                         MAYBE('=', T_ANDEQUAL)
1195                         ELSE('&')
1196                 case '*':
1197                         MAYBE_PROLOG
1198                         MAYBE('=', T_ASTERISKEQUAL)
1199                         ELSE('*')
1200                 case '+':
1201                         MAYBE_PROLOG
1202                         MAYBE('+', T_PLUSPLUS)
1203                         MAYBE('=', T_PLUSEQUAL)
1204                         ELSE('+')
1205                 case '-':
1206                         MAYBE_PROLOG
1207                         MAYBE('>', T_MINUSGREATER)
1208                         MAYBE('-', T_MINUSMINUS)
1209                         MAYBE('=', T_MINUSEQUAL)
1210                         ELSE('-')
1211                 case '!':
1212                         MAYBE_PROLOG
1213                         MAYBE('=', T_EXCLAMATIONMARKEQUAL)
1214                         ELSE('!')
1215                 case '/':
1216                         MAYBE_PROLOG
1217                         MAYBE('=', T_SLASHEQUAL)
1218                                 case '*':
1219                                         next_char();
1220                                         skip_multiline_comment();
1221                                         lexer_next_preprocessing_token();
1222                                         return;
1223                                 case '/':
1224                                         next_char();
1225                                         skip_line_comment();
1226                                         lexer_next_preprocessing_token();
1227                                         return;
1228                         ELSE('/')
1229                 case '%':
1230                         MAYBE_PROLOG
1231                         MAYBE('>', '}')
1232                         MAYBE('=', T_PERCENTEQUAL)
1233                                 case ':':
1234                                         MAYBE_PROLOG
1235                                                 case '%':
1236                                                         MAYBE_PROLOG
1237                                                         MAYBE(':', T_HASHHASH)
1238                                                         ELSE_CODE(
1239                                                                 put_back(c);
1240                                                                 c = '%';
1241                                                                 lexer_token.type = '#';
1242                                                         )
1243                                         ELSE('#')
1244                         ELSE('%')
1245                 case '<':
1246                         MAYBE_PROLOG
1247                         MAYBE(':', '[')
1248                         MAYBE('%', '{')
1249                         MAYBE('=', T_LESSEQUAL)
1250                                 case '<':
1251                                         MAYBE_PROLOG
1252                                         MAYBE('=', T_LESSLESSEQUAL)
1253                                         ELSE(T_LESSLESS)
1254                         ELSE('<')
1255                 case '>':
1256                         MAYBE_PROLOG
1257                         MAYBE('=', T_GREATEREQUAL)
1258                                 case '>':
1259                                         MAYBE_PROLOG
1260                                         MAYBE('=', T_GREATERGREATEREQUAL)
1261                                         ELSE(T_GREATERGREATER)
1262                         ELSE('>')
1263                 case '^':
1264                         MAYBE_PROLOG
1265                         MAYBE('=', T_CARETEQUAL)
1266                         ELSE('^')
1267                 case '|':
1268                         MAYBE_PROLOG
1269                         MAYBE('=', T_PIPEEQUAL)
1270                         MAYBE('|', T_PIPEPIPE)
1271                         ELSE('|')
1272                 case ':':
1273                         MAYBE_PROLOG
1274                         MAYBE('>', ']')
1275                         MAYBE_MODE(':', T_COLONCOLON, _CXX)
1276                         ELSE(':')
1277                 case '=':
1278                         MAYBE_PROLOG
1279                         MAYBE('=', T_EQUALEQUAL)
1280                         ELSE('=')
1281                 case '#':
1282                         MAYBE_PROLOG
1283                         MAYBE('#', T_HASHHASH)
1284                         ELSE('#')
1285
1286                 case '?':
1287                 case '[':
1288                 case ']':
1289                 case '(':
1290                 case ')':
1291                 case '{':
1292                 case '}':
1293                 case '~':
1294                 case ';':
1295                 case ',':
1296                 case '\\':
1297                         lexer_token.type = c;
1298                         next_char();
1299                         return;
1300
1301                 case EOF:
1302                         lexer_token.type = T_EOF;
1303                         return;
1304
1305                 default:
1306 dollar_sign:
1307                         errorf(&lexer_pos, "unknown character '%c' found", c);
1308                         next_char();
1309                         lexer_token.type = T_ERROR;
1310                         return;
1311                 }
1312         }
1313 }
1314
1315 void lexer_next_token(void)
1316 {
1317         lexer_next_preprocessing_token();
1318
1319         while (lexer_token.type == '\n') {
1320 newline_found:
1321                 lexer_next_preprocessing_token();
1322         }
1323
1324         if (lexer_token.type == '#') {
1325                 parse_preprocessor_directive();
1326                 goto newline_found;
1327         }
1328 }
1329
1330 void init_lexer(void)
1331 {
1332         strset_init(&stringset);
1333         symbol_L = symbol_table_insert("L");
1334 }
1335
1336 static void input_error(unsigned delta_lines, unsigned delta_cols,
1337                         const char *message)
1338 {
1339         lexer_pos.lineno += delta_lines;
1340         lexer_pos.colno  += delta_cols;
1341         errorf(&lexer_pos, "%s", message);
1342 }
1343
1344 void select_input_encoding(char const* new_encoding)
1345 {
1346         if (encoding != NULL)
1347                 xfree(encoding);
1348         encoding = xstrdup(new_encoding);
1349 }
1350
1351 void lexer_open_stream(FILE *stream, const char *input_name)
1352 {
1353         if (input != NULL) {
1354                 input_free(input);
1355                 input = NULL;
1356         }
1357
1358         lexer_pos.lineno     = 0;
1359         lexer_pos.colno      = 0;
1360         lexer_pos.input_name = input_name;
1361
1362         set_input_error_callback(input_error);
1363         input  = input_from_stream(stream, encoding);
1364         bufpos = NULL;
1365         bufend = NULL;
1366
1367         /* place a virtual \n at the beginning so the lexer knows that we're
1368          * at the beginning of a line */
1369         c = '\n';
1370 }
1371
1372 void exit_lexer(void)
1373 {
1374         if (input != NULL) {
1375                 input_free(input);
1376                 input = NULL;
1377         }
1378         strset_destroy(&stringset);
1379 }
1380
1381 static __attribute__((unused))
1382 void dbg_pos(const source_position_t source_position)
1383 {
1384         fprintf(stdout, "%s:%u:%u\n", source_position.input_name,
1385                 source_position.lineno, source_position.colno);
1386         fflush(stdout);
1387 }