3 #include "diagnostic.h"
6 #include "symbol_table_t.h"
8 #include "adt/strset.h"
12 #include "target_architecture.h"
25 /* No strtold on windows and no replacement yet */
26 #define strtold(s, e) strtod(s, e)
29 #if defined HAS_SIGNED_CHAR
30 typedef signed char char_type;
31 #elif defined HAS_UNSIGNED_CHAR
32 typedef unsigned char char_type;
34 # error signedness of char not determined
41 static char buf[1024 + MAX_PUTBACK];
42 static const char *bufend;
43 static const char *bufpos;
44 static strset_t stringset;
46 static void error_prefix_at(const char *input_name, unsigned linenr)
48 fprintf(stderr, "%s:%u: Error: ", input_name, linenr);
51 static void error_prefix(void)
53 error_prefix_at(lexer_token.source_position.input_name,
54 lexer_token.source_position.linenr);
57 static void parse_error(const char *msg)
60 fprintf(stderr, "%s\n", msg);
63 static inline void next_real_char(void)
66 if(bufpos >= bufend) {
67 size_t s = fread(buf + MAX_PUTBACK, 1, sizeof(buf) - MAX_PUTBACK,
73 bufpos = buf + MAX_PUTBACK;
74 bufend = buf + MAX_PUTBACK + s;
79 static inline void put_back(int pc)
81 assert(bufpos >= buf);
82 //assert(bufpos < buf+MAX_PUTBACK || *bufpos == pc);
84 char *p = buf + (bufpos - buf);
87 /* going backwards in the buffer is legal as long as it's not more often
92 printf("putback '%c'\n", pc);
96 static inline void next_char(void);
98 #define MATCH_NEWLINE(code) \
104 lexer_token.source_position.linenr++; \
108 lexer_token.source_position.linenr++; \
111 #define eat(c_type) do { assert(c == c_type); next_char(); } while(0)
113 static void maybe_concat_lines(void)
118 MATCH_NEWLINE(return;)
128 static inline void next_char(void)
132 /* filter trigraphs */
133 if(UNLIKELY(c == '\\')) {
134 maybe_concat_lines();
135 goto end_of_next_char;
139 goto end_of_next_char;
142 if(LIKELY(c != '?')) {
145 goto end_of_next_char;
150 case '=': c = '#'; break;
151 case '(': c = '['; break;
152 case '/': c = '\\'; maybe_concat_lines(); break;
153 case ')': c = ']'; break;
154 case '\'': c = '^'; break;
155 case '<': c = '{'; break;
156 case '!': c = '|'; break;
157 case '>': c = '}'; break;
158 case '-': c = '~'; break;
168 printf("nchar '%c'\n", c);
172 #define SYMBOL_CHARS \
239 static void parse_symbol(void)
244 obstack_1grow(&symbol_obstack, (char) c);
251 obstack_1grow(&symbol_obstack, (char) c);
261 obstack_1grow(&symbol_obstack, '\0');
263 string = obstack_finish(&symbol_obstack);
264 symbol = symbol_table_insert(string);
266 lexer_token.type = symbol->ID;
267 lexer_token.v.symbol = symbol;
269 if(symbol->string != string) {
270 obstack_free(&symbol_obstack, string);
274 static void parse_integer_suffix(bool is_oct_hex)
276 bool is_unsigned = false;
277 bool min_long = false;
278 bool min_longlong = false;
280 if(c == 'U' || c == 'u') {
283 if(c == 'L' || c == 'l') {
286 if(c == 'L' || c == 'l') {
291 } else if(c == 'l' || c == 'L') {
294 if(c == 'l' || c == 'L') {
297 if(c == 'u' || c == 'U') {
301 } else if(c == 'u' || c == 'U') {
304 lexer_token.datatype = type_unsigned_long;
309 long long v = lexer_token.v.intvalue;
311 if(v >= TARGET_INT_MIN && v <= TARGET_INT_MAX) {
312 lexer_token.datatype = type_int;
314 } else if(is_oct_hex && v >= 0 && v <= TARGET_UINT_MAX) {
315 lexer_token.datatype = type_unsigned_int;
320 if(v >= TARGET_LONG_MIN && v <= TARGET_LONG_MAX) {
321 lexer_token.datatype = type_long;
323 } else if(is_oct_hex && v >= 0 && v <= TARGET_ULONG_MAX) {
324 lexer_token.datatype = type_unsigned_long;
328 unsigned long long uv = (unsigned long long) v;
329 if(is_oct_hex && uv > (unsigned long long) TARGET_LONGLONG_MAX) {
330 lexer_token.datatype = type_unsigned_long_long;
334 lexer_token.datatype = type_long_long;
336 unsigned long long v = (unsigned long long) lexer_token.v.intvalue;
337 if(!min_long && v <= TARGET_UINT_MAX) {
338 lexer_token.datatype = type_unsigned_int;
341 if(!min_longlong && v <= TARGET_ULONG_MAX) {
342 lexer_token.datatype = type_unsigned_long;
345 lexer_token.datatype = type_unsigned_long_long;
349 static void parse_floating_suffix(void)
352 /* TODO: do something usefull with the suffixes... */
356 lexer_token.datatype = type_float;
361 lexer_token.datatype = type_long_double;
364 lexer_token.datatype = type_double;
370 * A replacement for strtoull. Only those parts needed for
371 * our parser are implemented.
373 static unsigned long long parse_int_string(const char *s, const char **endptr, int base) {
374 unsigned long long v = 0;
379 /* check for overrun */
380 if (v >= 0x1000000000000000ULL)
382 switch (tolower(*s)) {
383 case '0': v <<= 4; break;
384 case '1': v <<= 4; v |= 0x1; break;
385 case '2': v <<= 4; v |= 0x2; break;
386 case '3': v <<= 4; v |= 0x3; break;
387 case '4': v <<= 4; v |= 0x4; break;
388 case '5': v <<= 4; v |= 0x5; break;
389 case '6': v <<= 4; v |= 0x6; break;
390 case '7': v <<= 4; v |= 0x7; break;
391 case '8': v <<= 4; v |= 0x8; break;
392 case '9': v <<= 4; v |= 0x9; break;
393 case 'a': v <<= 4; v |= 0xa; break;
394 case 'b': v <<= 4; v |= 0xb; break;
395 case 'c': v <<= 4; v |= 0xc; break;
396 case 'd': v <<= 4; v |= 0xd; break;
397 case 'e': v <<= 4; v |= 0xe; break;
398 case 'f': v <<= 4; v |= 0xf; break;
406 /* check for overrun */
407 if (v >= 0x2000000000000000ULL)
409 switch (tolower(*s)) {
410 case '0': v <<= 3; break;
411 case '1': v <<= 3; v |= 1; break;
412 case '2': v <<= 3; v |= 2; break;
413 case '3': v <<= 3; v |= 3; break;
414 case '4': v <<= 3; v |= 4; break;
415 case '5': v <<= 3; v |= 5; break;
416 case '6': v <<= 3; v |= 6; break;
417 case '7': v <<= 3; v |= 7; break;
425 /* check for overrun */
426 if (v > 0x1999999999999999ULL)
428 switch (tolower(*s)) {
429 case '0': v *= 10; break;
430 case '1': v *= 10; v += 1; break;
431 case '2': v *= 10; v += 2; break;
432 case '3': v *= 10; v += 3; break;
433 case '4': v *= 10; v += 4; break;
434 case '5': v *= 10; v += 5; break;
435 case '6': v *= 10; v += 6; break;
436 case '7': v *= 10; v += 7; break;
437 case '8': v *= 10; v += 8; break;
438 case '9': v *= 10; v += 9; break;
453 static void parse_number_hex(void)
455 assert(c == 'x' || c == 'X');
459 obstack_1grow(&symbol_obstack, (char) c);
462 obstack_1grow(&symbol_obstack, '\0');
463 char *string = obstack_finish(&symbol_obstack);
465 if(c == '.' || c == 'p' || c == 'P') {
467 panic("Hex floating point numbers not implemented yet");
469 if(*string == '\0') {
470 parse_error("invalid hex number");
471 lexer_token.type = T_ERROR;
475 lexer_token.type = T_INTEGER;
476 lexer_token.v.intvalue = parse_int_string(string, &endptr, 16);
477 if(*endptr != '\0') {
478 parse_error("hex number literal too long");
481 obstack_free(&symbol_obstack, string);
482 parse_integer_suffix(true);
485 static inline bool is_octal_digit(int chr)
487 return '0' <= chr && chr <= '7';
490 static void parse_number_oct(void)
492 while(is_octal_digit(c)) {
493 obstack_1grow(&symbol_obstack, (char) c);
496 obstack_1grow(&symbol_obstack, '\0');
497 char *string = obstack_finish(&symbol_obstack);
500 lexer_token.type = T_INTEGER;
501 lexer_token.v.intvalue = parse_int_string(string, &endptr, 8);
502 if(*endptr != '\0') {
503 parse_error("octal number literal too long");
506 obstack_free(&symbol_obstack, string);
507 parse_integer_suffix(true);
510 static void parse_number_dec(void)
512 bool is_float = false;
514 obstack_1grow(&symbol_obstack, (char) c);
519 obstack_1grow(&symbol_obstack, '.');
523 obstack_1grow(&symbol_obstack, (char) c);
528 if(c == 'e' || c == 'E') {
529 obstack_1grow(&symbol_obstack, 'e');
532 if(c == '-' || c == '+') {
533 obstack_1grow(&symbol_obstack, (char) c);
538 obstack_1grow(&symbol_obstack, (char) c);
544 obstack_1grow(&symbol_obstack, '\0');
545 char *string = obstack_finish(&symbol_obstack);
549 lexer_token.type = T_FLOATINGPOINT;
550 lexer_token.v.floatvalue = strtold(string, &endptr);
552 if(*endptr != '\0') {
553 parse_error("invalid number literal");
556 parse_floating_suffix();
559 lexer_token.type = T_INTEGER;
560 lexer_token.v.intvalue = parse_int_string(string, &endptr, 10);
562 if(*endptr != '\0') {
563 parse_error("invalid number literal");
566 parse_integer_suffix(false);
568 obstack_free(&symbol_obstack, string);
571 static void parse_number(void)
593 parse_error("invalid octal number");
594 lexer_token.type = T_ERROR;
600 obstack_1grow(&symbol_obstack, '0');
609 static int parse_octal_sequence(const int first_digit)
611 assert(is_octal_digit(first_digit));
612 int value = first_digit - '0';
613 if (!is_octal_digit(c)) return value;
614 value = 8 * value + c - '0';
616 if (!is_octal_digit(c)) return value;
617 value = 8 * value + c - '0';
619 return (char_type)value;
622 static int parse_hex_sequence(void)
626 if (c >= '0' && c <= '9') {
627 value = 16 * value + c - '0';
628 } else if ('A' <= c && c <= 'F') {
629 value = 16 * value + c - 'A' + 10;
630 } else if ('a' <= c && c <= 'f') {
631 value = 16 * value + c - 'a' + 10;
638 return (char_type)value;
641 static int parse_escape_sequence(void)
649 case '"': return '"';
650 case '\'': return '\'';
651 case '\\': return '\\';
652 case '?': return '\?';
653 case 'a': return '\a';
654 case 'b': return '\b';
655 case 'f': return '\f';
656 case 'n': return '\n';
657 case 'r': return '\r';
658 case 't': return '\t';
659 case 'v': return '\v';
661 return parse_hex_sequence();
670 return parse_octal_sequence(ec);
672 parse_error("reached end of file while parsing escape sequence");
675 parse_error("unknown escape sequence");
680 const char *concat_strings(const char *s1, const char *s2)
682 size_t len1 = strlen(s1);
683 size_t len2 = strlen(s2);
685 char *concat = obstack_alloc(&symbol_obstack, len1 + len2 + 1);
686 memcpy(concat, s1, len1);
687 memcpy(concat + len1, s2, len2 + 1);
689 const char *result = strset_insert(&stringset, concat);
690 if(result != concat) {
691 obstack_free(&symbol_obstack, concat);
697 static void parse_string_literal(void)
699 unsigned start_linenr = lexer_token.source_position.linenr;
710 tc = parse_escape_sequence();
711 obstack_1grow(&symbol_obstack, (char) tc);
715 error_prefix_at(lexer_token.source_position.input_name,
717 fprintf(stderr, "string has no end\n");
718 lexer_token.type = T_ERROR;
726 obstack_1grow(&symbol_obstack, (char) c);
734 /* TODO: concatenate multiple strings separated by whitespace... */
736 /* add finishing 0 to the string */
737 obstack_1grow(&symbol_obstack, '\0');
738 string = obstack_finish(&symbol_obstack);
740 /* check if there is already a copy of the string */
741 result = strset_insert(&stringset, string);
742 if(result != string) {
743 obstack_free(&symbol_obstack, string);
746 lexer_token.type = T_STRING_LITERAL;
747 lexer_token.v.string = result;
750 static void parse_wide_character_constant(void)
758 found_char = parse_escape_sequence();
762 parse_error("newline while parsing character constant");
768 goto end_of_wide_char_constant;
771 parse_error("EOF while parsing character constant");
772 lexer_token.type = T_ERROR;
776 if(found_char != 0) {
777 parse_error("more than 1 characters in character "
779 goto end_of_wide_char_constant;
788 end_of_wide_char_constant:
789 lexer_token.type = T_INTEGER;
790 lexer_token.v.intvalue = found_char;
791 lexer_token.datatype = type_wchar_t;
794 static void parse_wide_string_literal(void)
796 const unsigned start_linenr = lexer_token.source_position.linenr;
804 wchar_rep_t tc = parse_escape_sequence();
805 obstack_grow(&symbol_obstack, &tc, sizeof(tc));
810 error_prefix_at(lexer_token.source_position.input_name,
812 fprintf(stderr, "string has no end\n");
813 lexer_token.type = T_ERROR;
822 obstack_grow(&symbol_obstack, &tc, sizeof(tc));
831 /* TODO: concatenate multiple strings separated by whitespace... */
833 /* add finishing 0 to the string */
834 wchar_rep_t nul = L'\0';
835 obstack_grow(&symbol_obstack, &nul, sizeof(nul));
836 const size_t size = (size_t)obstack_object_size(&symbol_obstack) / sizeof(wchar_rep_t);
837 const wchar_rep_t *const string = obstack_finish(&symbol_obstack);
839 #if 0 /* TODO hash */
840 /* check if there is already a copy of the string */
841 const wchar_rep_t *const result = strset_insert(&stringset, string);
842 if(result != string) {
843 obstack_free(&symbol_obstack, string);
846 const wchar_rep_t *const result = string;
849 lexer_token.type = T_WIDE_STRING_LITERAL;
850 lexer_token.v.wide_string.begin = result;
851 lexer_token.v.wide_string.size = size;
854 static void parse_character_constant(void)
862 found_char = parse_escape_sequence();
866 parse_error("newline while parsing character constant");
872 goto end_of_char_constant;
875 parse_error("EOF while parsing character constant");
876 lexer_token.type = T_ERROR;
880 if(found_char != 0) {
881 parse_error("more than 1 characters in character "
883 goto end_of_char_constant;
892 end_of_char_constant:
893 lexer_token.type = T_INTEGER;
894 lexer_token.v.intvalue = found_char;
895 lexer_token.datatype = type_int;
898 static void skip_multiline_comment(void)
900 unsigned start_linenr = lexer_token.source_position.linenr;
912 MATCH_NEWLINE(break;)
915 error_prefix_at(lexer_token.source_position.input_name,
917 fprintf(stderr, "at end of file while looking for comment end\n");
927 static void skip_line_comment(void)
945 static token_t pp_token;
947 static inline void next_pp_token(void)
949 lexer_next_preprocessing_token();
950 pp_token = lexer_token;
953 static void eat_until_newline(void)
955 while(pp_token.type != '\n' && pp_token.type != T_EOF) {
960 static void error_directive(void)
963 fprintf(stderr, "#error directive: \n");
965 /* parse pp-tokens until new-line */
968 static void define_directive(void)
970 lexer_next_preprocessing_token();
971 if(lexer_token.type != T_IDENTIFIER) {
972 parse_error("expected identifier after #define\n");
977 static void ifdef_directive(int is_ifndef)
980 lexer_next_preprocessing_token();
981 //expect_identifier();
985 static void endif_directive(void)
990 static void parse_line_directive(void)
992 if(pp_token.type != T_INTEGER) {
993 parse_error("expected integer");
995 lexer_token.source_position.linenr = (unsigned int)(pp_token.v.intvalue - 1);
998 if(pp_token.type == T_STRING_LITERAL) {
999 lexer_token.source_position.input_name = pp_token.v.string;
1003 eat_until_newline();
1006 static void parse_preprocessor_identifier(void)
1008 assert(pp_token.type == T_IDENTIFIER);
1009 symbol_t *symbol = pp_token.v.symbol;
1011 switch(symbol->pp_ID) {
1013 printf("include - enable header name parsing!\n");
1029 parse_line_directive();
1039 warningf(lexer_token.source_position, "encountered unknown #pragma");
1040 eat_until_newline();
1045 static void parse_preprocessor_directive(void)
1049 switch(pp_token.type) {
1051 parse_preprocessor_identifier();
1054 parse_line_directive();
1057 parse_error("invalid preprocessor directive");
1058 eat_until_newline();
1063 #define MAYBE_PROLOG \
1068 #define MAYBE(ch, set_type) \
1071 lexer_token.type = set_type; \
1074 #define ELSE_CODE(code) \
1078 } /* end of while(1) */ \
1081 #define ELSE(set_type) \
1083 lexer_token.type = set_type; \
1087 void lexer_next_preprocessing_token(void)
1097 lexer_token.type = '\n';
1103 /* might be a wide string ( L"string" ) */
1104 if(lexer_token.type == T_IDENTIFIER &&
1105 lexer_token.v.symbol == symbol_L) {
1107 parse_wide_string_literal();
1108 } else if(c == '\'') {
1109 parse_wide_character_constant();
1119 parse_string_literal();
1123 parse_character_constant();
1145 MAYBE('.', T_DOTDOTDOT)
1149 lexer_token.type = '.';
1155 MAYBE('&', T_ANDAND)
1156 MAYBE('=', T_ANDEQUAL)
1160 MAYBE('=', T_ASTERISKEQUAL)
1164 MAYBE('+', T_PLUSPLUS)
1165 MAYBE('=', T_PLUSEQUAL)
1169 MAYBE('>', T_MINUSGREATER)
1170 MAYBE('-', T_MINUSMINUS)
1171 MAYBE('=', T_MINUSEQUAL)
1175 MAYBE('=', T_EXCLAMATIONMARKEQUAL)
1179 MAYBE('=', T_SLASHEQUAL)
1182 skip_multiline_comment();
1183 lexer_next_preprocessing_token();
1187 skip_line_comment();
1188 lexer_next_preprocessing_token();
1193 MAYBE('>', T_PERCENTGREATER)
1194 MAYBE('=', T_PERCENTEQUAL)
1199 MAYBE(':', T_PERCENTCOLONPERCENTCOLON)
1203 lexer_token.type = T_PERCENTCOLON;
1206 ELSE(T_PERCENTCOLON)
1210 MAYBE(':', T_LESSCOLON)
1211 MAYBE('%', T_LESSPERCENT)
1212 MAYBE('=', T_LESSEQUAL)
1215 MAYBE('=', T_LESSLESSEQUAL)
1220 MAYBE('=', T_GREATEREQUAL)
1223 MAYBE('=', T_GREATERGREATEREQUAL)
1224 ELSE(T_GREATERGREATER)
1228 MAYBE('=', T_CARETEQUAL)
1232 MAYBE('=', T_PIPEEQUAL)
1233 MAYBE('|', T_PIPEPIPE)
1237 MAYBE('>', T_COLONGREATER)
1241 MAYBE('=', T_EQUALEQUAL)
1245 MAYBE('#', T_HASHHASH)
1259 lexer_token.type = c;
1264 lexer_token.type = T_EOF;
1270 fprintf(stderr, "unknown character '%c' found\n", c);
1271 lexer_token.type = T_ERROR;
1277 void lexer_next_token(void)
1279 lexer_next_preprocessing_token();
1280 if(lexer_token.type != '\n')
1285 lexer_next_preprocessing_token();
1286 } while(lexer_token.type == '\n');
1288 if(lexer_token.type == '#') {
1289 parse_preprocessor_directive();
1294 void init_lexer(void)
1296 strset_init(&stringset);
1299 void lexer_open_stream(FILE *stream, const char *input_name)
1302 lexer_token.source_position.linenr = 0;
1303 lexer_token.source_position.input_name = input_name;
1305 symbol_L = symbol_table_insert("L");
1307 /* place a virtual \n at the beginning so the lexer knows that we're
1308 * at the beginning of a line */
1312 void exit_lexer(void)
1314 strset_destroy(&stringset);
1317 static __attribute__((unused))
1318 void dbg_pos(const source_position_t source_position)
1320 fprintf(stdout, "%s:%u\n", source_position.input_name,
1321 source_position.linenr);