如何使用表将语法转换为解析算法?

问题描述

假设我有这样的语法:

[[24],[14,27],[11,20,12,55]]

它会像这样编译成 JSON:

match start
  match first
    match rule a
    match rule b

match a
  match string,"a"

match b
  match string,"b("
  match optional
    match rule start
  match optional
    match many
      match string,","
      match rule start
  match string,")"

理论上它可以匹配这些字符串中的任何一个

{
  "start": {
    "type": "rule","name": "start","children": [
      {
        "type": "match-first","children": [
          {
            "type": "match-rule","rule": "a"
          },{
            "type": "match-rule","rule": "b"
          }
        ]
      }
    ]
  },"a": {
    "type": "rule","name": "a","children": [
      {
        "type": "match-string","value": {
          "type": "string","value": "a"
        }
      }
    ]
  },"b": {
    "type": "rule","name": "b","value": "b("
        }
      },{
        "type": "match-optional","rule": "start"
          }
        ]
      },"children": [
          {
            "type": "match-many","children": [
              {
                "type": "match-string","value": {
                  "type": "string","value": ","
                }
              },{
                "type": "match-rule","rule": "start"
              }
            ]
          }
        ]
      },{
        "type": "match-string","value": ")"
        }
      }
    ]
  }
}

我如何从这个语法 JSON 中生成一个优化的解析器(它只是在输入字符串是否匹配时返回真/假)?我最初的想法是像我的 recursive descent parser 一样尝试这样做,它只需要一个语法和一个字符串并使用“未编译”语法进行解析。但有人指出,这将是低效的,这就是“解析器-生成器”生成特定于每个语法的解析器的原因。如何使用以 JSON 形式提供的这种语法来完成?它会以某种方式涉及“解析表”吗?我不确定如何做到这一点。理想情况下,它应该在没有递归的情况下完成,以某种方式只是循环并适当地移动解析器状态。

我不确定如何开始,因为我没有从 a b() b(a) b(a,a) b(b(b())) b(a,b(a,a,b(),a)) 函数输出中看到所需的结构。

generateParser(grammar)

查看 parse table implementation in JavaScript 似乎很原始,我不知道如何应用它。

如果无法使用表格来实现这一点,那么您还会如何生成解析算法?我正在寻找的是生成的解析器关于输入字符串是否与语法匹配的真/假答案。

解决方法

如何解析取决于语法符号的语义。它有多种结构,其中有替代方案:

  • 对于“匹配第一”行,替代项是其子行。
  • 对于“匹配可选”行,替代项是其子行和空字符串。
  • 对于“匹配多个”行,替代项是其子行的重复次数。

如果在每个有替代方案的地方,语义是每个替代方案都是“有效的”,那么您的符号基本上定义了上下文无关语法,因此您可以使用大量解析选项。

然而,“先匹配”行的措辞表明它的意思是“按照给定的顺序尝试‘孩子’并使用第一个成功的”。如果是这种情况,那么看起来您的符号定义了 Parsing Expression Grammar,因此解析选项更加有限。 Packrat 解析器似乎很受欢迎。

不清楚您是否可以使用基于表的解析算法,例如您链接到的 - 维基百科文章说“也可以从解析表达式语法构建 LL 解析器和 LR 解析器”,这意味着您可以使用LL 或 LR 解析表。但是,该声明没有引用,我怀疑它是否属实。

有人给您 generateParser 代码作为解析器实现的开始吗?它有一个名为 table 的变量,但请注意,它不是 LL 或 LR 意义上的表,尽管可能有一些相似之处。无论如何,它似乎有一些有用的代码块。