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

能否轻松消除脚本语言解析器中if语句的reduce/reduce冲突?

消除解析器中if语句的归约/归约冲突

我正在为自研脚本语言开发解析器,目前实现了支持else、elsif分支的if语句解析代码,代码简洁性尚可:

@_( 'IF LPAREN expr_comp RPAREN THEN NEWLINE statement_set { elsif_statement } ENDIF',
    'IF LPAREN expr_comp RPAREN THEN NEWLINE statement_set { elsif_statement } ELSE NEWLINE statement_set ENDIF',
    )
def if_statement(self, p):
    expressions = []
    expressions.append((p.expr_comp, p[6]))
    else_statement = None
    if (p[8] == 'else'):
        else_statement = p[10]

    expressions.extend(p.elsif_statement)

    return ('IF', expressions, else_statement)

@_('ELSIF LPAREN expr_comp RPAREN THEN NEWLINE statement_set')
def elsif_statement(self, p):
    return (p.expr_comp, p.statement_set)

该代码生成了如下语法规则:

Rule 64 if_statement -> IF LPAREN expr_comp RPAREN THEN NEWLINE statement_set _3_elsif_statement_repeat ELSE NEWLINE statement_set ENDIF
Rule 65 _3_elsif_statement_repeat -> _3_elsif_statement_items
Rule 66 _3_elsif_statement_repeat ->
Rule 67 _3_elsif_statement_items -> _3_elsif_statement_items _3_elsif_statement_item
Rule 68 _3_elsif_statement_items -> _3_elsif_statement_item
Rule 69 _3_elsif_statement_item -> elsif_statement
Rule 70 if_statement -> IF LPAREN expr_comp RPAREN THEN NEWLINE statement_set _4_elsif_statement_repeat ENDIF
Rule 71 _4_elsif_statement_repeat -> _4_elsif_statement_items
Rule 72 _4_elsif_statement_repeat ->
Rule 73 _4_elsif_statement_items -> _4_elsif_statement_items _4_elsif_statement_item
Rule 74 _4_elsif_statement_items -> _4_elsif_statement_item
Rule 75 _4_elsif_statement_item -> elsif_statement
Rule 76 elsif_statement -> ELSIF LPAREN expr_comp RPAREN THEN NEWLINE statement_set

但同时产生了如下冲突:

Conflicts:    

reduce/reduce conflict for ELSIF in state 111 resolved using rule _3_elsif_statement_item -> elsif_statement
rejected rule (_4_elsif_statement_item -> elsif_statement) in state 111
   reduce using _3_elsif_statement_item -> elsif_statement with lookahead ELSIF
   ╭╴
   │ elsif_statement ♦          ELSIF LPAREN expr_comp RPAREN THEN NEWLINE statement_set
   │ ╰_3_elsif_statement_item╯  ╰elsif_statement───────────────────────────────────────╯
   │ ╰_3_elsif_statement_items╯ ╰_3_elsif_statement_item───────────────────────────────╯
   │ ╰_3_elsif_statement_items─────────────────────────────────────────────────────────╯
   ╰╴

   reduce using _4_elsif_statement_item -> elsif_statement with lookahead ELSIF
   ╭╴
   │ elsif_statement ♦          ELSIF LPAREN expr_comp RPAREN THEN NEWLINE statement_set
   │ ╰_4_elsif_statement_item╯  ╰elsif_statement───────────────────────────────────────╯
   │ ╰_4_elsif_statement_items╯ ╰_4_elsif_statement_item───────────────────────────────╯
   │ ╰_4_elsif_statement_items─────────────────────────────────────────────────────────╯
   ╰╴

目前代码可正常运行,但我希望尽可能减少冲突,避免掩盖实际问题。我怀疑冲突源于可选列表的自动化处理,但不清楚具体原因。请问能否轻松消除该归约/归约冲突?


解决方案

冲突原因很明确:你定义了两个独立的if_statement规则,解析器为每个规则生成了一套完全独立的elsif重复列表规则(_3_elsif_statement_repeat和_4_elsif_statement_repeat)。这两套规则功能完全相同,但解析器会将它们视为不同规则,当遇到ELSIF时,无法判断该用哪套规则进行归约,从而触发归约/归约冲突。

轻松消除冲突的方法是合并两个if_statement规则,用[ ... ]将else分支标记为可选部分,这样只会生成一套重复列表规则。修改后的代码如下:

@_( 'IF LPAREN expr_comp RPAREN THEN NEWLINE statement_set { elsif_statement } [ ELSE NEWLINE statement_set ] ENDIF',
    )
def if_statement(self, p):
    expressions = [(p.expr_comp, p[6])]
    # 处理elsif_statement可能为空的情况
    expressions.extend(p.elsif_statement or [])
    # 通过hasattr判断是否存在else分支
    else_statement = p.statement_set if hasattr(p, 'statement_set') else None
    return ('IF', expressions, else_statement)

@_('ELSIF LPAREN expr_comp RPAREN THEN NEWLINE statement_set')
def elsif_statement(self, p):
    return (p.expr_comp, p.statement_set)

修改说明

  • 用[ ELSE NEWLINE statement_set ]替代原来的两个独立规则,将else分支设为可选,避免解析器生成重复的列表规则
  • 调整else_statement的获取逻辑,改用hasattr判断是否存在可选分支的内容,比依赖位置索引的判断更可靠,也更符合解析器的属性访问方式
  • 简化了expressions的初始化代码,保持简洁性

修改后,生成的语法规则中只会有一套elsif重复规则,归约/归约冲突会彻底消失,同时代码的简洁性也得到了保留。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 07:31:16