Scala - Combinator Parsing,替代品的顺序似乎很重要

时间:2015-03-03 10:58:17

标签: scala parsing

我对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中的p(x,y,z)一样,term是常量或变量,如1x,或者predicatepredicate是一个复合词,如p(x,y,z)。这段代码可以正常工作,但是如果我改变在term解析器中声明替代方法的顺序,则会出现问题。也就是说,如果我像{/ p>那样编写term解析器

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

predicate是这里的最后一个选择,虽然它是先前的),然后它无法解析像p(x,1,q(a,b,c),z)这样的“嵌套”表达式(虽然它仍适用于像{{1这样的“平面”表达式}})。有人可以说明我在这里缺少什么吗?

非常感谢

2 个答案:

答案 0 :(得分:6)

订单事项

原因是A | B将首先尝试满足A,并且B仅在A失败时才会尝试|

这与正则表达式(或一般的无上下文语法)中的"p(x,1,q(a,b,c),z)"不同。

在这种情况下,p ident满足|||,因此其他替代品不会匹配(并且没有回溯)。

出于这个原因,在具有冲突前缀的替代方案中,你可以先放一个接受较长字符串的字符串(或者你知道的那个字符串会产生更多短语)。

最长的替代匹配

请注意,您可以使用def term: Parser[Any] = ident ||| floatingPointNumber ||| predicate 组合器:

|||

根据Scala docs,{{1}}是一个解析器组合器,匹配具有最长匹配组合的替代方案。

答案 1 :(得分:3)

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

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