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"
25 #include "symbol_table_t.h"
26 #include "adt/error.h"
27 #include "adt/strset.h"
31 #include "target_architecture.h"
34 #include "lang_features.h"
46 /* No strtold on windows and no replacement yet */
47 #define strtold(s, e) strtod(s, e)
54 static char buf[1024 + MAX_PUTBACK];
55 static const char *bufend;
56 static const char *bufpos;
57 static strset_t stringset;
60 * Prints a parse error message at the current token.
62 * @param msg the error message
64 static void parse_error(const char *msg)
66 errorf(lexer_token.source_position, "%s", msg);
69 static inline void next_real_char(void)
71 assert(bufpos <= bufend);
72 if (bufpos >= bufend) {
73 size_t s = fread(buf + MAX_PUTBACK, 1, sizeof(buf) - MAX_PUTBACK,
79 bufpos = buf + MAX_PUTBACK;
80 bufend = buf + MAX_PUTBACK + s;
86 * Put a character back into the buffer.
88 * @param pc the character to put back
90 static inline void put_back(int pc)
93 *(--bufpos - buf + buf) = (char) pc;
96 printf("putback '%c'\n", pc);
100 static inline void next_char(void);
102 #define MATCH_NEWLINE(code) \
108 lexer_token.source_position.linenr++; \
112 lexer_token.source_position.linenr++; \
115 #define eat(c_type) do { assert(c == c_type); next_char(); } while(0)
117 static void maybe_concat_lines(void)
122 MATCH_NEWLINE(return;)
133 * Set c to the next input character, ie.
134 * after expanding trigraphs.
136 static inline void next_char(void)
140 /* filter trigraphs */
141 if(UNLIKELY(c == '\\')) {
142 maybe_concat_lines();
143 goto end_of_next_char;
147 goto end_of_next_char;
150 if(LIKELY(c != '?')) {
153 goto end_of_next_char;
158 case '=': c = '#'; break;
159 case '(': c = '['; break;
160 case '/': c = '\\'; maybe_concat_lines(); break;
161 case ')': c = ']'; break;
162 case '\'': c = '^'; break;
163 case '<': c = '{'; break;
164 case '!': c = '|'; break;
165 case '>': c = '}'; break;
166 case '-': c = '~'; break;
176 printf("nchar '%c'\n", c);
180 #define SYMBOL_CHARS \
248 * Read a symbol from the input and build
251 static void parse_symbol(void)
256 obstack_1grow(&symbol_obstack, (char) c);
263 obstack_1grow(&symbol_obstack, (char) c);
273 obstack_1grow(&symbol_obstack, '\0');
275 string = obstack_finish(&symbol_obstack);
276 symbol = symbol_table_insert(string);
278 lexer_token.type = symbol->ID;
279 lexer_token.v.symbol = symbol;
281 if(symbol->string != string) {
282 obstack_free(&symbol_obstack, string);
286 static void parse_integer_suffix(bool is_oct_hex)
288 bool is_unsigned = false;
289 bool min_long = false;
290 bool min_longlong = false;
292 if(c == 'U' || c == 'u') {
295 if(c == 'L' || c == 'l') {
298 if(c == 'L' || c == 'l') {
303 } else if(c == 'l' || c == 'L') {
306 if(c == 'l' || c == 'L') {
309 if(c == 'u' || c == 'U') {
313 } else if(c == 'u' || c == 'U') {
316 lexer_token.datatype = type_unsigned_long;
321 long long v = lexer_token.v.intvalue;
323 if(v >= TARGET_INT_MIN && v <= TARGET_INT_MAX) {
324 lexer_token.datatype = type_int;
326 } else if(is_oct_hex && v >= 0 && v <= TARGET_UINT_MAX) {
327 lexer_token.datatype = type_unsigned_int;
332 if(v >= TARGET_LONG_MIN && v <= TARGET_LONG_MAX) {
333 lexer_token.datatype = type_long;
335 } else if(is_oct_hex && v >= 0 && v <= TARGET_ULONG_MAX) {
336 lexer_token.datatype = type_unsigned_long;
340 unsigned long long uv = (unsigned long long) v;
341 if(is_oct_hex && uv > (unsigned long long) TARGET_LONGLONG_MAX) {
342 lexer_token.datatype = type_unsigned_long_long;
346 lexer_token.datatype = type_long_long;
348 unsigned long long v = (unsigned long long) lexer_token.v.intvalue;
349 if(!min_long && v <= TARGET_UINT_MAX) {
350 lexer_token.datatype = type_unsigned_int;
353 if(!min_longlong && v <= TARGET_ULONG_MAX) {
354 lexer_token.datatype = type_unsigned_long;
357 lexer_token.datatype = type_unsigned_long_long;
361 static void parse_floating_suffix(void)
364 /* TODO: do something useful with the suffixes... */
368 lexer_token.datatype = type_float;
373 lexer_token.datatype = type_long_double;
376 lexer_token.datatype = type_double;
382 * A replacement for strtoull. Only those parts needed for
383 * our parser are implemented.
385 static unsigned long long parse_int_string(const char *s, const char **endptr, int base) {
386 unsigned long long v = 0;
391 /* check for overrun */
392 if (v >= 0x1000000000000000ULL)
394 switch (tolower(*s)) {
395 case '0': v <<= 4; break;
396 case '1': v <<= 4; v |= 0x1; break;
397 case '2': v <<= 4; v |= 0x2; break;
398 case '3': v <<= 4; v |= 0x3; break;
399 case '4': v <<= 4; v |= 0x4; break;
400 case '5': v <<= 4; v |= 0x5; break;
401 case '6': v <<= 4; v |= 0x6; break;
402 case '7': v <<= 4; v |= 0x7; break;
403 case '8': v <<= 4; v |= 0x8; break;
404 case '9': v <<= 4; v |= 0x9; break;
405 case 'a': v <<= 4; v |= 0xa; break;
406 case 'b': v <<= 4; v |= 0xb; break;
407 case 'c': v <<= 4; v |= 0xc; break;
408 case 'd': v <<= 4; v |= 0xd; break;
409 case 'e': v <<= 4; v |= 0xe; break;
410 case 'f': v <<= 4; v |= 0xf; break;
418 /* check for overrun */
419 if (v >= 0x2000000000000000ULL)
421 switch (tolower(*s)) {
422 case '0': v <<= 3; break;
423 case '1': v <<= 3; v |= 1; break;
424 case '2': v <<= 3; v |= 2; break;
425 case '3': v <<= 3; v |= 3; break;
426 case '4': v <<= 3; v |= 4; break;
427 case '5': v <<= 3; v |= 5; break;
428 case '6': v <<= 3; v |= 6; break;
429 case '7': v <<= 3; v |= 7; break;
437 /* check for overrun */
438 if (v > 0x1999999999999999ULL)
440 switch (tolower(*s)) {
441 case '0': v *= 10; break;
442 case '1': v *= 10; v += 1; break;
443 case '2': v *= 10; v += 2; break;
444 case '3': v *= 10; v += 3; break;
445 case '4': v *= 10; v += 4; break;
446 case '5': v *= 10; v += 5; break;
447 case '6': v *= 10; v += 6; break;
448 case '7': v *= 10; v += 7; break;
449 case '8': v *= 10; v += 8; break;
450 case '9': v *= 10; v += 9; break;
466 * Parses a hex number including hex floats and set the
469 static void parse_number_hex(void)
471 assert(c == 'x' || c == 'X');
475 obstack_1grow(&symbol_obstack, (char) c);
478 obstack_1grow(&symbol_obstack, '\0');
479 char *string = obstack_finish(&symbol_obstack);
481 if(c == '.' || c == 'p' || c == 'P') {
483 panic("Hex floating point numbers not implemented yet");
485 if(*string == '\0') {
486 parse_error("invalid hex number");
487 lexer_token.type = T_ERROR;
491 lexer_token.type = T_INTEGER;
492 lexer_token.v.intvalue = parse_int_string(string, &endptr, 16);
493 if(*endptr != '\0') {
494 parse_error("hex number literal too long");
497 obstack_free(&symbol_obstack, string);
498 parse_integer_suffix(true);
502 * Returns true if the given char is a octal digit.
504 * @param char the character to check
506 static inline bool is_octal_digit(int chr)
524 * Parses a octal number and set the lexer_token.
526 static void parse_number_oct(void)
528 while(is_octal_digit(c)) {
529 obstack_1grow(&symbol_obstack, (char) c);
532 obstack_1grow(&symbol_obstack, '\0');
533 char *string = obstack_finish(&symbol_obstack);
536 lexer_token.type = T_INTEGER;
537 lexer_token.v.intvalue = parse_int_string(string, &endptr, 8);
538 if(*endptr != '\0') {
539 parse_error("octal number literal too long");
542 obstack_free(&symbol_obstack, string);
543 parse_integer_suffix(true);
547 * Parses a decimal including float number and set the
550 static void parse_number_dec(void)
552 bool is_float = false;
554 obstack_1grow(&symbol_obstack, (char) c);
559 obstack_1grow(&symbol_obstack, '.');
563 obstack_1grow(&symbol_obstack, (char) c);
568 if(c == 'e' || c == 'E') {
569 obstack_1grow(&symbol_obstack, 'e');
572 if(c == '-' || c == '+') {
573 obstack_1grow(&symbol_obstack, (char) c);
578 obstack_1grow(&symbol_obstack, (char) c);
584 obstack_1grow(&symbol_obstack, '\0');
585 char *string = obstack_finish(&symbol_obstack);
589 lexer_token.type = T_FLOATINGPOINT;
590 lexer_token.v.floatvalue = strtold(string, &endptr);
592 if(*endptr != '\0') {
593 parse_error("invalid number literal");
596 parse_floating_suffix();
599 lexer_token.type = T_INTEGER;
600 lexer_token.v.intvalue = parse_int_string(string, &endptr, 10);
602 if(*endptr != '\0') {
603 parse_error("invalid number literal");
606 parse_integer_suffix(false);
608 obstack_free(&symbol_obstack, string);
612 * Parses a number and sets the lexer_token.
614 static void parse_number(void)
636 parse_error("invalid octal number");
637 lexer_token.type = T_ERROR;
643 obstack_1grow(&symbol_obstack, '0');
653 * Returns the value of a digit.
654 * The only portable way to do it ...
656 static int digit_value(int digit) {
681 panic("wrong character given");
686 * Parses an octal character sequence.
688 * @param first_digit the already read first digit
690 static int parse_octal_sequence(const int first_digit)
692 assert(is_octal_digit(first_digit));
693 int value = digit_value(first_digit);
694 if (!is_octal_digit(c)) return value;
695 value = 8 * value + digit_value(c);
697 if (!is_octal_digit(c)) return value;
698 value = 8 * value + digit_value(c);
702 return (signed char) value;
704 return (unsigned char) value;
709 * Parses a hex character sequence.
711 static int parse_hex_sequence(void)
715 value = 16 * value + digit_value(c);
720 return (signed char) value;
722 return (unsigned char) value;
727 * Parse an escape sequence.
729 static int parse_escape_sequence(void)
737 case '"': return '"';
738 case '\'': return '\'';
739 case '\\': return '\\';
740 case '?': return '\?';
741 case 'a': return '\a';
742 case 'b': return '\b';
743 case 'f': return '\f';
744 case 'n': return '\n';
745 case 'r': return '\r';
746 case 't': return '\t';
747 case 'v': return '\v';
749 return parse_hex_sequence();
758 return parse_octal_sequence(ec);
760 parse_error("reached end of file while parsing escape sequence");
763 parse_error("unknown escape sequence");
769 * Concatenate two strings.
771 string_t concat_strings(const string_t *const s1, const string_t *const s2)
773 const size_t len1 = s1->size - 1;
774 const size_t len2 = s2->size - 1;
776 char *const concat = obstack_alloc(&symbol_obstack, len1 + len2 + 1);
777 memcpy(concat, s1->begin, len1);
778 memcpy(concat + len1, s2->begin, len2 + 1);
780 #if 0 /* TODO hash */
781 const char *result = strset_insert(&stringset, concat);
782 if(result != concat) {
783 obstack_free(&symbol_obstack, concat);
788 return (string_t){ concat, len1 + len2 + 1 };
793 * Concatenate a string and a wide string.
795 wide_string_t concat_string_wide_string(const string_t *const s1, const wide_string_t *const s2)
797 const size_t len1 = s1->size - 1;
798 const size_t len2 = s2->size - 1;
800 wchar_rep_t *const concat = obstack_alloc(&symbol_obstack, (len1 + len2 + 1) * sizeof(*concat));
801 const char *const src = s1->begin;
802 for (size_t i = 0; i != len1; ++i) {
805 memcpy(concat + len1, s2->begin, (len2 + 1) * sizeof(*concat));
807 return (wide_string_t){ concat, len1 + len2 + 1 };
811 * Concatenate two wide strings.
813 wide_string_t concat_wide_strings(const wide_string_t *const s1, const wide_string_t *const s2)
815 const size_t len1 = s1->size - 1;
816 const size_t len2 = s2->size - 1;
818 wchar_rep_t *const concat = obstack_alloc(&symbol_obstack, (len1 + len2 + 1) * sizeof(*concat));
819 memcpy(concat, s1->begin, len1 * sizeof(*concat));
820 memcpy(concat + len1, s2->begin, (len2 + 1) * sizeof(*concat));
822 return (wide_string_t){ concat, len1 + len2 + 1 };
826 * Concatenate a wide string and a string.
828 wide_string_t concat_wide_string_string(const wide_string_t *const s1, const string_t *const s2)
830 const size_t len1 = s1->size - 1;
831 const size_t len2 = s2->size - 1;
833 wchar_rep_t *const concat = obstack_alloc(&symbol_obstack, (len1 + len2 + 1) * sizeof(*concat));
834 memcpy(concat, s1->begin, len1 * sizeof(*concat));
835 const char *const src = s2->begin;
836 for (size_t i = 0; i != len2 + 1; ++i) {
840 return (wide_string_t){ concat, len1 + len2 + 1 };
844 * Parse a string literal and set lexer_token.
846 static void parse_string_literal(void)
848 const unsigned start_linenr = lexer_token.source_position.linenr;
856 tc = parse_escape_sequence();
857 obstack_1grow(&symbol_obstack, (char) tc);
861 source_position_t source_position;
862 source_position.input_name = lexer_token.source_position.input_name;
863 source_position.linenr = start_linenr;
864 errorf(source_position, "string has no end");
865 lexer_token.type = T_ERROR;
874 obstack_1grow(&symbol_obstack, (char) c);
882 /* TODO: concatenate multiple strings separated by whitespace... */
884 /* add finishing 0 to the string */
885 obstack_1grow(&symbol_obstack, '\0');
886 const size_t size = (size_t)obstack_object_size(&symbol_obstack);
887 const char *const string = obstack_finish(&symbol_obstack);
889 #if 0 /* TODO hash */
890 /* check if there is already a copy of the string */
891 result = strset_insert(&stringset, string);
892 if(result != string) {
893 obstack_free(&symbol_obstack, string);
896 const char *const result = string;
899 lexer_token.type = T_STRING_LITERAL;
900 lexer_token.v.string.begin = result;
901 lexer_token.v.string.size = size;
905 * Parse a wide character constant and set lexer_token.
907 static void parse_wide_character_constant(void)
915 found_char = parse_escape_sequence();
919 parse_error("newline while parsing character constant");
925 goto end_of_wide_char_constant;
928 parse_error("EOF while parsing character constant");
929 lexer_token.type = T_ERROR;
933 if(found_char != 0) {
934 parse_error("more than 1 characters in character "
936 goto end_of_wide_char_constant;
945 end_of_wide_char_constant:
946 lexer_token.type = T_INTEGER;
947 lexer_token.v.intvalue = found_char;
948 lexer_token.datatype = type_wchar_t;
952 * Parse a wide string literal and set lexer_token.
954 static void parse_wide_string_literal(void)
956 const unsigned start_linenr = lexer_token.source_position.linenr;
964 wchar_rep_t tc = parse_escape_sequence();
965 obstack_grow(&symbol_obstack, &tc, sizeof(tc));
970 source_position_t source_position;
971 source_position.input_name = lexer_token.source_position.input_name;
972 source_position.linenr = start_linenr;
973 errorf(source_position, "string has no end");
974 lexer_token.type = T_ERROR;
984 obstack_grow(&symbol_obstack, &tc, sizeof(tc));
993 /* TODO: concatenate multiple strings separated by whitespace... */
995 /* add finishing 0 to the string */
996 wchar_rep_t nul = L'\0';
997 obstack_grow(&symbol_obstack, &nul, sizeof(nul));
998 const size_t size = (size_t)obstack_object_size(&symbol_obstack) / sizeof(wchar_rep_t);
999 const wchar_rep_t *const string = obstack_finish(&symbol_obstack);
1001 #if 0 /* TODO hash */
1002 /* check if there is already a copy of the string */
1003 const wchar_rep_t *const result = strset_insert(&stringset, string);
1004 if(result != string) {
1005 obstack_free(&symbol_obstack, string);
1008 const wchar_rep_t *const result = string;
1011 lexer_token.type = T_WIDE_STRING_LITERAL;
1012 lexer_token.v.wide_string.begin = result;
1013 lexer_token.v.wide_string.size = size;
1017 * Parse a character constant and set lexer_token.
1019 static void parse_character_constant(void)
1021 const unsigned start_linenr = lexer_token.source_position.linenr;
1029 tc = parse_escape_sequence();
1030 obstack_1grow(&symbol_obstack, (char) tc);
1034 parse_error("newline while parsing character constant");
1039 source_position_t source_position;
1040 source_position.input_name = lexer_token.source_position.input_name;
1041 source_position.linenr = start_linenr;
1042 errorf(source_position, "EOF while parsing character constant");
1043 lexer_token.type = T_ERROR;
1049 goto end_of_char_constant;
1052 obstack_1grow(&symbol_obstack, (char) c);
1059 end_of_char_constant:;
1060 const size_t size = (size_t)obstack_object_size(&symbol_obstack);
1061 const char *const string = obstack_finish(&symbol_obstack);
1063 lexer_token.type = T_CHARS;
1064 lexer_token.v.string.begin = string;
1065 lexer_token.v.string.size = size;
1066 lexer_token.datatype = type_int;
1070 * Skip a multiline comment.
1072 static void skip_multiline_comment(void)
1074 unsigned start_linenr = lexer_token.source_position.linenr;
1081 /* TODO: nested comment, warn here */
1092 MATCH_NEWLINE(break;)
1095 source_position_t source_position;
1096 source_position.input_name = lexer_token.source_position.input_name;
1097 source_position.linenr = start_linenr;
1098 errorf(source_position, "at end of file while looking for comment end");
1110 * Skip a single line comment.
1112 static void skip_line_comment(void)
1130 /** The current preprocessor token. */
1131 static token_t pp_token;
1134 * Read the next preprocessor token.
1136 static inline void next_pp_token(void)
1138 lexer_next_preprocessing_token();
1139 pp_token = lexer_token;
1143 * Eat all preprocessor tokens until newline.
1145 static void eat_until_newline(void)
1147 while(pp_token.type != '\n' && pp_token.type != T_EOF) {
1153 * Handle the define directive.
1155 static void define_directive(void)
1157 lexer_next_preprocessing_token();
1158 if(lexer_token.type != T_IDENTIFIER) {
1159 parse_error("expected identifier after #define\n");
1160 eat_until_newline();
1165 * Handle the ifdef directive.
1167 static void ifdef_directive(int is_ifndef)
1170 lexer_next_preprocessing_token();
1171 //expect_identifier();
1176 * Handle the endif directive.
1178 static void endif_directive(void)
1184 * Parse the line directive.
1186 static void parse_line_directive(void)
1188 if(pp_token.type != T_INTEGER) {
1189 parse_error("expected integer");
1191 lexer_token.source_position.linenr = (unsigned int)(pp_token.v.intvalue - 1);
1194 if(pp_token.type == T_STRING_LITERAL) {
1195 lexer_token.source_position.input_name = pp_token.v.string.begin;
1199 eat_until_newline();
1209 STDC_CX_LIMITED_RANGE
1210 } stdc_pragma_kind_t;
1213 * STDC pragma values.
1220 } stdc_pragma_value_kind_t;
1223 * Parse a pragma directive.
1225 static void parse_pragma(void) {
1226 bool unknown_pragma = true;
1229 if (pp_token.v.symbol->pp_ID == TP_STDC) {
1230 stdc_pragma_kind_t kind = STDC_UNKNOWN;
1232 if (c_mode & _C99) {
1235 switch (pp_token.v.symbol->pp_ID) {
1236 case TP_FP_CONTRACT:
1237 kind = STDC_FP_CONTRACT;
1239 case TP_FENV_ACCESS:
1240 kind = STDC_FENV_ACCESS;
1242 case TP_CX_LIMITED_RANGE:
1243 kind = STDC_CX_LIMITED_RANGE;
1248 if (kind != STDC_UNKNOWN) {
1249 stdc_pragma_value_kind_t value = STDC_VALUE_UNKNOWN;
1251 switch (pp_token.v.symbol->pp_ID) {
1253 value = STDC_VALUE_ON;
1256 value = STDC_VALUE_OFF;
1259 value = STDC_VALUE_DEFAULT;
1264 if (value != STDC_VALUE_UNKNOWN) {
1265 unknown_pragma = false;
1267 errorf(pp_token.source_position, "bad STDC pragma argument");
1272 unknown_pragma = true;
1274 eat_until_newline();
1275 if (unknown_pragma && warning.unknown_pragmas) {
1276 warningf(pp_token.source_position, "encountered unknown #pragma");
1281 * Parse a preprocessor non-null directive.
1283 static void parse_preprocessor_identifier(void)
1285 assert(pp_token.type == T_IDENTIFIER);
1286 symbol_t *symbol = pp_token.v.symbol;
1288 switch(symbol->pp_ID) {
1290 printf("include - enable header name parsing!\n");
1306 parse_line_directive();
1313 /* TODO; output the rest of the line */
1314 parse_error("#error directive: ");
1323 * Parse a preprocessor directive.
1325 static void parse_preprocessor_directive(void)
1329 switch(pp_token.type) {
1331 parse_preprocessor_identifier();
1334 parse_line_directive();
1337 /* NULL directive, see § 6.10.7 */
1340 parse_error("invalid preprocessor directive");
1341 eat_until_newline();
1346 #define MAYBE_PROLOG \
1351 #define MAYBE(ch, set_type) \
1354 lexer_token.type = set_type; \
1357 #define ELSE_CODE(code) \
1361 } /* end of while(1) */ \
1364 #define ELSE(set_type) \
1366 lexer_token.type = set_type; \
1370 void lexer_next_preprocessing_token(void)
1380 lexer_token.type = '\n';
1386 /* might be a wide string ( L"string" ) */
1387 if(lexer_token.type == T_IDENTIFIER &&
1388 lexer_token.v.symbol == symbol_L) {
1390 parse_wide_string_literal();
1391 } else if(c == '\'') {
1392 parse_wide_character_constant();
1402 parse_string_literal();
1406 parse_character_constant();
1428 MAYBE('.', T_DOTDOTDOT)
1432 lexer_token.type = '.';
1438 MAYBE('&', T_ANDAND)
1439 MAYBE('=', T_ANDEQUAL)
1443 MAYBE('=', T_ASTERISKEQUAL)
1447 MAYBE('+', T_PLUSPLUS)
1448 MAYBE('=', T_PLUSEQUAL)
1452 MAYBE('>', T_MINUSGREATER)
1453 MAYBE('-', T_MINUSMINUS)
1454 MAYBE('=', T_MINUSEQUAL)
1458 MAYBE('=', T_EXCLAMATIONMARKEQUAL)
1462 MAYBE('=', T_SLASHEQUAL)
1465 skip_multiline_comment();
1466 lexer_next_preprocessing_token();
1470 skip_line_comment();
1471 lexer_next_preprocessing_token();
1476 MAYBE('>', T_PERCENTGREATER)
1477 MAYBE('=', T_PERCENTEQUAL)
1482 MAYBE(':', T_PERCENTCOLONPERCENTCOLON)
1486 lexer_token.type = T_PERCENTCOLON;
1489 ELSE(T_PERCENTCOLON)
1493 MAYBE(':', T_LESSCOLON)
1494 MAYBE('%', T_LESSPERCENT)
1495 MAYBE('=', T_LESSEQUAL)
1498 MAYBE('=', T_LESSLESSEQUAL)
1503 MAYBE('=', T_GREATEREQUAL)
1506 MAYBE('=', T_GREATERGREATEREQUAL)
1507 ELSE(T_GREATERGREATER)
1511 MAYBE('=', T_CARETEQUAL)
1515 MAYBE('=', T_PIPEEQUAL)
1516 MAYBE('|', T_PIPEPIPE)
1520 MAYBE('>', T_COLONGREATER)
1524 MAYBE('=', T_EQUALEQUAL)
1528 MAYBE('#', T_HASHHASH)
1542 lexer_token.type = c;
1547 lexer_token.type = T_EOF;
1552 errorf(lexer_token.source_position, "unknown character '%c' found\n", c);
1553 lexer_token.type = T_ERROR;
1559 void lexer_next_token(void)
1561 lexer_next_preprocessing_token();
1562 if(lexer_token.type != '\n')
1567 lexer_next_preprocessing_token();
1568 } while(lexer_token.type == '\n');
1570 if(lexer_token.type == '#') {
1571 parse_preprocessor_directive();
1576 void init_lexer(void)
1578 strset_init(&stringset);
1581 void lexer_open_stream(FILE *stream, const char *input_name)
1584 lexer_token.source_position.linenr = 0;
1585 lexer_token.source_position.input_name = input_name;
1587 symbol_L = symbol_table_insert("L");
1591 /* place a virtual \n at the beginning so the lexer knows that we're
1592 * at the beginning of a line */
1596 void exit_lexer(void)
1598 strset_destroy(&stringset);
1601 static __attribute__((unused))
1602 void dbg_pos(const source_position_t source_position)
1604 fprintf(stdout, "%s:%u\n", source_position.input_name,
1605 source_position.linenr);