使用Perl Yapp编写解析器遇S/R冲突与DEFAULT_GATEWAY报错求助
冲突原因
你遇到的移进/归约(S/R)冲突本质是上下文歧义:当解析器刚处理完INTERFACE IDENTIFIER、处于待解析if_attrs的状态时,遇到IP token会产生两个合法判断:
- 归约:认为
if_attrs已经为空结束,当前IP是全局IP DEFAULT_GATEWAY命令的开头 - 移进:将当前
IP入栈,作为接口属性IP ADDRESS规则的开头
Yapp默认会优先执行移进操作,这就导致解析全局ip default-gateway语句时,会错误尝试将其匹配为接口属性,遇到DEFAULT_GATEWAY不符合ADDRESS的预期就触发报错。
解决方案
方案1:改写语法消除歧义(最稳妥无副作用)
抽离IP开头的公共前缀,明确不同上下文的IP语句分支,从语法层面彻底消除冲突:
command: INTERFACE IDENTIFIER if_attrs | IP ip_command ; # 统一处理所有IP开头的命令 ip_command: DEFAULT_GATEWAY IP_ADDRESS # 若全局上下文不允许ip address语句,此分支可直接抛出语义错误 | ADDRESS IP_ADDRESS IP_ADDRESS { yyerror("全局上下文不允许配置ip address"); } ; if_attrs: # 空规则 | if_attrs if_attr ; if_attr: DESCRIPTION STRING | IP ADDRESS IP_ADDRESS IP_ADDRESS ;
方案2:优先级强制规则(适合不想大幅调整现有语法的场景)
通过优先级声明指定冲突时的选择逻辑,不用修改原有语法结构:
%nonassoc LOWEST_PRI %nonassoc DEFAULT_GATEWAY ADDRESS %% command: INTERFACE IDENTIFIER if_attrs | IP DEFAULT_GATEWAY IP_ADDRESS ; # 给空的if_attrs指定最低优先级 if_attrs: # empty %prec LOWEST_PRI | if_attrs if_attr ; if_attr: DESCRIPTION STRING | IP ADDRESS IP_ADDRESS IP_ADDRESS ;
上述配置中,空if_attrs的优先级最低,当解析器在if_attrs位置遇到IP后,若后续token是ADDRESS会优先匹配接口属性;若后续是DEFAULT_GATEWAY,会先归约结束if_attrs,再匹配全局IP DEFAULT_GATEWAY规则。
方案3:上下文感知词法拆分
如果你的词法分析器可以感知当前解析上下文(比如是否处于interface块内),可以将接口块内的ip token单独标记为IF_IP,和全局IP token完全区分,从词法层面消除前缀冲突,不过这种方案会增加词法分析的复杂度。
内容的提问来源于stack exchange,提问作者tge12345
相关产品推荐
相关产品推荐

