【问题标题】:Recursive Descent vs Lex/Parse?递归下降与 Lex/Parse?
【发布时间】:2012-03-17 02:29:51
【问题描述】:

我想我(大致)了解递归下降解析器(例如 Scala 的解析器组合器)是如何工作的:您使用一个解析器解析输入字符串,然后该解析器为整个输入的每个“部分”调用其他更小的解析器,并且以此类推,直到您到达直接从输入字符串的片段生成 AST 的低级解析器

我也认为我了解 Lexing/Parsing 的工作原理:首先运行词法分析器将整个输入分解为一个扁平的令牌列表,然后运行一个解析器来获取令牌列表并生成一个 AST。

但是,我不明白 Lex/Parse 策略如何处理您如何准确标记某事物取决于之前标记的标记的情况。例如,如果我取一大块 XML:

"<tag attr='moo' omg='wtf'>attr='moo' omg='wtf'</tag>"

递归下降解析器可能会将其分解(每个后续缩进代表父字符串的分解)

"<tag attr='moo' omg='wtf'>attr='moo' omg='wtf'</tag>" 
  -> "<tag attr='moo' omg='wtf'>"
       -> "<tag"
       -> "attr='moo'"
            -> "attr"
            -> "="
            -> "moo"
       -> "omg='wtf'"
            -> "omg"
            -> "="
            -> "wtf" 
       -> ">"
  -> "attr='moo' omg='wtf'"
  -> "</tag>"

然后,单独解析&lt;tagattr="moo" 等的小型解析器将构建 XML 标记的表示并为其添加属性。

但是,单步 Lex/Parse 如何工作?词法分析器如何知道&lt;tag&gt; 之前的字符串必须标记为单独的属性,而&gt;&lt;/tag&gt; 之间的字符串不需要?它不需要解析器告诉它第一个字符串在标签正文内,而第二种情况在标签正文外吗?

编辑:更改示例以使其更清晰

【问题讨论】:

  • 一个词法分析器会产生类似LEFTANGLE IDENT=tag IDENT=attr EQ STRING=moo IDENT=omg等的东西
  • @SK-logic:编辑问题以澄清。我的困惑是,如果标签主体有一个attr='moo' outside,词法分析器怎么知道不将其分解为IDENT=tag,而只是将其标记为一个大文本节点?跨度>
  • 好的,我明白了——它不会用词法分析器将这些东西标记为单个大字符串,你必须解构一个字符串(当然,丢失所有的空格)。
  • 您对它的工作原理有错误的概念。状态由递归处理。您的代码将从查看左尖括号开始,然后分支到 ReadTag 方法。 ReadTag 方法会在看到标识符时调用 ReadParameter。因此,您的上下文保存在 ReadTag 方法中。如果从来没有左尖括号,那么标签之外的部分将进入不同的子例程,并且可能在其中被视为文本。这就是递归下降得名的地方。

标签: parsing lexical-analysis


【解决方案1】:

Lexer 如何知道 must 后面的字符串 被标记为单独的属性,而 > 和之间的字符串 不需要吗?

没有。

它不需要解析器告诉它第一个字符串在 一个标签体,第二种情况在标签体之外?

是的。

通常,词法分析器将输入流转换为 tokens 序列。一个标记没有上下文——也就是说,一个标记无论出现在输入流中的什么位置都具有相同的含义。词法分析过程完成后,每个令牌都被视为一个单元。

对于 XML,生成的词法分析器通常会识别整数、标识符、字符串文字等以及控制字符,如“”,但不会识别整个标签。理解什么是打开标签、关闭标签、属性、元素等的工作留给了解析器本身。

【讨论】:

    【解决方案2】:

    通常,词法分析器会有一个“模式”或“状态”设置,它们会根据输入而变化。例如,在看到&lt; 字符时,模式将更改为“标记”模式,词法分析器将适当地进行标记,直到看到&gt;。然后它将进入“内容”模式,词法分析器会将所有attr='moo' omg='wtf' 作为单个字符串返回。例如,编程语言词法分析器以这种方式处理字符串文字:

    string s1 = "y = x+5";
    

    y = x+5 永远不会被处理为数学表达式,然后又转换回字符串。它被识别为字符串文字,因为" 更改了词法分析器模式。

    对于 XML 和 HTML 等语言,构建自定义解析器可能比使用 yacc、bison 或 ANTLR 等解析器生成器之一更容易。它们的结构与编程语言不同,更适合自动化工具。

    如果您的解析器需要将标记列表转换回它来自的字符串,这表明设计中有问题。您需要以不同的方式解析它。

    【讨论】:

    • 是否正确地说这些需要“上下文敏感标记化”的语言将需要在词法分析器中复制一些解析器逻辑(就让词法分析器的状态机与解析器的状态机),如果您大量使用词法分析器状态,哪种会破坏词法分析器/分析器的关注点分离?而且这种递归下降比一步式词法分析/解析更通用(即使分离得不太好)?
    • 通常,词法分析器状态将由词法分析器本身管理。上面的例子可以这样做。我确信存在解析器会与词法分析器通信以更改其状态的示例。但我同意你的说法。如果你必须做很多这样的事情,那么该语言不适合这些工具,递归下降,甚至是临时解析器会更好。我认为 FORTRAN 属于这一类。它早于自动化工具,也早于许多形式解析理论,解析它的唯一方法是使用完全自定义的解析器。
    • 感谢您的回答!这是困扰我一段时间的事情,尤其是因为大多数时候当我询问“解析”时,我只听到“正则表达式”和“lex/yacc”或“标记器/解析器”,而且我一直认为递归下降(解析器组合器)在一些非常简单的情况下感觉更自然。很高兴知道我没疯 =)。
    猜你喜欢
    • 1970-01-01
    • 2015-08-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多