这个文法能否被预测递归下降解析器和带回溯的解析器解析
Can this grammar be parsed by both predictive recursive descent parser and the parser with backtracking
我有以下语法:
IdentifierName ::
IdentifierStart
IdentifierName IdentifierPart
其中使用单词 git
应该被解析为以下解析树:
IdentifierName
/ \
IdentifierName IdentifierPart
/ \ |
IdentifierName IdentifierPart 't'
| |
IdentiiferStart 'i'
|
'g'
我想编写一个递归下降算法来做到这一点。现在我有两个选择,要么编写一个带有 backtracking 的递归下降解析器,要么编写一个 predictive 递归下降解析器。它们都是 而非 table 驱动解析器。但是,我已经读到,对于带回溯的递归下降,我需要消除左递归。问题中的语法似乎是递归的。
那么我是否需要重构语法或使用预测算法?
是的,语法是左递归的,因此不是 LL。回溯和预测 LL 解析器都不能处理这样的语法。因此,您要么需要更改语法,要么使用其他算法,例如 LR 解析算法。
注意这个文法是正则的,所以其实可以翻译成正则表达式或者直接翻译成有限自动机。
在编写 JavaScript 的真实世界实现时,像这样的词法规则将在词法分析器中处理,只有其他规则将由解析器处理(但是那些指定的左递归同样,因此它们也必须重写才能被 LL 解析器解析。
这往往是词法分析器的工作,而不是解析器的工作。通常,词法分析器在一个循环中一次处理一个字符,使用一个大的 switch 语句(或者等效的 "initial character table" 如果数据驱动。)
// near the end of the big "switch (ch) {" statement ...
default:
if (!isIdentifierStart(chInit))
{
log(Severity.ERROR, ILLEGAL_CHAR, new Object[]{quotedChar(chInit)},
lInitPos, source.getPosition());
}
// fall through
case 'A':case 'B':case 'C':case 'D':case 'E':case 'F':case 'G':
case 'H':case 'I':case 'J':case 'K':case 'L':case 'M':case 'N':
case 'O':case 'P':case 'Q':case 'R':case 'S':case 'T':case 'U':
case 'V':case 'W':case 'X':case 'Y':case 'Z':
case 'a':case 'b':case 'c':case 'd':case 'e':case 'f':case 'g':
case 'h':case 'i':case 'j':case 'k':case 'l':case 'm':case 'n':
case 'o':case 'p':case 'q':case 'r':case 's':case 't':case 'u':
case 'v':case 'w':case 'x':case 'y':case 'z':
case '_':
{
while (source.hasNext())
{
if (!isIdentifierPart(nextChar()))
{
source.rewind();
break;
}
}
String name = source.toString(lInitPos, source.getPosition());
// ...
}
如果手动构建,我发现拥有专用的词法分析器(从字符流中生成标记)和解析器(从标记流中生成 AST)比尝试将它们组合到一个解析器中要容易得多.
我有以下语法:
IdentifierName ::
IdentifierStart
IdentifierName IdentifierPart
其中使用单词 git
应该被解析为以下解析树:
IdentifierName
/ \
IdentifierName IdentifierPart
/ \ |
IdentifierName IdentifierPart 't'
| |
IdentiiferStart 'i'
|
'g'
我想编写一个递归下降算法来做到这一点。现在我有两个选择,要么编写一个带有 backtracking 的递归下降解析器,要么编写一个 predictive 递归下降解析器。它们都是 而非 table 驱动解析器。但是,我已经读到,对于带回溯的递归下降,我需要消除左递归。问题中的语法似乎是递归的。
那么我是否需要重构语法或使用预测算法?
是的,语法是左递归的,因此不是 LL。回溯和预测 LL 解析器都不能处理这样的语法。因此,您要么需要更改语法,要么使用其他算法,例如 LR 解析算法。
注意这个文法是正则的,所以其实可以翻译成正则表达式或者直接翻译成有限自动机。
在编写 JavaScript 的真实世界实现时,像这样的词法规则将在词法分析器中处理,只有其他规则将由解析器处理(但是那些指定的左递归同样,因此它们也必须重写才能被 LL 解析器解析。
这往往是词法分析器的工作,而不是解析器的工作。通常,词法分析器在一个循环中一次处理一个字符,使用一个大的 switch 语句(或者等效的 "initial character table" 如果数据驱动。)
// near the end of the big "switch (ch) {" statement ...
default:
if (!isIdentifierStart(chInit))
{
log(Severity.ERROR, ILLEGAL_CHAR, new Object[]{quotedChar(chInit)},
lInitPos, source.getPosition());
}
// fall through
case 'A':case 'B':case 'C':case 'D':case 'E':case 'F':case 'G':
case 'H':case 'I':case 'J':case 'K':case 'L':case 'M':case 'N':
case 'O':case 'P':case 'Q':case 'R':case 'S':case 'T':case 'U':
case 'V':case 'W':case 'X':case 'Y':case 'Z':
case 'a':case 'b':case 'c':case 'd':case 'e':case 'f':case 'g':
case 'h':case 'i':case 'j':case 'k':case 'l':case 'm':case 'n':
case 'o':case 'p':case 'q':case 'r':case 's':case 't':case 'u':
case 'v':case 'w':case 'x':case 'y':case 'z':
case '_':
{
while (source.hasNext())
{
if (!isIdentifierPart(nextChar()))
{
source.rewind();
break;
}
}
String name = source.toString(lInitPos, source.getPosition());
// ...
}
如果手动构建,我发现拥有专用的词法分析器(从字符流中生成标记)和解析器(从标记流中生成 AST)比尝试将它们组合到一个解析器中要容易得多.