我正在使用Parsec构建一个简单的Lisp解析器。
使用自定义ADT作为解析器类型与使用标准树(即Data.Tree
)有什么(dis)优势?
尝试了两种方法之后,我想出了几个 自定义ADT点(即Parser ASTNode
):
和一个反对(即Parser (Tree ASTNode)
:
Data.Tree
已经有Functor,Monad等实例,这对语义分析,评估,计算代码统计非常有帮助例如:
自定义ADT
import Text.ParserCombinators.Parsec
data ASTNode
= Application ASTNode [ASTNode]
| Symbol String
| Number Float
deriving (Show)
int :: Parser ASTNode
int = many1 digit >>= (return . Number . read)
symbol :: Parser ASTNode
symbol = many1 (oneOf ['a'..'z']) >>= (return . Symbol)
whitespace :: Parser String
whitespace = many1 (oneOf " \t\n\r\f")
app :: Parser ASTNode
app =
char '(' >>
sepBy1 expr whitespace >>= (\(e:es) ->
char ')' >>
(return $ Application e es))
expr :: Parser ASTNode
expr = symbol <|> int <|> app
使用示例:
ghci> parse expr "" "(a 12 (b 13))"
Right
(Application
(Symbol "a")
[Number 12.0, Application
(Symbol "b")
[Number 13.0]])
Data.Tree
import Text.ParserCombinators.Parsec
import Data.Tree
data ASTNode
= Application (Tree ASTNode)
| Symbol String
| Number Float
deriving (Show)
int :: Parser (Tree ASTNode)
int = many1 digit >>= (\x -> return $ Node (Number $ read x) [])
symbol :: Parser (Tree ASTNode)
symbol = many1 (oneOf ['a' .. 'z']) >>= (\x -> return $ Node (Symbol x) [])
whitespace :: Parser String
whitespace = many1 (oneOf " \t\n\r\f")
app :: Parser (Tree ASTNode)
app =
char '(' >>
sepBy1 expr whitespace >>= (\(e:es) ->
char ')' >>
(return $ Node (Application e) es))
expr :: Parser (Tree ASTNode)
expr = symbol <|> int <|> app
和示例使用:
ghci> parse expr "" "(a 12 (b 13))"
Right
(Node
(Application
(Node (Symbol "a") []))
[Node (Number 12.0) [],
Node
(Application
(Node (Symbol "b") []))
[Node (Number 13.0) []]])
(抱歉格式化 - 希望很清楚)
答案 0 :(得分:4)
我绝对会选择AST,因为一般来说,解释/编译/语言分析很大程度上取决于你的语言的结构。 AST将简单而自然地表示并尊重该结构,而Tree
则不会。
例如,一种常见的语言实现技术形式是通过翻译实现一些复杂的功能:将涉及这些功能或构造的程序翻译成不使用它们的语言子集中的程序(例如Lisp宏) ,都是这个)。例如,如果使用AST,类型系统通常会禁止您将非法翻译作为输出。而不了解您的程序的Tree
类型将无法帮助那里。
您的AST看起来并不复杂,因此为它编写实用程序功能应该不难。以此为例:
foldASTNode :: (r -> [r] -> r) -> (String -> r) -> (Float -> r) -> r
foldASTNode app sym num node =
case node of
Application f args -> app (subfold f) (map subfold args)
Symbol str -> sym str
Number n -> num n
where subfold = foldASTNode app sym num
在任何情况下,您希望在AST上使用哪种Functor
?它上面没有类型参数......