Advertisement
kronicmage

Reverse polish parser and interpreter

Jul 25th, 2020
2,688
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. {-# LANGUAGE ApplicativeDo #-}
  2. {-# LANGUAGE DeriveFunctor #-}
  3. {-# LANGUAGE LambdaCase #-}
  4.  
  5. import Control.Applicative
  6. import Control.Arrow
  7. import Data.Foldable
  8. import Data.Function
  9.  
  10. -- ======================================================================= --
  11. -- ======================================================================= --
  12. -- ======================== Reverse Polish Parser ======================== --
  13. -- ======================================================================= --
  14. -- ======================================================================= --
  15.  
  16. data Op = Plus | Times | Minus | Div deriving (Eq, Ord)
  17. data Expr = Number Int | Expr Op Expr Expr deriving (Eq, Ord)
  18. instance Show Op where
  19.     show Plus = "+"
  20.     show Times = "*"
  21.     show Minus = "-"
  22.     show Div = "/"
  23. opParse :: Char -> Op -> Parser Op
  24. opParse c o = char c *> pure o
  25. plus, minus, times, divide, op :: Parser Op
  26. plus   = opParse '+' Plus
  27. minus  = opParse '-' Minus
  28. times  = opParse '*' Times
  29. divide = opParse '/' Div
  30. op = oneOf [plus, minus, times, divide]
  31.  
  32. polish :: Parser Expr
  33. polish = do
  34.     many whitespace
  35.     fst <- Number <$> integer
  36.     rst <- many $ do many whitespace
  37.                      b <- polish
  38.                      many whitespace
  39.                      o <- op
  40.                      pure $ \a -> Expr o a b
  41.     pure $ foldl' (&) fst rst
  42.  
  43. opToFunc :: Op -> (Int -> Int -> Int)
  44. opToFunc Plus = (+)
  45. opToFunc Minus = (-)
  46. opToFunc Times = (*)
  47. opToFunc Div = quot
  48.  
  49. interp :: Expr -> Int
  50. interp (Number x) = x
  51. interp (Expr o a b) = (opToFunc o) (interp a) (interp b)
  52.  
  53. instance Show Expr where
  54.    show (Number x) = show x
  55.    show (Expr op a b) = foldl' (++) empty ["(", show a, show op, show b, ")"]
  56.  
  57. main :: IO ()
  58. main = do
  59.     input <- getLine
  60.     let tree = runParse polish input
  61.     putStrLn $ case tree of
  62.       [] -> empty
  63.       ((x,_):_) -> show x ++ " = " ++ (show $ interp x)
  64.     main
  65.  
  66. -- ======================================================================= --
  67. -- ======================================================================= --
  68. -- ===================== From-scratch Parser def ========================= --
  69. -- ======================================================================= --
  70. -- ======================================================================= --
  71.  
  72. data Parser a = Parser { runParse :: String -> [(a, String)] } deriving (Functor)
  73. instance Applicative Parser where
  74.     pure x = Parser $ \s -> [(x, s)]
  75.     p <*> q = Parser $ \s -> do
  76.         (f, s1) <- runParse p s
  77.         (a, s2) <- runParse q s1
  78.         pure $ (f a, s2)
  79. instance Alternative Parser where
  80.     empty = Parser $ pure []
  81.     f <|> g = Parser $ \s ->
  82.       case runParse f s of []  -> runParse g s
  83.                            res -> res
  84. char :: Char -> Parser Char
  85. char x = Parser $
  86.   \case (c:cs) | x == c -> [(c, cs)]
  87.         _               -> []
  88. oneOf :: [Parser a] -> Parser a
  89. oneOf       = foldr (<|>) empty
  90. oneOfChar   ::  String  -> Parser Char
  91. oneOfChar   = oneOf . fmap char
  92. zeroOrOne :: Parser a -> Parser (Maybe a)
  93. zeroOrOne x = Just <$> x <|> pure Nothing
  94. digit, leading_digit :: Parser Char
  95. digit         = oneOfChar ['0'..'9']
  96. leading_digit = oneOfChar ['1'..'9']
  97. natural :: Parser Int
  98. natural = read <$> do
  99.     lead <- leading_digit
  100.     rest <- many digit
  101.     pure $ lead:rest
  102. zero :: Parser Int
  103. zero = char '0' *> pure 0
  104. integer :: Parser Int
  105. integer = zero <|> do
  106.     minus <- zeroOrOne $ char '-'
  107.     num <- natural
  108.     pure $ case minus of
  109.              Nothing -> num
  110.              _ -> negate num
  111. whitespace :: Parser Char
  112. whitespace = char ' '
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement