[antlr-interest] Bug using rule action?

Kay Roepke kroepke at classdump.org
Sat Jun 16 06:34:44 PDT 2007


Hi Cameron!

On Jun 14, 2007, at 1:19 AM, Cameron Esfahani wrote:

> I'm trying to add an action to one of my rules and I'm seeing some  
> strange behavior:
>
> grammar Test;
> [...]
> number_size
> 	:	num = NUMBER size = size_qualifier {
> 			// Validate that NUMBER fits within the size qualifier.
> 			System.out.printf( "!\%s, !\%s\n", $num.toString(), $size.getTree 
> ().toString() );
> 		} -> size_qualifier NUMBER
> 	;
> If I try to run this through ANTLR, I get an error:
>
> error(116): Test.g:30:39: unknown attribute for rule  
> size_qualifier: getTree
>
> When I examine TestParser.java, I see that "$size" is still there.   
> If I change the action, to remove the $ character, then it works:
>
> 			System.out.printf( "!\%s, !\%s\n", $num.toString(), size.getTree 
> ().toString() );
>
> Why do I have to do this?  How come $num correctly causes a local  
> variable named num to be created, but not $size?

Don't remove the $ char, as this defeats any checking ANTLR can do on  
rule attributes. When doing that you rely on the internal naming
scheme ANTLR uses for the generated code. In the Objective-C target,  
for instance, this would break your code as I'm prefixing every local  
variable
with an _ character to avoid name clashes.

The reason for the behavior you are seeing is that ANTLR checks  
whether attributes on labels are valid. When it sees $size.getTree()  
it thinks you want to access the getTree field of whatever  
size_qualifier returns and discovers that size_qualifier doesn't  
declare any attribute with that name. Consequently it flags it as an  
error. It's a bit unfortuntate because it doesn't know about methods  
in the size_return class, even though it has generated that method  
itself.

When you use $size.tree.toString() it will work because the tree  
attribute is a "predefined attribute" of rules. The code generated  
would look like:

	// Validate that NUMBER fits within the size qualifier.
	System.out.printf( "!%s, !%s\n", num.toString(), ((CommonTree) 
size.tree).toString() );

The reason that $num.toString works is that $num refers to a Token  
and not a rule. It is allowed to reference a token or token label in  
a "stand-alone" manner, while this is not permitted for rule references.

Note that you can do without any labels in your example:

number_size
	:	NUMBER size_qualifier {
			// Validate that NUMBER fits within the size qualifier.
			System.out.printf( "!\%s, !\%s\n", $NUMBER.toString(),  
$size_qualifier.tree.toString() );
		} -> size_qualifier NUMBER
	;

generates your action as:

	// Validate that NUMBER fits within the size qualifier.
	System.out.printf( "!%s, !%s\n", NUMBER4.toString(), ((CommonTree) 
size_qualifier5.tree).toString() );

Labels are only necessary to disambiguate between multiple references  
to the same rule or token. This also nicely illustrates that you  
shouldn't rely on any naming scheme for rule returns because they  
will highly depend on the input grammar.
By using the predefined rule attributes we can ensure that we  
generate better code and are more flexible with future changes.

HTH,

-k

-- 
Kay Röpke
http://classdump.org/






More information about the antlr-interest mailing list