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"
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;
61 * Prints a parse error message at the current token.
63 * @param msg the error message
65 static void parse_error(const char *msg)
67 errorf(&lexer_token.source_position, "%s", msg);
71 * Prints an internal error message at the current token.
73 * @param msg the error message
75 static NORETURN internal_error(const char *msg)
77 internal_errorf(&lexer_token.source_position, "%s", msg);
80 static inline void next_real_char(void)
82 assert(bufpos <= bufend);
83 if (bufpos >= bufend) {
89 size_t s = fread(buf + MAX_PUTBACK, 1, sizeof(buf) - MAX_PUTBACK,
95 bufpos = buf + MAX_PUTBACK;
96 bufend = buf + MAX_PUTBACK + s;
102 * Put a character back into the buffer.
104 * @param pc the character to put back
106 static inline void put_back(int pc)
108 assert(bufpos > buf);
109 *(--bufpos - buf + buf) = (char) pc;
112 printf("putback '%c'\n", pc);
116 static inline void next_char(void);
118 #define MATCH_NEWLINE(code) \
124 lexer_token.source_position.linenr++; \
128 lexer_token.source_position.linenr++; \
131 #define eat(c_type) do { assert(c == c_type); next_char(); } while(0)
133 static void maybe_concat_lines(void)
138 MATCH_NEWLINE(return;)
149 * Set c to the next input character, ie.
150 * after expanding trigraphs.
152 static inline void next_char(void)
156 /* filter trigraphs */
157 if(UNLIKELY(c == '\\')) {
158 maybe_concat_lines();
159 goto end_of_next_char;
163 goto end_of_next_char;
166 if(LIKELY(c != '?')) {
169 goto end_of_next_char;
174 case '=': c = '#'; break;
175 case '(': c = '['; break;
176 case '/': c = '\\'; maybe_concat_lines(); break;
177 case ')': c = ']'; break;
178 case '\'': c = '^'; break;
179 case '<': c = '{'; break;
180 case '!': c = '|'; break;
181 case '>': c = '}'; break;
182 case '-': c = '~'; break;
192 printf("nchar '%c'\n", c);
196 #define SYMBOL_CHARS \
264 * Read a symbol from the input and build
267 static void parse_symbol(void)
272 obstack_1grow(&symbol_obstack, (char) c);
279 obstack_1grow(&symbol_obstack, (char) c);
289 obstack_1grow(&symbol_obstack, '\0');
291 string = obstack_finish(&symbol_obstack);
292 symbol = symbol_table_insert(string);
294 lexer_token.type = symbol->ID;
295 lexer_token.v.symbol = symbol;
297 if(symbol->string != string) {
298 obstack_free(&symbol_obstack, string);
302 static void parse_integer_suffix(bool is_oct_hex)
304 bool is_unsigned = false;
305 bool min_long = false;
306 bool min_longlong = false;
308 if(c == 'U' || c == 'u') {
311 if(c == 'L' || c == 'l') {
314 if(c == 'L' || c == 'l') {
319 } else if(c == 'l' || c == 'L') {
322 if(c == 'l' || c == 'L') {
325 if(c == 'u' || c == 'U') {
329 } else if(c == 'u' || c == 'U') {
332 lexer_token.datatype = type_unsigned_long;
337 long long v = lexer_token.v.intvalue;
339 if(v >= TARGET_INT_MIN && v <= TARGET_INT_MAX) {
340 lexer_token.datatype = type_int;
342 } else if(is_oct_hex && v >= 0 && v <= TARGET_UINT_MAX) {
343 lexer_token.datatype = type_unsigned_int;
348 if(v >= TARGET_LONG_MIN && v <= TARGET_LONG_MAX) {
349 lexer_token.datatype = type_long;
351 } else if(is_oct_hex && v >= 0 && (unsigned long long)v <= (unsigned long long)TARGET_ULONG_MAX) {
352 lexer_token.datatype = type_unsigned_long;
356 unsigned long long uv = (unsigned long long) v;
357 if(is_oct_hex && uv > (unsigned long long) TARGET_LONGLONG_MAX) {
358 lexer_token.datatype = type_unsigned_long_long;
362 lexer_token.datatype = type_long_long;
364 unsigned long long v = (unsigned long long) lexer_token.v.intvalue;
365 if(!min_long && v <= TARGET_UINT_MAX) {
366 lexer_token.datatype = type_unsigned_int;
369 if(!min_longlong && v <= TARGET_ULONG_MAX) {
370 lexer_token.datatype = type_unsigned_long;
373 lexer_token.datatype = type_unsigned_long_long;
377 static void parse_floating_suffix(void)
380 /* TODO: do something useful with the suffixes... */
384 lexer_token.datatype = type_float;
389 lexer_token.datatype = type_long_double;
392 lexer_token.datatype = type_double;
398 * A replacement for strtoull. Only those parts needed for
399 * our parser are implemented.
401 static unsigned long long parse_int_string(const char *s, const char **endptr, int base) {
402 unsigned long long v = 0;
407 /* check for overrun */
408 if (v >= 0x1000000000000000ULL)
410 switch (tolower(*s)) {
411 case '0': v <<= 4; break;
412 case '1': v <<= 4; v |= 0x1; break;
413 case '2': v <<= 4; v |= 0x2; break;
414 case '3': v <<= 4; v |= 0x3; break;
415 case '4': v <<= 4; v |= 0x4; break;
416 case '5': v <<= 4; v |= 0x5; break;
417 case '6': v <<= 4; v |= 0x6; break;
418 case '7': v <<= 4; v |= 0x7; break;
419 case '8': v <<= 4; v |= 0x8; break;
420 case '9': v <<= 4; v |= 0x9; break;
421 case 'a': v <<= 4; v |= 0xa; break;
422 case 'b': v <<= 4; v |= 0xb; break;
423 case 'c': v <<= 4; v |= 0xc; break;
424 case 'd': v <<= 4; v |= 0xd; break;
425 case 'e': v <<= 4; v |= 0xe; break;
426 case 'f': v <<= 4; v |= 0xf; break;
434 /* check for overrun */
435 if (v >= 0x2000000000000000ULL)
437 switch (tolower(*s)) {
438 case '0': v <<= 3; break;
439 case '1': v <<= 3; v |= 1; break;
440 case '2': v <<= 3; v |= 2; break;
441 case '3': v <<= 3; v |= 3; break;
442 case '4': v <<= 3; v |= 4; break;
443 case '5': v <<= 3; v |= 5; break;
444 case '6': v <<= 3; v |= 6; break;
445 case '7': v <<= 3; v |= 7; break;
453 /* check for overrun */
454 if (v > 0x1999999999999999ULL)
456 switch (tolower(*s)) {
457 case '0': v *= 10; break;
458 case '1': v *= 10; v += 1; break;
459 case '2': v *= 10; v += 2; break;
460 case '3': v *= 10; v += 3; break;
461 case '4': v *= 10; v += 4; break;
462 case '5': v *= 10; v += 5; break;
463 case '6': v *= 10; v += 6; break;
464 case '7': v *= 10; v += 7; break;
465 case '8': v *= 10; v += 8; break;
466 case '9': v *= 10; v += 9; break;
482 * Parses a hex number including hex floats and set the
485 static void parse_number_hex(void)
487 assert(c == 'x' || c == 'X');
491 obstack_1grow(&symbol_obstack, (char) c);
494 obstack_1grow(&symbol_obstack, '\0');
495 char *string = obstack_finish(&symbol_obstack);
497 if(c == '.' || c == 'p' || c == 'P') {
499 internal_error("Hex floating point numbers not implemented yet");
501 if(*string == '\0') {
502 parse_error("invalid hex number");
503 lexer_token.type = T_ERROR;
507 lexer_token.type = T_INTEGER;
508 lexer_token.v.intvalue = parse_int_string(string, &endptr, 16);
509 if(*endptr != '\0') {
510 parse_error("hex number literal too long");
513 obstack_free(&symbol_obstack, string);
514 parse_integer_suffix(true);
518 * Returns true if the given char is a octal digit.
520 * @param char the character to check
522 static inline bool is_octal_digit(int chr)
540 * Parses a octal number and set the lexer_token.
542 static void parse_number_oct(void)
544 while(is_octal_digit(c)) {
545 obstack_1grow(&symbol_obstack, (char) c);
548 obstack_1grow(&symbol_obstack, '\0');
549 char *string = obstack_finish(&symbol_obstack);
552 lexer_token.type = T_INTEGER;
553 lexer_token.v.intvalue = parse_int_string(string, &endptr, 8);
554 if(*endptr != '\0') {
555 parse_error("octal number literal too long");
558 obstack_free(&symbol_obstack, string);
559 parse_integer_suffix(true);
563 * Parses a decimal including float number and set the
566 static void parse_number_dec(void)
568 bool is_float = false;
570 obstack_1grow(&symbol_obstack, (char) c);
575 obstack_1grow(&symbol_obstack, '.');
579 obstack_1grow(&symbol_obstack, (char) c);
584 if(c == 'e' || c == 'E') {
585 obstack_1grow(&symbol_obstack, 'e');
588 if(c == '-' || c == '+') {
589 obstack_1grow(&symbol_obstack, (char) c);
594 obstack_1grow(&symbol_obstack, (char) c);
600 obstack_1grow(&symbol_obstack, '\0');
601 char *string = obstack_finish(&symbol_obstack);
605 lexer_token.type = T_FLOATINGPOINT;
606 lexer_token.v.floatvalue = strtold(string, &endptr);
608 if(*endptr != '\0') {
609 parse_error("invalid number literal");
612 parse_floating_suffix();
615 lexer_token.type = T_INTEGER;
616 lexer_token.v.intvalue = parse_int_string(string, &endptr, 10);
618 if(*endptr != '\0') {
619 parse_error("invalid number literal");
622 parse_integer_suffix(false);
624 obstack_free(&symbol_obstack, string);
628 * Parses a number and sets the lexer_token.
630 static void parse_number(void)
652 parse_error("invalid octal number");
653 lexer_token.type = T_ERROR;
659 obstack_1grow(&symbol_obstack, '0');
669 * Returns the value of a digit.
670 * The only portable way to do it ...
672 static int digit_value(int digit) {
697 internal_error("wrong character given");
702 * Parses an octal character sequence.
704 * @param first_digit the already read first digit
706 static int parse_octal_sequence(const int first_digit)
708 assert(is_octal_digit(first_digit));
709 int value = digit_value(first_digit);
710 if (!is_octal_digit(c)) return value;
711 value = 8 * value + digit_value(c);
713 if (!is_octal_digit(c)) return value;
714 value = 8 * value + digit_value(c);
718 return (signed char) value;
720 return (unsigned char) value;
725 * Parses a hex character sequence.
727 static int parse_hex_sequence(void)
731 value = 16 * value + digit_value(c);
736 return (signed char) value;
738 return (unsigned char) value;
743 * Parse an escape sequence.
745 static int parse_escape_sequence(void)
753 case '"': return '"';
754 case '\'': return '\'';
755 case '\\': return '\\';
756 case '?': return '\?';
757 case 'a': return '\a';
758 case 'b': return '\b';
759 case 'f': return '\f';
760 case 'n': return '\n';
761 case 'r': return '\r';
762 case 't': return '\t';
763 case 'v': return '\v';
765 return parse_hex_sequence();
774 return parse_octal_sequence(ec);
776 parse_error("reached end of file while parsing escape sequence");
779 parse_error("unknown escape sequence");
785 * Concatenate two strings.
787 string_t concat_strings(const string_t *const s1, const string_t *const s2)
789 const size_t len1 = s1->size - 1;
790 const size_t len2 = s2->size - 1;
792 char *const concat = obstack_alloc(&symbol_obstack, len1 + len2 + 1);
793 memcpy(concat, s1->begin, len1);
794 memcpy(concat + len1, s2->begin, len2 + 1);
796 #if 0 /* TODO hash */
797 const char *result = strset_insert(&stringset, concat);
798 if(result != concat) {
799 obstack_free(&symbol_obstack, concat);
804 return (string_t){ concat, len1 + len2 + 1 };
809 * Concatenate a string and a wide string.
811 wide_string_t concat_string_wide_string(const string_t *const s1, const wide_string_t *const s2)
813 const size_t len1 = s1->size - 1;
814 const size_t len2 = s2->size - 1;
816 wchar_rep_t *const concat = obstack_alloc(&symbol_obstack, (len1 + len2 + 1) * sizeof(*concat));
817 const char *const src = s1->begin;
818 for (size_t i = 0; i != len1; ++i) {
821 memcpy(concat + len1, s2->begin, (len2 + 1) * sizeof(*concat));
823 return (wide_string_t){ concat, len1 + len2 + 1 };
827 * Concatenate two wide strings.
829 wide_string_t concat_wide_strings(const wide_string_t *const s1, const wide_string_t *const s2)
831 const size_t len1 = s1->size - 1;
832 const size_t len2 = s2->size - 1;
834 wchar_rep_t *const concat = obstack_alloc(&symbol_obstack, (len1 + len2 + 1) * sizeof(*concat));
835 memcpy(concat, s1->begin, len1 * sizeof(*concat));
836 memcpy(concat + len1, s2->begin, (len2 + 1) * sizeof(*concat));
838 return (wide_string_t){ concat, len1 + len2 + 1 };
842 * Concatenate a wide string and a string.
844 wide_string_t concat_wide_string_string(const wide_string_t *const s1, const string_t *const s2)
846 const size_t len1 = s1->size - 1;
847 const size_t len2 = s2->size - 1;
849 wchar_rep_t *const concat = obstack_alloc(&symbol_obstack, (len1 + len2 + 1) * sizeof(*concat));
850 memcpy(concat, s1->begin, len1 * sizeof(*concat));
851 const char *const src = s2->begin;
852 for (size_t i = 0; i != len2 + 1; ++i) {
856 return (wide_string_t){ concat, len1 + len2 + 1 };
860 * Parse a string literal and set lexer_token.
862 static void parse_string_literal(void)
864 const unsigned start_linenr = lexer_token.source_position.linenr;
872 tc = parse_escape_sequence();
873 obstack_1grow(&symbol_obstack, (char) tc);
877 source_position_t source_position;
878 source_position.input_name = lexer_token.source_position.input_name;
879 source_position.linenr = start_linenr;
880 errorf(&source_position, "string has no end");
881 lexer_token.type = T_ERROR;
890 obstack_1grow(&symbol_obstack, (char) c);
898 /* TODO: concatenate multiple strings separated by whitespace... */
900 /* add finishing 0 to the string */
901 obstack_1grow(&symbol_obstack, '\0');
902 const size_t size = (size_t)obstack_object_size(&symbol_obstack);
903 const char *const string = obstack_finish(&symbol_obstack);
905 #if 0 /* TODO hash */
906 /* check if there is already a copy of the string */
907 result = strset_insert(&stringset, string);
908 if(result != string) {
909 obstack_free(&symbol_obstack, string);
912 const char *const result = string;
915 lexer_token.type = T_STRING_LITERAL;
916 lexer_token.v.string.begin = result;
917 lexer_token.v.string.size = size;
921 * Parse a wide character constant and set lexer_token.
923 static void parse_wide_character_constant(void)
925 const unsigned start_linenr = lexer_token.source_position.linenr;
932 wchar_rep_t tc = parse_escape_sequence();
933 obstack_grow(&symbol_obstack, &tc, sizeof(tc));
938 parse_error("newline while parsing character constant");
944 goto end_of_wide_char_constant;
947 source_position_t source_position = lexer_token.source_position;
948 source_position.linenr = start_linenr;
949 errorf(&source_position, "EOF while parsing character constant");
950 lexer_token.type = T_ERROR;
955 wchar_rep_t tc = (wchar_rep_t) c;
956 obstack_grow(&symbol_obstack, &tc, sizeof(tc));
963 end_of_wide_char_constant:;
964 size_t size = (size_t) obstack_object_size(&symbol_obstack);
965 assert(size % sizeof(wchar_rep_t) == 0);
966 size /= sizeof(wchar_rep_t);
968 const wchar_rep_t *string = obstack_finish(&symbol_obstack);
970 lexer_token.type = T_WIDE_CHARACTER_CONSTANT;
971 lexer_token.v.wide_string.begin = string;
972 lexer_token.v.wide_string.size = size;
973 lexer_token.datatype = type_wchar_t;
977 * Parse a wide string literal and set lexer_token.
979 static void parse_wide_string_literal(void)
981 const unsigned start_linenr = lexer_token.source_position.linenr;
989 wchar_rep_t tc = parse_escape_sequence();
990 obstack_grow(&symbol_obstack, &tc, sizeof(tc));
995 source_position_t source_position;
996 source_position.input_name = lexer_token.source_position.input_name;
997 source_position.linenr = start_linenr;
998 errorf(&source_position, "string has no end");
999 lexer_token.type = T_ERROR;
1009 obstack_grow(&symbol_obstack, &tc, sizeof(tc));
1018 /* TODO: concatenate multiple strings separated by whitespace... */
1020 /* add finishing 0 to the string */
1021 wchar_rep_t nul = L'\0';
1022 obstack_grow(&symbol_obstack, &nul, sizeof(nul));
1023 const size_t size = (size_t)obstack_object_size(&symbol_obstack) / sizeof(wchar_rep_t);
1024 const wchar_rep_t *const string = obstack_finish(&symbol_obstack);
1026 #if 0 /* TODO hash */
1027 /* check if there is already a copy of the string */
1028 const wchar_rep_t *const result = strset_insert(&stringset, string);
1029 if(result != string) {
1030 obstack_free(&symbol_obstack, string);
1033 const wchar_rep_t *const result = string;
1036 lexer_token.type = T_WIDE_STRING_LITERAL;
1037 lexer_token.v.wide_string.begin = result;
1038 lexer_token.v.wide_string.size = size;
1042 * Parse a character constant and set lexer_token.
1044 static void parse_character_constant(void)
1046 const unsigned start_linenr = lexer_token.source_position.linenr;
1053 int tc = parse_escape_sequence();
1054 obstack_1grow(&symbol_obstack, (char) tc);
1059 parse_error("newline while parsing character constant");
1065 goto end_of_char_constant;
1068 source_position_t source_position;
1069 source_position.input_name = lexer_token.source_position.input_name;
1070 source_position.linenr = start_linenr;
1071 errorf(&source_position, "EOF while parsing character constant");
1072 lexer_token.type = T_ERROR;
1077 obstack_1grow(&symbol_obstack, (char) c);
1084 end_of_char_constant:;
1085 const size_t size = (size_t)obstack_object_size(&symbol_obstack);
1086 const char *const string = obstack_finish(&symbol_obstack);
1088 lexer_token.type = T_CHARACTER_CONSTANT;
1089 lexer_token.v.string.begin = string;
1090 lexer_token.v.string.size = size;
1091 lexer_token.datatype = type_int;
1095 * Skip a multiline comment.
1097 static void skip_multiline_comment(void)
1099 unsigned start_linenr = lexer_token.source_position.linenr;
1106 /* TODO: nested comment, warn here */
1117 MATCH_NEWLINE(break;)
1120 source_position_t source_position;
1121 source_position.input_name = lexer_token.source_position.input_name;
1122 source_position.linenr = start_linenr;
1123 errorf(&source_position, "at end of file while looking for comment end");
1135 * Skip a single line comment.
1137 static void skip_line_comment(void)
1155 /** The current preprocessor token. */
1156 static token_t pp_token;
1159 * Read the next preprocessor token.
1161 static inline void next_pp_token(void)
1163 lexer_next_preprocessing_token();
1164 pp_token = lexer_token;
1168 * Eat all preprocessor tokens until newline.
1170 static void eat_until_newline(void)
1172 while(pp_token.type != '\n' && pp_token.type != T_EOF) {
1178 * Handle the define directive.
1180 static void define_directive(void)
1182 lexer_next_preprocessing_token();
1183 if(lexer_token.type != T_IDENTIFIER) {
1184 parse_error("expected identifier after #define\n");
1185 eat_until_newline();
1190 * Handle the ifdef directive.
1192 static void ifdef_directive(int is_ifndef)
1195 lexer_next_preprocessing_token();
1196 //expect_identifier();
1201 * Handle the endif directive.
1203 static void endif_directive(void)
1209 * Parse the line directive.
1211 static void parse_line_directive(void)
1213 if(pp_token.type != T_INTEGER) {
1214 parse_error("expected integer");
1216 lexer_token.source_position.linenr = (unsigned int)(pp_token.v.intvalue - 1);
1219 if(pp_token.type == T_STRING_LITERAL) {
1220 lexer_token.source_position.input_name = pp_token.v.string.begin;
1224 eat_until_newline();
1230 typedef enum stdc_pragma_kind_t {
1234 STDC_CX_LIMITED_RANGE
1235 } stdc_pragma_kind_t;
1238 * STDC pragma values.
1240 typedef enum stdc_pragma_value_kind_t {
1245 } stdc_pragma_value_kind_t;
1248 * Parse a pragma directive.
1250 static void parse_pragma(void) {
1251 bool unknown_pragma = true;
1254 if (pp_token.v.symbol->pp_ID == TP_STDC) {
1255 stdc_pragma_kind_t kind = STDC_UNKNOWN;
1257 if (c_mode & _C99) {
1260 switch (pp_token.v.symbol->pp_ID) {
1261 case TP_FP_CONTRACT:
1262 kind = STDC_FP_CONTRACT;
1264 case TP_FENV_ACCESS:
1265 kind = STDC_FENV_ACCESS;
1267 case TP_CX_LIMITED_RANGE:
1268 kind = STDC_CX_LIMITED_RANGE;
1273 if (kind != STDC_UNKNOWN) {
1274 stdc_pragma_value_kind_t value = STDC_VALUE_UNKNOWN;
1276 switch (pp_token.v.symbol->pp_ID) {
1278 value = STDC_VALUE_ON;
1281 value = STDC_VALUE_OFF;
1284 value = STDC_VALUE_DEFAULT;
1289 if (value != STDC_VALUE_UNKNOWN) {
1290 unknown_pragma = false;
1292 errorf(&pp_token.source_position, "bad STDC pragma argument");
1297 unknown_pragma = true;
1299 eat_until_newline();
1300 if (unknown_pragma && warning.unknown_pragmas) {
1301 warningf(&pp_token.source_position, "encountered unknown #pragma");
1306 * Parse a preprocessor non-null directive.
1308 static void parse_preprocessor_identifier(void)
1310 assert(pp_token.type == T_IDENTIFIER);
1311 symbol_t *symbol = pp_token.v.symbol;
1313 switch(symbol->pp_ID) {
1315 printf("include - enable header name parsing!\n");
1331 parse_line_directive();
1338 /* TODO; output the rest of the line */
1339 parse_error("#error directive: ");
1348 * Parse a preprocessor directive.
1350 static void parse_preprocessor_directive(void)
1354 switch(pp_token.type) {
1356 parse_preprocessor_identifier();
1359 parse_line_directive();
1362 /* NULL directive, see § 6.10.7 */
1365 parse_error("invalid preprocessor directive");
1366 eat_until_newline();
1371 #define MAYBE_PROLOG \
1376 #define MAYBE(ch, set_type) \
1379 lexer_token.type = set_type; \
1382 #define ELSE_CODE(code) \
1386 } /* end of while(1) */ \
1389 #define ELSE(set_type) \
1391 lexer_token.type = set_type; \
1395 void lexer_next_preprocessing_token(void)
1405 lexer_token.type = '\n';
1411 /* might be a wide string ( L"string" ) */
1412 if(lexer_token.type == T_IDENTIFIER &&
1413 lexer_token.v.symbol == symbol_L) {
1415 parse_wide_string_literal();
1416 } else if(c == '\'') {
1417 parse_wide_character_constant();
1427 parse_string_literal();
1431 parse_character_constant();
1453 MAYBE('.', T_DOTDOTDOT)
1457 lexer_token.type = '.';
1463 MAYBE('&', T_ANDAND)
1464 MAYBE('=', T_ANDEQUAL)
1468 MAYBE('=', T_ASTERISKEQUAL)
1472 MAYBE('+', T_PLUSPLUS)
1473 MAYBE('=', T_PLUSEQUAL)
1477 MAYBE('>', T_MINUSGREATER)
1478 MAYBE('-', T_MINUSMINUS)
1479 MAYBE('=', T_MINUSEQUAL)
1483 MAYBE('=', T_EXCLAMATIONMARKEQUAL)
1487 MAYBE('=', T_SLASHEQUAL)
1490 skip_multiline_comment();
1491 lexer_next_preprocessing_token();
1495 skip_line_comment();
1496 lexer_next_preprocessing_token();
1502 MAYBE('=', T_PERCENTEQUAL)
1507 MAYBE(':', T_HASHHASH)
1511 lexer_token.type = '#';
1520 MAYBE('=', T_LESSEQUAL)
1523 MAYBE('=', T_LESSLESSEQUAL)
1528 MAYBE('=', T_GREATEREQUAL)
1531 MAYBE('=', T_GREATERGREATEREQUAL)
1532 ELSE(T_GREATERGREATER)
1536 MAYBE('=', T_CARETEQUAL)
1540 MAYBE('=', T_PIPEEQUAL)
1541 MAYBE('|', T_PIPEPIPE)
1549 MAYBE('=', T_EQUALEQUAL)
1553 MAYBE('#', T_HASHHASH)
1567 lexer_token.type = c;
1572 lexer_token.type = T_EOF;
1577 errorf(&lexer_token.source_position, "unknown character '%c' found\n", c);
1578 lexer_token.type = T_ERROR;
1584 void lexer_next_token(void)
1586 lexer_next_preprocessing_token();
1588 while (lexer_token.type == '\n') {
1590 lexer_next_preprocessing_token();
1593 if (lexer_token.type == '#') {
1594 parse_preprocessor_directive();
1599 void init_lexer(void)
1601 strset_init(&stringset);
1602 symbol_L = symbol_table_insert("L");
1605 void lexer_open_stream(FILE *stream, const char *input_name)
1608 lexer_token.source_position.linenr = 0;
1609 lexer_token.source_position.input_name = input_name;
1614 /* place a virtual \n at the beginning so the lexer knows that we're
1615 * at the beginning of a line */
1619 void lexer_open_buffer(const char *buffer, size_t len, const char *input_name)
1622 lexer_token.source_position.linenr = 0;
1623 lexer_token.source_position.input_name = input_name;
1626 bufend = buffer + len;
1628 /* place a virtual \n at the beginning so the lexer knows that we're
1629 * at the beginning of a line */
1633 void exit_lexer(void)
1635 strset_destroy(&stringset);
1638 static __attribute__((unused))
1639 void dbg_pos(const source_position_t source_position)
1641 fprintf(stdout, "%s:%u\n", source_position.input_name,
1642 source_position.linenr);