Scala - 组合器解析,备选方案的顺序似乎很重要

Scala - Combinator Parsing, order of alternatives seems to matter

我对 Scala 比较陌生,我正在尝试掌握组合器解析。所以我有一些代码可以解析逻辑原子(一阶逻辑中的谓词),如 p(x,y,z)p(x,1,q(a,b,c),z)。我有这么一小段代码:

class Logic extends JavaTokenParsers {
    def functor: Parser[Any] = ident
    def term: Parser[Any] = predicate | ident | floatingPointNumber
    def predicate: Parser[Any] = functor~"("~repsep(term,",")~")"  
}

Functor是谓词符号,如p(x,y,z)中的pterm是常量或变量,如1x , 或 predicate, 而 predicate 是一个复合词, 如 p(x,y,z).此代码按原样运行良好,但如果我更改在 term 解析器中声明替代项的顺序,则会出现问题。也就是说,如果我将 term 解析器写成

def term: Parser[Any] = ident | floatingPointNumber | predicate

predicate 是这里的最后一个选项,而它之前是第一个),然后它无法解析像 p(x,1,q(a,b,c),z) 这样的 "nested" 表达式(虽然它仍然适用于 "flat" 表达式,如 p(x,y,z))。有人可以指出我在这里缺少什么吗?

非常感谢

订单事项

原因是A | B会先尝试满足A,只有当A失败时才会尝试B

这与正则表达式(或一般的上下文无关语法)中的 | 不同。

在这种情况下 "p(x,1,q(a,b,c),z)" p 满足 ident 所以不会匹配其他备选方案(并且没有回溯)。

因此,在具有冲突前缀的备选方案中,您可以将接受较长字符串的备选方案放在第一位(或者您知道会导致满足更多短语的备选方案)。

最长的替代匹配

请注意,您可以使用 ||| 组合器:

def term: Parser[Any] = ident ||| floatingPointNumber ||| predicate

根据Scala docs|||是一个解析器组合器匹配具有最长匹配组合的备选方案。

我假设您尝试通过 logic.parse(logic.term, "p(x,1,q(a,b,c),z)") 进行解析。

事实上,备选方案的顺序很重要,因为解析器将选择第一个备选方案来匹配给定的输入。在您的例子中,p 匹配 ident 定义。然后,解析器将 return 一个 ParseResult 包含匹配项(在您的情况下键入 Any )和输入的其余部分,在您的情况下为 (x,1,q(a,b,c),z)