【发布时间】:2018-05-09 20:44:40
【问题描述】:
我想解析算术表达式。
这是我当前的解析器:
data AExpr
= ExprAsAExpr Expr
| IntConst Integer
| Neg AExpr
| ABinary ABinOp AExpr AExpr
deriving (Show, Eq)
aExpr :: Parser AExpr
aExpr = makeExprParser aTerm aOperators
aTerm :: Parser AExpr
aTerm
= parens aExpr
<|> IntConst <$> integerParser
aOperators :: [[Operator Parser AExpr]]
aOperators =
[ [Prefix (Neg <$ symbol "-") ]
, [ InfixL (ABinary Multiply <$ symbol "*")
, InfixL (ABinary Divide <$ symbol "/") ]
, [ InfixL (ABinary Add <$ symbol "+")
, InfixL (ABinary Subtract <$ symbol "-") ]
]
使用这个我可以正确解析这个:
1 + 2
像这样生成 AST。
(ABinary Add (IntConst 1) (IntConst 2))
我可以解析的另一件事是通用表达式。这些可以是变量、方法调用、三元组等。
例如
标识符:
varName
这会生成:
(Identifier (Name "varName"))
方法调用:
methodCall()
这会生成:
(MethodCall (Name "methodCall") (BlockExpr []))
这是一个解析通用表达式的示例。
expressionParser :: Parser Expr
expressionParser
= methodCallParser
<|> identifierParser
这很好用,但我也想在其中解析算术表达式。
expressionParser :: Parser Expr
expressionParser
= newClassInstanceParser
<|> methodCallParser
<|> AExprAsExpr <$> aExpr
<|> identifierParser
这意味着使用expressionParser 我现在可以解析所有不同的表达式,包括算术表达式。如果它恰好是一个算术表达式,它会被包裹在AExprAsExpr 中。
问题
我想解析包含其他表达式的算术表达式。
例如
x + y
为此,我最初的想法是更改算术解析器,使其也解析表达式。
data AExpr
= ExprAsAExpr Expr
| IntConst Integer
| Neg AExpr
| ABinary ABinOp AExpr AExpr
deriving (Show, Eq)
aExpr :: Parser AExpr
aExpr = makeExprParser aTerm aOperators
aTerm :: Parser AExpr
aTerm
= parens aExpr
<|> IntConst <$> integerParser
<|> ExprAsAExpr <$> expressionParser
aOperators :: [[Operator Parser AExpr]]
aOperators =
[ [Prefix (Neg <$ symbol "-") ]
, [ InfixL (ABinary Multiply <$ symbol "*")
, InfixL (ABinary Divide <$ symbol "/") ]
, [ InfixL (ABinary Add <$ symbol "+")
, InfixL (ABinary Subtract <$ symbol "-") ]
]
问题在于存在递归循环,因为aTerm 调用表达式解析器,表达式解析器调用aExpr。这会导致无限循环。还有一个问题是所有identifiers 现在都将被包裹在AExprAsExpr 中。
在算术表达式中解析表达式的正确方法是什么?
【问题讨论】:
-
如果一个算术表达式可以是一个表达式并且一个表达式可以是一个算术表达式,那么它们根本不应该是分开的东西。只需合并
aExpr和expressionParser的定义即可。
标签: parsing haskell compiler-construction parsec megaparsec