Parsec入門

ちょっとParsecをいじってみた.整数定数の足し算と引き算の式,変数宣言が書ける(宣言できるけど使えない).計算をせずにASTだけを出力する.

import Text.ParserCombinators.Parsec

 --main
r :: String -> String
r input = case parse source "lisp" input of
    Left err -> "No match: " ++ show err
    Right val -> "Found value" ++ show val

 --util
mny :: Parser a -> Parser [a] 
mny p = many (do { spc; p } )
spc :: Parser ()
spc = skipMany space

 --grammar
source :: Parser [Decl]
source = do { bodies <- mny ( vardecl <|> statement)
            ; return bodies 
            }

vardecl :: Parser Decl
vardecl = do { string "var" ; spc
             ; name <- symbol; spc ; string ";"
             ; return $ VarDecl {vdName = name }
             } 
statement :: Parser Decl
statement = do { e <- expr; spc
               ; string ";"
               ; return $ Statement {ex = e}
               }
expr :: Parser Expr
expr = do { left <- intConst 
          ; rights <- mny (do { op   <- operators 
                              ; elem <- intConst 
                              ; return (op,elem) } )
          ; return (makeBinOp left rights)
          }
operators :: Parser String
operators = string "+" <|> string "-" 

intConst :: Parser Expr
intConst = do { v <- digits 
              ; return $ IntConst { iValue= v} 
              }

symbol  :: Parser String
symbol  = many1 letter
digits  :: Parser Int
digits  = do { d <- many1 (oneOf "0123456789")
             ; return (read d::Int)  -- ???
             }

 --semantics
makeBinOp :: Expr -> [(String,Expr)] -> Expr
makeBinOp left [] = left
makeBinOp left ((op,elem):rest) = 
   makeBinOp BinOp { bOp=op, bLeft = left, bRight= elem} rest

data Decl = VarDecl { vdName:: String } |
            Statement { ex :: Expr } 
            deriving Show

data Expr = BinOp { bOp::String, bLeft:: Expr,  bRight::Expr } |
            IntConst { iValue::Int }  |
            VarRef { vrName:: String }
            deriving Show

出力例

Main> r "1+2-3;4-5-6;"
Loading package parsec-2.0 ... linking ... done.
"Found value[Statement {ex = BinOp {bOp = \"-\", bLeft = BinOp {bOp = \"+\", bLe
ft = IntConst {iValue = 1}, bRight = IntConst {iValue = 2}}, bRight = IntConst {
iValue = 3}}},Statement {ex = BinOp {bOp = \"-\", bLeft = BinOp {bOp = \"-\", bL
eft = IntConst {iValue = 4}, bRight = IntConst {iValue = 5}}, bRight = IntConst
{iValue = 6}}}]"