// // Created for error reporting // #include #include #include #include "parser.h" #include "../utils/file.h" // ANSI 转义序列颜色代码 #define ANSI_COLOR_RED "\033[31m" #define ANSI_COLOR_YELLOW "\033[33m" #define ANSI_COLOR_CYAN "\033[36m" #define ANSI_COLOR_RESET "\033[0m" // 获取指定行的代码 static char* get_line_at(const char* source, int line_number) { if (source == NULL || line_number <= 0) return NULL; int current_line = 1; const char* line_start = source; const char* p = source; // 找到指定行的起始位置 while (*p != '\0') { if (current_line == line_number) { line_start = p; break; } if (*p == '\n') { current_line++; } p++; } // 如果没找到指定行,返回NULL if (current_line != line_number) return NULL; // 找到行的结束位置 p = line_start; while (*p != '\0' && *p != '\n') p++; // 复制行内容 int length = p - line_start; char* line = (char*)malloc(length + 1); if (line == NULL) return NULL; strncpy(line, line_start, length); line[length] = '\0'; return line; } // 在指定位置打印错误指示箭头 static void print_error_indicator(int column) { // 打印错误指示箭头 fprintf(stderr, " | " ANSI_COLOR_RED); for (int i = 1; i < column; i++) { fprintf(stderr, "~"); } // 打印错误指示箭头 fprintf(stderr, "^" ANSI_COLOR_RESET "\n"); } // 在当前token位置报告错误 void parser_error_at_current(Parser* parser, const char* message) { parser_error_at(parser, &parser->current_token, message); exit(0); } void parser_error_at(Parser* parser, Token* token, const char* message) { if (parser->had_error) return; // 添加错误到errors数组 parser->error_count++; parser->errors = realloc(parser->errors, sizeof(*parser->errors) * parser->error_count); parser->errors[parser->error_count - 1].message = strdup(message); parser->errors[parser->error_count - 1].line = token->line; parser->errors[parser->error_count - 1].column = token->column; // 打印错误位置和消息 fprintf(stderr, ANSI_COLOR_CYAN "%s" ANSI_COLOR_RESET ":" ANSI_COLOR_YELLOW "%d:%d" ANSI_COLOR_RESET ": " ANSI_COLOR_RED "Syntax error: %s" ANSI_COLOR_RESET "\n", parser->filename, token->line, token->column, message); char* source = read_file(parser->filename); if (source != NULL) { char* line = get_line_at(source, token->line); if (line != NULL) { fprintf(stderr, "%4d | %s\n", token->line, line); print_error_indicator(token->column); free(line); } free(source); } }