Phi*_*tel 5 haskell megaparsec
我正在尝试用 lamdba 表达式解析一种简单的语言。但runParser expr "lamdbda(x) (return x)返回Right (Var "lamdba")而不是Right (Lambda ["x"] (Return (Var "x")))
我的猜测是,我必须try在某个地方添加一个,但我不知道在哪里。lambdaExpr正确解析 lamdbas。
AST.HS
\n\ndata Expr = Const Integer\n | BinOp Op Expr Expr\n | Neg Expr\n | If Expr Expr Expr\n | Var String\n | Lambda [String] Stmt\n deriving (Show, Eq)\n\ndata Op = Multiply\n | Divide\n | Add\n | Subtract\n deriving (Show, Eq)\n\ndata Stmt = Decl String Expr\n | Seq [Stmt]\n | Print Expr\n | Return Expr\n deriving (Show, Eq)\nRun Code Online (Sandbox Code Playgroud)\n\n解析器.hs
\n\nmodule Parser where\n\nimport Ast\n\nimport Control.Monad\nimport Data.Void\nimport Control.Monad.Combinators.Expr\nimport Text.Megaparsec\nimport Text.Megaparsec.Char\nimport qualified Text.Megaparsec.Char.Lexer as L\n\ntype Parser = Parsec Void String\n\nsc :: Parser ()\nsc = L.space space1 lineCmnt blockCmnt\n where lineCmnt = L.skipLineComment "--"\n blockCmnt = L.skipBlockComment "{-" "-}"\n\nlexeme :: Parser a -> Parser a\nlexeme = L.lexeme sc\n\nsymbol :: String -> Parser String\nsymbol = L.symbol sc\n\nparens :: Parser a -> Parser a\nparens = between (symbol "(") (symbol ")")\n\n\ninteger :: Parser Integer\ninteger = lexeme L.decimal\n\nrword :: String -> Parser ()\nrword w = (lexeme . try) (string w *> notFollowedBy alphaNumChar)\n\nrws :: [String] -- list of reserved words\nrws = ["if", "then", "else", "let", "print", "lambda", "return"]\n\nidentifier :: Parser String\nidentifier = (lexeme . try) (p >>= check)\n where\n p = (:) <$> letterChar <*> many alphaNumChar\n check x = if x `elem` rws\n then fail $ "keyword " ++ show x ++ " cannot be an identifier"\n else return x\n\nifExpr :: Parser Expr\nifExpr = do rword "if"\n cond <- expr\n rword "then"\n thn <- expr\n rword "else"\n els <- expr\n return $ If cond thn els\n\nlambdaExpr :: Parser Expr\nlambdaExpr = do rword "lambda"\n args <- parens $ sepBy identifier (char \',\')\n s <- stmt\n return $ Lambda args s\n\nexpr :: Parser Expr\nexpr = makeExprParser term operators\n\nterm :: Parser Expr\nterm = parens expr\n <|> lambdaExpr\n <|> Const <$> integer\n <|> Var <$> identifier\n <|> ifExpr\n\noperators :: [[Operator Parser Expr]]\noperators =\n [ [Prefix (Neg <$ symbol "-") ]\n , [ InfixL (BinOp Multiply <$ symbol "*")\n , InfixL (BinOp Divide <$ symbol "/") ]\n , [ InfixL (BinOp Add <$ symbol "+")\n , InfixL (BinOp Subtract <$ symbol "-") ]\n ]\n\ndeclStmt :: Parser Stmt\ndeclStmt = do rword "let"\n name <- identifier\n void $ symbol "="\n e <- expr\n return $ Decl name e\n\nprintStmt :: Parser Stmt\nprintStmt = do rword "print"\n e <- expr\n return $ Print e\n\nreturnStmt :: Parser Stmt\nreturnStmt = do rword "return"\n e <- expr\n return $ Return e\n\nstmt :: Parser Stmt\nstmt = f <$> sepBy1 stmt\' (symbol ";")\n where\n -- if there\'s only one stmt return it without using \xe2\x80\x98Seq\xe2\x80\x99\n f l = if length l == 1 then head l else Seq l\n\nstmt\' :: Parser Stmt\nstmt\' = declStmt\n <|> printStmt\n <|> returnStmt\n\nrunParser :: Parser a -> String -> Either (ParseError (Token String) Void) a\nrunParser p input = Text.Megaparsec.runParser p "" input\nRun Code Online (Sandbox Code Playgroud)\n