基本操作中的分解表达式:ANTLR + StringTemplate [英] Decompose expression in base operation: ANTLR + StringTemplate

查看:18
本文介绍了基本操作中的分解表达式:ANTLR + StringTemplate的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试为 Java 类语言编写翻译器到多种语言.

现在我面临两个问题:

首先是将复杂的表达式分解为一系列基本操作,然后将它们翻译成目标语言.

例如我的起始语言可以是:

var a = (ln(b) + avg(c))*2

我想翻译成这样:

var x1 = log_N(b);var x2 = 平均值(c);var x3 = sum(x1, x2);var a = 乘法(x3, 2);

我想我必须使用树解析器,但是我不确定如何将它与 StringTemplate 集成.此外,我添加了 x1、x2 和 x3 等额外变量,但我不知道如何处理这种情况.

第二个问题是我的目标语言之一是类似 plsql 的语言.在这种情况下,需要确保所有输出变量都成为游标并将它们传递给函数.

例如表达式:

var a = (ln(b) + avg(c))*2

应该这样翻译:

log_N(x1, b);平均(x2,c);总和(x3,x1,x2);乘(a, x3, 2);

其中 x1、x2、x3 和 a 将成为输出游标.

谁能帮我找到合适的解决方案?

谢谢

解决方案

我想我必须使用树解析器,但我不确定如何将它与 StringTemplate 集成.

将 StringTemplate 集成到树解析器中与将其集成到标记解析器中基本相同:将 output 选项定义为 template,然后相应地编写规则产生式.

下面是一个使用模板进行输出的小树语法.请注意,此语法与 我在上一个答案中描述的语法 之间唯一有意义的区别是,此语法对树节点进行操作而不是令牌.模板的工作原理相同.

树语法 AstToTemplateParser;选项 {输出 = 模板;tokenVocab = JavaLikeToAst;ASTLabelType = CommonTree;}程序: ^(PROGRAM decls+=decl+) ->写(文本={$decls});声明: ^(DECL ID ^(op args+=arg*)) ->分配(名称={$ID.text},op={$op.st},args={$args})|^(DECL ID ^(CALL 方法 args+=arg*)) ->分配(名称={$ID.text},op={$method.st},args={$args});参数: ID ->写(文本={$ID.text})|INT ->写(文本={$INT.text});方法: ID ->操作(名称={$ID.text});操作:星 ->操作(名称={$STAR.text})|DIV ->操作(名称={$DIV.text})|加号 ->操作(名称={$PLUS.text})|减号 ->操作(名称={$MINUS.text});

<块引用>

此外,我添加了 x1、x2 和 x3 等额外变量,但我不知道如何处理这种情况.

这就是踢球者.我所知道的最简单的方法(这不是很容易)是首先使用令牌解析器生成基线 AST,然后使用树解析器将 AST 扁平化为声明列表,每个声明都表示来自原始输入的表达式——x1x2x3 在您的问题中.

中间阶段如下所示:

原始输入

var a = (ln(b) + avg(c))*2

基线 AST

扁平化的 AST

应用的标准模板

 var var0 = log_N(b);var var1 = 平均值(c);var var2 = add(var0, var1);var a = 乘法(var2, 2);

已应用 PLSQL 模板

 log_N(var0, b);平均值(var1,c);添加(var2,var0,var1);乘法(a,var2,2);

这是一个标记解析器语法,它只是生成一个与您的问题中的类似的基线 AST.这里没有什么值得注意的,它只是生成一个典型的 AST.

语法 JavaLikeToAst;选项 {输出 = AST;}令牌{程序;降价;称呼;}编译单元:语句* EOF ->^(程序语句*);声明:声明;decl : VAR ID EQ expr ->^(DECL ID expr);expr : add_expr;add_expr : mul_expr ((PLUS|MINUS)^ mul_expr)*;mul_expr : call_expr ((STAR|DIV)^ call_expr)*;call_expr :ID LPAR arglist?RPAR ->^(呼叫 ID arglist?)|主表达式;arglist : expr (COMMA! expr)*;primary_expr : ID |国际 |LPAR!expr RPAR!;VAR : 'var';ID : ('a'..'z'|'A'..'Z')('a'..'z'|'A'..'Z'|'_'|'0'..'9')*;INT : ('0'..'9')+;逗号:',';半:';';LCUR : '{';RCUR : '}';LPAR : '(';RPAR : ')';情商:'=';加号:'+';减   : '-';星星    : '*';DIV : '/';WS : (' '|'\t'|'\f'|'\r'|'\n'){skip();};

