如何解析简单的表达式?

时间:2015-07-22 15:15:45

标签: parsing haskell

我的作业是在Haskell中创建一个表达式解析器。我之前的问题是关于在Haskell中解析SO的问题,我找不到我的案例的帮助。

表达式定义如下:

data Expr =
| Const Int
| Var String
| Add Expr Expr | Sub Expr Expr | Mul Expr Expr | Pow Expr Int
deriving Show

类型Parser定义如下:

type Parser a = String -> Maybe (a, String)

我的作业中提供的解析器定义如下:

--Primitive parsers

success :: a -> Parser a
success v = \inp -> Just (v, inp)

failure :: Parser a
failure = \_ -> Nothing

item :: Parser Char
item = \inp -> case inp of 
                "" -> Nothing
                (c : cs) -> Just (c, cs)

--Sequential parsers

(>>>) :: Parser a -> (a -> Parser b) -> Parser b
p >>> f = \inp -> case p inp of
                    Nothing -> Nothing
                    Just (x, cs) -> f x cs

(&&&) :: Parser a -> Parser b -> Parser b 
p &&& q = p >>> \_ -> q

-- Conditional Parsers

sat :: (Char -> Bool) -> Parser Char
sat f = item >>> \c -> if f c then success c else failure

digit :: Parser Char 
digit = sat isDigit

space :: Parser Char
space = sat isSpace

char :: Char -> Parser Char
char c = sat (== c)

-- Alternative parsers

(+++) :: Parser a -> Parser a -> Parser a
p +++ q = \inp -> case p inp of
                    Nothing -> q inp 
                    Just res -> Just res

-- Iterative Parsers

many :: Parser a -> Parser [a]
many p = many1 p +++ success []

many1 :: Parser a -> Parser [a]
many1 p = p >>> \v -> many p >>> \vs -> success (v : vs)

--Token

nat :: Parser Int
nat = many1 digit >>> \cs -> success (read cs)

spaces :: Parser ()
spaces = many space &&& success ()

token :: Parser a -> Parser a
token p = spaces &&& p

natural :: Parser Int
natural = token nat

symbol :: Char -> Parser Char
symbol c = token (char c)

现在我必须开发一个expr函数,该函数需要String并将其转换为Expr

为了在我的作业中做到这一点,我发现已经定义了如下函数:

expr :: Parser Expr
expr = term >>> \t -> (symbol '+' &&& expr >>> \e -> success $ Add t e) +++ (symbol '-' &&& expr >>> \e -> success $ Sub t e) +++ success t

我知道我必须开发三个功能:termpowerfactor

函数factor应解析常量或变量。

函数term应解析单个factor(例如2)或两个factor之间的乘法(例如2*x)。

我不太了解monad是如何工作的,我在做作业时遇到了问题。有关如何编写这些函数的任何帮助吗?

这是我在作业中找到的图像。

Diagrams for the parsing of term factor and expressions.

1 个答案:

答案 0 :(得分:2)

您需要编写的各种解析器正在将算术运算顺序的优先级规则构建到解析器的结构中。从大多数到最不重要的顺序,这些是

  • 括号和原子文字,如数字和变量,您将称之为factor
  • 指数,您将调用power
  • 乘法,您将调用term
  • 加法和减法,您将调用expr

您从外部开始使用具有最低优先级的运算符,并使用具有最高优先级的运算符。进入乘法,您可以像编写term一样编写exprexprterm组成; term将包含power s

term :: Parser Expr
term = power >>> \p -> (symbol '*' &&& term >>> \e -> success $ Mul p e) +++ success p

同样,power将由factor组成。由于Pow的右侧是Int,因此它只使用自然数nat而不是递归。

power :: Parser Expr
power = factor >>> f -> (symbol '^' &&& nat >>> \n -> success $ Pow f n) +++ success f

我会为你写factor;我写的部分与expr几乎相同,你已经想到了。 factor中的括号将包含任意表达式expr,在外部以最小优先级重新开始。这样您就可以解析"2*(x+1)"

之类的内容