字符串模板:将所有变量声明设为全局 [英] String Template: make all variable declaration global

查看:120
本文介绍了字符串模板:将所有变量声明设为全局的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用ANTLR + StringTemplate实现翻译器. 我有一种像Java这样的起始语言和多种目标语言.

I am trying to implement a translator using ANTLR+StringTemplate. I have a starting language that is java like and multiple destination language.

我使用了示例: http://www.antlr.org/wiki/display/ST/Language+Translation+Using+ANTLR+和+ StringTemplate

我的一种目标语言需要在全局范围内声明所有变量. 我写了一个可以识别变量的语法,但是我无法在模板中找到使局部变量在全局范围内声明的方法.

One of my destination language needs all variables to be declared globally. I wrote a grammar that recognizes variables, but i cannot find e way in my template for making a local variable to be declared globally.

当然,如果我只有一个翻译,我就能做到,但是我有多个翻译,其中一些具有局部和全局变量. 我想在特定的模板文件中创建它.

Of course if I would have just one translation I would be able to do it, but I have multiple translation and some of them have local and global variables. I'd like to make it in the specific template file.

例如,如果我可以在模板中定义某种变量以保留所有变量声明的列表,并在定义全局范围时在末尾使用它,那将是很好的...但是我不知道是否这是可能的.

For example it would be great if I could define some sort of variables inside the template for keeping a list of all variable declarations and use it at the end when i define the global scope... but i don't know if this is possibile.

推荐答案

解析器必须在将变量传递到模板之前对其进行跟踪.这并不意味着您需要一个解析器用于基于全局的目标,而另一个则用于其他目标,只是意味着您需要在目标中定义一些空模板.

The parser will have to track the variables before passing them to a template. This doesn't mean that you need one parser for a global-based target and another for the other targets, it just means that you need to define some empty templates in the targets.

这是一个非常简单的示例,说明了如何完成此操作.我不建议您的案子是理想的选择,但我希望它能给您足够的帮助.

Here is a very simple example of how this can be done. I don't propose that your case is this ideal, but I hope it gives you enough to work with.

假设您的源语法(类似于Java)接受如下代码:

Assume that your source grammar, the Java-like one, accepts code like this:

class Foobar { 
    var a;
    var b;
    var myMethod(var x, var y) { 
       var c;
       var d;
    }
}

Foobar包含成员字段ab,成员方法myMethod包含局部变量cd.为论证起见,假设您希望将abcd视为全局目标的全局变量,其他情况下则与普通变量一样.

Class Foobar contains member fields a and b, and member method myMethod contains locals c and d. For argument's sake, assume that you want a, b, c, and d to be treated as global variables for a global target, and like normal variables otherwise.

这里是一种语法,它接受上面定义的输入,并准备用于模板输出:

Here is a grammar that accepts the input defined above, prepped for template output:

grammar JavaLikeToTemplate;

options { 
    output = template;
}

@members { 
    private java.util.ArrayList<String> globals = new java.util.ArrayList<String>();

}

compilationUnit : class_def EOF 
                    -> compilationUnit(classDef={$class_def.st}, globals={globals});
class_def       : CLASS ID LCUR class_body RCUR
                    -> class(name={$ID.text}, body={$class_body.st});
class_body      : (t+=class_element)+
                    -> append(parts={$t});
class_element   : class_field
                    -> {$class_field.st}
                | class_method
                    -> {$class_method.st};
class_field     : VAR ID SEMI {globals.add($ID.text);}
                    -> classField(name={$ID.text});
class_method    : VAR ID LPAR paramlist? RPAR LCUR method_body RCUR
                    -> classMethod(name={$ID.text}, params={$paramlist.st}, body={$method_body.st});
method_body     : (t+=method_element)+
                    -> append(parts={$t});
method_element  : method_field
                    -> {$method_field.st};
method_field    : VAR ID SEMI {globals.add($ID.text);}
                    -> methodField(name={$ID.text});
paramlist       : VAR t+=ID (COMMA VAR t+=ID)*
                    -> paramList(params={$t});

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

请注意,解析器成员globals跟踪仅全局目标所关注的变量的名称,但是仍调用与字段/变量有关的模板.这样可以确保语法是目标无关的.

Note that parser member globals tracks the names of variables that a globals-only target is concerned about, but that templates pertaining to fields/variables are still called. This ensures that the grammar is target-neutral.

