[antlr-interest] Problem with dynamic attribute scopes after upgrade to 3.1

Jim Idle jimi at temporal-wave.com
Fri Aug 15 10:21:46 PDT 2008


On Fri, 2008-08-15 at 13:08 -0400, Grzegorz Cieslewski wrote:

> Hey All,
> 
> I have encountered a little problem with the dynamic attribute scopes
> when upgraded to 3.1 (from 3.1b1 probably).  In my grammar I was using
> dynamic scopes communicate with distant rules.  In particular to allow
> the lower level rule (id) to identify  which rule has invoked it
> (type1 or type2).  In previous versions this grammar used to work:
> 
> expr
> 	: (type1 | type2)*
> 	;	
> type1
> scope{
> 	boolean isType1;
> }
> @init{
> 	$type1::isType1 = true;
> }
> 	: INT id
> 	;
> type2
> scope{
> 	boolean isType2;
> }
> @init{
> 	$type2::isType2 = true;
> }
> 	: id
> 	;	
> id
> 	:	ID
> 	{
> 		if($type1::isType1==true)
> 		{
> 			System.out.println("TYPE1");
> 		}
> 		if($type2::isType2==true)
> 		{
> 			System.out.println("TYPE2");
> 		}
> 	}
> 	;
> 
> Unfortunately in the 3.1 it gives me run-time errors:
> Exception in thread "main" java.util.EmptyStackException
> 	at java.util.Stack.peek(Stack.java:85)
> 	at G5Parser.id(G5Parser.java:292)
> 	at G5Parser.type1(G5Parser.java:186)
> 	at G5Parser.expr(G5Parser.java:107)
> 	at __Test__.main(__Test__.java:14)
> 
> I compared code generated in the two versions and it seems that the
> following changed:
> FROM:
> if(((type1_stack.size()>0)?((type1_scope)type1_stack.peek()).isType1:false)==true)
> {
>      System.out.println("TYPE1");
> }
> TO:
> if(((type1_scope)type1_stack.peek()).isType1==true)
> {
>      System.out.println("TYPE1");
> }
> The new code does not protect against checking the Stack when empty.
> 
> I am curious what is the reason for this change?


This was deliberately changed because the previous behavior was very
prone to generating silent bugs, as your grammar shows. In fact the bug
was so likely that even the example suffered from it. Actually it might
still be in the Java version of the example. What it means is that your
grammar has found a way to that point without stacking a new scope
level. Because flags like this would then appear to be not set (rather
than not there as they do now) rules and predicates and so on would
silently turn off when in fact it is a bug in the grammar.

So, if you want to be able to call this without a stack in place, then
you code to see if the stack is empty yourself, then your logic is
explicit and accurate to what you wanted.

Obviously here, whichever scope is in play when you get to id, will have
a scope in force, whereas the other one, by definition, will not and
will always give you an exception.


> Is there a better way to accomplish something similar?


1) You could not use the flags at all - you can pass a parameter to id
to indicate the type.
2) You could not use flags and just change the type of the returned ID,
by getting the token from the return rule's $start and changing it
(assuming AST output);
3) You can (and probably should) leave resolution of such things to the
tree parser.
4) Move the scope to the expr rule and use an enum rather than separate
types. type1 sets $expr::type = TYPE1; type2 to its type. The id rule
then checks $expr::type

Jim

> 
> Thanks
> 
> Greg
> 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://www.antlr.org/pipermail/antlr-interest/attachments/20080815/a00b1995/attachment.html 


More information about the antlr-interest mailing list