我正在为 Yacc 中的一种玩具语言(与 Go 打包的语言)编写语法,并且由于以下伪问题,我有一个预期的 shift-reduce 冲突。我必须将问题语法提炼成以下内容。
start:
stmt_list
expr:
INT | IDENT | lambda | '(' expr ')' { $$ = $2 }
lambda:
'(' params ')' '{' stmt_list '}'
params:
expr | params ',' expr
stmt:
/* empty */ | expr
stmt_list:
stmt | stmt_list ';' stmt
一个 lambda 函数看起来像这样:
map((v) { v * 2 }, collection)
我的解析器发出:
冲突:1班次/减少
给定输入:
(a)
expr
它按'(' expr ')'
规则正确解析。但是,如果输入:
(a) { a }
(这将是标识函数的 lambda,返回其输入)。我得到:
语法错误:意外的“{”
这是因为当(a)
被读取时,解析器选择将其归约为'(' expr ')'
,而不是将其视为'(' params ')'
。鉴于这种冲突是一个减少而不是减少的冲突,我假设这是可以解决的。我只是不知道如何构建语法来支持这种语法。
编辑 | 这很难看,但我正在考虑定义一个标记,以便词法分析器可以识别 ')' '{' 序列并将其作为单个标记发送以解决此问题。
编辑 2 | 实际上,更好的是,我会让 lambdas 需要语法->(a, b) { a * b}
中的语法,但是让词法分析器发出->
而不是在实际的源代码中。