【发布时间】:2012-08-10 01:53:07
【问题描述】:
我正在使用 Parsec 构建一个简单的 Lisp 解析器。
对解析器类型使用自定义 ADT 与使用标准树(即Data.Tree)相比有哪些(不利)优势?
在尝试了两种方法之后,我想出了几点自定义ADT(即Parser ASTNode):
- 似乎更清晰、更简单
- 其他人已经这样做了(包括Tiger,它与 Parsec 捆绑在一起)
和一个反对(即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.Treeimport 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) []]])(抱歉格式化——希望很清楚)
【问题讨论】:
-
鉴于子树被表示为 AST,我不太明白“树 ASTNode”会给您带来什么。我原以为您真正拥有的是终端树(字符串或数字),其中应用程序由节点值后跟子列表指示。