阅读括号和否定

时间:2016-11-23 07:33:24

标签: parsing haskell

我的目标是使用Text.ParserCombinators.ReadP在Haskell中构建一个计算器,它实现+, - ,*,/,^,以及否定,并遵循PEMDAS。首先,我必须将字符串输入解析为数学表达式(MathExp)。我的部分代码如下:

import Control.Applicative hiding (many)
import Control.Monad
import Data.Char
import Data.List
import Data.Ord
import Text.ParserCombinators.Readp
type Name   = String  
type Number = Int    

data MathExp
  = Number Number
  | Neg    MathExp
  | Plus   MathExp MathExp
  | Minus  MathExp MathExp
  | Mult   MathExp MathExp
  | Div    MathExp MathExp
  | Pow    MathExp MathExp
  | Var    String
  deriving (Eq, Show)

parseNumber :: ReadP MathExp
parseNumber = do
  skipSpaces
  x <- munch1 isDigit
  return (Number (read x :: Int))

parsePlus :: ReadP (MathExp -> MathExp -> MathExp)
parsePlus = do
  x <- char '+'
  return Plus

parseMinus :: ReadP (MathExp -> MathExp -> MathExp)
parseMinus = do
  skipSpaces
  x <- char '-'
  return Minus

parsePlusMinus = choice [parsePlus, parseMinus] --parse both--

parseMult :: ReadP (MathExp -> MathExp -> MathExp)
parseMult = do
  x <- char '*'
  return Mult

parseDiv :: ReadP (MathExp -> MathExp -> MathExp)
parseDiv = do
  x <- char '/'
  return Div

parseMultDiv = choice [parseMult, parseDiv] --parse both M,D--
parsePow :: ReadP (MathExp -> MathExp -> MathExp)
parsePow = do
  x <- char '^'
  return Pow

parseNeg :: ReadP MathExp
parseNeg = undefined
parseParens = undefined

我使用chainl1chainr1组合我目前拥有的解析器没有问题,以正确的顺序实现关联性和优先级,但我不知道如何正确实现否定和括号。

我知道如果该否定也是-符号,它可以在整数,括号或变量(字母串)之前出现。变量是计算器的另一部分(我没有遇到麻烦)。此外,否定可以包括空白区域;例如1+2* - 3是此计算器的有效字符串输入。

1 个答案:

答案 0 :(得分:3)

你可以这样做:

import Control.Applicative
import Data.Char
import Text.ParserCombinators.ReadP

type Name = String
type Number = Int

data MathExp
    = Number Number
    | Neg    MathExp
    | Plus   MathExp MathExp
    | Minus  MathExp MathExp
    | Mult   MathExp MathExp
    | Div    MathExp MathExp
    | Pow    MathExp MathExp
    | Var    Name
    deriving (Eq, Show)

runParser :: ReadP a -> String -> Maybe a
runParser p s =
    case readP_to_S p s of
        [(x, [])] -> Just x
        _         -> Nothing

mathExp  = mathExp' <* skipSpaces <* eof
mathExp' = term   `chainl1` addop
term     = factor `chainl1` mulop
factor   = expo   `chainr1` expop
expo     = number <|> var <|> parens mathExp' <|> neg expo

number = skipSpaces *> (Number . read <$> munch1 isDigit)
var    = skipSpaces *> (Var <$> munch1 isAlpha)
addop  = skipSpaces *> (Plus <$ char '+' <|> Minus <$ char '-')
mulop  = skipSpaces *> (Mult <$ char '*' <|> Div <$ char '/')
expop  = skipSpaces *> (Pow <$ char '^')
neg p  = skipSpaces *> (Neg <$> (char '-' *> p))

parens = between (skipSpaces *> char '(') (skipSpaces *> char ')')

main = print $ runParser mathExp "1+2* - 3"

输出将是:

Just (Plus (Number 1) (Mult (Number 2) (Neg (Number 3))))