【问题标题】:How is this grammar ambiguous?这个语法怎么模棱两可?
【发布时间】:2013-04-04 02:35:36
【问题描述】:

我正在用 Jison 编写一个简单的表达式解析器。这是我的语法:

{
    "operators": [
        ["left", "+", "-"],
        ["left", "*", "/", "%"]
    ],
    "bnf": {
        "program": [
            ["statement EOF", "return $1;"]
        ],
        "statement": [
            ["expression NEWLINE", "$$ = $1 + ';';"]
        ],
        "expression": [
            ["NUMBER",                       "$$ = yytext;"],
            ["expression binary expression", "$$ = $1 + $2 + $3;"]
        ],
        "binary": [
            ["+",              "$$ = ' + ';"],
            ["-",              "$$ = ' - ';"],
            ["*",              "$$ = ' * ';"],
            ["/",              "$$ = ' / ';"],
            ["%",              "$$ = ' % ';"],
            ["binary NEWLINE", "$$ = $1;"]
        ]
    }
}

当我尝试运行它时,它给了我以下错误:

Conflict in grammar: multiple actions possible when lookahead token is + in state
13
- reduce by rule: expression -> expression binary expression
- shift token (then go to state 8)
Conflict in grammar: multiple actions possible when lookahead token is - in state
13
- reduce by rule: expression -> expression binary expression
- shift token (then go to state 9)
Conflict in grammar: multiple actions possible when lookahead token is * in state
13
- reduce by rule: expression -> expression binary expression
- shift token (then go to state 10)
Conflict in grammar: multiple actions possible when lookahead token is / in state
13
- reduce by rule: expression -> expression binary expression
- shift token (then go to state 11)
Conflict in grammar: multiple actions possible when lookahead token is % in state
13
- reduce by rule: expression -> expression binary expression
- shift token (then go to state 12)

States with conflicts:
State 13
  expression -> expression binary expression . #lookaheads= NEWLINE + - * / %
  expression -> expression .binary expression
  binary -> .+
  binary -> .-
  binary -> .*
  binary -> ./
  binary -> .%
  binary -> .binary NEWLINE

但是它最终仍然会产生正确的输出。例如,2 + 3 * 5 / 7 % 11 被正确翻译为2 + 3 * 5 / 7 % 11;

在我看来,我的语法似乎很明确,那么为什么 Jison 会抱怨呢?

更新:正如@icktoofay 解释的那样,这是一个运算符关联性问题。通过将运算符解析为非终结符号运算符优先级和关联性信息会丢失。因此我解决了如下问题:

{
    "operators": [
        ["left", "+", "-"],
        ["left", "*", "/", "%"]
    ],
    "bnf": {
        "program": [
            ["statement EOF", "return $1;"]
        ],
        "statement": [
            ["expression NEWLINE", "$$ = $1 + ';';"]
        ],
        "expression": [
            ["NUMBER",                          "$$ = yytext;"],
            ["expression + expression",         "$$ = $1 + ' + ' + $3;"],
            ["expression - expression",         "$$ = $1 + ' - ' + $3;"],
            ["expression * expression",         "$$ = $1 + ' * ' + $3;"],
            ["expression / expression",         "$$ = $1 + ' / ' + $3;"],
            ["expression % expression",         "$$ = $1 + ' % ' + $3;"],
            ["expression + NEWLINE expression", "$$ = $1 + ' + ' + $4;"],
            ["expression - NEWLINE expression", "$$ = $1 + ' - ' + $4;"],
            ["expression * NEWLINE expression", "$$ = $1 + ' * ' + $4;"],
            ["expression / NEWLINE expression", "$$ = $1 + ' / ' + $4;"],
            ["expression % NEWLINE expression", "$$ = $1 + ' % ' + $4;"]
        ]
    }
}

话虽如此,这个语法只允许一个可选的换行符跟在二元运算符之后。如何重写它以允许任意数量的换行符跟随二元运算符?还必须有某种方式,我不必为每个运算符编写 2 条规则。

【问题讨论】:

    标签: javascript parsing bison parser-generator jison


    【解决方案1】:

    我对 Jison 并不完全熟悉,但看起来您正在定义一个如下所示的规则:

    expression ::= number;
    expression ::= expression binary expression;
    

    考虑表达式1 - 2 - 3。这可以解释为(1 - 2) - 31 - (2 - 3)。它是哪一个?你的语法模棱两可。正常的数学规则说它应该是左结合的。你需要让你的语法反映出来:

    expression ::= number;
    expression ::= expression binary number;
    

    【讨论】:

    • 你是对的。运算符关联性确实是问题所在。谢谢你。有什么事情可以麻烦您吗?我已经编辑了我的问题,我想知道您对此的看法。也许我应该把它作为一个单独的问题发布?
    • @AaditMShah:我只是修改词法分析器以合并连续的换行符。至于需要NEWLINE/没有NEWLINE 的两个产生式,也许你可以用两个产生式创建一个新的maybe_newline:一个空的,一个用于NEWLINE。 (事实上​​,如果你不想修改词法分析器,你可以有一个 maybe_newline 一个空产生式和一​​个 maybe_newline NEWLINE 产生式。)
    猜你喜欢
    • 1970-01-01
    • 2012-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-21
    相关资源
    最近更新 更多