我正在研究一个简单的表达式解析器,但是下面给出了下面的解析器组合子声明,我似乎无法通过我的测试,并且一个正确的关联树会一直弹出。
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的树。
上面的语法出了什么问题?
答案 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。