今天,我一直在努力从解析器中删除所有 s/r 冲突。我设法删除了所有这些,但只有一个。
我的语言的语法应该是类似 haskell 的。而不是 a main
,我有一个顶级表达式,即条目。
解析器如下所示。我还添加了 Happy 生成的文件的摘录Parser.info
,其中描述了 shift/reduce 冲突。
据我所知,问题是一旦解析器遇到varname
一个函数定义,它可能需要两个分支。它可以假设还有更多varname
的 s,因为它当前正在解析一个函数定义(它有一个或多个参数),或者它可以停止将其解析为变量表达式。之后的可能varname
只是另一种表达方式。
我玩过%prec
规则,但似乎没有任何帮助。
我的第一个理由是,鉴于解析器想要转换函数定义,我可以赋予该规则优先级。我还尝试为=
运算符(用于函数定义)添加优先级,以便我可以将其置于函数定义的优先级之下,但这也不起作用。我的猜测是我不完全理解解析器是如何工作的。非常感谢任何指针。
一个小的旁注,默认行为 - 我认为因此是一种转变 - 也是所需的行为。
state 25 contains 1 shift/reduce conflicts.
...
State 25
Definition -> varname . ':' ':' Type (rule 7)
Definition -> varname . FunctionParameters '=' Exp bl (rule 8)
Atom -> varname . (rule 20)
'(' reduce using rule 20
'<' reduce using rule 20
'>' reduce using rule 20
'/' reduce using rule 20
'*' reduce using rule 20
'-' reduce using rule 20
'+' reduce using rule 20
"eq?" reduce using rule 20
number reduce using rule 20
':' shift, and enter state 27
varname shift, and enter state 28
(reduce using rule 20)
%eof reduce using rule 20
FunctionParametersgoto state 26
解析器
%nonassoc PARS
%nonassoc VAR
%%
Program
: Definitions Exp { Program $1 $2 }
| Exp { Program [] $1 }
Definitions
: Definitions Definition { ($1 ++ [$2]) }
| Definition { [$1] }
Definition
: type upsym '=' Type { TypeDef $2 $4 }
| varname ':' ':' Type { FTypeDef $1 $4 }
| varname FunctionParameters '=' Exp bl { FDef $1 $2 $4 }
FunctionParameters
: FunctionParameters varname %prec PARS { $1 ++ [$2] }
| varname { [$1] }
Exp
: let varname '=' Exp "in" Exp { Let $2 $4 $6 }
| if Exp then Exp else Exp { If $2 $4 $6 }
| "Lam" varname "->" Exp { Abs $2 $4 }
| Form { $1 }
Form
: Juxt { $1 }
Juxt
: Juxt Atom { App $1 $2 }
| Atom { $1 }
Atom
: '(' Exp ')' { $2 }
| number { Value $ Number $1 }
| varname %prec VAR { Var $1 }
| Binfs { Value $ Binf $1 }
Binfs
: "eq?" { BinfEqual }
| '/' { BinfDiv }
| '*' { BinfTimes }
| '+' { BinfPlus }
| '-' { BinfMinus }
| '>' { BinfGT }
| '<' { BinfLT }