我很难将用户输入的表达式转换为我自己的数据类型
我是使用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)
我无法从这里继续前进。帮助会很棒。
谢谢。
答案 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;