【问题标题】:When would a parser append its input string?解析器何时会附加其输入字符串?
【发布时间】:2019-04-20 07:42:26
【问题描述】:

给定一个解析器

newtype Parser a = Parser { parse :: String -> [(a,String)] }

(>>=) :: Parser a -> (a -> Parser b) -> Parser b
p >>= f = Parser $ \s -> concat [ parse (f a) s' | (a, s') <- parse p s ]

return :: a -> Parser a
return a = Parser (\s -> [(a,s)])

item :: Parser Char
item = Parser $ \s -> case cs of
                         ""     -> []
                         (c:cs) -> [(c,cs)]

我们可以看到item 消耗了给它的部分输入字符串("abc" -&gt; [('a', "bc")])。是否存在解析器会产生额外的字符串输出或替换/修改它的情况(例如Parser $ \s -&gt; [((), 'a':s)])?我怀疑上下文相关的语法可能就是这种情况,但很难想出一个合理的例子。

对于现实世界的问题这样做有意义吗?

参考文献

【问题讨论】:

    标签: parsing haskell grammar


    【解决方案1】:

    这里有几种可以方便地将令牌注入输入流的情况。 (如何将其实际集成到解析管道中是另一个问题。)

    1. 宏扩展,采用 C/C++ 预处理阶段的风格。这可以说不是宏观扩张的最佳模式;卫生宏更有可能使用树转换来扩展,就像 C++ 模板解析一样。但是面向令牌的预处理器不会很快消失。由于它没有与语言语法紧密耦合,因此最简单的实现是将宏(和参数,如果适用)替换为其扩展中的标记。

    2. Ecmascript 样式的自动分号插入 (ASI)。语言语法要求在某些精确定义的情况下将分号插入到令牌流中,这很难(至少)合并到 CFG 中。由于 ASI 仅在输入流中的下一个标记不能移动(并且完成其他条件)时才有可能,因此它当然可以集成到解析器循环中。

    3. 同样,缩进感知块语法(例如在 Haskell 和 Python 中)当然可以通过用注入的 INDENT 令牌或一些注入的 DEDENT 替换前导空格来实现。由于这种替换取决于解析上下文(例如,它不是在括号内完成),因此在解析器中注入可能是一种合理的方法。

    这不是一个详尽的列表,但它可能至少具有指示性。并非所有这些情况都必然涉及上下文敏感性(我相信 ASI 在理论上可以用上下文无关语法处理,尽管我无意尝试)并且并非所有上下文敏感性实例都必然需要令牌注入(歧义在 C 中,类型和变量名称之间只需要选择正确的标记)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-10-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-03
      • 1970-01-01
      相关资源
      最近更新 更多