在ANTLR中编写语言转换器

时间:2010-03-22 11:12:33

标签: antlr rewrite

我正在使用相同编程语言的某些方言之间编写转换器。我在网上找到了一个语法 - 它很复杂,处理所有情况。现在我正在尝试编写适当的行动。

大部分输入都将被重写为输出。我需要做的是解析函数调用,执行我的魔法(重命名函数,重新排序参数等)并编写它。

我使用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 个答案:

答案 0 :(得分:5)

一旦你有了AST,你就需要编写一个树形漫步器,它将你的程序作为转换源发出。根据更改的复杂程度,您甚至可能有一个中间树步行器进行树转换。

那说,经历AST步骤,可能不是最好的方法。

你可能想看看Terrence Parr(实用程序员)的“语言设计模式”。第11章介绍了你的程序类型。

他提到了一种工具ANTLRMorph,它可能更适合你的问题。

答案 1 :(得分:2)

最简单的方法是创建一个重写器。将语法设置为重写,使用模板并就地创建模板。然后使用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());