【发布时间】:2022-08-19 01:38:16
【问题描述】:
我正在尝试构建一个布尔逻辑解析器,例如A == B AND C == D 输出类似And(Equals(A,B), Equals(C,D))
我的解析器有以下定义:
def program: Parser[Operator] = {
phrase(operator)
}
def operator: PackratParser[Operator] = {
leaf | node
}
def node: PackratParser[Operator] = {
and | or
}
def leaf: PackratParser[Operator] = {
equal | greater | less
}
def and: PackratParser[Operator] = {
(operator ~ ANDT() ~ operator) ^^ {
case left ~ _ ~ right => And(left, right)}
}
我希望解析器映射到program -> operator -> node -> and -> operator (left) -> leaf -> equal -> operator (right) -> leaf -> equal。这不起作用。
但是,如果在上面的代码中我进行更改
def operatorWithParens: PackratParser[Operator] = {
lparen ~> (operator | operatorWithParens) <~ rparen
}
并将and 更改为
def and: PackratParser[Operator] = {
(operatorWithParens ~ ANDT() ~ operatorWithParens) ^^ {
case left ~ _ ~ right => And(left, right)}
}
解析(A == B) AND (C == D) 成功。
我无法理解为什么前者不起作用而后者起作用。
我应该如何更改我的代码才能解析A == B AND C == D?
编辑: 遵循@Andrey Tyukin 的建议,我修改了语法以说明优先级
def program: Parser[Operator] = positioned {
phrase(expr)
}
def expr: PackratParser[Operator] = positioned {
(expr ~ ORT() ~ expr1) ^^ {
case left ~ _ ~ right => Or(left, right)} | expr1
}
def expr1: PackratParser[Operator] = positioned {
(expr1 ~ ANDT() ~ expr2) ^^ {
case left ~ _ ~ right => And(left, right)} | expr2
}
def expr2: PackratParser[Operator] = positioned {
(NOTT() ~ expr2) ^^ {case _ ~ opr => Not(opr)} | expr3
}
def expr3: PackratParser[Operator] = {
lparen ~> (expr) <~ rparen | leaf
}
尽管PackratParser 支持左递归语法,但我遇到了一个永远不会离开expr 的无限循环
-
phrase是什么?or是什么?它在某种程度上是不完整的。是否有可能提供包含所有导入的完整解析器,理想情况下作为具有所有依赖项的 ammonite 脚本? -
它是否有机会生成
Equals(And(Equals(A, B), C),D)?换句话说,它被解析为((A == B) AND C) == D?因为没有运算符优先级,这就是您所期望的。我们解析A*B/C*D与A*B + C*D不同,因为+的优先级低于*,但/的优先级与*相同。运算符优先级必须在语法中表示。 -
在询问有关解析器组合器的问题时,您应该指定正在使用哪个库。基于
^^的存在,我猜想scala-parser-combinators?这是非常缓慢和错误的,并且有更好的替代方案可用(例如cats-parse)。 -
@MatthiasBerndt 是的,它正在使用 scala-parser-combinators。线索是标题和问题本身中的
packrat-parsing标签和单词PackratParser。
标签: scala parsing packrat-parsing