3

原文

The difference between top-down parsing and bottom-up parsing
http://qntm.org/top


给定一套形式化文法和这套文法生成的字符串
parsing (解析)就是分析出字符串产生的过程

对于上下文无关文法, 生成过程以 parse tree 的形式出现
我买开始前, 先要知道 parse tree 的两件事:
根节点, 字符衍生出来的初始的符号
叶节点, 字符串按照顺序的所有字符
我们所不知道的是两者之间的节点和分支

比如对于字符串 acddf, 我们已经知道的是

    S
   /|\

   ???

| | | | |
a c d d f

这篇文章作为例子的文法:

  • S → xyz | aBC

  • B → c | cd

  • C → eg | df

自底向上解析

这个方案和拼图没有本质差别
我们从 parse tree 的底部开始, 从单个的字符开始
随后是有规则将字符尽自己所能拼接成更大的 token
字符串最终的结果, 一切都应该被结合到一个单个巨大的 S
而且 S 应该是我们剩下的唯一的内容
如果不是, 那么就需要回溯尝试用别的办法尝试合并出 token

在自底向上解析中,一般会维护一个 stack
也就是已经读取的所有的字符和 token
每一个步骤, 一个新的字符会被插图到 stack 顶部
然后尽可能地结合字符并归纳为更大的 token

例子

字符串是 acddf

步骤
  • ε 无法归纳

  • a 无法归纳

  • ac 可以被归纳, 如下:

  • 归纳 acaB

    • aB 无法归纳

    • aBd 无法归纳

    • aBdd 无法归纳

    • aBddf 可以被归纳, 如下:

    • 归纳 aBddfaBdC

      • aBdC 无法归纳

      • 字符串完. Stack 为 aBdC, 非 S. 失败! 需要回溯.

    • aBddf 无法归纳

  • ac 无法归纳

  • acd 可以被归纳, 如下:

  • 归纳 acdaB

    • aB 无法归纳

    • aBd 无法归纳

    • aBdf 可以被归纳, 如下:

    • 归纳 aBdfaBC

      • aBC 可以被归纳, 如下:

      • 归纳 aBCS

        • 字符串完. Stack 为 S. 成功!

Parse trees
|
a
| |
a c
  B
| |
a c
  B
| | |
a c d
  B
| | | |
a c d d
  B
| | | | |
a c d d f
  B   C
| | | |\
a c d d f
| |
a c
| | |
a c d
    B
|  /|
a c d
    B
|  /| |
a c d d
    B
|  /| | |
a c d d f
    B C
|  /| |\
a c d d f
    S
   /|\
  / | |
 /  B C
|  /| |\
a c d d f

例子 2

如果所有符合都失败, 那么字符串无法被解析

字符串为 acdg

步骤
  • ε 无法归纳

  • a 无法归纳

  • ac 可以被归纳, 如下:

  • 归纳 acaB

    • aB 无法归纳

    • aBd 无法归纳

    • aBdg 无法归纳

    • 字符串完. Stack 为 aBdg, 非 S. 失败! 需要回溯.

  • ac 无法归纳

  • acd 可以被归纳, 如下:

  • 归纳 acdaB

    • aB 无法归纳

    • aBg 无法归纳

    • 字符串完. Stack 为 aBg, 非 S. 失败! 需要回溯.

  • acd 无法归纳

  • acdg 无法归纳

  • 字符串完. Stack 为 acdg, 非 S. 没有可用的回溯. 失败!

Parse trees
|
a
| |
a c
  B
| |
a c
  B
| | |
a c d
  B
| | | |
a c d g
| |
a c
| | |
a c d
    B
|  /|
a c d
    B
|  /| |
a c d g
| | |
a c d
| | | |
a c d g

自顶向下解析

这套方案中设想字符串匹配 S 并查看这个假设的内部逻辑提示
比如当字符串匹配 S 逻辑上按时或者
(1) 字符串匹配 xyz 或 (2) 字符串匹配 aBC
当知道 (1) 不对, 那么 (2) 必须是对的, 而 (2) 内部有更深的逻辑提示
这些必须逐个检查以验证基本的假设

例子

字符串是 acddf

步骤
  • 断言 1: acddf 匹配 S

    • 断言 2: acddf 匹配 xyz:

    • 断言 为否. 尝试其他.

    • 断言 2: acddf 匹配 aBC, 即 cddf 匹配 BC:

      • 断言 3: cddf 匹配 cC, 即 ddf 匹配 C:

        • 断言 4: ddf 匹配 eg:

        • 否.

        • 断言 4: ddf 匹配 df:

        • 否.

      • 断言 3 为否. 尝试其他.

      • 断言 3: cddf 匹配 cdC, 即 df 匹配 C:

        • 断言 4: df 匹配 eg:

        • 否.

        • 断言 4: df 匹配 df:

        • 断言 4 为真.

      • 断言 3 为真.

    • 断言 2 为真.

  • 断言 1 为真. 成功!

Parse trees
    S
    |
    S
   /|\
  a B C
    | |
    S
   /|\
  a B C
    | |
    c
    S
   /|\
  a B C
   /| |
  c d
    S
   /|\
  a B C
   /| |\
  c d d f

例子 2

如果, 试验了所有逻辑线索, 依然无法验证基本假设("字符串匹配 S")
那么字符串无法被解析

字符串为 acdg

步骤
  • 断言 1: acdg 匹配 S:

    • 断言 2: acdg 匹配 xyz:

    • 否.

    • 断言 2: acdg 匹配 aBC, 即 cdg 匹配 BC:

      • 断言 3: cdg 匹配 cC, 即 dg 匹配 C:

        • 断言 4: dg 匹配 eg:

        • 否.

        • 断言 4: dg 匹配 df:

        • 否.

      • 否.

      • 断言 3: cdg 匹配 cdC, 即 g 匹配 C:

        • 断言 4: g 匹配 eg:

        • 否.

        • 断言 4: g 匹配 df:

        • 否.

      • 否.

    • 否.

  • 断言 1 为否. 失败!

Parse trees
    S
    |
    S
   /|\
  a B C
    | |
    S
   /|\
  a B C
    | |
    c
    S
   /|\
  a B C
   /| |
  c d

为什么做递归是自顶向下解析器的一个问题

如果规则是做递归, 比如这样的内容

  • S → Sb

可以注意到算法的行为是:

步骤

  • 断言 1: acddf 匹配 S:

    • 断言 2: acddf 匹配 Sb:

      • 断言 3: acddf 匹配 Sbb:

        • 断言 4: acddf 匹配 Sbbb:

          • ...无穷无尽

Parse trees

  S
  |
  S
  |\
  S b
  |
  S
  |\
  S b
  |\
  S b
  |
  S
  |\
  S b
  |\
  S b
  |\
  S b
  |
...

题叶
17.3k 声望2.6k 粉丝

Calcit 语言作者


引用和评论

0 条评论