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

能否在Bison动作中控制规则匹配?DIMACS格式容错解析咨询

问题解答:Bison中实现容错式解析DIMACS格式

核心结论

不能通过Bison动作来指示规则是否匹配。Bison的语法分析基于规则的匹配优先逻辑,动作是规则成功匹配后执行的代码,无法回溯或否定已经完成的匹配。必须通过语法规则本身或错误恢复机制来实现跳过不支持行的需求。

两种场景的具体实现方案

场景一:Flex返回统一的DESCRIPTOR令牌

如果Flex中把所有行描述符都返回为DESCRIPTOR令牌(比如^[a-z] { return DESCRIPTOR; }),需要在Bison规则中先判断描述符的具体值,再决定是否处理:

  1. Flex补充规则:添加匹配行剩余内容的规则,方便跳过整行:
^[a-z]          { yylval.c = yytext[0]; return DESCRIPTOR; } // 将字符存入yylval
[^\n]*\n        { return REST_OF_LINE; }
[0-9]+          { yylval.i = atoi(yytext); return INTEGER; }
[ \t]+          { /* 跳过空白字符 */ }
^c[^\n]*\n      { /* 直接跳过注释行,不提交给Bison */ }
  1. Bison规则编写:区分支持的行和需要跳过的行:
%union {
    int i;
    char c;
}
%token <c> DESCRIPTOR
%token <i> INTEGER
%token REST_OF_LINE

%%

// 主解析规则:edge格式的文件内容
edge_file: 
    'p' "edge" '\n' edge_content
    ;

edge_content: 
    /* 空规则 */
    | edge_content edge_supported_line
    | edge_content edge_unsupported_line
    ;

// 处理支持的e行
edge_supported_line:
    DESCRIPTOR INTEGER INTEGER '\n' {
        if ($1 == 'e') {
            do_something($2, $3); // 执行e行的业务逻辑
        }
    }
    ;

// 跳过不支持的行
edge_unsupported_line:
    DESCRIPTOR REST_OF_LINE {
        fprintf(stderr, "Warning: 跳过不支持的行,起始字符为 '%c'\n", $1);
    }
    ;

%%

场景二:Flex返回单个字符作为令牌

如果Flex直接返回描述符字符作为令牌(^[a-z] { return yytext[0]; }),可以更清晰地编写规则,同时用两种方式处理不支持的行:

方式1:显式定义不支持的描述符

^[a-z]          { return yytext[0]; }
[0-9]+          { yylval.i = atoi(yytext); return INTEGER; }
[ \t]+          { /* 跳过空白字符 */ }
^c[^\n]*\n      { /* 跳过注释行 */ }
[^\n]*\n        { return EOL; } // 匹配行尾
%union { int i; }
%token <i> INTEGER
%token EOL

%%

edge_file:
    'p' "edge" EOL edge_content
    ;

edge_content:
    /* 空规则 */
    | edge_content edge_supported_line
    | edge_content edge_unsupported_line
    ;

// 处理支持的e行
edge_supported_line:
    'e' INTEGER INTEGER EOL { do_something($2, $3); }
    ;

// 匹配所有不支持的描述符
edge_unsupported_line:
    UNSUPPORTED_DESCRIPTOR EOL {
        fprintf(stderr, "Warning: 跳过不支持的行,起始字符为 '%c'\n", $1);
    }
    | UNSUPPORTED_DESCRIPTOR .* EOL { // 处理带内容的不支持行
        fprintf(stderr, "Warning: 跳过不支持的行,起始字符为 '%c'\n", $1);
    }
    ;

// 定义所有非'e'的小写字母为不支持描述符
UNSUPPORTED_DESCRIPTOR: 'a'|'b'|'c'|'d'|'f'|'g'|'h'|'i'|'j'|'k'|'l'|'m'|'n'|'o'|'p'|'q'|'r'|'s'|'t'|'u'|'v'|'w'|'x'|'y'|'z'
    ;

%%

方式2:利用Bison错误恢复机制

这种方式更简洁,无需枚举所有不支持的字符:

edge_file:
    'p' "edge" EOL edge_content
    ;

edge_content:
    /* 空规则 */
    | edge_content edge_supported_line
    | edge_content error EOL {
        yyerror("跳过无效行");
        yyerrok; // 恢复解析状态,继续处理后续内容
    }
    ;

edge_supported_line:
    'e' INTEGER INTEGER EOL { do_something($2, $3); }
    ;

当Bison遇到无法匹配的行(比如a开头的行),会触发error规则,跳过直到EOL,再通过yyerrok恢复解析流程。

最佳实践建议

  1. 优先选择场景二:Flex返回单个字符令牌,Bison规则更直观,维护成本更低。
  2. 注释行在Flex中直接跳过:不需要交给Bison处理,减少解析逻辑复杂度。
  3. 用error规则做错误恢复:避免枚举所有不支持的字符,代码更简洁。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 15:26:07