用Haskell-Parsec解析算术表达式
我正在写一个算术解析器来处理像“1+2-3”这样的表达式。我用它作为参考。为了处理左关联性和优先级,我根据这个BNF(来自博客文章)用Parsec编写了一个解析器用Haskell-Parsec解析算术表达式,haskell,parsec,Haskell,Parsec,我正在写一个算术解析器来处理像“1+2-3”这样的表达式。我用它作为参考。为了处理左关联性和优先级,我根据这个BNF(来自博客文章)用Parsec编写了一个解析器 我不明白为什么会出现这种结果输入意外结束请考虑解析1+2。在parseExp中,将1解析为t1=Const 1,然后进入循环循环(Const 1)。循环尝试第一个可选的termSuffix(Const 1),它成功地解析了运算符+,下一个术语t2=Const 2,然后循环回termSuffix(Binary Plus(Const 1)
我不明白为什么会出现这种结果
输入意外结束
请考虑解析1+2
。在parseExp
中,将1
解析为t1=Const 1
,然后进入循环循环(Const 1)
。循环尝试第一个可选的termSuffix(Const 1)
,它成功地解析了运算符+
,下一个术语t2=Const 2
,然后循环回termSuffix(Binary Plus(Const 1)(Const 2))
,它需要一个+
或-
。解析失败。不要循环回termSuffix
,而应该循环回loop
,以允许在第一个+
之后有一个术语:
parseExp :: Parser Exp
parseExp = do
t1 <- parseTerm
loop t1
where termSuffix t1 = do
op <- lexeme $ oneOf "+-"
t2 <- parseTerm
case op of
-- *** use `loop` here, not `termSuffix` ***
'+' -> loop (Binary Plus t1 t2)
'-' -> loop (Binary Minus t1 t2)
loop t = termSuffix t <|> return t
parseExp::Parser Exp
parseExp=do
t1由于您使用的是parsec
,因此您可能对该模块感兴趣。
*Main CodeGen Parser> parseWithEof parseExp "-2"
Right (Unary ArithNeg (Const 2))
*Main CodeGen Parser> parseWithEof parseExp "(2)"
Right (Const 2)
*Main CodeGen Parser> parseWithEof parseExp "-!(((2)))"
Right (Unary ArithNeg (Unary LogNeg (Const 2)))
*Main CodeGen Parser> parseWithEof parseExp "1+2"
Left (line 1, column 4):
unexpected end of input
expecting digit
*Main CodeGen Parser> parseWithEof parseExp "1+2+3"
Left (line 1, column 6):
unexpected end of input
expecting digit
*Main CodeGen Parser> parseWithEof parseExp "1+2*3"
Left (line 1, column 6):
unexpected end of input
expecting digit
parseExp :: Parser Exp
parseExp = do
t1 <- parseTerm
loop t1
where termSuffix t1 = do
op <- lexeme $ oneOf "+-"
t2 <- parseTerm
case op of
-- *** use `loop` here, not `termSuffix` ***
'+' -> loop (Binary Plus t1 t2)
'-' -> loop (Binary Minus t1 t2)
loop t = termSuffix t <|> return t