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