Haskell:Parsec:整个文件的变换器管道

时间:2017-03-31 16:45:10

标签: haskell parsec

我试图使用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成员函数。)

1 个答案:

答案 0 :(得分:2)

您需要绑定Either Error,而不是Parser。您需要将绑定移到parse之外,并使用多个parse s:

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

可能有比你正在使用的更好的方法,但这将做你想要的。