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 之外,并使用多个 parses:

parse stringless "(stdin)" input >>= parse commentless "(stdin)"

可能有比您正在使用的方法更好的方法,但这会满足您的要求。