解析器组合语法不会产生正确的关联性

时间:2013-12-01 10:52:41

标签: scala parsing bnf parser-combinators associativity

我正在研究一个简单的表达式解析器,但是下面给出了下面的解析器组合子声明,我似乎无法通过我的测试,并且一个正确的关联树会一直弹出。

def EXPR:Parser[E] = FACTOR ~ rep(SUM|MINUS) ^^ {case a~b => (a /: b)((acc,f) => f(acc))}
def SUM:Parser[E => E] = "+" ~ EXPR ^^ {case "+" ~ b => Sum(_, b)}
def MINUS:Parser[E => E] = "-" ~ EXPR ^^ {case "-" ~ b => Diff(_, b)}

我一直在调试这个时间。我希望有人可以帮助我弄清楚它是不是正确的。

“5-4-3”将产生一个评估为4而不是预期-2的树。

上面的语法出了什么问题?

3 个答案:

答案 0 :(得分:2)

我不使用Scala,但可以使用F#解析器组合器,还需要与中缀运算符相关联。虽然我确信你可以做5-4或2 + 3,但问题在于两个或多个具有相同优先级和运算符的运算符的序列,即5-4-2或2 + 3 + 5。添加为(2 + 3)+5 = 2+(3 + 5)但(5-4)-2 - 的问题不会出现问题。如你所知,5-(4-2)。

请参阅:Monadic Parser Combinators 4.3重复使用有意义的分隔符。注意:分隔符是诸如“+”和“*”之类的运算符,而不是空格或逗号。

请参阅:Functional Parsers在第7节中查找chainl和chainr解析器。更多解析器组合器。

  

例如,算术表达式,运算符所在的位置   单独的子表达式必须是解析树的一部分。对于   在这种情况下,我们将开发函数chainr和chainl。这些   函数期望分隔符的解析器产生一个函数   (!);

     

函数f应该对元素和元组列表进行操作   包含运算符和元素。例如,f(e0; [(1; e1);   (2; e2); (3; e3)])应返回((eo 1 e1)2 e2)3 e3。你可以   识别这个版本的foldl(尽管是一个未经证实的版本),其中   列表中的元组(; y)和中间结果x组合在一起   应用x y。

语义解析器中需要fold function,即将标记从语法分析器转换为解析器输出的部分。在你的代码中,我相信它就是这一部分。

{case a~b => (a /: b)((acc,f) => f(acc))}

抱歉,我不能做得更好,因为我不使用Scala。

答案 1 :(得分:1)

"-" ~ EXPR ^^ {case "-" ~ b => Diff(_, b)}

对于5-4-3,它扩展为

Diff(5, 4-3)

Diff(5, Diff(4, 3))

然而,你需要的是:

Diff(Diff(5, 4), 3))

// for 5 + 4 - 3 it should be

Diff(Sum(5, 4), 3)

你需要涉及堆栈。

答案 2 :(得分:0)

似乎使用“+”~EXPR使答案不正确。它应该是FACTOR。