这里是生成Java代码的模板.请注意,compilationUnit会忽略输入globals,因为Java并未使用它们.

Here is a template that produces Java code. Note that compilationUnit ignores input globals because Java doesn't use them.

group JavaLikeToJava;

compilationUnit(globals, classDef) ::=
<<
<classDef>
>>

class(name, body) ::= 
<<
public class <name> { 
    <body>
}
>>

classField(name) ::=
<<
private Object <name>;
>>

classMethod(name, params, body) ::=
<<
public Object <name>(<params>) {
    <body> 
}
>>

methodField(name) ::=
<<
    Object <name>;
>>

paramList(params) ::=
<<
    <params:{p|Object <p.text>}; separator=", ">
>>

append(parts) ::=
<<
 <parts;separator="\n">
>>

这里是全局目标的模板.请注意,许多类模板都是空的,但是compilationUnit处理输入globals.

Here is a template for a globals target. Note that many of the class templates are empty, but that compilationUnit processes input globals.

group JavaLikeToGlobal;

globals(names) ::=
<<
    <names:global()>
>>

global(name) ::=
<<
global <name>
>>

compilationUnit(globals, classDef) ::=
<<
<globals:globals();separator="\n">
<classDef>
>>

class(name, body) ::= 
<<
<body>
>>

classField(name) ::=
<<>>

classMethod(name, params, body) ::=
<<
<name>(<params>):
    <body>
end
>>

methodField(name) ::=
<<
>>

paramList(params) ::=
<<
    <params:{p| <p.text>}; separator=", ">
>>

append(parts) ::=
<<
 <parts;separator="\n">
>>

这是我将用来测试语法和模板的启动器类.

Here is the launcher class I'll use to test the grammar and templates.

public class JavaLikeToTemplateTest {

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

        final String code = "class Foobar {\n var Foobar_a;\n var Foobar_b;\n var doSomething() {\n  var doSomething_a;\n  var doSomething_b;\n }\n}"; 

        process(code, "JavaLikeToJava.stg");
        process(code, "JavaLikeToGlobal.stg");

    }

    private static void process(final String code, String templateResourceName)
            throws IOException, RecognitionException, Exception {
        CharStream input = new ANTLRStringStream(code);
        JavaLikeToTemplateLexer lexer = new JavaLikeToTemplateLexer(input);
        CommonTokenStream tokens = new CommonTokenStream(lexer);

        JavaLikeToTemplateParser parser = new JavaLikeToTemplateParser(tokens);

        InputStream stream = JavaLikeToTemplateTest.class.getResourceAsStream(templateResourceName);
        Reader reader = new InputStreamReader(stream);
        parser.setTemplateLib(new StringTemplateGroup(reader));
        reader.close();
        stream.close();

        JavaLikeToTemplateParser.compilationUnit_return result = parser.compilationUnit();

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

        System.out.printf("Result with %s:%n%n", templateResourceName);
        System.out.println(result.toString());
    }
}

以下是在测试类中进行硬编码的输入:

Here is the input hard-coded in the test class:

class Foobar {
 var Foobar_a;
 var Foobar_b;
 var doSomething() {
  var doSomething_a;
  var doSomething_b;
 }
}

这是使用两个模板的代码产生的输出:

And here is the output produced by the code, using both templates:

Result with JavaLikeToJava.stg:

public class Foobar { 
     private Object Foobar_a;
     private Object Foobar_b;
     public Object doSomething() {
            Object doSomething_a;
            Object doSomething_b; 
     }
}

Result with JavaLikeToGlobal.stg:

    global Foobar_a
    global Foobar_b
    global doSomething_a
    global doSomething_b


 doSomething():


 end

关键是要在解析器中跟踪全局变量,而不管目标语言是什么,并将它们与非全局信息一起传递给语言的模板.目标语言的模板文件要么处理全局变量,要么忽略它们.模板接收到足够的信息来定义两种语言(无论是否全部使用),因此无需创建新的解析器.

The key is to track globals in the parser regardless of the target language and pass them along with non-global information to the language's template regardless. The target language's template file either processes the globals or it ignores them. A template receive enough information to define both types of languages (whether it uses it all or not), so there's no need to create a new parser.

这篇关于字符串模板:将所有变量声明设为全局的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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