2012-12-10 5 views
3

ANTLR + StringTemplate을 사용하여 변환기를 구현하려고합니다. 자바와 같은 여러 언어로 구성된 시작 언어가 있습니다. 내 대상 언어의 http://www.antlr.org/wiki/display/ST/Language+Translation+Using+ANTLR+and+StringTemplate문자열 템플릿 : 모든 변수 선언을 전역으로 지정하십시오.

하나는 모든 변수가 세계적으로 선언 할 필요가 :

나는 예제를 사용했다. 변수를 인식하는 문법을 썼지 만 전역 변수 선언을 위해 템플릿에서 전자 양식을 찾을 수 없습니다.

당연히 내가 할 수있는 번역은 하나 뿐이지 만 여러 번역이 있고 그 중 일부는 로컬 변수와 전역 변수가 있습니다. 특정 템플릿 파일에서 만들고 싶습니다.

예를 들어 전역 변수를 정의 할 때 모든 변수 선언 목록을 유지하고 끝에 사용하기 위해 템플릿 내부에 일종의 변수를 정의 할 수 있다면 좋을 것입니다. 그러나 잘 모르겠습니다. 이것이 가능하다면.

답변

3

구문 분석기는 변수를 템플릿으로 전달하기 전에 변수를 추적해야합니다. 이것은 글로벌 기반 대상에 대해 하나의 파서가 필요하고 다른 대상에 대해 하나의 파서가 필요하다는 것을 의미하지는 않습니다. 단지 대상에 빈 템플릿을 정의해야한다는 의미입니다.

다음은이 작업을 수행하는 방법에 대한 간단한 예입니다. 나는 네 사건이 이상이라고 제안하지는 않지만, 네가 일할만큼 충분히 주길 바란다.

는 소스 문법, 자바와 같은 하나, 다음과 같은 코드를 허용한다고 가정

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

클래스 Foobar는 멤버 필드 ab 및 구성원 방법 myMethod 지역 주민 cd이 포함되어 포함되어 있습니다. 논쟁을 위해 a, b, cd을 글로벌 대상의 전역 변수로 취급하고 다른 일반 변수처럼 취급한다고 가정합니다. 여기

템플릿 출력용 수험 공부 위에서 정의한 입력을 허용하는 문법이다

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은 Java가 입력을 사용하지 않으므로 입력 globals을 무시합니다.

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

다음은 문법과 템플릿을 테스트하는 데 사용할 런처 클래스입니다.

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 

키가 여기

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

모두 템플릿을 사용하여, 코드에 의해 생성 된 출력된다 : 여기

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

테스트 클래스에 하드 코딩 입력되고 파서의 전역 변수를 대상 언어와 상관없이 추적하고 비 전역 정보와 함께 언어 템플릿에 관계없이 전달합니다. 대상 언어의 템플릿 파일은 전역을 처리하거나 무시합니다. 템플릿은 두 가지 유형의 언어를 정의하는 데 충분한 정보를받습니다 (언어가 모두 사용 되든 아니든간에). 따라서 새 파서를 만들 필요가 없습니다.

+0

답변 해 주셔서 감사합니다. 내 문제를 해결하기위한 올바른 힌트를 제공합니다. –

관련 문제