这就是它变得丑陋的地方(至少是我选择的方式;)).下面的树语法将上面生成的基线 AST 转换为与 AST 表达式(扁平化 AST)相对应的声明列表.下面,我将逐步介绍语法中的有趣部分.

树语法 AstToFlatAstParser;选项 {输出 = AST;tokenVocab = JavaLikeToAst;ASTLabelType = CommonTree;过滤器=真;}@header {导入 java.util.HashMap;}@会员{私人 int currentId = 0;private HashMap<整数,对象>exprs = new HashMap();私有布尔 newDecls = false;私有 int nextId() {返回currentId++;}私有对象 generateId(int id) {return adapter.create(ID, "var" + id);}private void saveExpr(int id, Object expr){newDecls = 真;expr.put(id, expr);}私有对象 buildNewDecls() {Object newDecls = adapter.nil();for (int i = 0; i < currentId; ++i){如果 (!exprs.containsKey(i)){继续;//这个id被生成但没有被使用.}对象 expr = expr.get(i);Object decl = adapter.create(DECL, tokenNames[DECL]);adapter.addChild(decl, adapter.create(ID, "var" + i));适配器.addChild(decl, expr);适配器.addChild(newDecls, decl);}表达式.clear();返回新声明;}}自下而上: 退出程序|退出操作;退出操作@在里面 {int myId = nextId();}: ^(binary_op 减少减少){$start.parent != null &&$start.parent.getType() != DECL}?{saveExpr(myId, $start);}->{generateId(myId)}|^(来电显示.*){$start.parent != null &&$start.parent.getType() != DECL}?{saveExpr(myId, $start);}->{generateId(myId)};binary_op : 星 |格 |加号 |减;减少:ID |国际;退出程序//仅当要构建新声明时才重建 PROGRAM,即当newDecls"为真时.//否则,PROGRAM 未更改时被视为已更改,并且处理永远不会结束.:{newDecls}?^(PROGRAM old+=.*) {newDecls = false;}->^(程序{buildNewDecls()} $old*);

首先,请注意语法主要是 Java 代码.解析器规则只有五个,而且大部分都很简单.这是一个 filter 树语法,所以规则 bottomuptopdown 是入口点.在这种情况下,只有 bottomup 是必需的,因此没有指定 topdown.重复规则 bottomup 直到输出树不变,这对我们来说意味着没有更多的声明要生成并且树完全展平.

其次,请注意规则 exit_program 是将新声明写出到 AST 的地方.我使用语义谓词 ({newDecls}?) 来确保仅在添加新声明时修改 PROGRAM.还记得我说过 bottomup 被调用直到不再进行任何更改吗?如果没有这个语义谓词,exit_program总是修改PROGRAM,树解析将永远不会停止处理bottomup.对于这种特殊情况,这是一个粗略的解决方法,但它有效.新的声明被插入到 PROGRAM 的开头,以确保它们在被引用之前出现.在预期之后十行定义 x1 是不好的.

第三,注意规则exit_op 用声明(如var0)替换了表达式(如ln(b)).如果下列条件之一为真,则替换表达式:

  • 该表达式是一个二元运算,其操作数都是约简"(即它们都是整数或变量 ID),并且不是 DECL 节点的子节点.var a = 1 + 2 没有改变,因为 1 + 2 是声明的子元素.var b = a + (2 + c) 被改变,因为 (2 + c) 有两个减少"的操作数并且不是 DECL 节点(它是 a + ...+ 的子节点).

  • 表达式是一个 CALL,它不是 DECL 节点的子节点.var a = ln(b) 未受影响,但 var a = ln(b) + 3 已更改,因为 ln(b) 是一个+ 的孩子.

表达式在被 id 替换之前存储在 exprs 中.当规则调用 buildNewDecls 时,它会在 exit_program 规则中重新构建.buildNewDecls 只是使用解析器内置的TreeAdaptor 成员(名为adaptor)来生成出现在扁平化的 AST.适配器方法的 Javadoc 很好地解释了调用的作用,因此我不会详细介绍.

警告:上述语法生成的解析器适用于您所提供的非常有限的情况.我不知道将它们应用于更广泛的场景时会产生什么错误.

<块引用>

第二个问题是我的目标语言之一是类似 plsql 的语言.在这种情况下,需要确保所有输出变量都成为游标并将它们传递给函数...

一旦您的 AST 只是一个平面的声明列表,模板就可以为您管理,如上所示.

您将把扁平化的 AST 传递给基于模板的树解析器,就像上面那个解析器一样,生成不同的文本版本,就像您列出的那样.在这种情况下,模板将接受声明的所有部分变量名、操作/方法名和操作数/参数并生成类似 variable = method(arg0, arg1)method(variable, arg0, arg1) 的文本,具体取决于所使用的模板.关键是要确保输入是扁平的,并且模板接收到与声明相关的所有内容.

<小时>

这是一个将所有内容联系在一起的测试应用程序.

JavaLikeToAstTest.java

公共类 JavaLikeToAstTest {public static void main(String[] args) 抛出异常 {最终字符串代码 = "var a = (ln(b) + avg(c))*2";CharStream input = new ANTLRStringStream(code);JavaLikeToAstLexer 词法分析器 = new JavaLikeToAstLexer(input);CommonTokenStream 令牌 = new CommonTokenStream(lexer);JavaLikeToAstParser parser = new JavaLikeToAstParser(tokens);JavaLikeToAstParser.compilationUnit_return 结果 = 解析器.compilationUnit();if (lexer.getNumberOfSyntaxErrors() > 0 || parser.getNumberOfSyntaxErrors() > 0) {throw new Exception("遇到语法错误!");}CommonTree 树 = (CommonTree) result.tree;System.out.printf("基线 AST: %s%n%n", tree.toStringTree());树 = 展平(树);System.out.printf("Flattened AST: %s%n%n", tree.toStringTree());翻译(树,AstToPlsql.stg");翻译(树,AstToGlobal.stg");}私有静态 CommonTree 扁平化(CommonTree 树){AstToFlatAstParser 解析器 = 新 AstToFlatAstParser(新的 CommonTreeNodeStream(tree));return (CommonTree) parser.downup(tree, true);}private static void translate(CommonTree tree, String templateResourceName)抛出异常{AstToTemplateParser 解析器 = 新的 AstToTemplateParser(新的 CommonTreeNodeStream(tree));InputStream 流 = JavaLikeToTemplateTest.class.getResourceAsStream(templateResourceName);Reader reader = new InputStreamReader(stream);parser.setTemplateLib(new StringTemplateGroup(reader));reader.close();流.关闭();System.out.printf("%s%n%n%s%n%n 的结果", templateResourceName,parser.program().st.toString());}

这里有两个简单的 StringTemplate 组文件来处理翻译过程.

AstToGlobal.stg

group AstToGlobal;方法 ::= ["*":"multiply", "/":"divide", "+":"add", "-":"subtract", "avg":"average", "ln":"log_N",默认值:key]分配(名称,操作,参数)::= <<var <name>= <op>(<args;separator=", ">) >>op(name) ::= ""写(文本)::= <<<text;separator="\n">>>

AstToPlsql.stg

group AstToPlsql;方法 ::= ["*":"multiply", "/":"divide", "+":"add", "-":"subtract", "avg":"average", "ln":"log_N",默认值:key]分配(名称,操作,参数)::=<<<op>(<name>, <args;separator=", ">) >>op(name) ::= ""写(文本)::= <<<text;separator="\n">>>

应用程序产生以下输出:

基线 AST: (PROGRAM (DECL a (* (+ (CALL ln b) (CALL avg c)) 2)))(呼叫 ln b) ->变量0(CALL avg c) ->变量1(+ var0 var1) ->变量2(PROGRAM (DECL a (* var2 2))) ->(PROGRAM (DECL var0 (CALL ln b)) (DECL var1 (CALL avg c)) (DECL var2 (+ var0 var1)) (DECL a (* var2 2)))扁平化 AST: (PROGRAM (DECL var0 (CALL ln b)) (DECL var1 (CALL avg c)) (DECL var2 (+ var0 var1)) (DECL a (* var2 2)))AstToPlsql.stg 的结果log_N(var0, b )平均值(var1,c)添加(var2,var0,var1)乘法(a,var2,2)AstToGlobal.stg 的结果var var0 = log_N(b)var var1 = 平均值(c)var var2 = add(var0, var1)var a = 乘法(var2, 2)

AstToTemplate.g 中没有代码或模板来处理像 var a = 3 这样的简单赋值,但我认为添加代码很容易以操作/方法分配为指导来处理它.

I am trying to write a translator for a Java like language to multiple languages.

Right now I am facing 2 problems:

First is to decompose complex expression in a sequence of basic operation and then translating them to destination language.

For example my starting language can be:

var a = (ln(b) + avg(c))*2

I'd like to traslate it like:

var x1 = log_N(b);
var x2 = average(c);
var x3 = sum(x1, x2);
var a = multiply(x3, 2);

I think i have to use a Tree parser, nut I am not sure how to integrate it with StringTemplate. Moreover i am adding extra variables like x1, x2, and x3 and i don't know how to handle this situation.

The second problem is that one of my destination language is a plsql like language. In this case a need to ensure that all output variables become cursors and pass them to the functions.

For example the expression:

var a = (ln(b) + avg(c))*2

Should be translated in this way:

log_N(x1, b);
average(x2, c);
sum(x3, x1, x2);
multiply(a, x3, 2);

where x1, x2, x3 and a will become output cursors.

Can anyone help me finding the right solution?

Thanks

解决方案

I think i have to use a Tree parser, but I am not sure how to integrate it with StringTemplate.

Integrating StringTemplate into a tree parser is basically the same as integrating it into a token parser: define the output option as template, then write the rule productions accordingly.

Below is a small tree grammar that uses templates for output. Note that the only meaningful difference between this grammar and the one I described in a previous answer is that this one operates on tree nodes rather than tokens. The templates work the same.

tree grammar AstToTemplateParser;

options { 
    output = template;
    tokenVocab = JavaLikeToAst;
    ASTLabelType = CommonTree;
}


program
    : ^(PROGRAM decls+=decl+) -> write(text={$decls})
    ;

decl
    : ^(DECL ID ^(op args+=arg*)) -> assign(name={$ID.text}, op={$op.st}, args={$args})
    | ^(DECL ID ^(CALL method args+=arg*)) -> assign(name={$ID.text}, op={$method.st}, args={$args})
    ;

arg 
    : ID -> write(text={$ID.text})
    | INT -> write(text={$INT.text})
    ;

method
    : ID -> op(name={$ID.text})
    ;

op  : STAR  -> op(name={$STAR.text})
    | DIV   -> op(name={$DIV.text})
    | PLUS  -> op(name={$PLUS.text})
    | MINUS -> op(name={$MINUS.text})
    ;

Moreover i am adding extra variables like x1, x2, and x3 and i don't know how to handle this situation.

That's the kicker. The easiest way that I know of (which isn't terribly easy) is to first generate the baseline AST using the token parser then use a tree parser to flatten the AST into a list of declarations, each representing expressions from the original input -- x1, x2, and x3 in your question.

The intermediate stages look like this:

Original Input

var a = (ln(b) + avg(c))*2

Baseline AST

Flattened AST

Standard Template Applied

 var var0 = log_N(b);
 var var1 = average(c); 
 var var2 = add(var0, var1);
 var a = multiply(var2, 2);

PLSQL Template Applied

  log_N(var0, b);
  average(var1, c);
  add(var2, var0, var1);
  multiply(a, var2, 2);

Here's a token parser grammar that simply generates a baseline AST that resembles the one in your question. There's nothing really noteworthy here, it just produces a typical AST.

grammar JavaLikeToAst;

options { 
    output = AST;
}

tokens { 
    PROGRAM; DECL; CALL; 
}

compilationUnit : statement* EOF -> ^(PROGRAM statement*);
statement       : decl;
decl            : VAR ID EQ expr -> ^(DECL ID expr);
expr            : add_expr;
add_expr        : mul_expr ((PLUS|MINUS)^ mul_expr)*;
mul_expr        : call_expr ((STAR|DIV)^ call_expr)*;
call_expr       : ID LPAR arglist? RPAR -> ^(CALL ID arglist?)
                | primary_expr;
arglist         : expr (COMMA! expr)*;
primary_expr    : ID | INT | LPAR! expr RPAR!; 

VAR     : 'var';
ID      : ('a'..'z'|'A'..'Z')('a'..'z'|'A'..'Z'|'_'|'0'..'9')*;
INT     : ('0'..'9')+;
COMMA   : ',';
SEMI    : ';';
LCUR    : '{';
RCUR    : '}';
LPAR    : '(';
RPAR    : ')';
EQ      : '=';
PLUS    : '+';
MINUS   : '-';
STAR    : '*';
DIV     : '/';
WS      : (' '|'\t'|'\f'|'\r'|'\n'){skip();};

Here is where it gets ugly (at least the way I choose to do it ;)). The tree grammar below transforms a baseline AST produced from above into a list of declarations that correspond to the expressions of the AST -- the flattened AST. Below this, I'll step through the fun bits of the grammar.

tree grammar AstToFlatAstParser;

options { 
    output = AST;
    tokenVocab = JavaLikeToAst;
    ASTLabelType = CommonTree;
    filter = true;
}

@header { 
    import java.util.HashMap;
}

@members {
    private int currentId = 0;
    private HashMap<Integer, Object> exprs = new HashMap<Integer, Object>();
    private boolean newDecls = false;

    private int nextId() { 
        return currentId++;
    }

    private Object generateId(int id) { 
        return adaptor.create(ID, "var" + id);
    }  

    private void saveExpr(int id, Object expr){
        newDecls = true;
        exprs.put(id, expr);
    }

    private Object buildNewDecls() {
        Object newDecls = adaptor.nil();

        for (int i = 0; i < currentId; ++i){
            if (!exprs.containsKey(i)){
                continue; //This id was generated but not used.
            }

            Object expr = exprs.get(i);
            Object decl = adaptor.create(DECL, tokenNames[DECL]);
            adaptor.addChild(decl, adaptor.create(ID, "var" + i));
            adaptor.addChild(decl, expr);
            adaptor.addChild(newDecls, decl);
        }

        exprs.clear();

        return newDecls;
    }
}

bottomup
    : exit_program
    | exit_op
    ;

exit_op
    @init {
        int myId = nextId();
    }
    : ^(binary_op reduced reduced)
        {$start.parent != null && $start.parent.getType() != DECL}? 
        {saveExpr(myId, $start);} 
        -> {generateId(myId)}
    | ^(CALL ID .*) 
        {$start.parent != null && $start.parent.getType() != DECL}? 
        {saveExpr(myId, $start);} 
        -> {generateId(myId)}
    ;   

binary_op       : STAR | DIV | PLUS | MINUS;

reduced         : ID | INT; 

exit_program
    //Only rebuild PROGRAM if a new declaration is going to be built, that is, when "newDecls" is true.
    //Otherwise PROGRAM is considered changed when it isn't and the processing never ends.
    : {newDecls}? ^(PROGRAM old+=.*) {newDecls = false;} 
        -> ^(PROGRAM {buildNewDecls()} $old*)
    ;

First, notice that the grammar is mostly Java code. There are only five parser rules, and most of them are simple. This is a filter tree grammar, so rules bottomup and topdown are the entry points. Only bottomup is necessary in this case, so topdown isn't specified. Rule bottomup is repeated until the output tree is unchanged, which to us means when there are no more declarations to produce and the tree is fully flattened.

Second, notice that rule exit_program is where the new declarations are being written out to the AST. I'm using a semantic predicate ({newDecls}?) to ensure that PROGRAM is only modified when new declarations are added. Remember how I said bottomup is called until no more changes are made? Without this semantic predicate, exit_program will always modify PROGRAM and the tree parsing will never stop processing bottomup. This is a crude work-around for this special case but it works. The new declarations are inserted at the beginning of PROGRAM to ensure that they appear before they are referenced. It's no good defining x1 ten lines after it's expected.

Third, notice that rule exit_op replaces expressions (like ln(b)) with declarations (like var0). An expression is replaced if one of the following is true:

  • The expression is a binary operation whose operands are both "reduced" (that is, they're both integers or variable ids) and is not the child of a DECL node. var a = 1 + 2 is not changed because 1 + 2 is the child of a declaration. var b = a + (2 + c) is changed because (2 + c) has two "reduced" operands and is not the child of a DECL node (it's the child of the + in a + ...).

  • The expression is a CALL that is not the child of a DECL node. var a = ln(b) is untouched, but var a = ln(b) + 3 is changed because ln(b) is a child of +.

An expression is stored in exprs before it's replaced by an id. It's reconstituted in the exit_program rule when the rule calls buildNewDecls. buildNewDecls just uses the parser's built-in TreeAdaptor member (named adaptor) to generate the DECL nodes that appear in the flattened AST. The Javadoc for the adaptor methods does an adequate job explaining what the calls do, so I won't go into the details.

Caveat: The parsers produced by the grammars above work fine for the very limited case that you've presented. I don't know what errors they will produce when applied to any broader scenario.

The second problem is that one of my destination language is a plsql like language. In this case a need to ensure that all output variables become cursors and pass them to the functions...

That would be something that the templates could manage for you once your AST is just a flat list of declarations, as shown above.

You'll pass the flattened AST to a template-based tree parser, like the one up top, to produce the different text versions like those you've listed. In this case, a template would accept all the parts of a declaration – the variable name, the operation/method name, and the operands/arguments – and produce text like either variable = method(arg0, arg1) or method(variable, arg0, arg1), depending on the template used. The key is to ensure that the input is flat and that the template receives everything related to the declaration.


Here is a test application that ties it all together.

JavaLikeToAstTest.java

public class JavaLikeToAstTest {

    public static void main(String[] args) throws Exception {

        final String code = "var a = (ln(b) + avg(c))*2";

        CharStream input = new ANTLRStringStream(code);
        JavaLikeToAstLexer lexer = new JavaLikeToAstLexer(input);
        CommonTokenStream tokens = new CommonTokenStream(lexer);

        JavaLikeToAstParser parser = new JavaLikeToAstParser(tokens);

        JavaLikeToAstParser.compilationUnit_return result = parser
                .compilationUnit();

        if (lexer.getNumberOfSyntaxErrors() > 0 || parser.getNumberOfSyntaxErrors() > 0) {
            throw new Exception("Syntax Errors encountered!");
        }

        CommonTree tree = (CommonTree) result.tree;

        System.out.printf("Baseline AST: %s%n%n", tree.toStringTree());

        tree = flatten(tree);

        System.out.printf("Flattened AST: %s%n%n", tree.toStringTree());

        translate(tree, "AstToPlsql.stg");
        translate(tree, "AstToGlobal.stg");
    }

    private static CommonTree flatten(CommonTree tree) {
        AstToFlatAstParser parser = new AstToFlatAstParser(
                new CommonTreeNodeStream(tree));
        return (CommonTree) parser.downup(tree, true);
    }

    private static void translate(CommonTree tree, String templateResourceName)
            throws Exception {
        AstToTemplateParser parser = new AstToTemplateParser(
                new CommonTreeNodeStream(tree));
        InputStream stream = JavaLikeToTemplateTest.class
                .getResourceAsStream(templateResourceName);
        Reader reader = new InputStreamReader(stream);
        parser.setTemplateLib(new StringTemplateGroup(reader));
        reader.close();
        stream.close();

        System.out.printf("Result for %s%n%n%s%n%n", templateResourceName,
                parser.program().st.toString());

    }

Here are two simple StringTemplate group files to handle the translation process.

AstToGlobal.stg

group AstToGlobal;

methods ::= ["*":"multiply", "/":"divide", "+":"add", "-":"subtract", "avg":"average", "ln":"log_N", default:key]

assign(name, op, args) ::= <<var <name> = <op>(<args;separator=", ">) >>

op(name) ::= "<methods.(name)>"

write(text) ::= << <text;separator="\n"> >>

AstToPlsql.stg

group AstToPlsql;

methods ::= ["*":"multiply", "/":"divide", "+":"add", "-":"subtract", "avg":"average", "ln":"log_N", default:key]

assign(name, op, args) ::=<< <op>(<name>, <args;separator=", ">) >>

op(name) ::= "<methods.(name)>"

write(text) ::= << <text;separator="\n"> >>

The application produces the following output:

Baseline AST: (PROGRAM (DECL a (* (+ (CALL ln b) (CALL avg c)) 2)))

(CALL ln b) -> var0
(CALL avg c) -> var1
(+ var0 var1) -> var2
(PROGRAM (DECL a (* var2 2))) -> (PROGRAM (DECL var0 (CALL ln b)) (DECL var1 (CALL avg c)) (DECL var2 (+ var0 var1)) (DECL a (* var2 2)))
Flattened AST: (PROGRAM (DECL var0 (CALL ln b)) (DECL var1 (CALL avg c)) (DECL var2 (+ var0 var1)) (DECL a (* var2 2)))

Result for AstToPlsql.stg

  log_N(var0, b ) 
  average(var1, c ) 
  add(var2, var0 , var1 ) 
  multiply(a, var2 , 2 )  

Result for AstToGlobal.stg

 var var0 = log_N(b ) 
 var var1 = average(c ) 
 var var2 = add(var0 , var1 ) 
 var a = multiply(var2 , 2 )  

There is no code in AstToTemplate.g or the templates to handle simple assignments like var a = 3, but I think it will be easy enough to add the code to handle it using the op/method assignment as a guide.

这篇关于基本操作中的分解表达式:ANTLR + StringTemplate的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