移位/减少模棱两可的语法冲突

时间:2019-02-18 21:16:42

标签: parsing yacc shift-reduce-conflict

由于yacc报告了6个shift / reduce冲突,所以我一直迷糊了一段时间。我查看了y.output文件,并试图了解如何查看状态并找出解决歧义语法但无济于事的方法。我被合理地固定在应该如何解决这些问题上。我查看了很多关于堆栈溢出的问题,以了解其他人的解释是否可以帮助我解决我的问题,但这也没有太大帮助。作为记录,我不能使用任何优先级定义指令(例如%left)来解决解析冲突。

有人可以通过指导我如何改变语法以解决班次/减少冲突的方式来帮助我吗?也许通过尝试解决其中一个问题并向我展示其背后的思维过程?我知道语法很长很重,为此我深表歉意。如果有人愿意为此腾出时间,将不胜感激,但我意识到我可能无法拥有。

无论如何,这是我所关注的语法(它是MiniJava语法的略微扩展):

Grammar
0 $accept: program $end

1 program: main_class class_decl_list

2 main_class: CLASS ID '{' PUBLIC STATIC VOID MAIN '(' STRING '[' ']' ID ')' '{' statement '}' '}'

3 class_decl_list: class_decl_list class_decl
4                | %empty

5 class_decl: CLASS ID '{' var_decl_list method_decl_list '}'
6           | CLASS ID EXTENDS ID '{' var_decl_list method_decl_list '}'

7 var_decl_list: var_decl_list var_decl
8              | %empty

9 method_decl_list: method_decl_list method_decl
10                 | %empty

11 var_decl: type ID ';'

12 method_decl: PUBLIC type ID '(' formal_list ')' '{' var_decl_list statement_list RETURN exp ';' '}'

13 formal_list: type ID formal_rest_list
14            | %empty

15 formal_rest_list: formal_rest_list formal_rest
16                 | %empty

17 formal_rest: ',' type ID

18 type: INT
19     | BOOLEAN
20     | ID
21     | type '[' ']'

22 statement: '{' statement_list '}'
23          | IF '(' exp ')' statement ELSE statement
24          | WHILE '(' exp ')' statement
25          | SOUT '(' exp ')' ';'
26          | SOUT '(' STRING_LITERAL ')' ';'
27          | ID '=' exp ';'
28          | ID index '=' exp ';'
29 statement_list: statement_list statement
30               | %empty

31 index: '[' exp ']'
32      | index '[' exp ']'

33 exp: exp OP exp
34    | '!' exp
35    | '+' exp
36    | '-' exp
37    | '(' exp ')'
38    | ID index
39    | ID '.' LENGTH
40    | ID index '.' LENGTH
41    | INTEGER_LITERAL
42    | TRUE
43    | FALSE
44    | object
45    | object '.' ID '(' exp_list ')'

46 object: ID
47       | THIS
48       | NEW ID '(' ')'
49       | NEW type index

50 exp_list: exp exp_rest_list
51         | %empty

52 exp_rest_list: exp_rest_list exp_rest
53              | %empty
54 exp_rest: ',' exp

这是y.output中具有移位/减少冲突的相关状态。

State 58
7 var_decl_list: var_decl_list . var_decl
12 method_decl: PUBLIC type ID '(' formal_list ')' '{' var_decl_list . statement_list RETURN exp ';' '}'

INT      shift, and go to state 20
BOOLEAN  shift, and go to state 21
ID       shift, and go to state 22

ID        [reduce using rule 30 (statement_list)]
$default  reduce using rule 30 (statement_list)

var_decl        go to state 24
type            go to state 25
statement_list  go to state 69


State 76
38 exp: ID . index
39    | ID . '.' LENGTH
40    | ID . index '.' LENGTH
46 object: ID .

'['  shift, and go to state 64
'.'  shift, and go to state 97

'.'       [reduce using rule 46 (object)]
$default  reduce using rule 46 (object)

index  go to state 98


State 100
33 exp: exp . OP exp
34    | '!' exp .

OP  shift, and go to state 103

OP        [reduce using rule 34 (exp)]
$default  reduce using rule 34 (exp)


State 101
33 exp: exp . OP exp
35    | '+' exp .

OP  shift, and go to state 103

OP        [reduce using rule 35 (exp)]
$default  reduce using rule 35 (exp)


State 102
33 exp: exp . OP exp
36    | '-' exp .

OP  shift, and go to state 103

OP        [reduce using rule 36 (exp)]
$default  reduce using rule 36 (exp)


State 120
33 exp: exp . OP exp
33    | exp OP exp .

OP  shift, and go to state 103

OP        [reduce using rule 33 (exp)]
$default  reduce using rule 33 (exp)

就在那里。对于这种语法的长度以及移位/减少冲突的次数,我再次表示歉意。我似乎无法理解如何通过更改相关语法来解决这些问题。我们将不胜感激任何帮助,尽管如果没有人有时间浏览如此庞大的职位,我将理解。如果有人需要更多信息,请随时询问。

1 个答案:

答案 0 :(得分:2)

基本问题是,在解析method_decl正文时,它无法分辨var_decl_list的结尾和statement_list的开始位置。这是因为当前瞻为ID时,它不知道这是另一个var_decl的开始还是第一个statement的开始,因此需要减少一个空语句才能开始在statement_list上工作。

您可以通过多种方式处理此问题:

  • 让词法分析器为类型ID和其他ID返回不同的令牌-这样,差异将告诉解析器哪个是下一个。

  • 在语句列表的开头不需要空语句。将语法更改为:

    statement_list: statement | statement_list statement ;
    opt_statement_list: statement_list | %empty ;
    

    ,并在opt_statement_list规则中使用method_decl。可以解决在开始分析语句之前必须减少空statement_list的问题。当您用多个变体替换规则时,此过程称为“解因”语法。它使语法更加复杂,在这种情况下,它不能解决问题,而只是解决问题。然后您会在statement: ID . index前瞻中看到type: ID[之间的转移/减少冲突。此问题也可以通过分解来解决,但难度更大。


因此,这提出了通过分解来解决移位减少冲突的一般思想。基本思想是摆脱导致班次减少冲突减少的规则,而将其替换为上下文中更受限制的规则,因此不要触发冲突。上面的示例很容易通过“用1个或多个递归重复和一个可选规则替换0个或多个递归重复”来解决。如果以下情况意味着您可以轻松地确定何时0例应合法(在这种情况下仅当下一个标记为}时),这对于重复操作的epsilon规则上的shift-reduce冲突效果很好。 / p>

第二场冲突更加艰难。当提前量为type: ID时,冲突就在减少[上。因此,我们需要重复类型规则,直到没有必要为止。像这样:

type: simpleType | arrayType ;
simpleType: INT | BOOLEAN | ID ;
arrayType: INT '[' ']' | BOOLEAN '[' ']' | ID '[' ']'
         | arrayType '[' ']' ;

将“ '[' ']'后缀的0个或多个重复”替换为“ 1个或多个”,并且由于类似的原因起作用(将减少量推迟到看到'[' ']'之后再使用,而不是之前要求。)关键在于,{a {1}}的前瞻性永远不需要减少simpleType: ID规则,因为它仅在其他情况下有效。