0

I'm currently working on visual basic converter using jison, and I have these conflicts in my grammar:

Conflict in grammar: multiple actions possible when lookahead token is ELSE in state 11
- reduce by rule: If -> IfBlock
- shift token (then go to state 16)
Conflict in grammar: multiple actions possible when lookahead token is ELSE_IF in state 11
- reduce by rule: If -> IfBlock
- shift token (then go to state 17)
Conflict in grammar: multiple actions possible when lookahead token is TERMINATOR in state 27
- reduce by rule: IfBlock -> IF Expression THEN Body
- shift token (then go to state 13)
Conflict in grammar: multiple actions possible when lookahead token is TERMINATOR in state 29
- reduce by rule: IfBlock -> IfBlock ELSE_IF Expression THEN Body
- shift token (then go to state 13)

States with conflicts:
State 11
  If -> IfBlock . #lookaheads= $end TERMINATOR IF_END ELSE ELSE_IF SUB_END
  If -> IfBlock .ELSE Body IF_END #lookaheads= $end TERMINATOR IF_END ELSE ELSE_IF SUB_END
  IfBlock -> IfBlock .ELSE_IF Expression THEN Body #lookaheads= $end ELSE ELSE_IF TERMINATOR SUB_END IF_END
State 27
  IfBlock -> IF Expression THEN Body . #lookaheads= $end ELSE ELSE_IF TERMINATOR SUB_END IF_END
  Body -> Body .TERMINATOR Line
  Body -> Body .TERMINATOR
State 29
  IfBlock -> IfBlock ELSE_IF Expression THEN Body . #lookaheads= $end ELSE ELSE_IF TERMINATOR SUB_END IF_END
  Body -> Body .TERMINATOR Line
  Body -> Body .TERMINATOR



Here is simplified version of my grammar (actions deleted):

const grammar = {
  Root: [
    [
      ''
    ],
    [
      'Body'
    ]
  ],
  Body: [
    [
      'Line'
    ],
    [
      'Body TERMINATOR Line'
    ],
    [ 'Body TERMINATOR' ]
  ],
  Line: [ [ 'Expression' ], [ 'Statement' ] ],
  Statement: [ [ 'Return' ], [ 'If' ] ],
  Expression: [ [ 'Code' ] ],
  Return: [
    [
      'RETURN Expression'
    ],
    [
      'RETURN'
    ]
  ],
  Code: [
    [
      'SUB_START Identifier PARAM_START ParamList PARAM_END TERMINATOR Body SUB_END'
    ]
  ],
  IfBlock: [
    [
      'IF Expression THEN Body'
    ],
    [
      'IfBlock ELSE_IF Expression THEN Body'
    ]
  ],
  If: [
    [ 'IfBlock' ],
    [
      'IfBlock ELSE Body IF_END'
    ]
  ]
}

The conflict is happening when I'm trying to implement a rule for If statement, it seems to conflict with the Body rule.

I spent almost a day trying to solve it, but I can't. I know that the parser can look only one token ahead, but I can't figure out solution by myself. And I'm bound to jison so I cannot use another parser generator. Is there any workaround for my grammar?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129

1 Answers1

1

Looking at these these productions:

If: [
        [ 'IfBlock' ],
        [ 'IfBlock ELSE Body IF_END ']
    ]

It seems to me like the grammar is saying that an if statement must be terminated by IF_END only if it includes an else clause. An if which lacks an else clause cannot be terminated by IF_END.

That's not my understanding of the syntax of visual basic. END_IF is mandatory in the multiline syntax and is not used in the single line syntax.

So you have two conflicts, because your If production accepts some statements with END_IF and some without:

  • For if statements without END_IF, you have the classic "dangling else" ambiguity.

  • In addition, for multiline if statements without END_IF, the grammar provides no way to tell whether a following statement is part of the last clause in the if statement or a new statement. (That's why multiline if statements need END_IF.

The "dangling else" ambiguity is relatively benign -- that is, the normal resolution which prefers shift to reduce will produce the correct result. If you want to eliminate the error message, you can make the resolution explicit using precedence rules, giving ELSE and ELSE_IF higher precedence than IF. To use this technique, you must make the IF visible in the rules which depend on precedence, which basically means removing IF from IfBLock to leave you with:

IfBlock: [
  [ 'Expression THEN Body' ],
  [ 'IfBlock ELSE_IF Expression THEN Body' ]
],
If: [
  [ 'IF IfBlock' ],
  [ 'IF IfBlock ELSE Body' ]  // IF_END removed
]

You'll also need the precedence relations:

[ 'left', 'IF' ],
[ 'left', 'ELSE', 'ELSE_IF' ]

That will more or less get you going on single-line if statements, except that you'll need to replace Block with something which does not allow a TERMINATOR.

For multiline if statements, though, you'll need a different syntax:

  • The END_IF is mandatory

  • There must be a TERMINATOR after THEN and ELSE, and before ELSE and END_IF. In other words, the blocks of statements in a multiline if must start at the beginning of a line and be terminated with TERMINATOR.

These restrictions aren't just cosmetic: They are there because otherwise it is impossible to put a statement after a multiline if statement, since without the END_IF, any following statement would be added to the last THEN or ELSE clause.

rici
  • 234,347
  • 28
  • 237
  • 341
  • I tried your solution but it's not working. `multiple actions possible when lookahead token is TERMINATOR in state 70 - reduce by rule: If -> IF IfBlock ELSE Body - shift token (then go to state 26) Conflict in grammar: multiple actions possible when lookahead token is TERMINATOR in state 72 - reduce by rule: IfBlock -> Expression THEN Body - shift token (then go to state 26) Conflict in grammar: multiple actions possible when lookahead token is TERMINATOR in state 82 - reduce by rule: IfBlock -> IfBlock ELSE_IF Expression THEN Body - shift token (then go to state 26) ` –  Feb 27 '20 at 19:23
  • And you are right about End If, it's only required in multi line form. –  Feb 27 '20 at 19:25
  • For me, it seems that problem with Body and Line rule. I commented out half of it, even with Code clause, and i still got error –  Feb 27 '20 at 19:46
  • @PatrickBateman; Yeah, that rule is probably wrong. Is `TERMINATOR` a new line character? – rici Feb 27 '20 at 19:47
  • Yep, it is used for line breaks. –  Feb 27 '20 at 19:49
  • OK, I can answer that, but I need to know if you are really trying to implement VB. You need to distinguish between single line and multiline `if` statements; otherwise the grammar really is ambiguous. That's why `end if` is mandatory for multiline statements, something which your grammar doesn't address. – rici Feb 27 '20 at 19:49
  • To be correct, i'am trying to implement VBA which is simplified version of VB, that used for applications like excel etc. And yes VBA have single line if clause and multi line. [info](https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/ifthenelse-statement). And i need support for it. –  Feb 27 '20 at 19:53
  • Yes, it can. But not mixed up. You can't start with the single line syntax and then switch to the multiline syntax in the middle. – rici Feb 27 '20 at 19:54
  • OK, I added some more narrative but the complete solution is more complex than my time availability right now. Sorry. I might try to add it in the evening. – rici Feb 27 '20 at 20:18