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) {
84 size_t s = fread(buf + MAX_PUTBACK, 1, sizeof(buf) - MAX_PUTBACK,
90 bufpos = buf + MAX_PUTBACK;
91 bufend = buf + MAX_PUTBACK + s;
97 * Put a character back into the buffer.
99 * @param pc the character to put back
101 static inline void put_back(int pc)
103 assert(bufpos > buf);
104 *(--bufpos - buf + buf) = (char) pc;
107 printf("putback '%c'\n", pc);
111 static inline void next_char(void);
113 #define MATCH_NEWLINE(code) \
119 lexer_token.source_position.linenr++; \
123 lexer_token.source_position.linenr++; \
126 #define eat(c_type) do { assert(c == c_type); next_char(); } while(0)
128 static void maybe_concat_lines(void)
133 MATCH_NEWLINE(return;)
144 * Set c to the next input character, ie.
145 * after expanding trigraphs.
147 static inline void next_char(void)
151 /* filter trigraphs */
152 if(UNLIKELY(c == '\\')) {
153 maybe_concat_lines();
154 goto end_of_next_char;
158 goto end_of_next_char;
161 if(LIKELY(c != '?')) {
164 goto end_of_next_char;
169 case '=': c = '#'; break;
170 case '(': c = '['; break;
171 case '/': c = '\\'; maybe_concat_lines(); break;
172 case ')': c = ']'; break;
173 case '\'': c = '^'; break;
174 case '<': c = '{'; break;
175 case '!': c = '|'; break;
176 case '>': c = '}'; break;
177 case '-': c = '~'; break;
187 printf("nchar '%c'\n", c);
191 #define SYMBOL_CHARS \
259 * Read a symbol from the input and build
262 static void parse_symbol(void)
267 obstack_1grow(&symbol_obstack, (char) c);
274 obstack_1grow(&symbol_obstack, (char) c);
284 obstack_1grow(&symbol_obstack, '\0');
286 string = obstack_finish(&symbol_obstack);
287 symbol = symbol_table_insert(string);
289 lexer_token.type = symbol->ID;
290 lexer_token.v.symbol = symbol;
292 if(symbol->string != string) {
293 obstack_free(&symbol_obstack, string);
297 static void parse_integer_suffix(bool is_oct_hex)
299 bool is_unsigned = false;
300 bool min_long = false;
301 bool min_longlong = false;
303 if(c == 'U' || c == 'u') {
306 if(c == 'L' || c == 'l') {
309 if(c == 'L' || c == 'l') {
314 } else if(c == 'l' || c == 'L') {
317 if(c == 'l' || c == 'L') {
320 if(c == 'u' || c == 'U') {
324 } else if(c == 'u' || c == 'U') {
327 lexer_token.datatype = type_unsigned_long;
332 long long v = lexer_token.v.intvalue;
334 if(v >= TARGET_INT_MIN && v <= TARGET_INT_MAX) {
335 lexer_token.datatype = type_int;
337 } else if(is_oct_hex && v >= 0 && v <= TARGET_UINT_MAX) {
338 lexer_token.datatype = type_unsigned_int;
343 if(v >= TARGET_LONG_MIN && v <= TARGET_LONG_MAX) {
344 lexer_token.datatype = type_long;
346 } else if(is_oct_hex && v >= 0 && v <= TARGET_ULONG_MAX) {
347 lexer_token.datatype = type_unsigned_long;
351 unsigned long long uv = (unsigned long long) v;
352 if(is_oct_hex && uv > (unsigned long long) TARGET_LONGLONG_MAX) {
353 lexer_token.datatype = type_unsigned_long_long;
357 lexer_token.datatype = type_long_long;
359 unsigned long long v = (unsigned long long) lexer_token.v.intvalue;
360 if(!min_long && v <= TARGET_UINT_MAX) {
361 lexer_token.datatype = type_unsigned_int;
364 if(!min_longlong && v <= TARGET_ULONG_MAX) {
365 lexer_token.datatype = type_unsigned_long;
368 lexer_token.datatype = type_unsigned_long_long;
372 static void parse_floating_suffix(void)
375 /* TODO: do something useful with the suffixes... */
379 lexer_token.datatype = type_float;
384 lexer_token.datatype = type_long_double;
387 lexer_token.datatype = type_double;
393 * A replacement for strtoull. Only those parts needed for
394 * our parser are implemented.
396 static unsigned long long parse_int_string(const char *s, const char **endptr, int base) {
397 unsigned long long v = 0;
402 /* check for overrun */
403 if (v >= 0x1000000000000000ULL)
405 switch (tolower(*s)) {
406 case '0': v <<= 4; break;
407 case '1': v <<= 4; v |= 0x1; break;
408 case '2': v <<= 4; v |= 0x2; break;
409 case '3': v <<= 4; v |= 0x3; break;
410 case '4': v <<= 4; v |= 0x4; break;
411 case '5': v <<= 4; v |= 0x5; break;
412 case '6': v <<= 4; v |= 0x6; break;
413 case '7': v <<= 4; v |= 0x7; break;
414 case '8': v <<= 4; v |= 0x8; break;
415 case '9': v <<= 4; v |= 0x9; break;
416 case 'a': v <<= 4; v |= 0xa; break;
417 case 'b': v <<= 4; v |= 0xb; break;
418 case 'c': v <<= 4; v |= 0xc; break;
419 case 'd': v <<= 4; v |= 0xd; break;
420 case 'e': v <<= 4; v |= 0xe; break;
421 case 'f': v <<= 4; v |= 0xf; break;
429 /* check for overrun */
430 if (v >= 0x2000000000000000ULL)
432 switch (tolower(*s)) {
433 case '0': v <<= 3; break;
434 case '1': v <<= 3; v |= 1; break;
435 case '2': v <<= 3; v |= 2; break;
436 case '3': v <<= 3; v |= 3; break;
437 case '4': v <<= 3; v |= 4; break;
438 case '5': v <<= 3; v |= 5; break;
439 case '6': v <<= 3; v |= 6; break;
440 case '7': v <<= 3; v |= 7; break;
448 /* check for overrun */
449 if (v > 0x1999999999999999ULL)
451 switch (tolower(*s)) {
452 case '0': v *= 10; break;
453 case '1': v *= 10; v += 1; break;
454 case '2': v *= 10; v += 2; break;
455 case '3': v *= 10; v += 3; break;
456 case '4': v *= 10; v += 4; break;
457 case '5': v *= 10; v += 5; break;
458 case '6': v *= 10; v += 6; break;
459 case '7': v *= 10; v += 7; break;
460 case '8': v *= 10; v += 8; break;
461 case '9': v *= 10; v += 9; break;
477 * Parses a hex number including hex floats and set the
480 static void parse_number_hex(void)
482 assert(c == 'x' || c == 'X');
486 obstack_1grow(&symbol_obstack, (char) c);
489 obstack_1grow(&symbol_obstack, '\0');
490 char *string = obstack_finish(&symbol_obstack);
492 if(c == '.' || c == 'p' || c == 'P') {
494 internal_error("Hex floating point numbers not implemented yet");
496 if(*string == '\0') {
497 parse_error("invalid hex number");
498 lexer_token.type = T_ERROR;
502 lexer_token.type = T_INTEGER;
503 lexer_token.v.intvalue = parse_int_string(string, &endptr, 16);
504 if(*endptr != '\0') {
505 parse_error("hex number literal too long");
508 obstack_free(&symbol_obstack, string);
509 parse_integer_suffix(true);
513 * Returns true if the given char is a octal digit.
515 * @param char the character to check
517 static inline bool is_octal_digit(int chr)
535 * Parses a octal number and set the lexer_token.
537 static void parse_number_oct(void)
539 while(is_octal_digit(c)) {
540 obstack_1grow(&symbol_obstack, (char) c);
543 obstack_1grow(&symbol_obstack, '\0');
544 char *string = obstack_finish(&symbol_obstack);
547 lexer_token.type = T_INTEGER;
548 lexer_token.v.intvalue = parse_int_string(string, &endptr, 8);
549 if(*endptr != '\0') {
550 parse_error("octal number literal too long");
553 obstack_free(&symbol_obstack, string);
554 parse_integer_suffix(true);
558 * Parses a decimal including float number and set the
561 static void parse_number_dec(void)
563 bool is_float = false;
565 obstack_1grow(&symbol_obstack, (char) c);
570 obstack_1grow(&symbol_obstack, '.');
574 obstack_1grow(&symbol_obstack, (char) c);
579 if(c == 'e' || c == 'E') {
580 obstack_1grow(&symbol_obstack, 'e');
583 if(c == '-' || c == '+') {
584 obstack_1grow(&symbol_obstack, (char) c);
589 obstack_1grow(&symbol_obstack, (char) c);
595 obstack_1grow(&symbol_obstack, '\0');
596 char *string = obstack_finish(&symbol_obstack);
600 lexer_token.type = T_FLOATINGPOINT;
601 lexer_token.v.floatvalue = strtold(string, &endptr);
603 if(*endptr != '\0') {
604 parse_error("invalid number literal");
607 parse_floating_suffix();
610 lexer_token.type = T_INTEGER;
611 lexer_token.v.intvalue = parse_int_string(string, &endptr, 10);
613 if(*endptr != '\0') {
614 parse_error("invalid number literal");
617 parse_integer_suffix(false);
619 obstack_free(&symbol_obstack, string);
623 * Parses a number and sets the lexer_token.
625 static void parse_number(void)
647 parse_error("invalid octal number");
648 lexer_token.type = T_ERROR;
654 obstack_1grow(&symbol_obstack, '0');
664 * Returns the value of a digit.
665 * The only portable way to do it ...
667 static int digit_value(int digit) {
692 internal_error("wrong character given");
697 * Parses an octal character sequence.
699 * @param first_digit the already read first digit
701 static int parse_octal_sequence(const int first_digit)
703 assert(is_octal_digit(first_digit));
704 int value = digit_value(first_digit);
705 if (!is_octal_digit(c)) return value;
706 value = 8 * value + digit_value(c);
708 if (!is_octal_digit(c)) return value;
709 value = 8 * value + digit_value(c);
713 return (signed char) value;
715 return (unsigned char) value;
720 * Parses a hex character sequence.
722 static int parse_hex_sequence(void)
726 value = 16 * value + digit_value(c);
731 return (signed char) value;
733 return (unsigned char) value;
738 * Parse an escape sequence.
740 static int parse_escape_sequence(void)
748 case '"': return '"';
749 case '\'': return '\'';
750 case '\\': return '\\';
751 case '?': return '\?';
752 case 'a': return '\a';
753 case 'b': return '\b';
754 case 'f': return '\f';
755 case 'n': return '\n';
756 case 'r': return '\r';
757 case 't': return '\t';
758 case 'v': return '\v';
760 return parse_hex_sequence();
769 return parse_octal_sequence(ec);
771 parse_error("reached end of file while parsing escape sequence");
774 parse_error("unknown escape sequence");
780 * Concatenate two strings.
782 string_t concat_strings(const string_t *const s1, const string_t *const s2)
784 const size_t len1 = s1->size - 1;
785 const size_t len2 = s2->size - 1;
787 char *const concat = obstack_alloc(&symbol_obstack, len1 + len2 + 1);
788 memcpy(concat, s1->begin, len1);
789 memcpy(concat + len1, s2->begin, len2 + 1);
791 #if 0 /* TODO hash */
792 const char *result = strset_insert(&stringset, concat);
793 if(result != concat) {
794 obstack_free(&symbol_obstack, concat);
799 return (string_t){ concat, len1 + len2 + 1 };
804 * Concatenate a string and a wide string.
806 wide_string_t concat_string_wide_string(const string_t *const s1, const wide_string_t *const s2)
808 const size_t len1 = s1->size - 1;
809 const size_t len2 = s2->size - 1;
811 wchar_rep_t *const concat = obstack_alloc(&symbol_obstack, (len1 + len2 + 1) * sizeof(*concat));
812 const char *const src = s1->begin;
813 for (size_t i = 0; i != len1; ++i) {
816 memcpy(concat + len1, s2->begin, (len2 + 1) * sizeof(*concat));
818 return (wide_string_t){ concat, len1 + len2 + 1 };
822 * Concatenate two wide strings.
824 wide_string_t concat_wide_strings(const wide_string_t *const s1, const wide_string_t *const s2)
826 const size_t len1 = s1->size - 1;
827 const size_t len2 = s2->size - 1;
829 wchar_rep_t *const concat = obstack_alloc(&symbol_obstack, (len1 + len2 + 1) * sizeof(*concat));
830 memcpy(concat, s1->begin, len1 * sizeof(*concat));
831 memcpy(concat + len1, s2->begin, (len2 + 1) * sizeof(*concat));
833 return (wide_string_t){ concat, len1 + len2 + 1 };
837 * Concatenate a wide string and a string.
839 wide_string_t concat_wide_string_string(const wide_string_t *const s1, const string_t *const s2)
841 const size_t len1 = s1->size - 1;
842 const size_t len2 = s2->size - 1;
844 wchar_rep_t *const concat = obstack_alloc(&symbol_obstack, (len1 + len2 + 1) * sizeof(*concat));
845 memcpy(concat, s1->begin, len1 * sizeof(*concat));
846 const char *const src = s2->begin;
847 for (size_t i = 0; i != len2 + 1; ++i) {
851 return (wide_string_t){ concat, len1 + len2 + 1 };
855 * Parse a string literal and set lexer_token.
857 static void parse_string_literal(void)
859 const unsigned start_linenr = lexer_token.source_position.linenr;
867 tc = parse_escape_sequence();
868 obstack_1grow(&symbol_obstack, (char) tc);
872 source_position_t source_position;
873 source_position.input_name = lexer_token.source_position.input_name;
874 source_position.linenr = start_linenr;
875 errorf(source_position, "string has no end");
876 lexer_token.type = T_ERROR;
885 obstack_1grow(&symbol_obstack, (char) c);
893 /* TODO: concatenate multiple strings separated by whitespace... */
895 /* add finishing 0 to the string */
896 obstack_1grow(&symbol_obstack, '\0');
897 const size_t size = (size_t)obstack_object_size(&symbol_obstack);
898 const char *const string = obstack_finish(&symbol_obstack);
900 #if 0 /* TODO hash */
901 /* check if there is already a copy of the string */
902 result = strset_insert(&stringset, string);
903 if(result != string) {
904 obstack_free(&symbol_obstack, string);
907 const char *const result = string;
910 lexer_token.type = T_STRING_LITERAL;
911 lexer_token.v.string.begin = result;
912 lexer_token.v.string.size = size;
916 * Parse a wide character constant and set lexer_token.
918 static void parse_wide_character_constant(void)
920 const unsigned start_linenr = lexer_token.source_position.linenr;
927 wchar_rep_t tc = parse_escape_sequence();
928 obstack_grow(&symbol_obstack, &tc, sizeof(tc));
933 parse_error("newline while parsing character constant");
939 goto end_of_wide_char_constant;
942 source_position_t source_position = lexer_token.source_position;
943 source_position.linenr = start_linenr;
944 errorf(source_position, "EOF while parsing character constant");
945 lexer_token.type = T_ERROR;
950 wchar_rep_t tc = (wchar_rep_t) c;
951 obstack_grow(&symbol_obstack, &tc, sizeof(tc));
958 end_of_wide_char_constant:;
959 size_t size = (size_t) obstack_object_size(&symbol_obstack);
960 const wchar_rep_t *string = obstack_finish(&symbol_obstack);
962 lexer_token.type = T_WIDE_CHARACTER_CONSTANT;
963 lexer_token.v.wide_string.begin = string;
964 lexer_token.v.wide_string.size = size;
965 lexer_token.datatype = type_wchar_t;
969 * Parse a wide string literal and set lexer_token.
971 static void parse_wide_string_literal(void)
973 const unsigned start_linenr = lexer_token.source_position.linenr;
981 wchar_rep_t tc = parse_escape_sequence();
982 obstack_grow(&symbol_obstack, &tc, sizeof(tc));
987 source_position_t source_position;
988 source_position.input_name = lexer_token.source_position.input_name;
989 source_position.linenr = start_linenr;
990 errorf(source_position, "string has no end");
991 lexer_token.type = T_ERROR;
1001 obstack_grow(&symbol_obstack, &tc, sizeof(tc));
1010 /* TODO: concatenate multiple strings separated by whitespace... */
1012 /* add finishing 0 to the string */
1013 wchar_rep_t nul = L'\0';
1014 obstack_grow(&symbol_obstack, &nul, sizeof(nul));
1015 const size_t size = (size_t)obstack_object_size(&symbol_obstack) / sizeof(wchar_rep_t);
1016 const wchar_rep_t *const string = obstack_finish(&symbol_obstack);
1018 #if 0 /* TODO hash */
1019 /* check if there is already a copy of the string */
1020 const wchar_rep_t *const result = strset_insert(&stringset, string);
1021 if(result != string) {
1022 obstack_free(&symbol_obstack, string);
1025 const wchar_rep_t *const result = string;
1028 lexer_token.type = T_WIDE_STRING_LITERAL;
1029 lexer_token.v.wide_string.begin = result;
1030 lexer_token.v.wide_string.size = size;
1034 * Parse a character constant and set lexer_token.
1036 static void parse_character_constant(void)
1038 const unsigned start_linenr = lexer_token.source_position.linenr;
1045 int tc = parse_escape_sequence();
1046 obstack_1grow(&symbol_obstack, (char) tc);
1051 parse_error("newline while parsing character constant");
1057 goto end_of_char_constant;
1060 source_position_t source_position;
1061 source_position.input_name = lexer_token.source_position.input_name;
1062 source_position.linenr = start_linenr;
1063 errorf(source_position, "EOF while parsing character constant");
1064 lexer_token.type = T_ERROR;
1069 obstack_1grow(&symbol_obstack, (char) c);
1076 end_of_char_constant:;
1077 const size_t size = (size_t)obstack_object_size(&symbol_obstack);
1078 const char *const string = obstack_finish(&symbol_obstack);
1080 lexer_token.type = T_CHARACTER_CONSTANT;
1081 lexer_token.v.string.begin = string;
1082 lexer_token.v.string.size = size;
1083 lexer_token.datatype = type_int;
1087 * Skip a multiline comment.
1089 static void skip_multiline_comment(void)
1091 unsigned start_linenr = lexer_token.source_position.linenr;
1098 /* TODO: nested comment, warn here */
1109 MATCH_NEWLINE(break;)
1112 source_position_t source_position;
1113 source_position.input_name = lexer_token.source_position.input_name;
1114 source_position.linenr = start_linenr;
1115 errorf(source_position, "at end of file while looking for comment end");
1127 * Skip a single line comment.
1129 static void skip_line_comment(void)
1147 /** The current preprocessor token. */
1148 static token_t pp_token;
1151 * Read the next preprocessor token.
1153 static inline void next_pp_token(void)
1155 lexer_next_preprocessing_token();
1156 pp_token = lexer_token;
1160 * Eat all preprocessor tokens until newline.
1162 static void eat_until_newline(void)
1164 while(pp_token.type != '\n' && pp_token.type != T_EOF) {
1170 * Handle the define directive.
1172 static void define_directive(void)
1174 lexer_next_preprocessing_token();
1175 if(lexer_token.type != T_IDENTIFIER) {
1176 parse_error("expected identifier after #define\n");
1177 eat_until_newline();
1182 * Handle the ifdef directive.
1184 static void ifdef_directive(int is_ifndef)
1187 lexer_next_preprocessing_token();
1188 //expect_identifier();
1193 * Handle the endif directive.
1195 static void endif_directive(void)
1201 * Parse the line directive.
1203 static void parse_line_directive(void)
1205 if(pp_token.type != T_INTEGER) {
1206 parse_error("expected integer");
1208 lexer_token.source_position.linenr = (unsigned int)(pp_token.v.intvalue - 1);
1211 if(pp_token.type == T_STRING_LITERAL) {
1212 lexer_token.source_position.input_name = pp_token.v.string.begin;
1216 eat_until_newline();
1226 STDC_CX_LIMITED_RANGE
1227 } stdc_pragma_kind_t;
1230 * STDC pragma values.
1237 } stdc_pragma_value_kind_t;
1240 * Parse a pragma directive.
1242 static void parse_pragma(void) {
1243 bool unknown_pragma = true;
1246 if (pp_token.v.symbol->pp_ID == TP_STDC) {
1247 stdc_pragma_kind_t kind = STDC_UNKNOWN;
1249 if (c_mode & _C99) {
1252 switch (pp_token.v.symbol->pp_ID) {
1253 case TP_FP_CONTRACT:
1254 kind = STDC_FP_CONTRACT;
1256 case TP_FENV_ACCESS:
1257 kind = STDC_FENV_ACCESS;
1259 case TP_CX_LIMITED_RANGE:
1260 kind = STDC_CX_LIMITED_RANGE;
1265 if (kind != STDC_UNKNOWN) {
1266 stdc_pragma_value_kind_t value = STDC_VALUE_UNKNOWN;
1268 switch (pp_token.v.symbol->pp_ID) {
1270 value = STDC_VALUE_ON;
1273 value = STDC_VALUE_OFF;
1276 value = STDC_VALUE_DEFAULT;
1281 if (value != STDC_VALUE_UNKNOWN) {
1282 unknown_pragma = false;
1284 errorf(pp_token.source_position, "bad STDC pragma argument");
1289 unknown_pragma = true;
1291 eat_until_newline();
1292 if (unknown_pragma && warning.unknown_pragmas) {
1293 warningf(pp_token.source_position, "encountered unknown #pragma");
1298 * Parse a preprocessor non-null directive.
1300 static void parse_preprocessor_identifier(void)
1302 assert(pp_token.type == T_IDENTIFIER);
1303 symbol_t *symbol = pp_token.v.symbol;
1305 switch(symbol->pp_ID) {
1307 printf("include - enable header name parsing!\n");
1323 parse_line_directive();
1330 /* TODO; output the rest of the line */
1331 parse_error("#error directive: ");
1340 * Parse a preprocessor directive.
1342 static void parse_preprocessor_directive(void)
1346 switch(pp_token.type) {
1348 parse_preprocessor_identifier();
1351 parse_line_directive();
1354 /* NULL directive, see § 6.10.7 */
1357 parse_error("invalid preprocessor directive");
1358 eat_until_newline();
1363 #define MAYBE_PROLOG \
1368 #define MAYBE(ch, set_type) \
1371 lexer_token.type = set_type; \
1374 #define ELSE_CODE(code) \
1378 } /* end of while(1) */ \
1381 #define ELSE(set_type) \
1383 lexer_token.type = set_type; \
1387 void lexer_next_preprocessing_token(void)
1397 lexer_token.type = '\n';
1403 /* might be a wide string ( L"string" ) */
1404 if(lexer_token.type == T_IDENTIFIER &&
1405 lexer_token.v.symbol == symbol_L) {
1407 parse_wide_string_literal();
1408 } else if(c == '\'') {
1409 parse_wide_character_constant();
1419 parse_string_literal();
1423 parse_character_constant();
1445 MAYBE('.', T_DOTDOTDOT)
1449 lexer_token.type = '.';
1455 MAYBE('&', T_ANDAND)
1456 MAYBE('=', T_ANDEQUAL)
1460 MAYBE('=', T_ASTERISKEQUAL)
1464 MAYBE('+', T_PLUSPLUS)
1465 MAYBE('=', T_PLUSEQUAL)
1469 MAYBE('>', T_MINUSGREATER)
1470 MAYBE('-', T_MINUSMINUS)
1471 MAYBE('=', T_MINUSEQUAL)
1475 MAYBE('=', T_EXCLAMATIONMARKEQUAL)
1479 MAYBE('=', T_SLASHEQUAL)
1482 skip_multiline_comment();
1483 lexer_next_preprocessing_token();
1487 skip_line_comment();
1488 lexer_next_preprocessing_token();
1494 MAYBE('=', T_PERCENTEQUAL)
1499 MAYBE(':', T_HASHHASH)
1503 lexer_token.type = '#';
1512 MAYBE('=', T_LESSEQUAL)
1515 MAYBE('=', T_LESSLESSEQUAL)
1520 MAYBE('=', T_GREATEREQUAL)
1523 MAYBE('=', T_GREATERGREATEREQUAL)
1524 ELSE(T_GREATERGREATER)
1528 MAYBE('=', T_CARETEQUAL)
1532 MAYBE('=', T_PIPEEQUAL)
1533 MAYBE('|', T_PIPEPIPE)
1541 MAYBE('=', T_EQUALEQUAL)
1545 MAYBE('#', T_HASHHASH)
1559 lexer_token.type = c;
1564 lexer_token.type = T_EOF;
1569 errorf(lexer_token.source_position, "unknown character '%c' found\n", c);
1570 lexer_token.type = T_ERROR;
1576 void lexer_next_token(void)
1578 lexer_next_preprocessing_token();
1579 if(lexer_token.type != '\n')
1584 lexer_next_preprocessing_token();
1585 } while(lexer_token.type == '\n');
1587 if(lexer_token.type == '#') {
1588 parse_preprocessor_directive();
1593 void init_lexer(void)
1595 strset_init(&stringset);
1598 void lexer_open_stream(FILE *stream, const char *input_name)
1601 lexer_token.source_position.linenr = 0;
1602 lexer_token.source_position.input_name = input_name;
1604 symbol_L = symbol_table_insert("L");
1608 /* place a virtual \n at the beginning so the lexer knows that we're
1609 * at the beginning of a line */
1613 void exit_lexer(void)
1615 strset_destroy(&stringset);
1618 static __attribute__((unused))
1619 void dbg_pos(const source_position_t source_position)
1621 fprintf(stdout, "%s:%u\n", source_position.input_name,
1622 source_position.linenr);