AW: [antlr-interest] improving template support in antlr v3

hwk.cortex-brainware at t-online.de hwk.cortex-brainware at t-online.de
Mon Dec 26 15:47:12 PST 2005


Some quick remarks, before I go off skiing :-)

Basically, I like the idea of defining several template groups to organize
things. So the idea would be to define several groups, like you suggested
using

templates Java;
templates Debug;

And yes, I see those as a placeholder so we can still load groups
dynamically, which gives us polymorphism for free.

I prefer the Java::foo syntax over a similar syntax using string parameters
(Java["foo"]) for several reasons:
- similar to a C++ function call.
- template could be checked at compile time for existence, once interfaces
can be defined for string templates.

One more explanation why I want template handling (and template lists within
ANTLR): I have grammars, for which I generate a Java and a C#
implementation. The problem is that simple things like lists have different
names and interfaces for both languages (List, add() in Java, IList, Add()
in C#). Therefore, I have to rewrite my action code all over the place. If I
can handle simple things like adding a template to a list, or calling a
template from within ANTLR, correct code would be generated for Java and C#
automatically and I could keep my action code the same...

So global::myList.add($MyTemplates::xxx()); would be OK as long as it is
translated to the proper target language.

BTW, I do call setTemplateLibrary in between phases when I use multiple
passes thru the same grammar. It actually works very nicely, if you use C#
with partial classes! A great feature that's missing in Java...

I'll be back next year :-)

So I wish you and everybody on the list a Happy New Year 2006!

Dr. Hartmut Kocher
Cortex Brainware GmbH


-----Ursprüngliche Nachricht-----
Von: antlr-interest-bounces at antlr.org
[mailto:antlr-interest-bounces at antlr.org] Im Auftrag von Terence Parr
Gesendet: Freitag, 23. Dezember 2005 21:25
An: ANTLR Interest; stringtemplate-interest
Betreff: [antlr-interest] improving template support in antlr v3

On Dec 23, 2005, at 3:12 AM, hwk.cortex-brainware at t-online.de wrote:
> I think there are some common scenarios:
>
> 1) Call different templates (even when I only return one template,  
> I might
> use some templates during calculation). We could use a common  
> syntax here
> like $ST["name"] to extract a template form the group. This would be a
> reserved word.

Yes, i have been working with this cool start-up company recently and  
I have been trying to use the template stuff.  I have not needed  
multiple templates from a single rule, but let me add my own  
frustrations here and we can probably come up with a nice bit of  
extension.  John Mitchell suggested this exact strategy...get  
something working (avoiding the complicated thing I was designing)  
and then try to build something with it! ;)

So, I do this a few times in a Java grammar:

StringTemplate fcallST = templateLib.getInstanceOf("fcall");
fcallST.setAttribute("ids", $type.st);  // type is a rule reference  
above
$anEnclosingTemplateVisibleHere.setAttribute("fcalls",fcallST);

Wouldn't it be nice to do as you say (a rewrite like constructor but  
in an action):

StringTemplate fcallST = $fcall(ids=$type.st);

and then we could have a syntax like pyStringTemplate to use array  
syntax instead of setAttribute:

$anEnclosingTemplateVisibleHere["fcalls"] = fcallST;

The problem of course is clear: The dollar syntax $x.y is way to  
simple to handle the above and it's ambiguous anyway.  We'd need a  
keyword as you say I think, but that makes it messy.

<sidetracked>
Actually, given that I must be consistent across output options, how  
will we build trees inline?

{AST t = ^($ID.text, $INT.text);}

I suppose we could make ^ significant like we did with #(...)  
before.  Hmm...What would a node constructor be?

^ID["blort]

I suppose that would be ok.
</sidetracked>

So, do we need a special symbol for inline stringtemplate stuff?   
Ick.  @ is action, $ is attribute.  Hm...keyword is probably better.   
Ack...can't just randomly look for a keyword...need a symbol.   
Hmm...well, what about, symbol plus braces:

StringTemplate fcallST = ${fcall(ids=$type.st)};
${anEnclosingTemplateVisibleHere["fcalls"] = fcallST};

I don't like overloading $ though but I hate to create another  
special symbol just for templates like:

StringTemplate fcallST = %{fcall(ids=$type.st)}
%{anEnclosingTemplateVisibleHere["fcalls"] = fcallST};

Is there some generic thing I could do with %{...}?  Ick.  Would they  
have to nest?

%{anEnclosingTemplateVisibleHere["fcalls"] = %{fcall(ids=$type.st)}};

Probably.  To me that is not very readable to the casual observer  
where the explicit is very readable.

Perhaps your $templates::fcall(ids=$type.st) would work with  
"templates" being the keyword / built-in scope of templates.   
Actually that would work. :)

StringTemplate fcallST = $templates::fcall(ids=$type.st);
$anEnclosingTemplateVisibleHere.setAttribute("fcalls",fcallST);

