打印 AST 以显示缩进
Printing an AST to show indentation
我想在 Haskell 中打印抽象语法树。目前我可以逐行打印树,但我更喜欢为解析代码所在的每个块缩进它。
例如
要解析的代码:
module test
foo(x,y):
foo x y
x + y
这是我创建和打印 AST 的函数。
Returns树.
parse :: String -> Either ParseError [Expr]
parse = runParser (many expr <* eof) () "[input]" . indentConfig
打印树。
printTree :: String -> IO ()
printTree line = do
let res = parse line
case res of
Left err -> print err
Right ex -> mapM_ print ex
当前输出:
Function "foo" ["x","y"] (FunctionCall "foo" [Variable "x",Variable "y"])
BinOp Plus (FunctionCall "x" []) (FunctionCall "y" [])
期望输出:
Function "foo" ["x","y"]
(FunctionCall "foo" [Variable "x",Variable "y"])
BinOp Plus (FunctionCall "x" []) (FunctionCall "y" [])
实现此目标的最佳方法是什么?
Hackage 上有几个软件包可以让您以 "indented" 方式显示此类树结构。以前,我使用 Iavor Diatchki 的 pretty-show
包,它确实做得很好。您可能想尝试一下:https://hackage.haskell.org/package/pretty-show
您可以创建自己的 prettyPrint
函数,该函数接受 AST 和缩进级别,然后递归打印 AST 中的节点,并根据需要增加缩进级别。
在此函数中,您需要专门处理增加缩进级别的 AST 节点。
下面是此类函数的示例。
data AST =
Function String [String] [AST]
| BinOp AST AST AST
| Plus
| FunctionCall String [AST]
| Variable String
deriving (Show)
prettyPrint :: Int -> AST -> String
prettyPrint n (Function a b c) = "Function " ++ show a ++ " " ++ show b ++
foldl (++) "" (map (\x -> "\n" ++ take (n + 1) (repeat '\t') ++
prettyPrint (n + 1) x) c)
prettyPrint n a = show a
请注意,可能有更简洁的方法来编写此函数,但此版本展示了实际的想法。
如果我们 运行 在您提供的示例 AST 上执行此操作,我们将得到以下内容。
λ ~ let a = (Function "foo" ["x","y"] [FunctionCall "foo" [Variable "x",Variable "y"], BinOp Plus (FunctionCall "x" []) (FunctionCall "y" [])])
λ ~ putStrLn (prettyPrint 0 a)
Function "foo" ["x","y"]
FunctionCall "foo" [Variable "x",Variable "y"]
BinOp Plus (FunctionCall "x" []) (FunctionCall "y" [])
这也适用于多级缩进。
λ ~ let b = (Function "foo" ["x","y"] [FunctionCall "foo" [Variable "x",Variable "y"], BinOp Plus (FunctionCall "x" []) (FunctionCall "y" []), Function "bar" ["x"] [BinOp Plus (FunctionCall "x" []) (FunctionCall "y" [])]])
b :: AST
λ ~ putStrLn (prettyPrint 0 b)
Function "foo" ["x","y"]
FunctionCall "foo" [Variable "x",Variable "y"]
BinOp Plus (FunctionCall "x" []) (FunctionCall "y" [])
Function "bar" ["x"]
BinOp Plus (FunctionCall "x" []) (FunctionCall "y" [])
请注意,这仅适用于您想自己实现功能的情况。从长远来看,这可能是一个更好的举措 运行 使用一个漂亮的打印库来为你处理这个问题。
我想在 Haskell 中打印抽象语法树。目前我可以逐行打印树,但我更喜欢为解析代码所在的每个块缩进它。
例如
要解析的代码:
module test
foo(x,y):
foo x y
x + y
这是我创建和打印 AST 的函数。
Returns树.
parse :: String -> Either ParseError [Expr]
parse = runParser (many expr <* eof) () "[input]" . indentConfig
打印树。
printTree :: String -> IO ()
printTree line = do
let res = parse line
case res of
Left err -> print err
Right ex -> mapM_ print ex
当前输出:
Function "foo" ["x","y"] (FunctionCall "foo" [Variable "x",Variable "y"])
BinOp Plus (FunctionCall "x" []) (FunctionCall "y" [])
期望输出:
Function "foo" ["x","y"]
(FunctionCall "foo" [Variable "x",Variable "y"])
BinOp Plus (FunctionCall "x" []) (FunctionCall "y" [])
实现此目标的最佳方法是什么?
Hackage 上有几个软件包可以让您以 "indented" 方式显示此类树结构。以前,我使用 Iavor Diatchki 的 pretty-show
包,它确实做得很好。您可能想尝试一下:https://hackage.haskell.org/package/pretty-show
您可以创建自己的 prettyPrint
函数,该函数接受 AST 和缩进级别,然后递归打印 AST 中的节点,并根据需要增加缩进级别。
在此函数中,您需要专门处理增加缩进级别的 AST 节点。
下面是此类函数的示例。
data AST =
Function String [String] [AST]
| BinOp AST AST AST
| Plus
| FunctionCall String [AST]
| Variable String
deriving (Show)
prettyPrint :: Int -> AST -> String
prettyPrint n (Function a b c) = "Function " ++ show a ++ " " ++ show b ++
foldl (++) "" (map (\x -> "\n" ++ take (n + 1) (repeat '\t') ++
prettyPrint (n + 1) x) c)
prettyPrint n a = show a
请注意,可能有更简洁的方法来编写此函数,但此版本展示了实际的想法。
如果我们 运行 在您提供的示例 AST 上执行此操作,我们将得到以下内容。
λ ~ let a = (Function "foo" ["x","y"] [FunctionCall "foo" [Variable "x",Variable "y"], BinOp Plus (FunctionCall "x" []) (FunctionCall "y" [])])
λ ~ putStrLn (prettyPrint 0 a)
Function "foo" ["x","y"]
FunctionCall "foo" [Variable "x",Variable "y"]
BinOp Plus (FunctionCall "x" []) (FunctionCall "y" [])
这也适用于多级缩进。
λ ~ let b = (Function "foo" ["x","y"] [FunctionCall "foo" [Variable "x",Variable "y"], BinOp Plus (FunctionCall "x" []) (FunctionCall "y" []), Function "bar" ["x"] [BinOp Plus (FunctionCall "x" []) (FunctionCall "y" [])]])
b :: AST
λ ~ putStrLn (prettyPrint 0 b)
Function "foo" ["x","y"]
FunctionCall "foo" [Variable "x",Variable "y"]
BinOp Plus (FunctionCall "x" []) (FunctionCall "y" [])
Function "bar" ["x"]
BinOp Plus (FunctionCall "x" []) (FunctionCall "y" [])
请注意,这仅适用于您想自己实现功能的情况。从长远来看,这可能是一个更好的举措 运行 使用一个漂亮的打印库来为你处理这个问题。