Parsing 使用Haskell';用于编程语言转换器的s-Parsec

Parsing 使用Haskell';用于编程语言转换器的s-Parsec,parsing,haskell,interpreter,parsec,Parsing,Haskell,Interpreter,Parsec,假设我有两种语言(A和B)。我的目标是编写某种类型的程序,将A中的语法转换为B的等效语法。目前我的解决方案是使用Haskell的Parsec来执行此任务。然而,对于刚接触Haskell和函数式编程的人来说,在Parsec中找到一个简单的例子是相当困难的。我在网上找到的例子要么是不完整的例子(对于一个新的Haskell程序员来说令人沮丧),要么离我的目标太远 那么,有人能给我提供一个非常简单和明确的例子,说明如何使用Parsec来实现我想要实现的目标吗?或者甚至是一些与我的目标类似的教程 谢谢 考

假设我有两种语言(A和B)。我的目标是编写某种类型的程序,将A中的语法转换为B的等效语法。目前我的解决方案是使用Haskell的Parsec来执行此任务。然而,对于刚接触Haskell和函数式编程的人来说,在Parsec中找到一个简单的例子是相当困难的。我在网上找到的例子要么是不完整的例子(对于一个新的Haskell程序员来说令人沮丧),要么离我的目标太远

那么,有人能给我提供一个非常简单和明确的例子,说明如何使用Parsec来实现我想要实现的目标吗?或者甚至是一些与我的目标类似的教程


谢谢

考虑以下CSV文档的简单语法(在ABNF中):

我们想编写一个转换器,将此语法转换为TSV(制表符分隔值)文档:

tsv   = *trow
trow  = *(tcell HTAB) tcell CR
tcell = DQUOTE *(ALPHA / DIGIT) DQUOTE
首先,让我们创建一个描述抽象语法树的代数数据类型。包括类型同义词以便于理解:

data XSV  = [Row]
type Row  = [Cell]
type Cell = String
为这种语法编写解析器非常简单。我们编写一个解析器,就像我们要描述ABNF一样:

csv :: Parser XSV
csv = XSV <$> many crow

crow :: Parser Row
crow = do cells <- ccell `sepBy` (char ',')
          newline
          return cells

ccell :: Parser Cell
ccell = do char '\''
           content <- many (digit <|> letter)
           char '\''
           return content
将这两件事联系起来,就可以得到一个转换函数:

csvToTSV :: String -> Maybe String
csvToTSV document = case parse csv "" document of
  Left _    -> Nothing
  Right xsv -> xsvToTSV xsv

就这些!Parsec还有许多其他功能来构建极其复杂的解析器。这本书有一个很好的关于解析器的章节,但是有点过时了。不过,其中大部分仍然是正确的。如果您还有其他问题,请随时提问。

我感觉到您的痛苦。如果你不想把解析和词法混为一谈的话,你可能还想调查一下alex。看看人们认为拥有AST就足以对大多数编程语言做任何真正有用的事情。这是完全错误的;你需要更多的机器。解析器不能做到这一点。当然,正如您所观察到的,解析是一个先决条件。很高兴在芥子气之外被警告有钉子坑,但你可能仍然需要使用防毒面具的帮助。我不介意人们得到防毒面具。我反对那种天真的想法,认为一个人所需要的就是一个防毒面具;在他们到达之前,没有人问起钉坑的事,然后他们表现得很惊讶。更重要的是,在意外发生后,他们自然会掉进坑里死去,除了浪费时间和宝贵资源外,什么也没有发生。问题是社区似乎根本不理解这一课。请注意,这段代码未经测试。如果它不起作用,请责怪我,并详细说明什么不起作用。CSV文档语法中的“cell”必须是“ccell”(第二行),不是吗?你能告诉我“CR”在语法中代表什么吗?XSV解析器在哪里负责对文档中的每一行应用行进行解析?提前谢谢!CR为回车;在本例中,它只是表示一个换行符。换行符因操作系统而异。解析器
crow
解析整行,包括换行符
csv
只需尽可能频繁地应用
crow
解析器,直到它失败或消耗所有输入。
只是结束结果。(我这样做是为了避免也可能出现的do符号)有关
CR
的定义,请参阅。这是ABNF中预定义的规则之一。
xsvToTSV :: XSV -> String
xsvToTSV xst = unlines (map toLines xst) where
  toLines = intersperse '\t'
csvToTSV :: String -> Maybe String
csvToTSV document = case parse csv "" document of
  Left _    -> Nothing
  Right xsv -> xsvToTSV xsv