You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在flex/lex中获取当前词法分析行用于yyerror错误提示

问题:Flex+Bison开发AQL解析器时,如何正确获取语法错误所在行内容?

我正在用flex+bison开发一款简易AQL解析器,想要在语法错误发生时给出友好提示,格式如下:

Syntax error:
<line_index>: INSERT { name: "John Doe", 1123: 2, is_working: true } IN users
                                         ^^^^

已经拿到了错误的行号和列号,但没法正确获取错误行的内容。我尝试用全局行缓冲区current_line,在YY_USER_ACTION宏里写入yytext内容,代码如下:

#define YY_USER_ACTION \
    strcpy(current_line+cl_length, yytext); \
    for(int i = 0; yytext[i] != '\0'; i++) { \
        if(yytext[i] == '\n') { \
            memset(current_line, 0, cl_length);
            cl_length = 0;
        } else {
            cl_length++;
        }
    }
}

但因为用了解析Python式缩进作用域的起始条件,导致行首出现重复字符。有没有其他借助flex宏实现的方法?


可行解决方案

方法1:调整行缓存维护逻辑,规避起始条件重复扫描

问题根源是缩进起始条件下,flex可能重复扫描行首内容,导致YY_USER_ACTION重复写入行缓存。可以针对性修改逻辑:

  • 仅在非缩进起始条件下写入行内容
  • 严格控制换行时的缓存重置操作

修改后的YY_USER_ACTION示例:

#define YY_USER_ACTION \
    /* 替换成你的缩进起始条件判断宏 */ \
    if (!IN_INDENT_SCOPE) { \
        /* 用strncat避免缓冲区溢出 */ \
        strncat(current_line, yytext, sizeof(current_line) - cl_length - 1); \
    } \
    for(int i = 0; yytext[i] != '\0'; i++) { \
        if(yytext[i] == '\n') { \
            memset(current_line, 0, sizeof(current_line)); \
            cl_length = 0; \
            yylineno++; \
        } else { \
            if (!IN_INDENT_SCOPE) { \
                cl_length++; \
            } \
        } \
    }

方法2:将行内容维护放在词法规则中,替代YY_USER_ACTION

放弃在YY_USER_ACTION中统一处理,转而在flex的词法规则里针对性维护行内容,能更灵活地避开起始条件的干扰:

char current_line[256];
int current_col = 0;

%option yylineno

%%
\n          { 
                memset(current_line, 0, sizeof(current_line)); 
                current_col = 0; 
            }
.|\t        { 
                /* 仅在非缩进起始条件下更新行内容 */
                if (!IN_INDENT_SCOPE && current_col < sizeof(current_line)-1) {
                    current_line[current_col++] = *yytext;
                }
            }
/* 你的其他词法规则,包括缩进相关的起始条件规则 */
%%

方法3:错误发生时从输入流回溯读取目标行

如果维护行缓存的问题难以解决,可以直接在错误触发时,从输入流中定位并读取目标行:

void print_syntax_error(int line_num, int col_num) {
    char error_line[256];
    long current_pos = ftell(yyin);
    
    // 回溯到文件开头,定位到目标行
    fseek(yyin, 0, SEEK_SET);
    for(int i = 1; i < line_num; i++) {
        while(fgetc(yyin) != '\n' && !feof(yyin));
    }
    // 读取错误行内容
    fgets(error_line, sizeof(error_line), yyin);
    // 恢复输入流到错误前的位置
    fseek(yyin, current_pos, SEEK_SET);
    
    // 打印错误提示
    printf("Syntax error:\n%d: %s", line_num, error_line);
    // 打印错误位置标记
    printf("%*s^^^^\n", col_num - 1, "");
}

内容的提问来源于stack exchange,提问作者vlad613

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 07:47:29