#include "parser.h" #include #include #include #include #include #include std::unordered_set type_names; extern FILE * yyin; static const char * input_fname; void parse(const char * filename) { input_fname = filename; yyin = fopen(filename, "r"); if (yyin == NULL) { fprintf(stderr, "Error opening \"%s\"\n", filename); return; } if (yyparse() != 0) { fprintf(stderr, "Parsing error\n"); return; } } static char * read_file(const char * filename, size_t * length) { int fd = open(filename, O_RDONLY); if (fd < 0) return NULL; size_t size = (size_t)lseek(fd, 0, SEEK_END); lseek(fd, 0, SEEK_SET); *length = size; size_t n_bytes_read = 0u; char * buf = (char *)malloc(size); if (buf == NULL) { close(fd); return NULL; } for (;;) { off_t rd_size = read(fd, &buf[n_bytes_read], size - n_bytes_read); if (rd_size <= 0) break; n_bytes_read += (size_t)rd_size; if (n_bytes_read >= size) break; } if (n_bytes_read != size) { free(buf); close(fd); return NULL; } close(fd); return buf; } int orig_line = -1; const char * orig_file = NULL; static void scan_source_line_for_orig_location(char * source_line, int max_length) { int state = 0; char * orig_file_build = NULL; for (int i = 0; (i < max_length) && (source_line[i] != '\n'); i++) { char c = source_line[i]; switch (state) { case 0: if (c == '#') { state++; } else if (c != ' ') { return; } break; case 1: if (('0' <= c) && (c <= '9')) { orig_line = c - '0'; state++; } else if (c != ' ') { return; } break; case 2: if (('0' <= c) && (c <= '9')) { orig_line *= 10; orig_line += c - '0'; } else if (c == ' ') { state++; } else { return; } break; case 3: if (c == '"') { orig_line--; orig_file_build = &source_line[i + 1]; state++; } else if (c != ' ') { return; } break; case 4: if (c == '"') { source_line[i] = '\0'; orig_file = orig_file_build; return; } break; } } } static void display_error_source(int line, int column) { if (line < 0) return; size_t length = 0u; char * file = read_file(input_fname, &length); if (file == NULL) return; int search_line = 1; const char * line_begin = NULL; bool scan_for_location = true; for (size_t i = 0u; i < length; i++) { if (search_line == line) { line_begin = &file[i]; search_line++; } if (scan_for_location) { scan_source_line_for_orig_location(&file[i], length - i); scan_for_location = false; } if (file[i] == '\n') { if (line_begin != NULL) { file[i] = '\0'; fprintf(stderr, "%s\n", line_begin); for (int i = 0; i < (column - 1); i++) { fprintf(stderr, " "); } fprintf(stderr, "^\n"); if (orig_file != NULL) { fprintf(stderr, "Originally from %s:%d\n", orig_file, orig_line); } break; } search_line++; orig_line++; scan_for_location = true; } } } void handle_parse_error(const char * str, const YYLTYPE * yylloc) { fprintf(stderr, "error: %s (line %d, column %d)\n", str, yylloc->last_line, yylloc->last_column); display_error_source(yylloc->last_line, yylloc->last_column); } void observe_type_name(const std::string & type_name) { type_names.insert(type_name); } static const char * builtin_types[] = { "__builtin_va_list", }; bool is_type_name(const std::string & type_name) { if (type_names.count(type_name) != 0u) { return true; } for (size_t i = 0u; i < sizeof(builtin_types) / sizeof(builtin_types[0]); i++) { if (type_name == builtin_types[i]) { return true; } } return false; }