Flex/Bison中如何处理此类优先级冲突问题?
问题背景
我正在开发项目内部配置文件的解析器,配置支持简单字符串或自定义「函数」,函数可接收字符串参数和代表「条件」的特殊类型。
Flex词法规则片段
[a-zA-Z][a-zA-Z0-9_/=\.]* SAVE_TOKEN; return TSTRING; "(" SAVE_TOKEN; return TLPAREN; ")" SAVE_TOKEN; return TRPAREN; "," SAVE_TOKEN; return TCOMMA; "==" SAVE_TOKEN; return TIFEQUAL; "!=" SAVE_TOKEN; return TIFNEQUAL;
Bison语法规则片段
condition: expr TIFEQUAL expr { $$ = new NCondition($1, TIFEQUAL, $3);} |expr TIFNEQUAL expr { $$ = new NCondition($1, TIFNEQUAL, $3);} ; string: TSTRING { $$ = new NString(*$1); } ; expr: string {$<nstring>$ = $1;} | string TLPAREN call_args TRPAREN { $$ = new NFunction($1, *$3); } ; call_args: { $$ = new CallArg(); } | expr { $$ = new CallArg(); } | call_args TCOMMA condition { $1->conds.push_back($3); } | call_args TCOMMA expr { $1->exprs.push_back($3); } ;
核心冲突
字符串类型允许包含等号「=」,而「=」又是TIFEQUAL(==)令牌的组成部分。比如解析函数调用function(arg1, arg2, arg_cond==condition)时,解析器会把arg_cond==匹配成TSTRING令牌,而非识别出==作为TIFEQUAL,导致条件无法正确解析。已知Flex采用贪心匹配原则,优先匹配最长的匹配项,这种情况是否需要在Bison层面解决?如果是,该怎么处理?
解决思路与步骤
这个冲突无法仅靠Bison解决,必须先调整Flex的词法规则——因为Flex的贪心匹配在词法阶段生效,一旦错误识别令牌,Bison根本无法获取正确的运算符信息。
1. 调整Flex规则优先级
Flex的规则匹配顺序是从上到下的,把==、!=这类运算符规则放在TSTRING规则的前面,确保Flex优先匹配完整的运算符令牌,而非将运算符的一部分纳入字符串。
调整后的Flex规则示例:
"==" SAVE_TOKEN; return TIFEQUAL; "!=" SAVE_TOKEN; return TIFNEQUAL; [a-zA-Z][a-zA-Z0-9_/\=\.]* SAVE_TOKEN; return TSTRING; "(" SAVE_TOKEN; return TLPAREN; ")" SAVE_TOKEN; return TRPAREN; "," SAVE_TOKEN; return TCOMMA;
2. 处理字符串中的单个=
调整规则后,单个=不会被运算符规则匹配,会自然被纳入TSTRING的匹配范围,满足你对字符串包含=的需求。比如arg_cond=会被正确识别为单个TSTRING,而arg_cond==condition会拆分为arg_cond(TSTRING)、==(TIFEQUAL)、condition(TSTRING)三个令牌。
3. Bison语法验证
调整Flex规则后,原有的Bison语法即可正常工作:对于function(arg1, arg2, arg_cond==condition),Bison会将arg_cond==condition解析为condition节点,并正确加入call_args的conds列表中。
内容的提问来源于stack exchange,提问作者Jie Liu

