구문 분석기는 변수를 템플릿으로 전달하기 전에 변수를 추적해야합니다. 이것은 글로벌 기반 대상에 대해 하나의 파서가 필요하고 다른 대상에 대해 하나의 파서가 필요하다는 것을 의미하지는 않습니다. 단지 대상에 빈 템플릿을 정의해야한다는 의미입니다.
다음은이 작업을 수행하는 방법에 대한 간단한 예입니다. 나는 네 사건이 이상이라고 제안하지는 않지만, 네가 일할만큼 충분히 주길 바란다.
는 소스 문법, 자바와 같은 하나, 다음과 같은 코드를 허용한다고 가정
class Foobar {
var a;
var b;
var myMethod(var x, var y) {
var c;
var d;
}
}
클래스 Foobar
는 멤버 필드 a
및 b
및 구성원 방법 myMethod
지역 주민 c
및 d
이 포함되어 포함되어 있습니다. 논쟁을 위해 a
, b
, c
및 d
을 글로벌 대상의 전역 변수로 취급하고 다른 일반 변수처럼 취급한다고 가정합니다. 여기
템플릿 출력용 수험 공부 위에서 정의한 입력을 허용하는 문법이다
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());
}
}
테스트 클래스에 하드 코딩 입력되고 파서의 전역 변수를 대상 언어와 상관없이 추적하고 비 전역 정보와 함께 언어 템플릿에 관계없이 전달합니다. 대상 언어의 템플릿 파일은 전역을 처리하거나 무시합니다. 템플릿은 두 가지 유형의 언어를 정의하는 데 충분한 정보를받습니다 (언어가 모두 사용 되든 아니든간에). 따라서 새 파서를 만들 필요가 없습니다.
답변 해 주셔서 감사합니다. 내 문제를 해결하기위한 올바른 힌트를 제공합니다. –