2013-04-04 95 views
4

我正在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条规则。

回答

5

我不完全熟悉Jison,但它看起来像你定义的规则,看起来像这样:

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

考虑表达1 - 2 - 3。这可以解释为(1 - 2) - 31 - (2 - 3)。这是什么?你的语法不明确。正常的数学规则说它应该是左联合的。你需要让你的语法反映:

expression ::= number; 
expression ::= expression binary number; 
+0

你说得对。操作员的关联确实是问题。谢谢。我可以为其他事情烦恼吗?我编辑了我的问题,我想知道您对此的看法。也许我应该把它作为一个单独的问题发布? – 2013-04-04 03:50:31

+1

@AaditMShah:我只是修改词法分析器来合并连续的换行符。至于需要两个作品与'NEWLINE' /没有'NEWLINE'的情况下,你可以用两个作品创作一个新的'maybe_newline':一个是空的,一个是用于'NEWLINE'的。 (事实上​​,如果你不想修改词法分析器,你可以有一个'maybe_newline',一个空白的制作和一个'maybe_newline NEWLINE'制作。) – icktoofay 2013-04-04 05:24:08