2 * This file is part of cparser.
3 * Copyright (C) 2007-2008 Matthias Braun <matze@braunis.de>
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.
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.
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
22 #include "diagnostic.h"
26 #include "symbol_table_t.h"
27 #include "adt/error.h"
28 #include "adt/strset.h"
32 #include "target_architecture.h"
35 #include "lang_features.h"
46 #if defined(_WIN32) || defined(__CYGWIN__)
47 /* No strtold on windows and no replacement yet */
48 #define strtold(s, e) strtod(s, e)
55 static char buf[1024 + MAX_PUTBACK];
56 static const char *bufend;
57 static const char *bufpos;
58 static strset_t stringset;
59 bool allow_dollar_in_symbol = true;
62 * Prints a parse error message at the current token.
64 * @param msg the error message
66 static void parse_error(const char *msg)
68 errorf(&lexer_token.source_position, "%s", msg);
72 * Prints an internal error message at the current token.
74 * @param msg the error message
76 static NORETURN internal_error(const char *msg)
78 internal_errorf(&lexer_token.source_position, "%s", msg);
81 static inline void next_real_char(void)
83 assert(bufpos <= bufend);
84 if (bufpos >= bufend) {
90 size_t s = fread(buf + MAX_PUTBACK, 1, sizeof(buf) - MAX_PUTBACK,
96 bufpos = buf + MAX_PUTBACK;
97 bufend = buf + MAX_PUTBACK + s;
99 c = (unsigned char)*bufpos++;
103 * Put a character back into the buffer.
105 * @param pc the character to put back
107 static inline void put_back(int pc)
109 assert(bufpos > buf);
110 *(--bufpos - buf + buf) = (char) pc;
113 printf("putback '%c'\n", pc);
117 static inline void next_char(void);
119 #define MATCH_NEWLINE(code) \
125 lexer_token.source_position.linenr++; \
129 lexer_token.source_position.linenr++; \
132 #define eat(c_type) do { assert(c == c_type); next_char(); } while(0)
134 static void maybe_concat_lines(void)
139 MATCH_NEWLINE(return;)
150 * Set c to the next input character, ie.
151 * after expanding trigraphs.
153 static inline void next_char(void)
157 /* filter trigraphs */
158 if(UNLIKELY(c == '\\')) {
159 maybe_concat_lines();
160 goto end_of_next_char;
164 goto end_of_next_char;
167 if(LIKELY(c != '?')) {
170 goto end_of_next_char;
175 case '=': c = '#'; break;
176 case '(': c = '['; break;
177 case '/': c = '\\'; maybe_concat_lines(); break;
178 case ')': c = ']'; break;
179 case '\'': c = '^'; break;
180 case '<': c = '{'; break;
181 case '!': c = '|'; break;
182 case '>': c = '}'; break;
183 case '-': c = '~'; break;
193 printf("nchar '%c'\n", c);
197 #define SYMBOL_CHARS \
198 case '$': if (!allow_dollar_in_symbol) goto dollar_sign; \
266 * Read a symbol from the input and build
269 static void parse_symbol(void)
274 obstack_1grow(&symbol_obstack, (char) c);
281 obstack_1grow(&symbol_obstack, (char) c);
292 obstack_1grow(&symbol_obstack, '\0');
294 string = obstack_finish(&symbol_obstack);
295 symbol = symbol_table_insert(string);
297 lexer_token.type = symbol->ID;
298 lexer_token.v.symbol = symbol;
300 if(symbol->string != string) {
301 obstack_free(&symbol_obstack, string);
305 static void parse_integer_suffix(bool is_oct_hex)
307 bool is_unsigned = false;
308 bool min_long = false;
309 bool min_longlong = false;
310 bool not_traditional = false;
314 if (c == 'U' || c == 'u') {
315 not_traditional = true;
316 suffix[pos++] = toupper(c);
319 if (c == 'L' || c == 'l') {
320 suffix[pos++] = toupper(c);
323 if (c == 'L' || c == 'l') {
324 suffix[pos++] = toupper(c);
329 } else if (c == 'l' || c == 'L') {
330 suffix[pos++] = toupper(c);
333 if (c == 'l' || c == 'L') {
334 not_traditional = true;
335 suffix[pos++] = toupper(c);
338 if (c == 'u' || c == 'U') {
339 suffix[pos++] = toupper(c);
343 } else if (c == 'u' || c == 'U') {
344 not_traditional = true;
345 suffix[pos++] = toupper(c);
348 lexer_token.datatype = type_unsigned_long;
352 if (warning.traditional && not_traditional) {
354 warningf(&lexer_token.source_position,
355 "traditional C rejects the '%s' suffix", suffix);
358 long long v = lexer_token.v.intvalue;
360 if (v >= TARGET_INT_MIN && v <= TARGET_INT_MAX) {
361 lexer_token.datatype = type_int;
363 } else if (is_oct_hex && v >= 0 && v <= TARGET_UINT_MAX) {
364 lexer_token.datatype = type_unsigned_int;
369 if (v >= TARGET_LONG_MIN && v <= TARGET_LONG_MAX) {
370 lexer_token.datatype = type_long;
372 } else if (is_oct_hex && v >= 0 && (unsigned long long)v <= (unsigned long long)TARGET_ULONG_MAX) {
373 lexer_token.datatype = type_unsigned_long;
377 unsigned long long uv = (unsigned long long) v;
378 if (is_oct_hex && uv > (unsigned long long) TARGET_LONGLONG_MAX) {
379 lexer_token.datatype = type_unsigned_long_long;
383 lexer_token.datatype = type_long_long;
385 unsigned long long v = (unsigned long long) lexer_token.v.intvalue;
386 if (!min_long && v <= TARGET_UINT_MAX) {
387 lexer_token.datatype = type_unsigned_int;
390 if (!min_longlong && v <= TARGET_ULONG_MAX) {
391 lexer_token.datatype = type_unsigned_long;
394 lexer_token.datatype = type_unsigned_long_long;
398 static void parse_floating_suffix(void)
401 /* TODO: do something useful with the suffixes... */
404 if (warning.traditional) {
405 warningf(&lexer_token.source_position,
406 "traditional C rejects the 'F' suffix");
409 lexer_token.datatype = type_float;
413 if (warning.traditional) {
414 warningf(&lexer_token.source_position,
415 "traditional C rejects the 'F' suffix");
418 lexer_token.datatype = type_long_double;
421 lexer_token.datatype = type_double;
427 * A replacement for strtoull. Only those parts needed for
428 * our parser are implemented.
430 static unsigned long long parse_int_string(const char *s, const char **endptr, int base) {
431 unsigned long long v = 0;
436 /* check for overrun */
437 if (v >= 0x1000000000000000ULL)
439 switch (tolower(*s)) {
440 case '0': v <<= 4; break;
441 case '1': v <<= 4; v |= 0x1; break;
442 case '2': v <<= 4; v |= 0x2; break;
443 case '3': v <<= 4; v |= 0x3; break;
444 case '4': v <<= 4; v |= 0x4; break;
445 case '5': v <<= 4; v |= 0x5; break;
446 case '6': v <<= 4; v |= 0x6; break;
447 case '7': v <<= 4; v |= 0x7; break;
448 case '8': v <<= 4; v |= 0x8; break;
449 case '9': v <<= 4; v |= 0x9; break;
450 case 'a': v <<= 4; v |= 0xa; break;
451 case 'b': v <<= 4; v |= 0xb; break;
452 case 'c': v <<= 4; v |= 0xc; break;
453 case 'd': v <<= 4; v |= 0xd; break;
454 case 'e': v <<= 4; v |= 0xe; break;
455 case 'f': v <<= 4; v |= 0xf; break;
463 /* check for overrun */
464 if (v >= 0x2000000000000000ULL)
466 switch (tolower(*s)) {
467 case '0': v <<= 3; break;
468 case '1': v <<= 3; v |= 1; break;
469 case '2': v <<= 3; v |= 2; break;
470 case '3': v <<= 3; v |= 3; break;
471 case '4': v <<= 3; v |= 4; break;
472 case '5': v <<= 3; v |= 5; break;
473 case '6': v <<= 3; v |= 6; break;
474 case '7': v <<= 3; v |= 7; break;
482 /* check for overrun */
483 if (v > 0x1999999999999999ULL)
485 switch (tolower(*s)) {
486 case '0': v *= 10; break;
487 case '1': v *= 10; v += 1; break;
488 case '2': v *= 10; v += 2; break;
489 case '3': v *= 10; v += 3; break;
490 case '4': v *= 10; v += 4; break;
491 case '5': v *= 10; v += 5; break;
492 case '6': v *= 10; v += 6; break;
493 case '7': v *= 10; v += 7; break;
494 case '8': v *= 10; v += 8; break;
495 case '9': v *= 10; v += 9; break;
511 * Parses a hex number including hex floats and set the
514 static void parse_number_hex(void)
516 bool is_float = false;
517 assert(c == 'x' || c == 'X');
520 obstack_1grow(&symbol_obstack, '0');
521 obstack_1grow(&symbol_obstack, 'x');
524 obstack_1grow(&symbol_obstack, (char) c);
529 obstack_1grow(&symbol_obstack, (char) c);
532 while (isxdigit(c)) {
533 obstack_1grow(&symbol_obstack, (char) c);
538 if (c == 'p' || c == 'P') {
539 obstack_1grow(&symbol_obstack, (char) c);
542 if (c == '-' || c == '+') {
543 obstack_1grow(&symbol_obstack, (char) c);
547 while (isxdigit(c)) {
548 obstack_1grow(&symbol_obstack, (char) c);
554 obstack_1grow(&symbol_obstack, '\0');
555 char *string = obstack_finish(&symbol_obstack);
556 if(*string == '\0') {
557 parse_error("invalid hex number");
558 lexer_token.type = T_ERROR;
559 obstack_free(&symbol_obstack, string);
565 lexer_token.type = T_FLOATINGPOINT;
566 lexer_token.v.floatvalue = strtold(string, &endptr);
568 if(*endptr != '\0') {
569 parse_error("invalid hex float literal");
572 parse_floating_suffix();
575 lexer_token.type = T_INTEGER;
576 lexer_token.v.intvalue = parse_int_string(string + 2, &endptr, 16);
577 if(*endptr != '\0') {
578 parse_error("hex number literal too long");
580 parse_integer_suffix(true);
583 obstack_free(&symbol_obstack, string);
587 * Returns true if the given char is a octal digit.
589 * @param char the character to check
591 static inline bool is_octal_digit(int chr)
609 * Parses a octal number and set the lexer_token.
611 static void parse_number_oct(void)
613 while(is_octal_digit(c)) {
614 obstack_1grow(&symbol_obstack, (char) c);
617 obstack_1grow(&symbol_obstack, '\0');
618 char *string = obstack_finish(&symbol_obstack);
621 lexer_token.type = T_INTEGER;
622 lexer_token.v.intvalue = parse_int_string(string, &endptr, 8);
623 if(*endptr != '\0') {
624 parse_error("octal number literal too long");
627 obstack_free(&symbol_obstack, string);
628 parse_integer_suffix(true);
632 * Parses a decimal including float number and set the
635 static void parse_number_dec(void)
637 bool is_float = false;
639 obstack_1grow(&symbol_obstack, (char) c);
644 obstack_1grow(&symbol_obstack, '.');
648 obstack_1grow(&symbol_obstack, (char) c);
653 if(c == 'e' || c == 'E') {
654 obstack_1grow(&symbol_obstack, (char) c);
657 if(c == '-' || c == '+') {
658 obstack_1grow(&symbol_obstack, (char) c);
663 obstack_1grow(&symbol_obstack, (char) c);
669 obstack_1grow(&symbol_obstack, '\0');
670 char *string = obstack_finish(&symbol_obstack);
674 lexer_token.type = T_FLOATINGPOINT;
675 lexer_token.v.floatvalue = strtold(string, &endptr);
677 if(*endptr != '\0') {
678 parse_error("invalid number literal");
681 parse_floating_suffix();
684 lexer_token.type = T_INTEGER;
685 lexer_token.v.intvalue = parse_int_string(string, &endptr, 10);
687 if(*endptr != '\0') {
688 parse_error("invalid number literal");
691 parse_integer_suffix(false);
693 obstack_free(&symbol_obstack, string);
697 * Parses a number and sets the lexer_token.
699 static void parse_number(void)
721 parse_error("invalid octal number");
722 lexer_token.type = T_ERROR;
728 obstack_1grow(&symbol_obstack, '0');
738 * Returns the value of a digit.
739 * The only portable way to do it ...
741 static int digit_value(int digit) {
766 internal_error("wrong character given");
771 * Parses an octal character sequence.
773 * @param first_digit the already read first digit
775 static int parse_octal_sequence(const int first_digit)
777 assert(is_octal_digit(first_digit));
778 int value = digit_value(first_digit);
779 if (!is_octal_digit(c)) return value;
780 value = 8 * value + digit_value(c);
782 if (!is_octal_digit(c)) return value;
783 value = 8 * value + digit_value(c);
787 return (signed char) value;
789 return (unsigned char) value;
794 * Parses a hex character sequence.
796 static int parse_hex_sequence(void)
800 value = 16 * value + digit_value(c);
805 return (signed char) value;
807 return (unsigned char) value;
812 * Parse an escape sequence.
814 static int parse_escape_sequence(void)
822 case '"': return '"';
823 case '\'': return '\'';
824 case '\\': return '\\';
825 case '?': return '\?';
826 case 'a': return '\a';
827 case 'b': return '\b';
828 case 'f': return '\f';
829 case 'n': return '\n';
830 case 'r': return '\r';
831 case 't': return '\t';
832 case 'v': return '\v';
834 return parse_hex_sequence();
843 return parse_octal_sequence(ec);
845 parse_error("reached end of file while parsing escape sequence");
847 /* \E is not documented, but handled, by GCC. It is acceptable according
848 * to §6.11.4, whereas \e is not. */
852 return 27; /* hopefully 27 is ALWAYS the code for ESCAPE */
855 /* §6.4.4.4:8 footnote 64 */
856 parse_error("unknown escape sequence");
862 * Concatenate two strings.
864 string_t concat_strings(const string_t *const s1, const string_t *const s2)
866 const size_t len1 = s1->size - 1;
867 const size_t len2 = s2->size - 1;
869 char *const concat = obstack_alloc(&symbol_obstack, len1 + len2 + 1);
870 memcpy(concat, s1->begin, len1);
871 memcpy(concat + len1, s2->begin, len2 + 1);
873 if (warning.traditional) {
874 warningf(&lexer_token.source_position,
875 "traditional C rejects string constant concatenation");
877 #if 0 /* TODO hash */
878 const char *result = strset_insert(&stringset, concat);
879 if(result != concat) {
880 obstack_free(&symbol_obstack, concat);
885 return (string_t){ concat, len1 + len2 + 1 };
890 * Concatenate a string and a wide string.
892 wide_string_t concat_string_wide_string(const string_t *const s1, const wide_string_t *const s2)
894 const size_t len1 = s1->size - 1;
895 const size_t len2 = s2->size - 1;
897 wchar_rep_t *const concat = obstack_alloc(&symbol_obstack, (len1 + len2 + 1) * sizeof(*concat));
898 const char *const src = s1->begin;
899 for (size_t i = 0; i != len1; ++i) {
902 memcpy(concat + len1, s2->begin, (len2 + 1) * sizeof(*concat));
903 if (warning.traditional) {
904 warningf(&lexer_token.source_position,
905 "traditional C rejects string constant concatenation");
908 return (wide_string_t){ concat, len1 + len2 + 1 };
912 * Concatenate two wide strings.
914 wide_string_t concat_wide_strings(const wide_string_t *const s1, const wide_string_t *const s2)
916 const size_t len1 = s1->size - 1;
917 const size_t len2 = s2->size - 1;
919 wchar_rep_t *const concat = obstack_alloc(&symbol_obstack, (len1 + len2 + 1) * sizeof(*concat));
920 memcpy(concat, s1->begin, len1 * sizeof(*concat));
921 memcpy(concat + len1, s2->begin, (len2 + 1) * sizeof(*concat));
922 if (warning.traditional) {
923 warningf(&lexer_token.source_position,
924 "traditional C rejects string constant concatenation");
927 return (wide_string_t){ concat, len1 + len2 + 1 };
931 * Concatenate a wide string and a string.
933 wide_string_t concat_wide_string_string(const wide_string_t *const s1, const string_t *const s2)
935 const size_t len1 = s1->size - 1;
936 const size_t len2 = s2->size - 1;
938 wchar_rep_t *const concat = obstack_alloc(&symbol_obstack, (len1 + len2 + 1) * sizeof(*concat));
939 memcpy(concat, s1->begin, len1 * sizeof(*concat));
940 const char *const src = s2->begin;
941 wchar_rep_t *const dst = concat + len1;
942 for (size_t i = 0; i != len2 + 1; ++i) {
945 if (warning.traditional) {
946 warningf(&lexer_token.source_position,
947 "traditional C rejects string constant concatenation");
950 return (wide_string_t){ concat, len1 + len2 + 1 };
954 * Parse a string literal and set lexer_token.
956 static void parse_string_literal(void)
958 const unsigned start_linenr = lexer_token.source_position.linenr;
966 tc = parse_escape_sequence();
967 obstack_1grow(&symbol_obstack, (char) tc);
971 source_position_t source_position;
972 source_position.input_name = lexer_token.source_position.input_name;
973 source_position.linenr = start_linenr;
974 errorf(&source_position, "string has no end");
975 lexer_token.type = T_ERROR;
984 obstack_1grow(&symbol_obstack, (char) c);
992 /* TODO: concatenate multiple strings separated by whitespace... */
994 /* add finishing 0 to the string */
995 obstack_1grow(&symbol_obstack, '\0');
996 const size_t size = (size_t)obstack_object_size(&symbol_obstack);
997 const char *const string = obstack_finish(&symbol_obstack);
999 #if 0 /* TODO hash */
1000 /* check if there is already a copy of the string */
1001 result = strset_insert(&stringset, string);
1002 if(result != string) {
1003 obstack_free(&symbol_obstack, string);
1006 const char *const result = string;
1009 lexer_token.type = T_STRING_LITERAL;
1010 lexer_token.v.string.begin = result;
1011 lexer_token.v.string.size = size;
1015 * Parse a wide character constant and set lexer_token.
1017 static void parse_wide_character_constant(void)
1019 const unsigned start_linenr = lexer_token.source_position.linenr;
1026 wchar_rep_t tc = parse_escape_sequence();
1027 obstack_grow(&symbol_obstack, &tc, sizeof(tc));
1032 parse_error("newline while parsing character constant");
1038 goto end_of_wide_char_constant;
1041 source_position_t source_position = lexer_token.source_position;
1042 source_position.linenr = start_linenr;
1043 errorf(&source_position, "EOF while parsing character constant");
1044 lexer_token.type = T_ERROR;
1049 wchar_rep_t tc = (wchar_rep_t) c;
1050 obstack_grow(&symbol_obstack, &tc, sizeof(tc));
1057 end_of_wide_char_constant:;
1058 size_t size = (size_t) obstack_object_size(&symbol_obstack);
1059 assert(size % sizeof(wchar_rep_t) == 0);
1060 size /= sizeof(wchar_rep_t);
1062 const wchar_rep_t *string = obstack_finish(&symbol_obstack);
1064 lexer_token.type = T_WIDE_CHARACTER_CONSTANT;
1065 lexer_token.v.wide_string.begin = string;
1066 lexer_token.v.wide_string.size = size;
1067 lexer_token.datatype = type_wchar_t;
1071 * Parse a wide string literal and set lexer_token.
1073 static void parse_wide_string_literal(void)
1075 const unsigned start_linenr = lexer_token.source_position.linenr;
1083 wchar_rep_t tc = parse_escape_sequence();
1084 obstack_grow(&symbol_obstack, &tc, sizeof(tc));
1089 source_position_t source_position;
1090 source_position.input_name = lexer_token.source_position.input_name;
1091 source_position.linenr = start_linenr;
1092 errorf(&source_position, "string has no end");
1093 lexer_token.type = T_ERROR;
1103 obstack_grow(&symbol_obstack, &tc, sizeof(tc));
1112 /* TODO: concatenate multiple strings separated by whitespace... */
1114 /* add finishing 0 to the string */
1115 wchar_rep_t nul = L'\0';
1116 obstack_grow(&symbol_obstack, &nul, sizeof(nul));
1117 const size_t size = (size_t)obstack_object_size(&symbol_obstack) / sizeof(wchar_rep_t);
1118 const wchar_rep_t *const string = obstack_finish(&symbol_obstack);
1120 #if 0 /* TODO hash */
1121 /* check if there is already a copy of the string */
1122 const wchar_rep_t *const result = strset_insert(&stringset, string);
1123 if(result != string) {
1124 obstack_free(&symbol_obstack, string);
1127 const wchar_rep_t *const result = string;
1130 lexer_token.type = T_WIDE_STRING_LITERAL;
1131 lexer_token.v.wide_string.begin = result;
1132 lexer_token.v.wide_string.size = size;
1136 * Parse a character constant and set lexer_token.
1138 static void parse_character_constant(void)
1140 const unsigned start_linenr = lexer_token.source_position.linenr;
1147 int tc = parse_escape_sequence();
1148 obstack_1grow(&symbol_obstack, (char) tc);
1153 parse_error("newline while parsing character constant");
1159 goto end_of_char_constant;
1162 source_position_t source_position;
1163 source_position.input_name = lexer_token.source_position.input_name;
1164 source_position.linenr = start_linenr;
1165 errorf(&source_position, "EOF while parsing character constant");
1166 lexer_token.type = T_ERROR;
1171 obstack_1grow(&symbol_obstack, (char) c);
1178 end_of_char_constant:;
1179 const size_t size = (size_t)obstack_object_size(&symbol_obstack);
1180 const char *const string = obstack_finish(&symbol_obstack);
1182 lexer_token.type = T_CHARACTER_CONSTANT;
1183 lexer_token.v.string.begin = string;
1184 lexer_token.v.string.size = size;
1185 lexer_token.datatype = c_mode & _CXX && size == 1 ? type_char : type_int;
1189 * Skip a multiline comment.
1191 static void skip_multiline_comment(void)
1193 unsigned start_linenr = lexer_token.source_position.linenr;
1200 /* nested comment, warn here */
1201 if (warning.comment) {
1202 warningf(&lexer_token.source_position, "'/*' within comment");
1214 MATCH_NEWLINE(break;)
1217 source_position_t source_position;
1218 source_position.input_name = lexer_token.source_position.input_name;
1219 source_position.linenr = start_linenr;
1220 errorf(&source_position, "at end of file while looking for comment end");
1232 * Skip a single line comment.
1234 static void skip_line_comment(void)
1247 if (c == '\n' || c == '\r') {
1248 if (warning.comment)
1249 warningf(&lexer_token.source_position, "multi-line comment");
1261 /** The current preprocessor token. */
1262 static token_t pp_token;
1265 * Read the next preprocessor token.
1267 static inline void next_pp_token(void)
1269 lexer_next_preprocessing_token();
1270 pp_token = lexer_token;
1274 * Eat all preprocessor tokens until newline.
1276 static void eat_until_newline(void)
1278 while(pp_token.type != '\n' && pp_token.type != T_EOF) {
1284 * Handle the define directive.
1286 static void define_directive(void)
1288 lexer_next_preprocessing_token();
1289 if(lexer_token.type != T_IDENTIFIER) {
1290 parse_error("expected identifier after #define\n");
1291 eat_until_newline();
1296 * Handle the ifdef directive.
1298 static void ifdef_directive(int is_ifndef)
1301 lexer_next_preprocessing_token();
1302 //expect_identifier();
1307 * Handle the endif directive.
1309 static void endif_directive(void)
1315 * Parse the line directive.
1317 static void parse_line_directive(void)
1319 if(pp_token.type != T_INTEGER) {
1320 parse_error("expected integer");
1322 lexer_token.source_position.linenr = (unsigned int)(pp_token.v.intvalue - 1);
1325 if(pp_token.type == T_STRING_LITERAL) {
1326 lexer_token.source_position.input_name = pp_token.v.string.begin;
1330 eat_until_newline();
1336 typedef enum stdc_pragma_kind_t {
1340 STDC_CX_LIMITED_RANGE
1341 } stdc_pragma_kind_t;
1344 * STDC pragma values.
1346 typedef enum stdc_pragma_value_kind_t {
1351 } stdc_pragma_value_kind_t;
1354 * Parse a pragma directive.
1356 static void parse_pragma(void) {
1357 bool unknown_pragma = true;
1360 if (pp_token.v.symbol->pp_ID == TP_STDC) {
1361 stdc_pragma_kind_t kind = STDC_UNKNOWN;
1363 if (c_mode & _C99) {
1366 switch (pp_token.v.symbol->pp_ID) {
1367 case TP_FP_CONTRACT:
1368 kind = STDC_FP_CONTRACT;
1370 case TP_FENV_ACCESS:
1371 kind = STDC_FENV_ACCESS;
1373 case TP_CX_LIMITED_RANGE:
1374 kind = STDC_CX_LIMITED_RANGE;
1379 if (kind != STDC_UNKNOWN) {
1380 stdc_pragma_value_kind_t value = STDC_VALUE_UNKNOWN;
1382 switch (pp_token.v.symbol->pp_ID) {
1384 value = STDC_VALUE_ON;
1387 value = STDC_VALUE_OFF;
1390 value = STDC_VALUE_DEFAULT;
1395 if (value != STDC_VALUE_UNKNOWN) {
1396 unknown_pragma = false;
1398 errorf(&pp_token.source_position, "bad STDC pragma argument");
1403 unknown_pragma = true;
1405 eat_until_newline();
1406 if (unknown_pragma && warning.unknown_pragmas) {
1407 warningf(&pp_token.source_position, "encountered unknown #pragma");
1412 * Parse a preprocessor non-null directive.
1414 static void parse_preprocessor_identifier(void)
1416 assert(pp_token.type == T_IDENTIFIER);
1417 symbol_t *symbol = pp_token.v.symbol;
1419 switch(symbol->pp_ID) {
1421 printf("include - enable header name parsing!\n");
1437 parse_line_directive();
1444 /* TODO; output the rest of the line */
1445 parse_error("#error directive: ");
1454 * Parse a preprocessor directive.
1456 static void parse_preprocessor_directive(void)
1460 switch(pp_token.type) {
1462 parse_preprocessor_identifier();
1465 parse_line_directive();
1468 /* NULL directive, see § 6.10.7 */
1471 parse_error("invalid preprocessor directive");
1472 eat_until_newline();
1477 #define MAYBE_PROLOG \
1482 #define MAYBE(ch, set_type) \
1485 lexer_token.type = set_type; \
1488 #define ELSE_CODE(code) \
1492 } /* end of while(1) */ \
1495 #define ELSE(set_type) \
1497 lexer_token.type = set_type; \
1501 void lexer_next_preprocessing_token(void)
1511 lexer_token.type = '\n';
1517 /* might be a wide string ( L"string" ) */
1518 if(lexer_token.type == T_IDENTIFIER &&
1519 lexer_token.v.symbol == symbol_L) {
1521 parse_wide_string_literal();
1522 } else if(c == '\'') {
1523 parse_wide_character_constant();
1533 parse_string_literal();
1537 parse_character_constant();
1550 MAYBE('.', T_DOTDOTDOT)
1554 lexer_token.type = '.';
1560 MAYBE('&', T_ANDAND)
1561 MAYBE('=', T_ANDEQUAL)
1565 MAYBE('=', T_ASTERISKEQUAL)
1569 MAYBE('+', T_PLUSPLUS)
1570 MAYBE('=', T_PLUSEQUAL)
1574 MAYBE('>', T_MINUSGREATER)
1575 MAYBE('-', T_MINUSMINUS)
1576 MAYBE('=', T_MINUSEQUAL)
1580 MAYBE('=', T_EXCLAMATIONMARKEQUAL)
1584 MAYBE('=', T_SLASHEQUAL)
1587 skip_multiline_comment();
1588 lexer_next_preprocessing_token();
1592 skip_line_comment();
1593 lexer_next_preprocessing_token();
1599 MAYBE('=', T_PERCENTEQUAL)
1604 MAYBE(':', T_HASHHASH)
1608 lexer_token.type = '#';
1617 MAYBE('=', T_LESSEQUAL)
1620 MAYBE('=', T_LESSLESSEQUAL)
1625 MAYBE('=', T_GREATEREQUAL)
1628 MAYBE('=', T_GREATERGREATEREQUAL)
1629 ELSE(T_GREATERGREATER)
1633 MAYBE('=', T_CARETEQUAL)
1637 MAYBE('=', T_PIPEEQUAL)
1638 MAYBE('|', T_PIPEPIPE)
1646 MAYBE('=', T_EQUALEQUAL)
1650 MAYBE('#', T_HASHHASH)
1664 lexer_token.type = c;
1669 lexer_token.type = T_EOF;
1674 errorf(&lexer_token.source_position, "unknown character '%c' found", c);
1676 lexer_token.type = T_ERROR;
1682 void lexer_next_token(void)
1684 lexer_next_preprocessing_token();
1686 while (lexer_token.type == '\n') {
1688 lexer_next_preprocessing_token();
1691 if (lexer_token.type == '#') {
1692 parse_preprocessor_directive();
1697 void init_lexer(void)
1699 strset_init(&stringset);
1700 symbol_L = symbol_table_insert("L");
1703 void lexer_open_stream(FILE *stream, const char *input_name)
1706 lexer_token.source_position.linenr = 0;
1707 lexer_token.source_position.input_name = input_name;
1712 /* place a virtual \n at the beginning so the lexer knows that we're
1713 * at the beginning of a line */
1717 void lexer_open_buffer(const char *buffer, size_t len, const char *input_name)
1720 lexer_token.source_position.linenr = 0;
1721 lexer_token.source_position.input_name = input_name;
1724 bufend = buffer + len;
1726 /* place a virtual \n at the beginning so the lexer knows that we're
1727 * at the beginning of a line */
1731 void exit_lexer(void)
1733 strset_destroy(&stringset);
1736 static __attribute__((unused))
1737 void dbg_pos(const source_position_t source_position)
1739 fprintf(stdout, "%s:%u\n", source_position.input_name,
1740 source_position.linenr);