It saves a bit of typing and is more clear. :)

> Better yet: How about defining a string template group in the
> grammar:
>
> group MyTemplates;  // This only a defines a property in the parser  
> to set a
> string template group. Later, we could allow to define the  
> templates inline.

I think you want this to be dynamic so, as you request below, you can  
reset the template group for each pass using setTemplateLib().

> Then one could call templates of the group using a syntax like
> MyTemplates::Name. There would be a default group, which is used if  
> the
> group name is omitted.

We can just use the $templates::name(...) generic mechanism so we can  
dynamically change the actual group.  Your way might be useful with  
the ST interface I plan on implementing.  In this way, I could verify  
that your template names actually make sense.  Heh, i like it!

> -> xxx  calls default group "xxx" and returns this as result
> -> MyTemplates::xxx calls "xxx" in the the MyTemplates group and  
> returns
> this as result.

Interesting.  You want to be able to define multiple template  
libraries?  Ok, so

$templates::fcall(...)
$MyTemplates::blort(...)

I dislike overriding the $scope::x syntax so much, but it seems like  
it would work.  How would we specify the new template groups?

templates Java;
templates Debug;

then you could say $Java::fcall(...) and $Debug::dump(...).  But, the  
lib names should be interfaces so you're not locked into a specific  
template group, right?  This would generate methods like:

setJavaTemplateLib(...)

in the parser so you could set the actual lib.

How often would this multiple template lib thing be used do you think?

> Within actions $MyTemplates::xxx would call the template.
>
> Now, we could nest them:
>
> -> ResultTemplate(MyTemplates::xxx($Name), MyTemplates::yyy($Id)), or
> whatever...

Yup.

Oh, right we'd need to allow

-> Java::fcall(...)

syntax too.

> 2) Build a collection of templates. These are useful to pass them  
> to other
> templates...
>
> Currently, only the result of a rule can be added to a list. This  
> could be
> expanded to support multiple lists, one per template.
>
> Just allow the same syntax to be used in front of each template call:
> myList+=MyTemplates::xxx adds the template to a list called myList.

Is that in an action?  You can pass in multiple templates to fill  
with templates you create in that rule.  You can pass multiple return  
values back and just add to a list manually.  How often do you need  
to return multiple templates though?  When I need this I just access  
the outer template where they will go and then setAttribute for each  
new template.  I've yet to need multiple return templates.

> Maybe we should add the possibility to define lists in a scope:
> scope global {
> Templatecollection myList;  // or something like that
> }
>
> Use it like this: global::myList+=MyTemplates::xxx(...).

We're getting closer and closer to the simple neutral action language  
I was thinking of adding later ;)  Hm...this is getting a big much. I  
think:

global::myList.add($MyTemplates::xxx());

would be just as good ;)

> Overall, I think, template manipulation within ANTLR should be  
> expanded. Of

I plan on it...just trying to let actual need guide us. :)

> course, I can code that now within actions but it would be far more  
> user
> friendly if normal cases could be expressed in a standard and  
> uniform way.

Yes, let's come up with a nice extension.

> I have several 2.7.5 grammars in C# and Java, which only differs in  
> the
> action code because of different method and class names. Using  
> ANTLR 3 with
> templates I was hoping to move all differences to a set of  
> templates. This
> only works if templates can be manipulated within ANTLR itself.

Can't you just a different template group with setTemplateLib?

> Kind regards
>
>
> BTW: I was thinking about using multiple passes using the same  
> action code,
> but using different template groups for each pass...

Are you using setTemplateLib?

Let me add my own frustrations now.

This is a drag:

packageDefinition
	:	'package' identifier SEMI -> {$identifier.st}
	;

Could we do this?

packageDefinition
	:	'package' identifier SEMI -> identifier
	;

What if we always returned the template for a single element?

type
	:	identifier
	|	builtInType
	;

the template for identifier / builtInType would be autocopied to  
$type.st return value.  I don't like this actually... it's not  
consistent with having multiple elements in a production.  Perhaps

type
	:	identifier -> identifier
	|	builtInType
	;

is "better".  Weird looking though.

Here is a case where I might have just plain foo instead of a.b.c.   
In either case I need to set the return type.  I hate doing ( x ->  
template(...) ) syntax in the middle of a rule.  I want that -> on  
the end!  Here is what I do now:

identifier
	:	(i=IDENT -> qid(id={$i.text}))
		( DOT i=IDENT {$identifier.st.setAttribute("id",$i.text);}
)*
	;

Oh, actually we can do this properly even now.  Duh, just queue up  
the IDs.

identifier
	:	ids+=IDENT ( DOT ids+=IDENT )*
                 -> qid(id={toStrings($ids)})
	;

I've posted this to the blog too.

http://www.antlr.org/blog/antlr3/rewrite.tml

Ter




More information about the antlr-interest mailing list