Haskell: Parsec: 整个文件的转换器流水线
Haskell: Parsec: Pipeline of transformers of the whole file
我正在尝试使用 parsec 读取 C/C++/java 源文件并对整个文件进行一系列转换。第一阶段删除字符串,第二阶段删除评论。 (那是因为您可能会在字符串中得到一个 /*。)
所以每个阶段都将一个字符串转换为 Either String Error,我想将它们绑定(在 Either 的意义上)在一起以创建整个文件的转换管道。这似乎是一个相当普遍的要求。
import Text.ParserCombinators.Parsec
commentless, stringless :: Parser String
stringless = fmap concat ( (many (noneOf "\"")) `sepBy` quotedString )
quotedString = (char '"') >> (many quotedChar) >> (char '"')
quotedChar = try (string "\\"" >> return '"' ) <|> (noneOf "\"")
commentless = fmap concat $ notComment `sepBy` comment
notComment = manyTill anyChar (lookAhead (comment <|> eof))
comment = (string "//" >> manyTill anyChar newline >> spaces >> return ())
<|> (string "/*" >> manyTill anyChar (string "*/") >> spaces >> return ())
main =
do c <- getContents
case parse commentless "(stdin)" c of -- THIS WORKS
-- case parse stringless "(stdin)" c of -- THIS WORKS TOO
-- case parse (stringless `THISISWHATIWANT` commentless) "(stdin)" c of
Left e -> do putStrLn "Error parsing input:"
print e
Right r -> print r
那我该怎么做呢?我尝试了 parserBind 但它没有用。
(万一有人关心为什么,我正在尝试做一种简单的解析,我只提取我想要的东西,但避免解析整个语法,甚至不知道它是 C++ 还是 Java。所有我需要提取的是所有 类 和函数的开始和结束行号。所以我设想了一堆预处理阶段,这些阶段只是清除注释、#defines/ifdefs、模板序言和括号的内容(因为for 子句中的分号),然后我将解析 {s 之前的片段(或由于 typedef 而在 } 之后的片段)并通过另一个阶段填充这些片段以获取它的类型和名称,然后递归到第二层获得java个成员函数。)
您需要绑定 Either Error
,而不是 Parser
。您需要将绑定移到 parse
之外,并使用多个 parse
s:
parse stringless "(stdin)" input >>= parse commentless "(stdin)"
可能有比您正在使用的方法更好的方法,但这会满足您的要求。
我正在尝试使用 parsec 读取 C/C++/java 源文件并对整个文件进行一系列转换。第一阶段删除字符串,第二阶段删除评论。 (那是因为您可能会在字符串中得到一个 /*。)
所以每个阶段都将一个字符串转换为 Either String Error,我想将它们绑定(在 Either 的意义上)在一起以创建整个文件的转换管道。这似乎是一个相当普遍的要求。
import Text.ParserCombinators.Parsec
commentless, stringless :: Parser String
stringless = fmap concat ( (many (noneOf "\"")) `sepBy` quotedString )
quotedString = (char '"') >> (many quotedChar) >> (char '"')
quotedChar = try (string "\\"" >> return '"' ) <|> (noneOf "\"")
commentless = fmap concat $ notComment `sepBy` comment
notComment = manyTill anyChar (lookAhead (comment <|> eof))
comment = (string "//" >> manyTill anyChar newline >> spaces >> return ())
<|> (string "/*" >> manyTill anyChar (string "*/") >> spaces >> return ())
main =
do c <- getContents
case parse commentless "(stdin)" c of -- THIS WORKS
-- case parse stringless "(stdin)" c of -- THIS WORKS TOO
-- case parse (stringless `THISISWHATIWANT` commentless) "(stdin)" c of
Left e -> do putStrLn "Error parsing input:"
print e
Right r -> print r
那我该怎么做呢?我尝试了 parserBind 但它没有用。
(万一有人关心为什么,我正在尝试做一种简单的解析,我只提取我想要的东西,但避免解析整个语法,甚至不知道它是 C++ 还是 Java。所有我需要提取的是所有 类 和函数的开始和结束行号。所以我设想了一堆预处理阶段,这些阶段只是清除注释、#defines/ifdefs、模板序言和括号的内容(因为for 子句中的分号),然后我将解析 {s 之前的片段(或由于 typedef 而在 } 之后的片段)并通过另一个阶段填充这些片段以获取它的类型和名称,然后递归到第二层获得java个成员函数。)
您需要绑定 Either Error
,而不是 Parser
。您需要将绑定移到 parse
之外,并使用多个 parse
s:
parse stringless "(stdin)" input >>= parse commentless "(stdin)"
可能有比您正在使用的方法更好的方法,但这会满足您的要求。