gpt4 book ai didi

antlr - 字符串模板 : make all variable declaration global

转载 作者:行者123 更新时间:2023-12-02 00:14:43 25 4
gpt4 key购买 nike

我正在尝试使用 ANTLR+StringTemplate 实现一个翻译器。我有一种类似于 Java 的起始语言和多种目标语言。

我用了这个例子:http://www.antlr.org/wiki/display/ST/Language+Translation+Using+ANTLR+and+StringTemplate

我的目标语言之一需要全局声明所有变量。我写了一个识别变量的语法,但我无法在我的模板中找到使局部变量全局声明的方法。

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

例如,如果我可以在模板中定义某种变量来保存所有变量声明的列表并在我定义全局范围时在最后使用它,那就太好了……但我不知道是否这是可能的。

最佳答案

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

这是一个非常简单的例子,说明如何做到这一点。我不认为您的情况如此理想,但我希望它能为您提供足够的工作空间。

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

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

Foobar包含成员字段ab,成员方法myMethod包含局部变量c d。为了便于讨论,假设您希望将 abcd 视为全局变量对于全局目标,否则就像普通变量一样。

这是一个接受上面定义的输入的语法,为模板输出做准备:

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 跟踪仅全局目标所关注的变量名称,但仍会调用属于字段/变量的模板。这确保语法是目标中立的。

这是一个生成 Java 代码的模板。请注意,compilationUnit 会忽略输入 globals,因为 Java 不使用它们。

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

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

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

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

这是在测试类中硬编码的输入:

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

下面是代码使用两个模板生成的输出:

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

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

关于antlr - 字符串模板 : make all variable declaration global,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13798395/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com