Writing a translator using Antlr/Stringtemplates

805 Views Asked by At

I want to write a translator. The idea is to translate special formed C++ interfaces to C++/CLI. I have an antlr grammar that parses everything and generates an AST. Now I want to use this information and some string templates to emit source code.

My idea was to transform the AST in some kind of object hierarchy with properties (e.g. an interface object containing the indexed property methods which contains method-description-objects. The master string template is then fed with the root object and inserts the properties at the correct positions or passes them to sub-templates.

Now my question: How do I write a string template / property that needs to be called some undefined number of times? Example: an interface contains a number of methods. This means, that the subtemplate for method needs to be called several times, each time with a different property. How can I write this down as a mix of stringtemplate & indexed property?

Thank you for your help Tobias

1

There are 1 best solutions below

0
On

I'm doing something very similar. The basic idea is that your model must expose a list of some object, and you use that list within your string templates. For instance, let's say I have a very braindead implementation. I'm going to use Java because that's what I know best; you should get the idea.

https://gist.github.com/894632

public class GeneratedClass {
    private String accessModifier;
    private String name;
    private String superClass;
    private List<Method> methods;
}

public class Method {
    private String comments;
    private String name;
    private String accessModifier;
    private Type returnType;
    private List<Argument> arguments;
    private String body;
}

public class Argument {
    private Type type;
    private String name;
}

public class Type {
    private String name;
}

For my template I might have the following:

group Java;

class(accessModifier, name, superclass, methods)::=<<

$accessModifier$ class $name$ extends $superclass$ {

    $methods:method(); separator="\n"$

}
>>

method(method)::=<<
/**
 $method.comments$
*/
$method.accessModifier$ $method.returnType.name$ $name$ ($method.arguments:argument(); separator=","$) {
    $method.body$
}
>>

argument(argument)::=<<
$argument.type.name$ $argument.name$
>>

The key is that I functionally apply a template for each method object I have; that's what $methods:method() does. If I had an empty list, no template would be invoked at all. This handles the variable size problem. I do a similar thing within the method definition; ($method.arguments:argument(); separator=","$). This is going to create a comma separated list of method parameters in between parentheses, just like you'd expect.