【问题标题】:Is there an established way to write parsers that can reconstruct their exact input?是否有一种既定的方法来编写可以重建其确切输入的解析器?
【发布时间】:2016-05-30 15:54:08
【问题描述】:

假设我想解析语言 X 的文件。真的,我只对其中的一小部分信息感兴趣。为此目的,在 Haskell 的众多 eDSL 之一中编写解析器很容易(例如 Megaparsec)。

data Foo = Foo Int  -- the information I'm after.

parseFoo :: Parsec Text Foo
parseFoo = ...

这很容易产生一个函数getFoo :: Text -> Maybe Foo

但是现在我也想修改Foo信息的来源,即基本上我要实现

changeFoo :: (Foo -> Foo) -> Text -> Text

属性

changeFoo id ≡ id
getFoo . changeFoo f ≡ fmap f . getFoo

可以通过将解析器的结果更改为类似镜头的东西来做到这一点

parseFoo :: Parsec Text (Foo, Foo -> Text)
parseFoo = ...

但这使得定义变得更加麻烦——我不能再仅仅掩盖不相关的信息,而是需要存储每个 string 子解析的匹配项并手动重新组合它。

这可以通过将字符串重新组合保持在解析器 monad 周围的 StateT 层中来实现某种程度的自动化,但我不能只使用现有的原始解析器。

这个问题有现成的解决方案吗?

【问题讨论】:

  • 解析库通常会构建一个“抽象语法树”,它会忽略所有格式。您正在寻找的是“具体语法树”。我不知道有什么库可以构建它。
  • 我通常在Prolog中使用definite clause grammars进行双向解析,但是在Haskell中我没见过这样的东西。

标签: parsing haskell parsec bijection


【解决方案1】:

这是“双向转换”的情况吗?例如,http://ceur-ws.org/Vol-1571/

特别是 Rendel 和 Osterman 的“可逆语法描述:统一解析和漂亮打印” http://dblp.org/rec/conf/haskell/RendelO10,2010 年 Haskell 研讨会(参见 http://lambda-the-ultimate.org/node/4191

【讨论】:

  • 是的,这很棒;但它真的解决了我的问题吗?我的印象是这些可逆解析器主要保证parse . print ≡ id。他们还能保证print . parse的任何事情吗?
  • 如果你的打印很漂亮,那么print ( parse s) === s 模空格?构建用于精确打印的基本打印机/解析器应该更容易。
  • 嗯,问题是,在我的应用程序中,文件的大部分是“空白”(或者更确切地说是“cmets”),因为我并不费心去实际解析大部分详细的内容,只有几个变量。
  • 您需要一个空白解析器来返回它所读取的内容,而不是忽略它? “镜头”模型对我来说看起来很合理。它是否有用取决于组合器。我不会只责怪类型......
【解决方案2】:

在 Haskell 中实现的解决方案?我一个都不知道;它们可能存在。

不过,一般来说,通过使用收集的令牌存储“格式化”信息,可以存储足够的信息来重新生成在任意程度上类似于原始程序的合法版本的程序。在限制中,格式信息为token的原始字符串;任何近似值都会给出越来越不准确的答案。

如果您将空格作为显式标记保留在解析树中,则在限制范围内您甚至可以重新生成它。这是否有用可能取决于应用程序。总的来说,我认为这是矫枉过正。

关于捕获什么/如何捕获以及如何重新生成的详细信息可以在我的 SO 答案中找到:Compiling an AST back to source code

【讨论】:

    猜你喜欢
    • 2011-02-15
    • 1970-01-01
    • 1970-01-01
    • 2011-02-27
    • 2011-03-05
    • 2020-01-14
    • 2021-02-21
    • 1970-01-01
    • 2021-08-04
    相关资源
    最近更新 更多