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?
Looking at these these productions:
It seems to me like the grammar is saying that an
ifstatement must be terminated byIF_ENDonly if it includes anelseclause. Anifwhich lacks anelseclause cannot be terminated byIF_END.That's not my understanding of the syntax of visual basic.
END_IFis mandatory in the multiline syntax and is not used in the single line syntax.So you have two conflicts, because your
Ifproduction accepts some statements withEND_IFand some without:For
ifstatements withoutEND_IF, you have the classic "dangling else" ambiguity.In addition, for multiline
ifstatements withoutEND_IF, the grammar provides no way to tell whether a following statement is part of the last clause in theifstatement or a new statement. (That's why multilineifstatements needEND_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
ELSEandELSE_IFhigher precedence thanIF. To use this technique, you must make theIFvisible in the rules which depend on precedence, which basically means removingIFfromIfBLockto leave you with:You'll also need the precedence relations:
That will more or less get you going on single-line if statements, except that you'll need to replace
Blockwith something which does not allow aTERMINATOR.For multiline
ifstatements, though, you'll need a different syntax:The
END_IFis mandatoryThere must be a
TERMINATORafterTHENandELSE, and beforeELSEandEND_IF. In other words, the blocks of statements in a multilineifmust start at the beginning of a line and be terminated withTERMINATOR.These restrictions aren't just cosmetic: They are there because otherwise it is impossible to put a statement after a multiline
ifstatement, since without theEND_IF, any following statement would be added to the lastTHENorELSEclause.