ANTLR: использование stringTemplate - PullRequest
2 голосов
/ 11 мая 2010

(я нуб с Antlr) ... У меня проблемы с получением моей грамматики с помощью StringTemplates. В основном я пытаюсь написать немного DSL. Я могу получить мою грамматику так, как я хочу (она анализируется правильно), но я не могу заставить генерацию целевого кода работать с шаблонами. Итак, вот фрагмент моей грамматики:

grammar Pfig;

options { 
    output=template;  
 language=CSharp2;
 }

conf 
    : globalName
    ;


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

Я немного упростил это, просто чтобы объяснить суть. По сути, когда lex / parse встречается с `GlobalName: Foo ', я хочу, чтобы он выплевывал текст на основе StringTemplate, называемого localConf. Супер просто.

Итак, давайте запустим парсер в тестовом приложении и обработаем входной файл.

// 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
        }

Я могу просмотреть код синтаксического анализатора и убедиться, что он правильно идентифицирует мой текст и правильно применяет stringTemplate . Проблема в том, что поскольку это правило globalName является подправилом conf, оно не выполняется напрямую - метод просто находит его и возвращает. Но вызывающий метод 'Conf' не сохраняет возвращаемое значение из подчиненного правила - он уходит в воздух. Это означает, что мой результирующий шаблон в последней строке является нулевым.

Если я избавлюсь от правила 'conf' в моей грамматике и сразу вызову 'globalName', оно будет работать (так как это единственное правило в стеке). Но я, очевидно, хочу больше, чем одно правило. Я создал парсер в Java, и он делает то же самое:

// 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

Легко видеть, что у меня нет какой-то базовой концепции о том, как шаблонный подход должен работать с Antlr. Я вполне уверен, что это моя проблема, но я не могу понять, что я делаю неправильно ... примеры, которые я видел, на самом деле не показывают реальную передачу шаблона из кода .

Ответы [ 2 ]

2 голосов
/ 10 января 2011

Кажется, я наконец понял идею шаблонов :) Шаблоны должны быть «вложены» друг в друга иерархически. Следующий пример работает отлично:

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>;
>>

Тест C # код:

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);

Пример ввода:

a = 5
b = 6
c = 7

Вывод:

srart expressions
a := 5;
b := 6;
c := 7;
end
2 голосов
/ 29 августа 2010

По сути, вам нужно явно переслать выходные данные шаблона в подправило:

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

Это не красиво, но работает.

...