在表达式解析器中添加infix运算符

时间:2020-02-02 17:29:29

标签: haskell parsec

我正在尝试将用于中缀运算符的解析器添加到一个简单的表达式解析器中。我已经看过documentation和这个question,但似乎我遗漏了一些东西。

import qualified Text.Parsec.Expr as Expr
import qualified Text.Parsec.Token as Tokens
import Text.ParserCombinators.Parsec
import Text.Parsec

data Expr = Number Integer
          | Op Expr Expr
          | Boolean Bool
      
instance Show Expr where
  show (Op l r) = "(+ " ++ (show l) ++ " " ++ (show r) ++ ")"
  show (Number r) = show r
  show (Boolean b) = show b

parens = Tokens.parens haskell
reserved = Tokens.reservedOp haskell

infix_ operator func =
  Expr.Infix (spaces >> reserved operator >> spaces >> return func) Expr.AssocLeft

infixOp =
  Expr.buildExpressionParser table parser
  where
    table = [[infix_ "+" Op]]

number :: Parser Expr
number = 
  do num <- many1 digit
     return $ Number $ read num

bool :: Parser Expr
bool = (string "true" >> return (Boolean True)) <|> (string "false" >> return (Boolean False))

parser = parens infixOp <|> number <|> bool

run = Text.Parsec.runParser parser () ""

此解析器能够解析诸如1false(1 + 2)(1 + false)之类的表达式,但不能解析1 + 2(它被解析为{{1} })。如果我尝试将解析器更改为1,则会卡住。

为了解析不带括号的parens infixOp <|> infixOp <|> number <|> bool之类的表达式,我应该改变什么?

1 个答案:

答案 0 :(得分:1)

您必须像这样在顶层运行infixOp解析器:

run = Text.Parsec.runParser infixOp () ""

否则,仅在括号中出现时,才能解析您的中缀表达式。

使用parens infixOp <|> infixOp <|> number <|> bool的尝试很可能会因为循环而停滞:parser尝试使用infixOp进行解析,而尝试使用parse进行解析,依此类推。

这些教程可能会帮助您开始使用parsec(他们为我做了):

https://wiki.haskell.org/Parsing_a_simple_imperative_language

http://dev.stephendiehl.com/fun/002_parsers.html

相关问题