If you can reproduce this issue in the Java code (which it appears you can), you can report it as a bug on the reference implementation's issue tracker. Otherwise, if this is specific to the C# target, you can report it on the C# target's issue tracker.
If you have one grammar, I highly recommend the only separation you ever consider is splitting it into a
lexer grammar
andparser grammar
, and not use theimport
statement. The cases where animport
statement actually helps are few and far between.The actions you've indicated in your question are not essential for correct parsing, and as such should be relocated to a listener or visitor which executes after the parse is complete. With these actions in the correct location, you will no longer be constrained by the issue you've described.
Problems importing a grammar with @init statements
Question
I have the Grammar_A
grammar and i want to split in two grammars, Grammar_A1
and Grammar_A2
; Grammar_A2
imports Grammar_A1
(i have been included all on the end of the question).
When i try to compile my project, i obtain the error redefinition of 'init' action
two times in Grammar_A2
, despite that there are three '@init' actions.
If i comment two of the three @init
actions, no matter wich, compiles fine.
I translate the grammar to Java and compile like the tutorial in Antlr4 website: i obtain the same errors making java -classpath .;../antlr-4.2-complete.jar org.antlr.v4.Tool Grammar_A2.g4
, but indicates error 94, ACTION_REDEFINITION.
I have tryed to compile with antlr version 4.1 and version 4.2.
Any idea of what can i am doing wrong?
Grammar_A
grammar Grammar_A;
@parser::members
{
protected const int EOF = Eof;
int numPrints, numReads;
}
@lexer::members
{
protected const int EOF = Eof;
protected const int HIDDEN = Hidden;
}
program
@init { numPrints = numReads = 0; }
: (printExpression | readExpression)+
;
printExpression
@init {numPrints++;}
: PRINT_KEY
( id
| QUOT id QUOT
)
SEMICOLON
;
readExpression
@init {numReads++;}
: ID READ_KEY SEMICOLON
;
id
: ID | PRINT_KEY | READ_KEY
;
WS
: (' ' | '\r' | '\n') -> channel(HIDDEN)
;
PRINT_KEY : 'print';
READ_KEY : 'read';
ID : ('a'..'z')+ ;
SEMICOLON : ';';
QUOT : '"';
Grammar_A1
grammar Grammar_A1;
@parser::members
{
protected const int EOF = Eof;
}
@lexer::members
{
protected const int EOF = Eof;
protected const int HIDDEN = Hidden;
}
id
: ID | PRINT_KEY | READ_KEY
;
WS
: (' ' | '\r' | '\n') -> channel(HIDDEN)
;
PRINT_KEY : 'print';
READ_KEY : 'read';
ID : ('a'..'z')+ ;
Grammar_A2
grammar Grammar_A2;
import Grammar_A1;
@parser::members {
int numPrints, numReads;
}
program
@init { numPrints = numReads = 0; }
: (printExpression | readExpression)+
;
printExpression
@init {numPrints++;}
: PRINT_KEY
( id
| QUOT id QUOT
)
SEMICOLON
;
readExpression
@init {numReads++;}
: ID READ_KEY SEMICOLON
;
SEMICOLON : ';';
QUOT : '"';
Solution
OTHER TIPS
I had the same problem, it could be a bug in ANTLR ?
To work around this I relocated all @init
and @after
blocks inline.
Something like this (not tested):
grammar Grammar_A2;
import Grammar_A1;
@parser::members {
int numPrints, numReads;
}
program
: { numPrints = numReads = 0; } // previously @init
(printExpression | readExpression)+
{ int numWhat = (numPrints + numReads);
System.out.println(numWhat); } // @after block
;
printExpression
: {numPrints++;} // previously @init
PRINT_KEY
( id
| QUOT id QUOT
)
SEMICOLON
;
readExpression
: {numReads++;} // previously @init
ID READ_KEY SEMICOLON
;
SEMICOLON : ';';
QUOT : '"';
edit: I opened an issue here https://github.com/antlr/antlr4/issues/2041