问题
I need to recognize arrays of integers in Fortran's I4 format (stands for an integer of width four) as the following example:
Using a pure context-free grammar:
WS : ' ' ;
MINUS : '-' ;
DIGIT : '0'..'9' ;
int4:
WS WS (WS| MINUS ) DIGIT
| WS (WS| MINUS ) DIGIT DIGIT
| (WS| MINUS | DIGIT ) DIGIT DIGIT DIGIT
;
numbers
: int4*;
The above example is correctly matched:
However if I use semantic predicates to encode semantic constraints of rule int4 :int4
scope { int n; }
@init { $int4::n = 0; }
: ( {$int4::n < 3}?=> WS {$int4::n++;} )*
( MINUS {$int4::n++;} )?
( {$int4::n < 4}?=> DIGIT{$int4::n++;} )+
{$int4::n == 4}?
;
it works for the int4 rule, but it's not the same for the numbers rule, because it doesn't recognize the array of integers of the first example:
In this case may be better pure context-free grammar, but in case of the format I30 (stands for an integer of width 30)?
The main question is: Is it possible to use Semantic Predicates with this grammar?
回答1:
Your parse tree seems to end at the numbers rule because your numbers rule throws an exception (but it does not show up in the diagram...). You can see it if you run the code generated, and if you take a closer look at the exception, it says (line info may differ for you):
Exception in thread "main" java.util.EmptyStackException at java.util.Stack.peek(Stack.java:102) at FortranParser.numbers(FortranParser.java:305) at Main.main(Main.java:9)
and the code throwing the exception is:
public final void numbers() throws RecognitionException {
....
else if ( (LA5_0==DIGIT) && ((int4_stack.peek().n < 4))) {
alt5=1;
}
So your problem is that the semantic predicate gets propagated to the numbers rule, and at that level the scope stack is empty, hence int4_stack.peek()
throws an exception
A trick to avoid it is that you use a variable in the global scope, e.g.:
@members {
int level=0;
}
and modify the semantic predicates to check level before the predicates, just like:
int4
scope { int n; }
@init { $int4::n = 0; level++; }
@after { level--; }
: ( {level==0 || $int4::n < 3}?=> WS {$int4::n++;} )*
( MINUS {$int4::n++;} )?
( {level==0 || $int4::n < 4}?=> DIGIT{$int4::n++;} )+
{$int4::n == 4}?
;
This is just a workaround to avoid the error that you get, maybe (knowing the error) there is a better solution and you don't need to mess up your semantic predicates.
But, I think, the answer is yes, it is possible to use semantic predicates with that grammar.
来源:https://stackoverflow.com/questions/27605243/semantic-predicates-antlr-dont-recognize-chain-of-integers-of-width-4