Use of StringTemplate in Antlr
I would have this problem : Given this rules
defField: type VAR ( ',' VAR)* SEP ;
VAR : ('a'..'z'|'A'..'Z')+ ;
type: 'Number'|'String' ;
SEP : '\n'|';' ;
where I have to do is to associate a template with a rule "defField", that returns the string that represents the xml-schema for the field, that is:
Number a,b,c ;-> "<xs:element name="a" type = "xs:Number"\>" ,also for b and c.
my p开发者_开发知识库roblem is in * of Kleene, that is, how do I write the template to do what I described above in the light of the '*' ??
Thanks you!!!
Collect all VAR
tokens in a java.util.List
by using the +=
operator:
defField
: t=type v+=VAR (',' v+=VAR)* SEP
;
Now v
(a List) contains all VAR
's.
Then pass t
and v
as a parameter to a method in your StringTemplateGroup:
defField
: t=type v+=VAR (',' v+=VAR)* SEP -> defFieldSchema(type={$t.text}, vars={$v})
;
where defFieldSchema(...)
must be declared in your StringTemplateGroup, which might look like (file: T.stg):
group T;
defFieldSchema(type, vars) ::= <<
<vars:{ v | \<xs:element name="<v.text>" type="xs:<type>"\>
}>
>>
The syntax for iterating over a collection is as follows:
<COLLECTION:{ EACH_ITEM_IN_COLLECTION | TEXT_TO_EMIT }>
Ans since vars
is a List
containing CommonTokens
's, I grabbed its .text
attribute instead of relying on its toString()
method.
Demo
Take the following grammar (file T.g):
grammar T;
options {
output=template;
}
defField
: t=type v+=VAR (',' v+=VAR)* SEP -> defFieldSchema(type={$t.text}, vars={$v})
;
type
: NUMBER
| STRING
;
NUMBER
: 'Number'
;
STRING
: 'String'
;
VAR
: ('a'..'z'|'A'..'Z')+
;
SEP
: '\n'
| ';'
;
SPACE
: ' ' {skip();}
;
which can be tested with the following class (file: Main.java):
import org.antlr.runtime.*;
import org.antlr.stringtemplate.*;
import java.io.*;
public class Main {
public static void main(String[] args) throws Exception {
StringTemplateGroup group = new StringTemplateGroup(new FileReader("T.stg"));
ANTLRStringStream in = new ANTLRStringStream("Number a,b,c;");
TLexer lexer = new TLexer(in);
CommonTokenStream tokens = new CommonTokenStream(lexer);
TParser parser = new TParser(tokens);
parser.setTemplateLib(group);
TParser.defField_return returnValue = parser.defField();
StringTemplate st = (StringTemplate)returnValue.getTemplate();
System.out.println(st.toString());
}
}
As you will see when you run this class, it parses the input "Number a,b,c;"
and produces the following output:
<xs:element name="a" type="xs:Number">
<xs:element name="b" type="xs:Number">
<xs:element name="c" type="xs:Number">
EDIT
To run the demo, make sure you have all of the following files in the same directory:
T.g
(the combined grammar file)T.stg
(the StringTemplateGroup file)antlr-3.3.jar
(the latest stable ANTLR build as of this writing)Main.java
(the test class)
then execute to following commands from your OS's shell/prompt (from the same directory all the files are in):
java -cp antlr-3.3.jar org.antlr.Tool T.g # generate the lexer & parser javac -cp antlr-3.3.jar *.java # compile all .java source files java -cp .:antlr-3.3.jar Main # run the main class (*nix) # or java -cp .;antlr-3.3.jar Main # run the main class (Windows)
Probably not necessary to mention, but the #
including the text after it should not be a part of the commands: these are only comments to indicate what these commands are for.
精彩评论