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);
70 static inline void next_real_char(void)
72 assert(bufpos <= bufend);
73 if (bufpos >= bufend) {
74 size_t s = fread(buf + MAX_PUTBACK, 1, sizeof(buf) - MAX_PUTBACK,
80 bufpos = buf + MAX_PUTBACK;
81 bufend = buf + MAX_PUTBACK + s;
87 * Put a character back into the buffer.
89 * @param pc the character to put back
91 static inline void put_back(int pc)
94 *(--bufpos - buf + buf) = (char) pc;
97 printf("putback '%c'\n", pc);
101 static inline void next_char(void);
103 #define MATCH_NEWLINE(code) \
109 lexer_token.source_position.linenr++; \
113 lexer_token.source_position.linenr++; \
116 #define eat(c_type) do { assert(c == c_type); next_char(); } while(0)
118 static void maybe_concat_lines(void)
123 MATCH_NEWLINE(return;)
134 * Set c to the next input character, ie.
135 * after expanding trigraphs.
137 static inline void next_char(void)
141 /* filter trigraphs */
142 if(UNLIKELY(c == '\\')) {
143 maybe_concat_lines();
144 goto end_of_next_char;
148 goto end_of_next_char;
151 if(LIKELY(c != '?')) {
154 goto end_of_next_char;
159 case '=': c = '#'; break;
160 case '(': c = '['; break;
161 case '/': c = '\\'; maybe_concat_lines(); break;
162 case ')': c = ']'; break;
163 case '\'': c = '^'; break;
164 case '<': c = '{'; break;
165 case '!': c = '|'; break;
166 case '>': c = '}'; break;
167 case '-': c = '~'; break;
177 printf("nchar '%c'\n", c);
181 #define SYMBOL_CHARS \
249 * Read a symbol from the input and build
252 static void parse_symbol(void)
257 obstack_1grow(&symbol_obstack, (char) c);
264 obstack_1grow(&symbol_obstack, (char) c);
274 obstack_1grow(&symbol_obstack, '\0');
276 string = obstack_finish(&symbol_obstack);
277 symbol = symbol_table_insert(string);
279 lexer_token.type = symbol->ID;
280 lexer_token.v.symbol = symbol;
282 if(symbol->string != string) {
283 obstack_free(&symbol_obstack, string);
287 static void parse_integer_suffix(bool is_oct_hex)
289 bool is_unsigned = false;
290 bool min_long = false;
291 bool min_longlong = false;
293 if(c == 'U' || c == 'u') {
296 if(c == 'L' || c == 'l') {
299 if(c == 'L' || c == 'l') {
304 } else if(c == 'l' || c == 'L') {
307 if(c == 'l' || c == 'L') {
310 if(c == 'u' || c == 'U') {
314 } else if(c == 'u' || c == 'U') {
317 lexer_token.datatype = type_unsigned_long;
322 long long v = lexer_token.v.intvalue;
324 if(v >= TARGET_INT_MIN && v <= TARGET_INT_MAX) {
325 lexer_token.datatype = type_int;
327 } else if(is_oct_hex && v >= 0 && v <= TARGET_UINT_MAX) {
328 lexer_token.datatype = type_unsigned_int;
333 if(v >= TARGET_LONG_MIN && v <= TARGET_LONG_MAX) {
334 lexer_token.datatype = type_long;
336 } else if(is_oct_hex && v >= 0 && v <= TARGET_ULONG_MAX) {
337 lexer_token.datatype = type_unsigned_long;
341 unsigned long long uv = (unsigned long long) v;
342 if(is_oct_hex && uv > (unsigned long long) TARGET_LONGLONG_MAX) {
343 lexer_token.datatype = type_unsigned_long_long;
347 lexer_token.datatype = type_long_long;
349 unsigned long long v = (unsigned long long) lexer_token.v.intvalue;
350 if(!min_long && v <= TARGET_UINT_MAX) {
351 lexer_token.datatype = type_unsigned_int;
354 if(!min_longlong && v <= TARGET_ULONG_MAX) {
355 lexer_token.datatype = type_unsigned_long;
358 lexer_token.datatype = type_unsigned_long_long;
362 static void parse_floating_suffix(void)
365 /* TODO: do something useful with the suffixes... */
369 lexer_token.datatype = type_float;
374 lexer_token.datatype = type_long_double;
377 lexer_token.datatype = type_double;
383 * A replacement for strtoull. Only those parts needed for
384 * our parser are implemented.
386 static unsigned long long parse_int_string(const char *s, const char **endptr, int base) {
387 unsigned long long v = 0;
392 /* check for overrun */
393 if (v >= 0x1000000000000000ULL)
395 switch (tolower(*s)) {
396 case '0': v <<= 4; break;
397 case '1': v <<= 4; v |= 0x1; break;
398 case '2': v <<= 4; v |= 0x2; break;
399 case '3': v <<= 4; v |= 0x3; break;
400 case '4': v <<= 4; v |= 0x4; break;
401 case '5': v <<= 4; v |= 0x5; break;
402 case '6': v <<= 4; v |= 0x6; break;
403 case '7': v <<= 4; v |= 0x7; break;
404 case '8': v <<= 4; v |= 0x8; break;
405 case '9': v <<= 4; v |= 0x9; break;
406 case 'a': v <<= 4; v |= 0xa; break;
407 case 'b': v <<= 4; v |= 0xb; break;
408 case 'c': v <<= 4; v |= 0xc; break;
409 case 'd': v <<= 4; v |= 0xd; break;
410 case 'e': v <<= 4; v |= 0xe; break;
411 case 'f': v <<= 4; v |= 0xf; break;
419 /* check for overrun */
420 if (v >= 0x2000000000000000ULL)
422 switch (tolower(*s)) {
423 case '0': v <<= 3; break;
424 case '1': v <<= 3; v |= 1; break;
425 case '2': v <<= 3; v |= 2; break;
426 case '3': v <<= 3; v |= 3; break;
427 case '4': v <<= 3; v |= 4; break;
428 case '5': v <<= 3; v |= 5; break;
429 case '6': v <<= 3; v |= 6; break;
430 case '7': v <<= 3; v |= 7; break;
438 /* check for overrun */
439 if (v > 0x1999999999999999ULL)
441 switch (tolower(*s)) {
442 case '0': v *= 10; break;
443 case '1': v *= 10; v += 1; break;
444 case '2': v *= 10; v += 2; break;
445 case '3': v *= 10; v += 3; break;
446 case '4': v *= 10; v += 4; break;
447 case '5': v *= 10; v += 5; break;
448 case '6': v *= 10; v += 6; break;
449 case '7': v *= 10; v += 7; break;
450 case '8': v *= 10; v += 8; break;
451 case '9': v *= 10; v += 9; break;
467 * Parses a hex number including hex floats and set the
470 static void parse_number_hex(void)
472 assert(c == 'x' || c == 'X');
476 obstack_1grow(&symbol_obstack, (char) c);
479 obstack_1grow(&symbol_obstack, '\0');
480 char *string = obstack_finish(&symbol_obstack);
482 if(c == '.' || c == 'p' || c == 'P') {
484 panic("Hex floating point numbers not implemented yet");
486 if(*string == '\0') {
487 parse_error("invalid hex number");
488 lexer_token.type = T_ERROR;
492 lexer_token.type = T_INTEGER;
493 lexer_token.v.intvalue = parse_int_string(string, &endptr, 16);
494 if(*endptr != '\0') {
495 parse_error("hex number literal too long");
498 obstack_free(&symbol_obstack, string);
499 parse_integer_suffix(true);
503 * Returns true if the given char is a octal digit.
505 * @param char the character to check
507 static inline bool is_octal_digit(int chr)
525 * Parses a octal number and set the lexer_token.
527 static void parse_number_oct(void)
529 while(is_octal_digit(c)) {
530 obstack_1grow(&symbol_obstack, (char) c);
533 obstack_1grow(&symbol_obstack, '\0');
534 char *string = obstack_finish(&symbol_obstack);
537 lexer_token.type = T_INTEGER;
538 lexer_token.v.intvalue = parse_int_string(string, &endptr, 8);
539 if(*endptr != '\0') {
540 parse_error("octal number literal too long");
543 obstack_free(&symbol_obstack, string);
544 parse_integer_suffix(true);
548 * Parses a decimal including float number and set the
551 static void parse_number_dec(void)
553 bool is_float = false;
555 obstack_1grow(&symbol_obstack, (char) c);
560 obstack_1grow(&symbol_obstack, '.');
564 obstack_1grow(&symbol_obstack, (char) c);
569 if(c == 'e' || c == 'E') {
570 obstack_1grow(&symbol_obstack, 'e');
573 if(c == '-' || c == '+') {
574 obstack_1grow(&symbol_obstack, (char) c);
579 obstack_1grow(&symbol_obstack, (char) c);
585 obstack_1grow(&symbol_obstack, '\0');
586 char *string = obstack_finish(&symbol_obstack);
590 lexer_token.type = T_FLOATINGPOINT;
591 lexer_token.v.floatvalue = strtold(string, &endptr);
593 if(*endptr != '\0') {
594 parse_error("invalid number literal");
597 parse_floating_suffix();
600 lexer_token.type = T_INTEGER;
601 lexer_token.v.intvalue = parse_int_string(string, &endptr, 10);
603 if(*endptr != '\0') {
604 parse_error("invalid number literal");
607 parse_integer_suffix(false);
609 obstack_free(&symbol_obstack, string);
613 * Parses a number and sets the lexer_token.
615 static void parse_number(void)
637 parse_error("invalid octal number");
638 lexer_token.type = T_ERROR;
644 obstack_1grow(&symbol_obstack, '0');
654 * Returns the value of a digit.
655 * The only portable way to do it ...
657 static int digit_value(int digit) {
682 panic("wrong character given");
687 * Parses an octal character sequence.
689 * @param first_digit the already read first digit
691 static int parse_octal_sequence(const int first_digit)
693 assert(is_octal_digit(first_digit));
694 int value = digit_value(first_digit);
695 if (!is_octal_digit(c)) return value;
696 value = 8 * value + digit_value(c);
698 if (!is_octal_digit(c)) return value;
699 value = 8 * value + digit_value(c);
703 return (signed char) value;
705 return (unsigned char) value;
710 * Parses a hex character sequence.
712 static int parse_hex_sequence(void)
716 value = 16 * value + digit_value(c);
721 return (signed char) value;
723 return (unsigned char) value;
728 * Parse an escape sequence.
730 static int parse_escape_sequence(void)
738 case '"': return '"';
739 case '\'': return '\'';
740 case '\\': return '\\';
741 case '?': return '\?';
742 case 'a': return '\a';
743 case 'b': return '\b';
744 case 'f': return '\f';
745 case 'n': return '\n';
746 case 'r': return '\r';
747 case 't': return '\t';
748 case 'v': return '\v';
750 return parse_hex_sequence();
759 return parse_octal_sequence(ec);
761 parse_error("reached end of file while parsing escape sequence");
764 parse_error("unknown escape sequence");
770 * Concatenate two strings.
772 string_t concat_strings(const string_t *const s1, const string_t *const s2)
774 const size_t len1 = s1->size - 1;
775 const size_t len2 = s2->size - 1;
777 char *const concat = obstack_alloc(&symbol_obstack, len1 + len2 + 1);
778 memcpy(concat, s1->begin, len1);
779 memcpy(concat + len1, s2->begin, len2 + 1);
781 #if 0 /* TODO hash */
782 const char *result = strset_insert(&stringset, concat);
783 if(result != concat) {
784 obstack_free(&symbol_obstack, concat);
789 return (string_t){ concat, len1 + len2 + 1 };
794 * Concatenate a string and a wide string.
796 wide_string_t concat_string_wide_string(const string_t *const s1, const wide_string_t *const s2)
798 const size_t len1 = s1->size - 1;
799 const size_t len2 = s2->size - 1;
801 wchar_rep_t *const concat = obstack_alloc(&symbol_obstack, (len1 + len2 + 1) * sizeof(*concat));
802 const char *const src = s1->begin;
803 for (size_t i = 0; i != len1; ++i) {
806 memcpy(concat + len1, s2->begin, (len2 + 1) * sizeof(*concat));
808 return (wide_string_t){ concat, len1 + len2 + 1 };
812 * Concatenate two wide strings.
814 wide_string_t concat_wide_strings(const wide_string_t *const s1, const wide_string_t *const s2)
816 const size_t len1 = s1->size - 1;
817 const size_t len2 = s2->size - 1;
819 wchar_rep_t *const concat = obstack_alloc(&symbol_obstack, (len1 + len2 + 1) * sizeof(*concat));
820 memcpy(concat, s1->begin, len1 * sizeof(*concat));
821 memcpy(concat + len1, s2->begin, (len2 + 1) * sizeof(*concat));
823 return (wide_string_t){ concat, len1 + len2 + 1 };
827 * Concatenate a wide string and a string.
829 wide_string_t concat_wide_string_string(const wide_string_t *const s1, const 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 const char *const src = s2->begin;
837 for (size_t i = 0; i != len2 + 1; ++i) {
841 return (wide_string_t){ concat, len1 + len2 + 1 };
845 * Parse a string literal and set lexer_token.
847 static void parse_string_literal(void)
849 const unsigned start_linenr = lexer_token.source_position.linenr;
857 tc = parse_escape_sequence();
858 obstack_1grow(&symbol_obstack, (char) tc);
862 source_position_t source_position;
863 source_position.input_name = lexer_token.source_position.input_name;
864 source_position.linenr = start_linenr;
865 errorf(source_position, "string has no end");
866 lexer_token.type = T_ERROR;
875 obstack_1grow(&symbol_obstack, (char) c);
883 /* TODO: concatenate multiple strings separated by whitespace... */
885 /* add finishing 0 to the string */
886 obstack_1grow(&symbol_obstack, '\0');
887 const size_t size = (size_t)obstack_object_size(&symbol_obstack);
888 const char *const string = obstack_finish(&symbol_obstack);
890 #if 0 /* TODO hash */
891 /* check if there is already a copy of the string */
892 result = strset_insert(&stringset, string);
893 if(result != string) {
894 obstack_free(&symbol_obstack, string);
897 const char *const result = string;
900 lexer_token.type = T_STRING_LITERAL;
901 lexer_token.v.string.begin = result;
902 lexer_token.v.string.size = size;
906 * Parse a wide character constant and set lexer_token.
908 static void parse_wide_character_constant(void)
910 const unsigned start_linenr = lexer_token.source_position.linenr;
917 wchar_rep_t tc = parse_escape_sequence();
918 obstack_grow(&symbol_obstack, &tc, sizeof(tc));
923 parse_error("newline while parsing character constant");
929 goto end_of_wide_char_constant;
932 source_position_t source_position = lexer_token.source_position;
933 source_position.linenr = start_linenr;
934 errorf(source_position, "EOF while parsing character constant");
935 lexer_token.type = T_ERROR;
940 wchar_rep_t tc = (wchar_rep_t) c;
941 obstack_grow(&symbol_obstack, &tc, sizeof(tc));
948 end_of_wide_char_constant:;
949 size_t size = (size_t) obstack_object_size(&symbol_obstack);
950 const wchar_rep_t *string = obstack_finish(&symbol_obstack);
952 lexer_token.type = T_WIDE_CHARACTER_CONSTANT;
953 lexer_token.v.wide_string.begin = string;
954 lexer_token.v.wide_string.size = size;
955 lexer_token.datatype = type_wchar_t;
959 * Parse a wide string literal and set lexer_token.
961 static void parse_wide_string_literal(void)
963 const unsigned start_linenr = lexer_token.source_position.linenr;
971 wchar_rep_t tc = parse_escape_sequence();
972 obstack_grow(&symbol_obstack, &tc, sizeof(tc));
977 source_position_t source_position;
978 source_position.input_name = lexer_token.source_position.input_name;
979 source_position.linenr = start_linenr;
980 errorf(source_position, "string has no end");
981 lexer_token.type = T_ERROR;
991 obstack_grow(&symbol_obstack, &tc, sizeof(tc));
1000 /* TODO: concatenate multiple strings separated by whitespace... */
1002 /* add finishing 0 to the string */
1003 wchar_rep_t nul = L'\0';
1004 obstack_grow(&symbol_obstack, &nul, sizeof(nul));
1005 const size_t size = (size_t)obstack_object_size(&symbol_obstack) / sizeof(wchar_rep_t);
1006 const wchar_rep_t *const string = obstack_finish(&symbol_obstack);
1008 #if 0 /* TODO hash */
1009 /* check if there is already a copy of the string */
1010 const wchar_rep_t *const result = strset_insert(&stringset, string);
1011 if(result != string) {
1012 obstack_free(&symbol_obstack, string);
1015 const wchar_rep_t *const result = string;
1018 lexer_token.type = T_WIDE_STRING_LITERAL;
1019 lexer_token.v.wide_string.begin = result;
1020 lexer_token.v.wide_string.size = size;
1024 * Parse a character constant and set lexer_token.
1026 static void parse_character_constant(void)
1028 const unsigned start_linenr = lexer_token.source_position.linenr;
1035 int tc = parse_escape_sequence();
1036 obstack_1grow(&symbol_obstack, (char) tc);
1041 parse_error("newline while parsing character constant");
1047 goto end_of_char_constant;
1050 source_position_t source_position;
1051 source_position.input_name = lexer_token.source_position.input_name;
1052 source_position.linenr = start_linenr;
1053 errorf(source_position, "EOF while parsing character constant");
1054 lexer_token.type = T_ERROR;
1059 obstack_1grow(&symbol_obstack, (char) c);
1066 end_of_char_constant:;
1067 const size_t size = (size_t)obstack_object_size(&symbol_obstack);
1068 const char *const string = obstack_finish(&symbol_obstack);
1070 lexer_token.type = T_CHARACTER_CONSTANT;
1071 lexer_token.v.string.begin = string;
1072 lexer_token.v.string.size = size;
1073 lexer_token.datatype = type_int;
1077 * Skip a multiline comment.
1079 static void skip_multiline_comment(void)
1081 unsigned start_linenr = lexer_token.source_position.linenr;
1088 /* TODO: nested comment, warn here */
1099 MATCH_NEWLINE(break;)
1102 source_position_t source_position;
1103 source_position.input_name = lexer_token.source_position.input_name;
1104 source_position.linenr = start_linenr;
1105 errorf(source_position, "at end of file while looking for comment end");
1117 * Skip a single line comment.
1119 static void skip_line_comment(void)
1137 /** The current preprocessor token. */
1138 static token_t pp_token;
1141 * Read the next preprocessor token.
1143 static inline void next_pp_token(void)
1145 lexer_next_preprocessing_token();
1146 pp_token = lexer_token;
1150 * Eat all preprocessor tokens until newline.
1152 static void eat_until_newline(void)
1154 while(pp_token.type != '\n' && pp_token.type != T_EOF) {
1160 * Handle the define directive.
1162 static void define_directive(void)
1164 lexer_next_preprocessing_token();
1165 if(lexer_token.type != T_IDENTIFIER) {
1166 parse_error("expected identifier after #define\n");
1167 eat_until_newline();
1172 * Handle the ifdef directive.
1174 static void ifdef_directive(int is_ifndef)
1177 lexer_next_preprocessing_token();
1178 //expect_identifier();
1183 * Handle the endif directive.
1185 static void endif_directive(void)
1191 * Parse the line directive.
1193 static void parse_line_directive(void)
1195 if(pp_token.type != T_INTEGER) {
1196 parse_error("expected integer");
1198 lexer_token.source_position.linenr = (unsigned int)(pp_token.v.intvalue - 1);
1201 if(pp_token.type == T_STRING_LITERAL) {
1202 lexer_token.source_position.input_name = pp_token.v.string.begin;
1206 eat_until_newline();
1216 STDC_CX_LIMITED_RANGE
1217 } stdc_pragma_kind_t;
1220 * STDC pragma values.
1227 } stdc_pragma_value_kind_t;
1230 * Parse a pragma directive.
1232 static void parse_pragma(void) {
1233 bool unknown_pragma = true;
1236 if (pp_token.v.symbol->pp_ID == TP_STDC) {
1237 stdc_pragma_kind_t kind = STDC_UNKNOWN;
1239 if (c_mode & _C99) {
1242 switch (pp_token.v.symbol->pp_ID) {
1243 case TP_FP_CONTRACT:
1244 kind = STDC_FP_CONTRACT;
1246 case TP_FENV_ACCESS:
1247 kind = STDC_FENV_ACCESS;
1249 case TP_CX_LIMITED_RANGE:
1250 kind = STDC_CX_LIMITED_RANGE;
1255 if (kind != STDC_UNKNOWN) {
1256 stdc_pragma_value_kind_t value = STDC_VALUE_UNKNOWN;
1258 switch (pp_token.v.symbol->pp_ID) {
1260 value = STDC_VALUE_ON;
1263 value = STDC_VALUE_OFF;
1266 value = STDC_VALUE_DEFAULT;
1271 if (value != STDC_VALUE_UNKNOWN) {
1272 unknown_pragma = false;
1274 errorf(pp_token.source_position, "bad STDC pragma argument");
1279 unknown_pragma = true;
1281 eat_until_newline();
1282 if (unknown_pragma && warning.unknown_pragmas) {
1283 warningf(pp_token.source_position, "encountered unknown #pragma");
1288 * Parse a preprocessor non-null directive.
1290 static void parse_preprocessor_identifier(void)
1292 assert(pp_token.type == T_IDENTIFIER);
1293 symbol_t *symbol = pp_token.v.symbol;
1295 switch(symbol->pp_ID) {
1297 printf("include - enable header name parsing!\n");
1313 parse_line_directive();
1320 /* TODO; output the rest of the line */
1321 parse_error("#error directive: ");
1330 * Parse a preprocessor directive.
1332 static void parse_preprocessor_directive(void)
1336 switch(pp_token.type) {
1338 parse_preprocessor_identifier();
1341 parse_line_directive();
1344 /* NULL directive, see § 6.10.7 */
1347 parse_error("invalid preprocessor directive");
1348 eat_until_newline();
1353 #define MAYBE_PROLOG \
1358 #define MAYBE(ch, set_type) \
1361 lexer_token.type = set_type; \
1364 #define ELSE_CODE(code) \
1368 } /* end of while(1) */ \
1371 #define ELSE(set_type) \
1373 lexer_token.type = set_type; \
1377 void lexer_next_preprocessing_token(void)
1387 lexer_token.type = '\n';
1393 /* might be a wide string ( L"string" ) */
1394 if(lexer_token.type == T_IDENTIFIER &&
1395 lexer_token.v.symbol == symbol_L) {
1397 parse_wide_string_literal();
1398 } else if(c == '\'') {
1399 parse_wide_character_constant();
1409 parse_string_literal();
1413 parse_character_constant();
1435 MAYBE('.', T_DOTDOTDOT)
1439 lexer_token.type = '.';
1445 MAYBE('&', T_ANDAND)
1446 MAYBE('=', T_ANDEQUAL)
1450 MAYBE('=', T_ASTERISKEQUAL)
1454 MAYBE('+', T_PLUSPLUS)
1455 MAYBE('=', T_PLUSEQUAL)
1459 MAYBE('>', T_MINUSGREATER)
1460 MAYBE('-', T_MINUSMINUS)
1461 MAYBE('=', T_MINUSEQUAL)
1465 MAYBE('=', T_EXCLAMATIONMARKEQUAL)
1469 MAYBE('=', T_SLASHEQUAL)
1472 skip_multiline_comment();
1473 lexer_next_preprocessing_token();
1477 skip_line_comment();
1478 lexer_next_preprocessing_token();
1484 MAYBE('=', T_PERCENTEQUAL)
1489 MAYBE(':', T_HASHHASH)
1493 lexer_token.type = '#';
1502 MAYBE('=', T_LESSEQUAL)
1505 MAYBE('=', T_LESSLESSEQUAL)
1510 MAYBE('=', T_GREATEREQUAL)
1513 MAYBE('=', T_GREATERGREATEREQUAL)
1514 ELSE(T_GREATERGREATER)
1518 MAYBE('=', T_CARETEQUAL)
1522 MAYBE('=', T_PIPEEQUAL)
1523 MAYBE('|', T_PIPEPIPE)
1531 MAYBE('=', T_EQUALEQUAL)
1535 MAYBE('#', T_HASHHASH)
1549 lexer_token.type = c;
1554 lexer_token.type = T_EOF;
1559 errorf(lexer_token.source_position, "unknown character '%c' found\n", c);
1560 lexer_token.type = T_ERROR;
1566 void lexer_next_token(void)
1568 lexer_next_preprocessing_token();
1569 if(lexer_token.type != '\n')
1574 lexer_next_preprocessing_token();
1575 } while(lexer_token.type == '\n');
1577 if(lexer_token.type == '#') {
1578 parse_preprocessor_directive();
1583 void init_lexer(void)
1585 strset_init(&stringset);
1588 void lexer_open_stream(FILE *stream, const char *input_name)
1591 lexer_token.source_position.linenr = 0;
1592 lexer_token.source_position.input_name = input_name;
1594 symbol_L = symbol_table_insert("L");
1598 /* place a virtual \n at the beginning so the lexer knows that we're
1599 * at the beginning of a line */
1603 void exit_lexer(void)
1605 strset_destroy(&stringset);
1608 static __attribute__((unused))
1609 void dbg_pos(const source_position_t source_position)
1611 fprintf(stdout, "%s:%u\n", source_position.input_name,
1612 source_position.linenr);