我正在使用Trifecta解析器组合器库,我的解析器输出 AST 数据类型的实例。我希望每个实例都有唯一的 ID(简单的 Int)。
在 Parsec 中,我将创建自定义状态并在需要时增加 ID。我们如何在 Trifecta 中做到这一点?
Parser
您可以使用monad 转换器增强monadStateT
以获得您想要的。这与库的其余部分很好地集成在一起,因为大多数组合器使用类型类而不是具体类型(这意味着您不必为代码工作做太多提升)。这是一个很好的例子。它解析带有由空格分隔的标识符和符号的语法。每个标识符都有一个唯一的编号。
module Main where
import Text.Trifecta
import Control.Monad.State
import Control.Applicative
import Data.Monoid
data Identifier = Identifier String Int deriving (Show)
identifier :: StateT Int Parser Identifier
identifier = do
name <- some letter
newId <- get
modify (+1)
return $ Identifier name newId
symbolToken :: Parser Char
symbolToken = oneOf "+-*/"
data Token = IdentifierToken Identifier | SymbolToken Char deriving (Show)
singleToken :: StateT Int Parser Token
singleToken = try (IdentifierToken <$> identifier) <|> (SymbolToken <$> lift symbolToken)
parseTokens :: StateT Int Parser [Token]
parseTokens = singleToken `sepBy1` spaces
testParse :: String -> Result [Token]
testParse = parseString (evalStateT parseTokens 0) mempty
test1 :: Result [Token]
test1 = testParse "these are identifiers and + some / symbols -"
test1
结果是:
Success [IdentifierToken (Identifier "these" 0)
,IdentifierToken (Identifier "are" 1)
,IdentifierToken (Identifier "identifiers" 2)
,IdentifierToken (Identifier "and" 3)
,SymbolToken '+',IdentifierToken (Identifier "some" 4)
,SymbolToken '/',IdentifierToken (Identifier "symbols" 5),SymbolToken '-']