ANTLR: using stringTemplate

(I'm a Noob with Antlr) ... I am having difficulty getting my grammar using StringTemplates. Basically I am trying to write a little DSL. I can get my grammar the way I want (it parses correctly), but I can't get the target code generation to work with templates. So here's a snippet of my grammar:

grammar Pfig;

options { 
    output=template;  
 language=CSharp2;
 }

conf 
    : globalName
    ;


globalName 
    : 'GlobalName:'  ID
     -> localConf(name ={$ID.text})
    ;

      

I've simplified this a bit to get the gist of the problem. Basically, when lex / parse comes across the name "GlobalName: Foo" I want it to spit out text based on a StringTemplate called "localConf". Super easy.

So, let's run a parser in a test application and process it.

// C# processing a file with the lex/parser.
// the 'app.pfig' file just has one line that reads 'GlobalName: Bla'
using (FileStream fs = File.OpenRead("c:\\app.pfig"))
        {
            PfigParser parser = new PfigParser(new CommonTokenStream(
                new PfigLexer(new ANTLRInputStream(fs))));

            using (TextReader tr = File.OpenText("./Pfig.stg"))
            {
                parser.TemplateLib = new StringTemplateGroup(tr);
            }

            var parseResult = parser.conf();
            string code = parseResult.Template.ToString(); // Fail: template is null
        }

      

I can execute the parser code and see that it correctly identifies my text and applies the stringTemplate correctly . The problem is that since this "globalName" rule is subordinate to "conf", it is not executed directly - the method simply finds it and returns. But the calling method "Conf" does not save the return value from the subwheel - it goes into the air. This means that my final template on the last line is NULL.

If I get rid of the "conf" rule in my grammar and call "globalName" directly, it works (since it's the only rule on the stack). But I obviously want more than one rule. I created a parser in Java and it does the same thing:

// antlr generated parser code
public PfigParser.conf_return conf() // throws RecognitionException [1]
{   
    PfigParser.conf_return retval = new PfigParser.conf_return();

    try 
 {
        {
         PushFollow(FOLLOW_globalName_in_conf30);
         globalName(); // <- it calls globalName() but doesn't keep the return.
         state.followingStackPointer--;

        }

        retval.Stop = input.LT(-1);

    }

// snip

      

It's easier to see that I am not getting a basic understanding of how the Template approach to Antlr should work. I'm pretty sure this is my problem, but I'm running into errors to find out what I'm doing wrong. ... the examples I've seen don't actually show the actual matrix emissions code.

+2


a source to share


2 answers


Basically, you need to explicitly redirect the template output to the subrule:

conf 
    : a=globalName -> {$a.st}
    ;

      



It's not pretty, but it works.

+2


a source


I think I finally caught the idea of ​​templates :) Templates should be "nested" hierarchically within each other. The following example works great:

TemplatesTest.g:

grammar TemplatesTest;

options
{
    output=template;
    language=CSharp2;
}

ID  :   ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*
    ;

INT :   '0'..'9'+
    ;

COMMENT
    :   '//' ~('\n'|'\r')* '\r'? '\n' {$channel=HIDDEN;}
    |   '/*' ( options {greedy=false;} : . )* '*/' {$channel=HIDDEN;}
    ;

WS  :   ( ' '
        | '\t'
        | '\r'
        | '\n'
        ) {$channel=HIDDEN;}
    ;

STRING
    :  '\'' ( ESC_SEQ | ~('\\'|'\'') )* '\''
    ;

fragment
HEX_DIGIT : ('0'..'9'|'a'..'f'|'A'..'F') ;

fragment
ESC_SEQ
    :   '\\' ('b'|'t'|'n'|'f'|'r'|'\"'|'\''|'\\')
    |   UNICODE_ESC
    |   OCTAL_ESC
    ;

fragment
OCTAL_ESC
    :   '\\' ('0'..'3') ('0'..'7') ('0'..'7')
    |   '\\' ('0'..'7') ('0'..'7')
    |   '\\' ('0'..'7')
    ;

fragment
UNICODE_ESC
    :   '\\' 'u' HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
    ;

doc
    : (e+=expr)+ -> doc(expressions={$e})
    ;

expr
    : ID '=' INT -> expression(id={$ID.text}, value={$INT.text})
    ;

      

TemplatesTest.stg:

group TemplatesTest;

doc(expressions) ::=
<<
srart expressions
<expressions; separator="\n">
end
>>

expression(id, value) ::= 
<<
<id> := <value>;
>>

      

Testing C # code:



var lexer = new TemplatesTestLexer(new ANTLRFileStream("sample.txt"));
var parser = new TemplatesTestParser(new CommonTokenStream(lexer));

using (var reader = new StreamReader("TemplatesTest.stg"))
{
  parser.TemplateLib = new StringTemplateGroup(reader);
}

var doc = parser.doc();
Console.WriteLine(doc.Template);

      

Input example:

a = 5
b = 6
c = 7

      

Exit:

srart expressions
a := 5;
b := 6;
c := 7;
end

      

+2


a source







All Articles