不使用buildExpressionParser进行数据类型转换

时间:2014-10-28 09:29:21

标签: haskell parsec haskell-platform

我很难将用户输入的表达式转换为我自己的数据类型

我是使用biuldExpressionParser完成的,但使用简单的解析器和递归,我按如下方式做了

 openBrace = char '('

 closeBrace :: GenParser Char st Char
 closeBrace = char ')'

bracketExpr = do
            spaces >> openBrace
            expr <- expressionParser
            spaces >> closeBrace
            return expr

bracketExpr将以我自己的数据类型

返回输入的表达式

将其转换为我为否定所做的数据类型,如果表达式是数字或变量,则如下所示:

 expressionParser = negate1
                 <|> number
                 <|> variable
                 --<|> addition
                 <?> "simple expression"

 negate1 :: Parser Expr
 negate1 = do{ char '-'
             ;ds <-  number
             ;return (ExprNeg (ds) )
             }
        <?> "negate"

variable :: Parser Expr
variable = do{ ds<- many1 (letter <|> digit)
             ; return (ExprVar ds)}
         <?> "variable"

number :: Parser Expr
number = do{ ds<- many1 digit
           ; return (ExprNum (read ds))}
          <?> "number"

要对添加进行相同操作,我尝试使用sepBy分隔表达式,但我遇到了几个问题。

如果外延展示为1+2 然后我应该得到ExprAdd (ExprNum 1) (ExprNum 2)

我无法从这里继续前进。帮助会很棒。

谢谢。

1 个答案:

答案 0 :(得分:1)

如果你想用解析器组合器编写解析器,你需要先考虑高级规则。这是Parsec中的骨架解析器;它 100%满足您的需求,因为所有运算符都是相同优先级和右关联的,而您可能需要不同的优先级和左关联性。不过,这是编写解析器的基本方法:

import Text.Parsec
import Text.Parsec.Char
import Data.Char (isDigit)

-- basic data type
data Expr = Op Char Expr Expr | N Integer deriving (Show)
type Parser x = Parsec String () x

-- reverse-sequenced >>, used to implement `parenthesized` and `whitespaced`
(<<) :: Monad m => m x -> m y -> m x
mx << my = mx >>= \x -> my >> return x
infixl 1 <<

parenthesized :: Parser e -> Parser e
parenthesized e = char '(' >> e << char ')'

whitespaced :: Parser e -> Parser e
whitespaced e = spaces >> e << spaces

number :: Parser Expr
number = do
    c <- oneOf "123456789" -- leading 0's can be reserved for octal/hexadecimal
    cs <- many digit
    return (N (read (c:cs)))

operator :: Parser Expr
operator = do
    e1 <- expr_no_op
    o <- whitespaced (oneOf "+*/-")
    e2 <- expression
    return (Op o e1 e2)

expr_no_op :: Parser Expr
expr_no_op = whitespaced (try number <|> parenthesized expression)

expression :: Parser Expr
expression = whitespaced (try operator <|> try number <|> parenthesized expression)

请注意,您定义了令牌(上面,只是&#39;数字&#39;),然后将它们与&#34结合使用;尝试<|>尝试<|>否则...& #34;句法。另请注意,阻止operator将表达式作为其第一个参数,否则您将在解析中获得operator -> expression -> operator循环。这被称为&#34;左保理。&#34;