0 에서 컴 파일 러(12):코드 생 성의 생 성 논리
머리말
지난 편 에서 기본 적 인 자바 바이트 코드 명령 을 설명 한 후에 본 격 적 으로 진정한 코드 생 성 부분 에 들 어 갈 수 있다.그러나 이 부분 에서 먼저 말 한 것 은 코드 생 성 에 의존 하 는 몇 가지 유형,즉 명령 을 생 성 하 는 작업 이다.
이 파일 은 모두 codegen 아래 에 있 습 니 다.
Directive.java
이것 은 매 거 진 클래스 로 비교적 특수 한 명령 을 만 드 는 데 쓰 인 다.
하나의 클래스 나 하나의 방법 을 설명 하 는 범위 의 명령 을 만 드 는 것 은 비교적 간단 하 다.
public enum Directive {
CLASS_PUBLIC(".class public"),
END_CLASS(".end class"),
SUPER(".super"),
FIELD_PRIVATE_STATIC(".field private static"),
METHOD_STATIC(".method static"),
METHOD_PUBLIC(".method public"),
FIELD_PUBLIC(".field public"),
METHOD_PUBBLIC_STATIC(".method public static"),
END_METHOD(".end method"),
LIMIT_LOCALS(".limit locals"),
LIMIT_STACK(".limit stack"),
VAR(".var"),
LINE(".line");
private String text;
Directive(String text) {
this.text = text;
}
public String toString() {
return text;
}
}
Instruction.java
이것 도 하나의 매 거 류 로 기본 적 인 명령 을 만 드 는 데 쓰 인 다.
public enum Instruction {
LDC("ldc"),
GETSTATIC("getstatic"),
SIPUSH("sipush"),
IADD("iadd"),
IMUL("imul"),
ISUB("isub"),
IDIV("idiv"),
INVOKEVIRTUAL("invokevirtual"),
INVOKESTATIC("invokestatic"),
INVOKESPECIAL("invokespecial"),
RETURN("return"),
IRETURN("ireturn"),
ILOAD("iload"),
ISTORE("istore"),
NEWARRAY("newarray"),
NEW("new"),
DUP("dup"),
ASTORE("astore"),
IASTORE("iastore"),
ALOAD("aload"),
PUTFIELD("putfield"),
GETFIELD("getfield"),
ANEWARRAY("anewarray"),
AASTORE("aastore"),
AALOAD("aaload"),
IF_ICMPEG("if_icmpeq"),
IF_ICMPNE("if_icmpne"),
IF_ICMPLT("if_icmplt"),
IF_ICMPGE("if_icmpge"),
IF_ICMPGT("if_icmpgt"),
IF_ICMPLE("if_icmple"),
GOTO("goto"),
IALOAD("iaload");
private String text;
Instruction(String s) {
this.text = s;
}
public String toString() {
return text;
}
}
CodeGenerator.java
중요 한 것 은 생 성 된 논 리 는 주로 CodeGenerator 와 ProgramGenerator 에 있 고 CodeGenerator 는 ProgramGenerator 의 부류 이다.
CodeGenerator 의 구조 함수 new 는 xxx.j 에 바이트 코드 를 출력 하 는 출력 흐름 을 만 들 었 습 니 다.
public CodeGenerator() {
String assemblyFileName = programName + ".j";
try {
bytecodeFile = new PrintWriter(new PrintStream(new
File(assemblyFileName)));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
emit,emitString,emitDirective,emitBlankLine 은 모두 출력 기본 명령 에 속 하 며,서로 다른 조작 과 조작 수 에 대응 하 는 여러 가지 재 로드 방법 이 있다.주의해 야 할 것 은 어떤 명령 은 먼저 캐 시 를 해 야 할 수도 있 습 니 다.마지막 에 같이 제출 해 야 합 니 다.예 를 들 어 buffered,classDefine 은 먼저 캐 시 해 야 할 불 값 인지 아 닌 지 를 판단 하 는 데 사 용 됩 니 다.
public void emitString(String s) {
if (buffered) {
bufferedContent += s + "
";
return;
}
if (classDefine) {
classDefinition += s + "
";
return;
}
bytecodeFile.print(s);
bytecodeFile.flush();
}
public void emit(Instruction opcode) {
if (buffered) {
bufferedContent += "\t" + opcode.toString() + "
";
return;
}
if (classDefine) {
classDefinition += "\t" + opcode.toString() + "
";
return;
}
bytecodeFile.println("\t" + opcode.toString());
bytecodeFile.flush();
++instructionCount;
}
public void emitDirective(Directive directive, String operand1, String operand2, String operand3) {
if (buffered) {
bufferedContent += directive.toString() + " " + operand1 + " " + operand2 + " " + operand3 + "
";
return;
}
if (classDefine) {
classDefinition += directive.toString() + " " + operand1 + " " + operand2 + " " + operand3 + "
";
return;
}
bytecodeFile.println(directive.toString() + " " + operand1 + " " + operand2 + " " + operand3);
++instructionCount;
}
public void emitBlankLine() {
if (buffered) {
bufferedContent += "
";
return;
}
if (classDefine) {
classDefinition += "
";
return;
}
bytecodeFile.println();
bytecodeFile.flush();
}
ProgramGenerator.java
ProgramGenerator 는 CodeGenerator 를 계승 했다.즉,기본 적 인 조작 을 계승 했다.이전 구조 체,배열 의 명령 출력 은 모두 이런 종류 에 있 었 다.
처리 플러그 인
먼저 네 개의 속성 을 보 세 요.이 네 개의 속성 은 주로 포 함 된 분기 와 순환 을 처리 합 니 다.
private int branch_count = 0;
private int branch_out = 0;
private String embedded = "";
private int loopCount = 0;
4
public void incraseIfElseEmbed() {
embedded += "i";
}
public void decraseIfElseEmbed() {
embedded = embedded.substring(1);
}
public void emitBranchOut() {
String s = "
" + embedded + "branch_out" + branch_out + ":
";
this.emitString(s);
branch_out++;
}
loopCount 는 끼 워 넣 기 순환 에 대한 처리 입 니 다.
public void emitLoopBranch() {
String s = "
" + "loop" + loopCount + ":" + "
";
emitString(s);
}
public String getLoopBranch() {
return "loop" + loopCount;
}
public void increaseLoopCount() {
loopCount++;
}
처리 구조 체
putStructToClassDeclaration 은 구조 체,즉 new 클래스 를 정의 합 니 다.declaresStructAsClass 는 처리 구조 체 의 변수,즉 처리 류 에 해당 하 는 속성 입 니 다.
public void putStructToClassDeclaration(Symbol symbol) {
Specifier sp = symbol.getSpecifierByType(Specifier.STRUCTURE);
if (sp == null) {
return;
}
StructDefine struct = sp.getStruct();
if (structNameList.contains(struct.getTag())) {
return;
} else {
structNameList.add(struct.getTag());
}
if (symbol.getValueSetter() == null) {
this.emit(Instruction.NEW, struct.getTag());
this.emit(Instruction.DUP);
this.emit(Instruction.INVOKESPECIAL, struct.getTag() + "/" + "()V");
int idx = this.getLocalVariableIndex(symbol);
this.emit(Instruction.ASTORE, "" + idx);
}
declareStructAsClass(struct);
}
private void declareStructAsClass(StructDefine struct) {
this.setClassDefinition(true);
this.emitDirective(Directive.CLASS_PUBLIC, struct.getTag());
this.emitDirective(Directive.SUPER, "java/lang/Object");
Symbol fields = struct.getFields();
do {
String fieldName = fields.getName() + " ";
if (fields.getDeclarator(Declarator.ARRAY) != null) {
fieldName += "[";
}
if (fields.hasType(Specifier.INT)) {
fieldName += "I";
} else if (fields.hasType(Specifier.CHAR)) {
fieldName += "C";
} else if (fields.hasType(Specifier.CHAR) && fields.getDeclarator(Declarator.POINTER) != null) {
fieldName += "Ljava/lang/String;";
}
this.emitDirective(Directive.FIELD_PUBLIC, fieldName);
fields = fields.getNextSymbol();
} while (fields != null);
this.emitDirective(Directive.METHOD_PUBLIC, "()V");
this.emit(Instruction.ALOAD, "0");
String superInit = "java/lang/Object/()V";
this.emit(Instruction.INVOKESPECIAL, superInit);
fields = struct.getFields();
do {
this.emit(Instruction.ALOAD, "0");
String fieldName = struct.getTag() + "/" + fields.getName();
String fieldType = "";
if (fields.hasType(Specifier.INT)) {
fieldType = "I";
this.emit(Instruction.SIPUSH, "0");
} else if (fields.hasType(Specifier.CHAR)) {
fieldType = "C";
this.emit(Instruction.SIPUSH, "0");
} else if (fields.hasType(Specifier.CHAR) && fields.getDeclarator(Declarator.POINTER) != null) {
fieldType = "Ljava/lang/String;";
this.emit(Instruction.LDC, " ");
}
String classField = fieldName + " " + fieldType;
this.emit(Instruction.PUTFIELD, classField);
fields = fields.getNextSymbol();
} while (fields != null);
this.emit(Instruction.RETURN);
this.emitDirective(Directive.END_METHOD);
this.emitDirective(Directive.END_CLASS);
this.setClassDefinition(false);
}
스 택 정보 가 져 오기
다른 자바 바이트 코드 는 모두 이전 편 에 따라 이 루어 집 니 다.논리 가 복잡 하지 않 습 니 다.지금 방법 을 보 겠 습 니 다:getLocalVariableIndex,이 방법 은 현재 대기 열 에 있 는 변 수 를 가 져 오 는 것 입 니 다.
4.567917.현재 실 행 된 함 수 를 먼저 받 은 다음 에 함수 의 대응 하 는 매개 변 수 를 받 은 다음 에 반전(이것 은 매개 변수 스 택 의 순서 와 관계 가 있다)4.567917.그리고 현재 기호 가 대응 하 는 역할 역 의 기 호 를 모두 목록 에 추가 합 니 다4.567917.그 다음 에 이 목록 을 옮 겨 다 니 면 이 기호 가 대열 에 대응 하 는 위 치 를 계산 할 수 있 습 니 다
public int getLocalVariableIndex(Symbol symbol) {
TypeSystem typeSys = TypeSystem.getInstance();
String funcName = nameStack.peek();
Symbol funcSym = typeSys.getSymbolByText(funcName, 0, "main");
ArrayList localVariables = new ArrayList<>();
Symbol s = funcSym.getArgList();
while (s != null) {
localVariables.add(s);
s = s.getNextSymbol();
}
Collections.reverse(localVariables);
ArrayList list = typeSys.getSymbolsByScope(symbol.getScope());
for (int i = 0; i < list.size(); i++) {
if (!localVariables.contains(list.get(i))) {
localVariables.add(list.get(i));
}
}
for (int i = 0; i < localVariables.size(); i++) {
if (localVariables.get(i) == symbol) {
return i;
}
}
return -1;
}
작은 매듭
이 편 은 주로 전편 의 JVM 바이트 코드 에 따라 서로 다른 조작 에 대해 서로 다른 방법 으로 이 명령 을 출력 하 는 것 이다.
환영 스타!
다음으로 전송:https://www.cnblogs.com/secoding/p/11388347.html
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.