【问题标题】:Combining lexer and parser in a parser combinator在解析器组合器中组合词法分析器和解析器
【发布时间】:2013-08-13 16:17:26
【问题描述】:

我正在使用uu-parsinglib,但我认为以下问题是解析器组合器泛型。

让我们考虑以下示例:

我有一个带有组合器pLex 的词法分析器,它产生一个标记列表(类型为MyToken)。我现在想编写一个解析器,它将使用令牌并构建一个AST

连接词法分析器和解析器的最佳方式是什么?现在我有一个lex 函数:

lex s = parse ( (,) <$> pLex <*> pEnd) (createStr (LineColPos 0 0 0) s)

我应该创建一个函数parse p = ...吗?如果是,我如何构造它来跟踪来自词法分析器的列和行?或者我应该创建一个parserCombinator,它会以某种方式使用pLex 组合器?

【问题讨论】:

  • 在我的手机上,所以我现在只指出:在 BasicInstances 模块中有 Str 类型和 createStr 可用于创建令牌流。
  • 其他解析组合库有时也包含词法分析。为此,请参阅 Parsec 或解析器中的令牌解析模块。通常,这就是您使用解析器组合器的方向。但是您始终可以将杠杆的输出(例如 [MyToken])作为输入提供给令牌解析器。
  • @J.Abrahamson:我有相当大的语法,所以我不知道包含词法分析器和解析器是否是个好主意(但也许使用解析器组合器这是要走的路?)我'我遇到了这个问题,因为例如我的组合器“pString”返回一个标记的 list (因为在我的语言中,stirngs cna 有像"test: $name" 这样的变量。所以通常我写了一些“结束" 组合器,这会产生令牌列表,然后我将它们加在一起。这是一个不好的方法吗?
  • @J.Abrahamson:如果你能告诉我如果你有一些组合器,你将如何设计解析器,我将非常感激,它们必须返回一个令牌列表(如上面的字符串或 pNewline,它应该返回 NewlineIndent Int(新行缩进)标记)。令牌流可能有效,但也许有更好的方法?
  • 您可以在主解析期间生成的每个令牌流上触发子解析器。因此,如果tokenizeSegment :: P String [MyToken]parseSegment :: P [MyToken] SegmentAST 则执行parse parseSegment &lt;$&gt; tokenizeSegment :: P String (Either ParseError SegmentAST) 之类的操作。您还可以通过解构 Either 并将 ParseError 传递给主解析器来处理该错误。

标签: parsing haskell parser-combinators uu-parsinglib


【解决方案1】:

基于表的解析器需要分离词法分析和解析,因为它们的先行能力有限。向前看足够远以将词法分析结合到解析器中会爆炸状态空间。

基于组合器的方法通常不会遇到这个问题,因为它们通常进行递归下降解析。除非库作者另有说明,否则合并这些阶段并没有什么害处,分离它们也不会带来太多好处。

虽然 uu-parsinglib 提供了 Str 类来抽象不同的类似字符串的输入,但查看它的定义表明它仍然假设您最终读取的是一个 Char 序列,无论它们来自 String、ByteString、文本等。因此试图让它解析 MyToken 流似乎很困难。如果您觉得需要,Parsec 可能是更好的选择。

关于你的字符串实现的问题,组合器接受一个包含句法结构的类似字符串的输入,如果它们匹配,则返回相应的语义值。在组合器内部,您可以通过从输入流中获取直接解析的内容构建该语义值,并且通过组合来自您调用的子组合器的语义值。

因此,由于它所做的解析,您示例中的“字符串匹配”组合器将在其范围内包含一个标记列表。您可以使用 Haskell 的全部功能以任何对您的语言有意义的方式将这些标记组合成一个 MyString 值:也许是一个 'SplicedString' 类型,表示要切入其中的值。

字符串组合器可能由“表达式”组合器调用,它能够将 MyString 值与其他解析值组合成 MyExpression 值。它是组合器一直返回语义值!

【讨论】:

  • 感谢您的回答 - 似乎我不应该将解析步骤分为词法分析和解析。我一直觉得创建“lexer/toenizer”和“parser”非常“纯粹”,但现在我正在慢慢改变主意:)
  • 对它们进行一些划分仍然可能有意义,将您的令牌匹配组合器放在一个模块中,将您的解析组合器放在另一个模块中。但是,将解析器构建到词位级别的一个有趣之处在于,您可以根据解析上下文以不同方式进行词法分析。例如,您的特殊字符串可以使用一组不同的组合子来对字符串内的拼接进行词法分析。
  • 谢谢 :) 你知道(顺便说一句)是否有一种简单的方法可以在uu-parsinglib 中创建“状态”?我的意思是 - 创建一个组合器,它可以使用来自StateMonadputget
  • 我在您所做的另一篇文章中回答了这个问题,并提示您如何制作令牌解析器,因为两者是相关的。如果您发现我的回答有帮助,请不要忘记投票/标记为已回答。谢谢!
  • 谢谢 :) 我从来没有忘记投票/标记为已回答 :) 我有时只想简单地阅读答案,检查我是否可以继续进行并进一步询问是否有不清楚的地方 :) 谢谢再次向您求助! :)
【解决方案2】:

我认为 uu-parsinglib 中没有任何内容可以阻止您使用不同于 Text 的输入。只是对于文本(和朋友),我们提供了您可能需要的相当多的功能。如果您查看较旧的 uulib 解析器组合器,您会发现一种基于扫描器的方法,它可以与较新的 uu-parsinglib 一起使用。

如果您想处理大量数据,最好有单独的扫描阶段。错误消息往往提供更多信息。在 uulib 中,您会发现一些对编写扫描器的支持(大多数语言以某种方式对词汇结构施加了一些特殊限制/要求,相当多的工具会(失败/需要调整)来创建您的扫描器(例如越位规则))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-09-13
    • 2015-09-15
    • 2020-01-17
    • 1970-01-01
    • 1970-01-01
    • 2013-01-31
    • 1970-01-01
    相关资源
    最近更新 更多