Написание языкового конвертера в ANTLR - PullRequest
3 голосов
/ 22 марта 2010

Я пишу конвертер между несколькими диалектами одного и того же языка программирования. Я нашел грамматику в сети - она ​​сложная и обрабатывает все случаи. Сейчас я пытаюсь написать соответствующие действия.

Большая часть ввода будет просто переписана для вывода. Что мне нужно сделать, так это проанализировать вызовы функций, сделать мою магию (переименовать функцию, изменить порядок аргументов и т. Д.) И написать ее.

Я использую AST в качестве вывода. Когда я сталкиваюсь с вызовом функции, я строю пользовательскую структуру объекта (из классов, определенных на моем целевом языке), вызываю соответствующую функцию, и у меня есть строка, представляющая преобразованную функцию, которую я хочу получить.

Проблема в том, что я должен делать с этой строкой? Я хотел бы заменить атрибут .text правила включения, но setText () доступен только для правил лексера, а атрибут правила .text доступен только для чтения. Как решить эту проблему?

program
    : statement_list            { output = $statement_list.text; }
    ;

//...

statement
    :   expression_statement
    // ...
    ;

expression_statement
    : function_call
    // ...
    ;

function_call
    : ID '('                    { /* build the object, assign name */
                                  Function function = new Function();
                                  //...
                                }
      (
      arg1 = expression         { /* add first parameter */ }
      ( ',' arg2 = expression   { /* add the rest of parameters */ }
      )*
      )?
      ')'                       { /* convert the function call */
                                  string converted = Tools.Convert(function);
                                  // $setText(converted);               // doesn't work
                                  // $functionCall.text = converted;    // doesn't work
                                }
    ;

Ответы [ 2 ]

5 голосов
/ 22 марта 2010

После того, как у вас есть AST, вам нужно написать обходчик дерева, который выдает вашу программу в качестве преобразованного источника. У вас может даже быть промежуточный обходчик дерева, выполняющий преобразования дерева, в зависимости от сложности ваших изменений.

При этом прохождение AST-шага может быть не лучшим подходом.

Возможно, вы захотите взглянуть на «Шаблоны языкового дизайна» Терренса Парра (Pragmatic Programmers). Глава 11 посвящена вашему типу программ.

Он упоминает инструмент, ANTLRMorph, который лучше подходит для вашей проблемы.

2 голосов
/ 24 марта 2010

Самый простой способ - создать переписчик.Установите грамматику для перезаписи, используйте шаблоны и создайте шаблон на месте.Затем используйте TokenRewriteStream и его метод ToString ().

grammar Test;

options {
    language = CSharp2;
    output = template;
    rewrite = true;
}

program
    : statement_list
    ;

//...

statement
    :   expression_statement
    // ...
    ;

expression_statement
    : function_call
    // ...
    ;

function_call
    : ID '('                    { /* build the object, assign name */
                                  Function function = new Function();
                                  //...
                                }
      (
      arg1 = expression         { /* add first parameter */ }
      ( ',' arg2 = expression   { /* add the rest of parameters */ }
      )*
      )?
      ')' -> { new StringTemplate(Tools.Convert(function)) }
    ;

И драйвер:

    string input = "....";

    var stream = new ANTLRStringStream(input);
    var lexer = new TestLexer(stream);

    // need to use TokenRewriteStream
    var tokenStream = new TokenRewriteStream(lexer);
    var parser = new TestParser(tokenStream);

    parser.program();

    // original text
    Console.WriteLine(tokenStream.ToOriginalString());
    // rewritten text
    Console.WriteLine(tokenStream.ToString());
...