问题描述
假设我有这样的语法:
[[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 意义上的表,尽管可能有一些相似之处。无论如何,它似乎有一些有用的代码块。