3 #include "diagnostic.h"
6 #include "symbol_table_t.h"
8 #include "adt/strset.h"
12 #include "target_architecture.h"
15 #include "lang_features.h"
27 /* No strtold on windows and no replacement yet */
28 #define strtold(s, e) strtod(s, e)
31 #if defined HAS_SIGNED_CHAR
32 typedef signed char char_type;
33 #elif defined HAS_UNSIGNED_CHAR
34 typedef unsigned char char_type;
36 # error signedness of char not determined
43 static char buf[1024 + MAX_PUTBACK];
44 static const char *bufend;
45 static const char *bufpos;
46 static strset_t stringset;
49 * Prints a parse error message at the current token.
51 * @param msg the error message
53 static void parse_error(const char *msg)
55 errorf(lexer_token.source_position, "%s", msg);
58 static inline void next_real_char(void)
60 assert(bufpos <= bufend);
61 if (bufpos >= bufend) {
62 size_t s = fread(buf + MAX_PUTBACK, 1, sizeof(buf) - MAX_PUTBACK,
68 bufpos = buf + MAX_PUTBACK;
69 bufend = buf + MAX_PUTBACK + s;
75 * Put a character back into the buffer.
77 * @param pc the character to put back
79 static inline void put_back(int pc)
82 *(--bufpos - buf + buf) = (char) pc;
85 printf("putback '%c'\n", pc);
89 static inline void next_char(void);
91 #define MATCH_NEWLINE(code) \
97 lexer_token.source_position.linenr++; \
101 lexer_token.source_position.linenr++; \
104 #define eat(c_type) do { assert(c == c_type); next_char(); } while(0)
106 static void maybe_concat_lines(void)
111 MATCH_NEWLINE(return;)
122 * Set c to the next input character, ie.
123 * after expanding trigraphs.
125 static inline void next_char(void)
129 /* filter trigraphs */
130 if(UNLIKELY(c == '\\')) {
131 maybe_concat_lines();
132 goto end_of_next_char;
136 goto end_of_next_char;
139 if(LIKELY(c != '?')) {
142 goto end_of_next_char;
147 case '=': c = '#'; break;
148 case '(': c = '['; break;
149 case '/': c = '\\'; maybe_concat_lines(); break;
150 case ')': c = ']'; break;
151 case '\'': c = '^'; break;
152 case '<': c = '{'; break;
153 case '!': c = '|'; break;
154 case '>': c = '}'; break;
155 case '-': c = '~'; break;
165 printf("nchar '%c'\n", c);
169 #define SYMBOL_CHARS \
237 * Read a symbol from the input and build
240 static void parse_symbol(void)
245 obstack_1grow(&symbol_obstack, (char) c);
252 obstack_1grow(&symbol_obstack, (char) c);
262 obstack_1grow(&symbol_obstack, '\0');
264 string = obstack_finish(&symbol_obstack);
265 symbol = symbol_table_insert(string);
267 lexer_token.type = symbol->ID;
268 lexer_token.v.symbol = symbol;
270 if(symbol->string != string) {
271 obstack_free(&symbol_obstack, string);
275 static void parse_integer_suffix(bool is_oct_hex)
277 bool is_unsigned = false;
278 bool min_long = false;
279 bool min_longlong = false;
281 if(c == 'U' || c == 'u') {
284 if(c == 'L' || c == 'l') {
287 if(c == 'L' || c == 'l') {
292 } else if(c == 'l' || c == 'L') {
295 if(c == 'l' || c == 'L') {
298 if(c == 'u' || c == 'U') {
302 } else if(c == 'u' || c == 'U') {
305 lexer_token.datatype = type_unsigned_long;
310 long long v = lexer_token.v.intvalue;
312 if(v >= TARGET_INT_MIN && v <= TARGET_INT_MAX) {
313 lexer_token.datatype = type_int;
315 } else if(is_oct_hex && v >= 0 && v <= TARGET_UINT_MAX) {
316 lexer_token.datatype = type_unsigned_int;
321 if(v >= TARGET_LONG_MIN && v <= TARGET_LONG_MAX) {
322 lexer_token.datatype = type_long;
324 } else if(is_oct_hex && v >= 0 && v <= TARGET_ULONG_MAX) {
325 lexer_token.datatype = type_unsigned_long;
329 unsigned long long uv = (unsigned long long) v;
330 if(is_oct_hex && uv > (unsigned long long) TARGET_LONGLONG_MAX) {
331 lexer_token.datatype = type_unsigned_long_long;
335 lexer_token.datatype = type_long_long;
337 unsigned long long v = (unsigned long long) lexer_token.v.intvalue;
338 if(!min_long && v <= TARGET_UINT_MAX) {
339 lexer_token.datatype = type_unsigned_int;
342 if(!min_longlong && v <= TARGET_ULONG_MAX) {
343 lexer_token.datatype = type_unsigned_long;
346 lexer_token.datatype = type_unsigned_long_long;
350 static void parse_floating_suffix(void)
353 /* TODO: do something useful with the suffixes... */
357 lexer_token.datatype = type_float;
362 lexer_token.datatype = type_long_double;
365 lexer_token.datatype = type_double;
371 * A replacement for strtoull. Only those parts needed for
372 * our parser are implemented.
374 static unsigned long long parse_int_string(const char *s, const char **endptr, int base) {
375 unsigned long long v = 0;
380 /* check for overrun */
381 if (v >= 0x1000000000000000ULL)
383 switch (tolower(*s)) {
384 case '0': v <<= 4; break;
385 case '1': v <<= 4; v |= 0x1; break;
386 case '2': v <<= 4; v |= 0x2; break;
387 case '3': v <<= 4; v |= 0x3; break;
388 case '4': v <<= 4; v |= 0x4; break;
389 case '5': v <<= 4; v |= 0x5; break;
390 case '6': v <<= 4; v |= 0x6; break;
391 case '7': v <<= 4; v |= 0x7; break;
392 case '8': v <<= 4; v |= 0x8; break;
393 case '9': v <<= 4; v |= 0x9; break;
394 case 'a': v <<= 4; v |= 0xa; break;
395 case 'b': v <<= 4; v |= 0xb; break;
396 case 'c': v <<= 4; v |= 0xc; break;
397 case 'd': v <<= 4; v |= 0xd; break;
398 case 'e': v <<= 4; v |= 0xe; break;
399 case 'f': v <<= 4; v |= 0xf; break;
407 /* check for overrun */
408 if (v >= 0x2000000000000000ULL)
410 switch (tolower(*s)) {
411 case '0': v <<= 3; break;
412 case '1': v <<= 3; v |= 1; break;
413 case '2': v <<= 3; v |= 2; break;
414 case '3': v <<= 3; v |= 3; break;
415 case '4': v <<= 3; v |= 4; break;
416 case '5': v <<= 3; v |= 5; break;
417 case '6': v <<= 3; v |= 6; break;
418 case '7': v <<= 3; v |= 7; break;
426 /* check for overrun */
427 if (v > 0x1999999999999999ULL)
429 switch (tolower(*s)) {
430 case '0': v *= 10; break;
431 case '1': v *= 10; v += 1; break;
432 case '2': v *= 10; v += 2; break;
433 case '3': v *= 10; v += 3; break;
434 case '4': v *= 10; v += 4; break;
435 case '5': v *= 10; v += 5; break;
436 case '6': v *= 10; v += 6; break;
437 case '7': v *= 10; v += 7; break;
438 case '8': v *= 10; v += 8; break;
439 case '9': v *= 10; v += 9; break;
455 * Parses a hex number including hex floats and set the
458 static void parse_number_hex(void)
460 assert(c == 'x' || c == 'X');
464 obstack_1grow(&symbol_obstack, (char) c);
467 obstack_1grow(&symbol_obstack, '\0');
468 char *string = obstack_finish(&symbol_obstack);
470 if(c == '.' || c == 'p' || c == 'P') {
472 panic("Hex floating point numbers not implemented yet");
474 if(*string == '\0') {
475 parse_error("invalid hex number");
476 lexer_token.type = T_ERROR;
480 lexer_token.type = T_INTEGER;
481 lexer_token.v.intvalue = parse_int_string(string, &endptr, 16);
482 if(*endptr != '\0') {
483 parse_error("hex number literal too long");
486 obstack_free(&symbol_obstack, string);
487 parse_integer_suffix(true);
491 * Returns true if the given char is a octal digit.
493 * @param char the character to check
495 static inline bool is_octal_digit(int chr)
513 * Parses a octal number and set the lexer_token.
515 static void parse_number_oct(void)
517 while(is_octal_digit(c)) {
518 obstack_1grow(&symbol_obstack, (char) c);
521 obstack_1grow(&symbol_obstack, '\0');
522 char *string = obstack_finish(&symbol_obstack);
525 lexer_token.type = T_INTEGER;
526 lexer_token.v.intvalue = parse_int_string(string, &endptr, 8);
527 if(*endptr != '\0') {
528 parse_error("octal number literal too long");
531 obstack_free(&symbol_obstack, string);
532 parse_integer_suffix(true);
536 * Parses a decimal including float number and set the
539 static void parse_number_dec(void)
541 bool is_float = false;
543 obstack_1grow(&symbol_obstack, (char) c);
548 obstack_1grow(&symbol_obstack, '.');
552 obstack_1grow(&symbol_obstack, (char) c);
557 if(c == 'e' || c == 'E') {
558 obstack_1grow(&symbol_obstack, 'e');
561 if(c == '-' || c == '+') {
562 obstack_1grow(&symbol_obstack, (char) c);
567 obstack_1grow(&symbol_obstack, (char) c);
573 obstack_1grow(&symbol_obstack, '\0');
574 char *string = obstack_finish(&symbol_obstack);
578 lexer_token.type = T_FLOATINGPOINT;
579 lexer_token.v.floatvalue = strtold(string, &endptr);
581 if(*endptr != '\0') {
582 parse_error("invalid number literal");
585 parse_floating_suffix();
588 lexer_token.type = T_INTEGER;
589 lexer_token.v.intvalue = parse_int_string(string, &endptr, 10);
591 if(*endptr != '\0') {
592 parse_error("invalid number literal");
595 parse_integer_suffix(false);
597 obstack_free(&symbol_obstack, string);
601 * Parses a number and sets the lexer_token.
603 static void parse_number(void)
625 parse_error("invalid octal number");
626 lexer_token.type = T_ERROR;
632 obstack_1grow(&symbol_obstack, '0');
642 * Returns the value of a digit.
643 * The only portable way to do it ...
645 static int digit_value(int digit) {
670 panic("wrong character given");
675 * Parses an octal character sequence.
677 * @param first_digit the already read first digit
679 static int parse_octal_sequence(const int first_digit)
681 assert(is_octal_digit(first_digit));
682 int value = digit_value(first_digit);
683 if (!is_octal_digit(c)) return value;
684 value = 8 * value + digit_value(c);
686 if (!is_octal_digit(c)) return value;
687 value = 8 * value + digit_value(c);
689 return (char_type)value;
693 * Parses a hex character sequence.
695 static int parse_hex_sequence(void)
699 value = 16 * value + digit_value(c);
703 return (char_type)value;
707 * Parse an escape sequence.
709 static int parse_escape_sequence(void)
717 case '"': return '"';
718 case '\'': return '\'';
719 case '\\': return '\\';
720 case '?': return '\?';
721 case 'a': return '\a';
722 case 'b': return '\b';
723 case 'f': return '\f';
724 case 'n': return '\n';
725 case 'r': return '\r';
726 case 't': return '\t';
727 case 'v': return '\v';
729 return parse_hex_sequence();
738 return parse_octal_sequence(ec);
740 parse_error("reached end of file while parsing escape sequence");
743 parse_error("unknown escape sequence");
749 * Concatenate two strings.
751 string_t concat_strings(const string_t *const s1, const string_t *const s2)
753 const size_t len1 = s1->size - 1;
754 const size_t len2 = s2->size - 1;
756 char *const concat = obstack_alloc(&symbol_obstack, len1 + len2 + 1);
757 memcpy(concat, s1->begin, len1);
758 memcpy(concat + len1, s2->begin, len2 + 1);
760 #if 0 /* TODO hash */
761 const char *result = strset_insert(&stringset, concat);
762 if(result != concat) {
763 obstack_free(&symbol_obstack, concat);
768 return (string_t){ concat, len1 + len2 + 1 };
773 * Concatenate a string and a wide string.
775 wide_string_t concat_string_wide_string(const string_t *const s1, const wide_string_t *const s2)
777 const size_t len1 = s1->size - 1;
778 const size_t len2 = s2->size - 1;
780 wchar_rep_t *const concat = obstack_alloc(&symbol_obstack, (len1 + len2 + 1) * sizeof(*concat));
781 const char *const src = s1->begin;
782 for (size_t i = 0; i != len1; ++i) {
785 memcpy(concat + len1, s2->begin, (len2 + 1) * sizeof(*concat));
787 return (wide_string_t){ concat, len1 + len2 + 1 };
791 * Concatenate two wide strings.
793 wide_string_t concat_wide_strings(const wide_string_t *const s1, const wide_string_t *const s2)
795 const size_t len1 = s1->size - 1;
796 const size_t len2 = s2->size - 1;
798 wchar_rep_t *const concat = obstack_alloc(&symbol_obstack, (len1 + len2 + 1) * sizeof(*concat));
799 memcpy(concat, s1->begin, len1 * sizeof(*concat));
800 memcpy(concat + len1, s2->begin, (len2 + 1) * sizeof(*concat));
802 return (wide_string_t){ concat, len1 + len2 + 1 };
806 * Concatenate a wide string and a string.
808 wide_string_t concat_wide_string_string(const wide_string_t *const s1, const string_t *const s2)
810 const size_t len1 = s1->size - 1;
811 const size_t len2 = s2->size - 1;
813 wchar_rep_t *const concat = obstack_alloc(&symbol_obstack, (len1 + len2 + 1) * sizeof(*concat));
814 memcpy(concat, s1->begin, len1 * sizeof(*concat));
815 const char *const src = s2->begin;
816 for (size_t i = 0; i != len2 + 1; ++i) {
820 return (wide_string_t){ concat, len1 + len2 + 1 };
824 * Parse a string literal and set lexer_token.
826 static void parse_string_literal(void)
828 const unsigned start_linenr = lexer_token.source_position.linenr;
836 tc = parse_escape_sequence();
837 obstack_1grow(&symbol_obstack, (char) tc);
841 source_position_t source_position;
842 source_position.input_name = lexer_token.source_position.input_name;
843 source_position.linenr = start_linenr;
844 errorf(source_position, "string has no end");
845 lexer_token.type = T_ERROR;
854 obstack_1grow(&symbol_obstack, (char) c);
862 /* TODO: concatenate multiple strings separated by whitespace... */
864 /* add finishing 0 to the string */
865 obstack_1grow(&symbol_obstack, '\0');
866 const size_t size = (size_t)obstack_object_size(&symbol_obstack);
867 const char *const string = obstack_finish(&symbol_obstack);
869 #if 0 /* TODO hash */
870 /* check if there is already a copy of the string */
871 result = strset_insert(&stringset, string);
872 if(result != string) {
873 obstack_free(&symbol_obstack, string);
876 const char *const result = string;
879 lexer_token.type = T_STRING_LITERAL;
880 lexer_token.v.string.begin = result;
881 lexer_token.v.string.size = size;
885 * Parse a wide character constant and set lexer_token.
887 static void parse_wide_character_constant(void)
895 found_char = parse_escape_sequence();
899 parse_error("newline while parsing character constant");
905 goto end_of_wide_char_constant;
908 parse_error("EOF while parsing character constant");
909 lexer_token.type = T_ERROR;
913 if(found_char != 0) {
914 parse_error("more than 1 characters in character "
916 goto end_of_wide_char_constant;
925 end_of_wide_char_constant:
926 lexer_token.type = T_INTEGER;
927 lexer_token.v.intvalue = found_char;
928 lexer_token.datatype = type_wchar_t;
932 * Parse a wide string literal and set lexer_token.
934 static void parse_wide_string_literal(void)
936 const unsigned start_linenr = lexer_token.source_position.linenr;
944 wchar_rep_t tc = parse_escape_sequence();
945 obstack_grow(&symbol_obstack, &tc, sizeof(tc));
950 source_position_t source_position;
951 source_position.input_name = lexer_token.source_position.input_name;
952 source_position.linenr = start_linenr;
953 errorf(source_position, "string has no end");
954 lexer_token.type = T_ERROR;
964 obstack_grow(&symbol_obstack, &tc, sizeof(tc));
973 /* TODO: concatenate multiple strings separated by whitespace... */
975 /* add finishing 0 to the string */
976 wchar_rep_t nul = L'\0';
977 obstack_grow(&symbol_obstack, &nul, sizeof(nul));
978 const size_t size = (size_t)obstack_object_size(&symbol_obstack) / sizeof(wchar_rep_t);
979 const wchar_rep_t *const string = obstack_finish(&symbol_obstack);
981 #if 0 /* TODO hash */
982 /* check if there is already a copy of the string */
983 const wchar_rep_t *const result = strset_insert(&stringset, string);
984 if(result != string) {
985 obstack_free(&symbol_obstack, string);
988 const wchar_rep_t *const result = string;
991 lexer_token.type = T_WIDE_STRING_LITERAL;
992 lexer_token.v.wide_string.begin = result;
993 lexer_token.v.wide_string.size = size;
997 * Parse a character constant and set lexer_token.
999 static void parse_character_constant(void)
1001 const unsigned start_linenr = lexer_token.source_position.linenr;
1009 tc = parse_escape_sequence();
1010 obstack_1grow(&symbol_obstack, (char) tc);
1014 parse_error("newline while parsing character constant");
1019 source_position_t source_position;
1020 source_position.input_name = lexer_token.source_position.input_name;
1021 source_position.linenr = start_linenr;
1022 errorf(source_position, "EOF while parsing character constant");
1023 lexer_token.type = T_ERROR;
1029 goto end_of_char_constant;
1032 obstack_1grow(&symbol_obstack, (char) c);
1039 end_of_char_constant:;
1040 const size_t size = (size_t)obstack_object_size(&symbol_obstack);
1041 const char *const string = obstack_finish(&symbol_obstack);
1043 lexer_token.type = T_CHARS;
1044 lexer_token.v.string.begin = string;
1045 lexer_token.v.string.size = size;
1046 lexer_token.datatype = type_int;
1050 * Skip a multiline comment.
1052 static void skip_multiline_comment(void)
1054 unsigned start_linenr = lexer_token.source_position.linenr;
1061 /* TODO: nested comment, warn here */
1072 MATCH_NEWLINE(break;)
1075 source_position_t source_position;
1076 source_position.input_name = lexer_token.source_position.input_name;
1077 source_position.linenr = start_linenr;
1078 errorf(source_position, "at end of file while looking for comment end");
1090 * Skip a single line comment.
1092 static void skip_line_comment(void)
1110 /** The current preprocessor token. */
1111 static token_t pp_token;
1114 * Read the next preprocessor token.
1116 static inline void next_pp_token(void)
1118 lexer_next_preprocessing_token();
1119 pp_token = lexer_token;
1123 * Eat all preprocessor tokens until newline.
1125 static void eat_until_newline(void)
1127 while(pp_token.type != '\n' && pp_token.type != T_EOF) {
1133 * Handle the define directive.
1135 static void define_directive(void)
1137 lexer_next_preprocessing_token();
1138 if(lexer_token.type != T_IDENTIFIER) {
1139 parse_error("expected identifier after #define\n");
1140 eat_until_newline();
1145 * Handle the ifdef directive.
1147 static void ifdef_directive(int is_ifndef)
1150 lexer_next_preprocessing_token();
1151 //expect_identifier();
1156 * Handle the endif directive.
1158 static void endif_directive(void)
1164 * Parse the line directive.
1166 static void parse_line_directive(void)
1168 if(pp_token.type != T_INTEGER) {
1169 parse_error("expected integer");
1171 lexer_token.source_position.linenr = (unsigned int)(pp_token.v.intvalue - 1);
1174 if(pp_token.type == T_STRING_LITERAL) {
1175 lexer_token.source_position.input_name = pp_token.v.string.begin;
1179 eat_until_newline();
1189 STDC_CX_LIMITED_RANGE
1190 } stdc_pragma_kind_t;
1193 * STDC pragma values.
1200 } stdc_pragma_value_kind_t;
1203 * Parse a pragma directive.
1205 static void parse_pragma(void) {
1206 bool unknown_pragma = true;
1209 if (pp_token.v.symbol->pp_ID == TP_STDC) {
1210 stdc_pragma_kind_t kind = STDC_UNKNOWN;
1212 if (c_mode & _C99) {
1215 switch (pp_token.v.symbol->pp_ID) {
1216 case TP_FP_CONTRACT:
1217 kind = STDC_FP_CONTRACT;
1219 case TP_FENV_ACCESS:
1220 kind = STDC_FENV_ACCESS;
1222 case TP_CX_LIMITED_RANGE:
1223 kind = STDC_CX_LIMITED_RANGE;
1228 if (kind != STDC_UNKNOWN) {
1229 stdc_pragma_value_kind_t value = STDC_VALUE_UNKNOWN;
1231 switch (pp_token.v.symbol->pp_ID) {
1233 value = STDC_VALUE_ON;
1236 value = STDC_VALUE_OFF;
1239 value = STDC_VALUE_DEFAULT;
1244 if (value != STDC_VALUE_UNKNOWN) {
1245 unknown_pragma = false;
1247 errorf(pp_token.source_position, "bad STDC pragma argument");
1252 unknown_pragma = true;
1254 eat_until_newline();
1255 if (unknown_pragma && warning.unknown_pragmas) {
1256 warningf(pp_token.source_position, "encountered unknown #pragma");
1261 * Parse a preprocessor non-null directive.
1263 static void parse_preprocessor_identifier(void)
1265 assert(pp_token.type == T_IDENTIFIER);
1266 symbol_t *symbol = pp_token.v.symbol;
1268 switch(symbol->pp_ID) {
1270 printf("include - enable header name parsing!\n");
1286 parse_line_directive();
1293 /* TODO; output the rest of the line */
1294 parse_error("#error directive: ");
1303 * Parse a preprocessor directive.
1305 static void parse_preprocessor_directive(void)
1309 switch(pp_token.type) {
1311 parse_preprocessor_identifier();
1314 parse_line_directive();
1317 /* NULL directive, see § 6.10.7 */
1320 parse_error("invalid preprocessor directive");
1321 eat_until_newline();
1326 #define MAYBE_PROLOG \
1331 #define MAYBE(ch, set_type) \
1334 lexer_token.type = set_type; \
1337 #define ELSE_CODE(code) \
1341 } /* end of while(1) */ \
1344 #define ELSE(set_type) \
1346 lexer_token.type = set_type; \
1350 void lexer_next_preprocessing_token(void)
1360 lexer_token.type = '\n';
1366 /* might be a wide string ( L"string" ) */
1367 if(lexer_token.type == T_IDENTIFIER &&
1368 lexer_token.v.symbol == symbol_L) {
1370 parse_wide_string_literal();
1371 } else if(c == '\'') {
1372 parse_wide_character_constant();
1382 parse_string_literal();
1386 parse_character_constant();
1408 MAYBE('.', T_DOTDOTDOT)
1412 lexer_token.type = '.';
1418 MAYBE('&', T_ANDAND)
1419 MAYBE('=', T_ANDEQUAL)
1423 MAYBE('=', T_ASTERISKEQUAL)
1427 MAYBE('+', T_PLUSPLUS)
1428 MAYBE('=', T_PLUSEQUAL)
1432 MAYBE('>', T_MINUSGREATER)
1433 MAYBE('-', T_MINUSMINUS)
1434 MAYBE('=', T_MINUSEQUAL)
1438 MAYBE('=', T_EXCLAMATIONMARKEQUAL)
1442 MAYBE('=', T_SLASHEQUAL)
1445 skip_multiline_comment();
1446 lexer_next_preprocessing_token();
1450 skip_line_comment();
1451 lexer_next_preprocessing_token();
1456 MAYBE('>', T_PERCENTGREATER)
1457 MAYBE('=', T_PERCENTEQUAL)
1462 MAYBE(':', T_PERCENTCOLONPERCENTCOLON)
1466 lexer_token.type = T_PERCENTCOLON;
1469 ELSE(T_PERCENTCOLON)
1473 MAYBE(':', T_LESSCOLON)
1474 MAYBE('%', T_LESSPERCENT)
1475 MAYBE('=', T_LESSEQUAL)
1478 MAYBE('=', T_LESSLESSEQUAL)
1483 MAYBE('=', T_GREATEREQUAL)
1486 MAYBE('=', T_GREATERGREATEREQUAL)
1487 ELSE(T_GREATERGREATER)
1491 MAYBE('=', T_CARETEQUAL)
1495 MAYBE('=', T_PIPEEQUAL)
1496 MAYBE('|', T_PIPEPIPE)
1500 MAYBE('>', T_COLONGREATER)
1504 MAYBE('=', T_EQUALEQUAL)
1508 MAYBE('#', T_HASHHASH)
1522 lexer_token.type = c;
1527 lexer_token.type = T_EOF;
1532 errorf(lexer_token.source_position, "unknown character '%c' found\n", c);
1533 lexer_token.type = T_ERROR;
1539 void lexer_next_token(void)
1541 lexer_next_preprocessing_token();
1542 if(lexer_token.type != '\n')
1547 lexer_next_preprocessing_token();
1548 } while(lexer_token.type == '\n');
1550 if(lexer_token.type == '#') {
1551 parse_preprocessor_directive();
1556 void init_lexer(void)
1558 strset_init(&stringset);
1561 void lexer_open_stream(FILE *stream, const char *input_name)
1564 lexer_token.source_position.linenr = 0;
1565 lexer_token.source_position.input_name = input_name;
1567 symbol_L = symbol_table_insert("L");
1571 /* place a virtual \n at the beginning so the lexer knows that we're
1572 * at the beginning of a line */
1576 void exit_lexer(void)
1578 strset_destroy(&stringset);
1581 static __attribute__((unused))
1582 void dbg_pos(const source_position_t source_position)
1584 fprintf(stdout, "%s:%u\n", source_position.input_name,
1585 source_position.linenr);