我试图使用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。所有我需要提取的是所有类和函数的起始行和结束行号。所以我设想了一堆预处理阶段,它们只是擦除了注释,#definitions / ifdefs,模板前导和括号内容(因为for子句中有分号) ),然后我将解析{s(或因为typedef而导致的)之前的片段,并将这些片段填入另一个阶段,以获取其类型和名称,然后递归到第二级获取java成员函数。)
答案 0 :(得分:2)
您需要绑定Either Error
,而不是Parser
。您需要将绑定移到parse
之外,并使用多个parse
s:
parse stringless "(stdin)" input >>= parse commentless "(stdin)"
可能有比你正在使用的更好的方法,但这将做你想要的。