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}}}]"