【问题标题】:Haskell: Parsec: Pipeline of transformers of the whole fileHaskell: Parsec: 整个文件的转换器管道
【发布时间】:2017-03-31 16:45:10
【问题描述】:

我正在尝试使用 parsec 读取 C/C++/java 源文件并对整个文件进行一系列转换。第一阶段删除字符串,第二阶段删除 cmets。 (那是因为你可能会在字符串中得到 /*。)

所以每个阶段都将一个字符串转换为 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。我需要提取的只是所有类和函数的开始和结束行号。所以我设想了一堆预处理阶段,它们只是清除 cmets、#defines/ifdefs、模板前导码和括号内容(因为 for 子句中的分号),然后我会解析 {s 之前的 sn-ps(或因为 typedefs 而在 }s 之后)并通过另一个阶段填充这些 sn-ps 以获取它的类型和名称,然后递归到第二级以获取 java 成员函数.)

【问题讨论】:

    标签: haskell parsec


    【解决方案1】:

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

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

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

    【讨论】:

    • 这行得通,但它看起来有点讨厌。是否可以编写一个运算符来包装它,以便我可以将其编写为 parse (stringless >>> commentless) "stdin" 输入?
    • 你可以使用do-notation。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多