haskell - 带有秒差距的完整解析器示例?

标签 haskell parsec

我正在尝试为一种简单的函数式语言(有点像 Caml)制作一个解析器,但我似乎只专注于最简单的事情。

所以我想知道是否有一些更完整的例子 parsec解析器,超越“这就是解析 2 + 3 的方式”的东西。特别是术语等中的函数调用。

我读过“为你写一个Scheme”,但是Scheme的语法非常简单,对学习没有太大帮助。

我遇到的最多的问题是如何使用try , <|>choice正确地,因为我真的不明白为什么 parsec 似乎永远不会解析 a(6)作为使用此解析器的函数调用:

expr = choice [number, call, ident]

number = liftM Number float <?> "Number"

ident = liftM Identifier identifier <?> "Identifier"

call = do
    name <- identifier
    args <- parens $ commaSep expr
    return $ FuncCall name args
    <?> "Function call"

编辑添加了一些完成代码,尽管这实际上不是我要求的:

AST.hs

module AST where

data AST
    = Number Double
    | Identifier String
    | Operation BinOp AST AST
    | FuncCall String [AST]
    deriving (Show, Eq)

data BinOp = Plus | Minus | Mul | Div
    deriving (Show, Eq, Enum)

Lexer.hs

module Lexer (
            identifier, reserved, operator, reservedOp, charLiteral, stringLiteral,
            natural, integer, float, naturalOrFloat, decimal, hexadecimal, octal,
            symbol, lexeme, whiteSpace, parens, braces, angles, brackets, semi,
            comma, colon, dot, semiSep, semiSep1, commaSep, commaSep1
    ) where

import Text.Parsec
import qualified Text.Parsec.Token as P
import Text.Parsec.Language (haskellStyle)

lexer = P.makeTokenParser haskellStyle

identifier = P.identifier lexer
reserved = P.reserved lexer
operator = P.operator lexer
reservedOp = P.reservedOp lexer
charLiteral = P.charLiteral lexer
stringLiteral = P.stringLiteral lexer
natural = P.natural lexer
integer = P.integer lexer
float = P.float lexer
naturalOrFloat = P.naturalOrFloat lexer
decimal = P.decimal lexer
hexadecimal = P.hexadecimal lexer
octal = P.octal lexer
symbol = P.symbol lexer
lexeme = P.lexeme lexer
whiteSpace = P.whiteSpace lexer
parens = P.parens lexer
braces = P.braces lexer
angles = P.angles lexer
brackets = P.brackets lexer
semi = P.semi lexer
comma = P.comma lexer
colon = P.colon lexer
dot = P.dot lexer
semiSep = P.semiSep lexer
semiSep1 = P.semiSep1 lexer
commaSep = P.commaSep lexer
commaSep1 = P.commaSep1 lexer

Parser.hs

module Parser where

import Control.Monad (liftM)
import Text.Parsec
import Text.Parsec.String (Parser)
import Lexer
import AST

expr = number <|> callOrIdent

number = liftM Number float <?> "Number"

callOrIdent = do
    name <- identifier
    liftM (FuncCall name) (parens $ commaSep expr) <|> return (Identifier name)

最佳答案

嗯,

*Expr> parse expr "" "a(6)"
Right (FuncCall "a" [Number 6.0])

在填写缺失的部分后,该部分对我有用。

编辑:我通过编写自己的float解析器来填写缺失的部分,它可以解析整数文字。另一方面,来自 Text.Parsec.Tokenfloat 解析器仅解析带有小数部分或指数的文字,因此无法解析“6”。

但是,

*Expr> parse expr "" "variable"
Left (line 1, column 9):
unexpected end of input
expecting "("

当解析标识符后调用失败时,该部分输入将被消耗,因此不会尝试 ident,并且整个解析失败。您可以 a) 在 expr 的选择列表中使其try call,以便调用在不消耗输入的情况下失败,或者 b) 编写一个解析器 callOrIdent 以在 中使用expr,例如

callOrIdent = do
    name <- identifier
    liftM (FuncCall name) (parens $ commaSep expr) <|> return (Identifier name)

这避免了try,因此可能表现更好。

关于haskell - 带有秒差距的完整解析器示例?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8218529/

相关文章:

Haskell - Parsec::解析空格直到字符串文字

Haskell 秒差距匹配 if (3) as if (3 > 0)

haskell - 了解 Parsec 中的 SourceName

debugging - Haskell - 在 if block 中调试打印

haskell - 类型类函数调用的 GHC 代码生成

haskell - 实现最后一个函数

haskell - 如何使用仅显示警告的 cabal 构建重新编译 Haskell

haskell - Parsec 如何在字符串中找到 "matches"

pointers - Haskell 中的低级指针

parsing - 使用 Haskell/Parsec 转换\"into "