The complete code for the project in C2j-Compiler
Foreword
To complete the generation of a JVM instructions on, you can actually enter the following section of code generation. Modern compilers are usually first generation IR, and then through code optimization and so on, and finally compiled into code for the target platform. However, the level of the limited time, we did not IR code optimization, direct Java bytecodes using AST generated
Entrance
Code generated in CodeGen inlet, and is the same as explained before: to obtain the main function of the head node, the node from the beginning, into the first function is defined, and then enter the code blocks
Function definition node
When entering the node function definition, it is necessary to generate a corresponding function defined in Java byte code, i.e., a static method (since we generated as a C language file for the entire class, a method for the main public static main, others are the corresponding the static method, the structure is another class)
- Definition of a function to get the start node and the corresponding function command parameters
- emitArgs processing parameter is used to generate the corresponding Java bytecode in accordance with the parameters
- If this function is main it has been handed over to the previous process, almost logic (in particular in start.Start)
case SyntaxProductionInit.NewName_LP_RP_TO_FunctDecl:
root.reverseChildren();
AstNode n = root.getChildren().get(0);
String name = (String) n.getAttribute(NodeKey.TEXT);
symbol = (Symbol) root.getAttribute(NodeKey.SYMBOL);
generator.setCurrentFuncName(name);
if (name != null && !name.equals("main")) {
String declaration = name + emitArgs(symbol);
generator.emitDirective(Directive.METHOD_PUBBLIC_STATIC, declaration);
generator.setNameAndDeclaration(name, declaration);
}
copyChild(root, root.getChildren().get(0));
break;
case SyntaxProductionInit.NewName_LP_VarList_RP_TO_FunctDecl:
n = root.getChildren().get(0);
name = (String) n.getAttribute(NodeKey.TEXT);
symbol = (Symbol) root.getAttribute(NodeKey.SYMBOL);
generator.setCurrentFuncName(name);
if (name != null && !name.equals("main")) {
String declaration = name + emitArgs(symbol);
generator.emitDirective(Directive.METHOD_PUBBLIC_STATIC, declaration);
generator.setNameAndDeclaration(name, declaration);
}
Symbol args = symbol.getArgList();
if (args == null || argsList == null || argsList.isEmpty()) {
System.err.println("generate function with arg list but arg list is null");
System.exit(1);
}
break;
Creating structures and arrays
Array
Node creates structures and arrays in DefGenerate, you can see here only deal with ordinary variables and arrays, it is dealing with the structure of the structure at the time of first use. Incidentally code generation operation for the initial value is not processed.
- If it is an array, wine directly call ProgramGenerator generated directly create an array of command
- If an ordinary variable, and assigned directly to it is 0 (the position in the queue where the variable is calculated according to the symbol table, specifically a fancy method of getLocalVariableIndex)
public class DefGenerate extends BaseGenerate {
@Override
public Object generate(AstNode root) {
int production = (int) root.getAttribute(NodeKey.PRODUCTION);
ProgramGenerator generator = ProgramGenerator.getInstance();
Symbol symbol = (Symbol) root.getAttribute(NodeKey.SYMBOL);
switch (production) {
case SyntaxProductionInit.Specifiers_DeclList_Semi_TO_Def:
Declarator declarator = symbol.getDeclarator(Declarator.ARRAY);
if (declarator != null) {
if (symbol.getSpecifierByType(Specifier.STRUCTURE) == null) {
generator.createArray(symbol);
}
} else {
int i = generator.getLocalVariableIndex(symbol);
generator.emit(Instruction.SIPUSH, "" + 0);
generator.emit(Instruction.ISTORE, "" + i);
}
break;
default:
break;
}
return root;
}
}
Structure
Treatment structure defined code UnaryNodeGenerate, i.e. only when used to define the structure will be defined
- First get the current UNARY symbol, if instanceof ArrayValueSetter on the note is an array of structures, to enter getStructSymbolFromStructArray way to create an array of structures, and returns the current structure of the object under the subject
- Set the current scope range structure
- It is defined as the structure of the class
- Then read the domain structure
- In fact, the pointer portion can be ignored, because the code generation does not simulate the pointer
case SyntaxProductionInit.Unary_StructOP_Name_TO_Unary:
child = root.getChildren().get(0);
String fieldName = (String) root.getAttribute(NodeKey.TEXT);
Object object = child.getAttribute(NodeKey.SYMBOL);
boolean isStructArray = false;
if (object instanceof ArrayValueSetter) {
symbol = getStructSymbolFromStructArray(object);
symbol.addValueSetter(object);
isStructArray = true;
} else {
symbol = (Symbol) child.getAttribute(NodeKey.SYMBOL);
}
if (isStructArray) {
ArrayValueSetter vs = (ArrayValueSetter) object;
Symbol structArray = vs.getSymbol();
structArray.addScope(ProgramGenerator.getInstance().getCurrentFuncName());
} else {
symbol.addScope(ProgramGenerator.getInstance().getCurrentFuncName());
}
ProgramGenerator.getInstance().putStructToClassDeclaration(symbol);
if (isSymbolStructPointer(symbol)) {
copyBetweenStructAndMem(symbol, false);
}
Symbol args = symbol.getArgList();
while (args != null) {
if (args.getName().equals(fieldName)) {
args.setStructParent(symbol);
break;
}
args = args.getNextSymbol();
}
if (args == null) {
System.err.println("access a filed not in struct object!");
System.exit(1);
}
if (args.getValue() != null) {
ProgramGenerator.getInstance().readValueFromStructMember(symbol, args);
}
root.setAttribute(NodeKey.SYMBOL, args);
root.setAttribute(NodeKey.VALUE, args.getValue());
if (isSymbolStructPointer(symbol)) {
checkValidPointer(symbol);
structObjSymbol = symbol;
monitorSymbol = args;
GenerateBrocasterImpl.getInstance().registerReceiverForAfterExe(this);
} else {
structObjSymbol = null;
}
break;
Unary operators node
This node has the same number and in the interpreter, in addition to the operation of the structure, the other is also a very important role
- Like numbers, strings or variables and operations are the prior information is transmitted to the parent node, a parent node process referred to
case SyntaxProductionInit.Number_TO_Unary:
text = (String) root.getAttribute(NodeKey.TEXT);
boolean isFloat = text.indexOf('.') != -1;
if (isFloat) {
value = Float.valueOf(text);
root.setAttribute(NodeKey.VALUE, value);
} else {
value = Integer.valueOf(text);
root.setAttribute(NodeKey.VALUE, value);
}
break;
case SyntaxProductionInit.Name_TO_Unary:
symbol = (Symbol) root.getAttribute(NodeKey.SYMBOL);
if (symbol != null) {
root.setAttribute(NodeKey.VALUE, symbol.getValue());
root.setAttribute(NodeKey.TEXT, symbol.getName());
}
break;
case SyntaxProductionInit.String_TO_Unary:
text = (String) root.getAttribute(NodeKey.TEXT);
root.setAttribute(NodeKey.VALUE, text);
break;
case SyntaxProductionInit.Unary_LB_Expr_RB_TO_Unary:
child = root.getChildren().get(0);
symbol = (Symbol) child.getAttribute(NodeKey.SYMBOL);
child = root.getChildren().get(1);
int index = 0;
if (child.getAttribute(NodeKey.VALUE) != null) {
index = (Integer) child.getAttribute(NodeKey.VALUE);
}
Object idxObj = child.getAttribute(NodeKey.SYMBOL);
try {
Declarator declarator = symbol.getDeclarator(Declarator.ARRAY);
if (declarator != null) {
Object val = declarator.getElement((int) index);
root.setAttribute(NodeKey.VALUE, val);
ArrayValueSetter setter;
if (idxObj == null) {
setter = new ArrayValueSetter(symbol, index);
} else {
setter = new ArrayValueSetter(symbol, idxObj);
}
root.setAttribute(NodeKey.SYMBOL, setter);
root.setAttribute(NodeKey.TEXT, symbol.getName());
}
Declarator pointer = symbol.getDeclarator(Declarator.POINTER);
if (pointer != null) {
setPointerValue(root, symbol, index);
PointerValueSetter pv = new PointerValueSetter(symbol, index);
root.setAttribute(NodeKey.SYMBOL, pv);
root.setAttribute(NodeKey.TEXT, symbol.getName());
}
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
break;
Assignment
- If the current is an array, first get its symbols and subscript
- If it is not an array of structures, the subscript generation instruction to get the array element read directly readArrayElement
- If the symbol is a symbol with a value read getLocalVariableIndex
- If it is a constant, directly generate instructions IPUSH
- Finally assignment, if it is not to assign a domain structure would get directly with getLocalVariableIndex then generates a queue position ISTORE
- If an assignment to field elements of an array of structures, it calls assignValueToStructMemberFromArray generated code, but if the structure is directly generated code calls assignValueToStructMember
ProgramGenerator generator = ProgramGenerator.getInstance();
if (BaseGenerate.resultOnStack) {
this.value = obj;
BaseGenerate.resultOnStack = false;
} else if (obj instanceof ArrayValueSetter) {
ArrayValueSetter setter = (ArrayValueSetter) obj;
Symbol symbol = setter.getSymbol();
Object index = setter.getIndex();
if (symbol.getSpecifierByType(Specifier.STRUCTURE) == null) {
if (index instanceof Symbol) {
ProgramGenerator.getInstance().readArrayElement(symbol, index);
if (((Symbol) index).getValue() != null) {
int i = (int) ((Symbol) index).getValue();
try {
this.value = symbol.getDeclarator(Declarator.ARRAY).getElement(i);
} catch (Exception e) {
e.printStackTrace();
}
}
} else {
int i = (int) index;
try {
this.value = symbol.getDeclarator(Declarator.ARRAY).getElement(i);
} catch (Exception e) {
e.printStackTrace();
}
ProgramGenerator.getInstance().readArrayElement(symbol, index);
}
}
} else if (obj instanceof Symbol) {
Symbol symbol = (Symbol) obj;
this.value = symbol.value;
int i = generator.getLocalVariableIndex(symbol);
generator.emit(Instruction.ILOAD, "" + i);
} else if (obj instanceof Integer) {
Integer val = (Integer) obj;
generator.emit(Instruction.SIPUSH, "" + val);
this.value = obj;
}
if (!this.isStructMember()) {
int idx = generator.getLocalVariableIndex(this);
if (!generator.isPassingArguments()) {
generator.emit(Instruction.ISTORE, "" + idx);
}
} else {
if (this.getStructSymbol().getValueSetter() != null) {
generator.assignValueToStructMemberFromArray(this.getStructSymbol().getValueSetter(), this, this.value);
} else {
generator.assignValueToStructMember(this.getStructSymbol(), this, this.value);
}
}
At last
After completion of this section, the following code
void quicksort(int A[10], int p, int r) {
int x;
int i;
i = p - 1;
int j;
int t;
int v;
v = r - 1;
if (p < r) {
x = A[r];
for (j = p; j <= v; j++) {
if (A[j] <= x) {
i++;
t = A[i];
A[i] = A[j];
A[j] = t;
}
}
v = i + 1;
t = A[v];
A[v] = A[r];
A[r] = t;
t = v - 1;
quicksort(A, p, t);
t = v + 1;
quicksort(A, t, r);
}
}
void main () {
int a[10];
int i;
int t;
printf("before quick sort:");
for(i = 0; i < 10; i++) {
t = (10 - i);
a[i] = t;
printf("value of a[%d] is %d", i, a[i]);
}
quicksort(a, 0, 9);
printf("after quick sort:");
for (i = 0; i < 10; i++) {
printf("value of a[%d] is %d", i, a[i]);
}
}
It is generated following Java bytecode
.class public C2Bytecode
.super java/lang/Object
.method public static main([Ljava/lang/String;)V
sipush 10
newarray int
astore 0
sipush 0
istore 1
sipush 0
istore 2
getstatic java/lang/System/out Ljava/io/PrintStream;
ldc "before quick sort:"
invokevirtual java/io/PrintStream/print(Ljava/lang/String;)V
getstatic java/lang/System/out Ljava/io/PrintStream;
ldc "
"
invokevirtual java/io/PrintStream/print(Ljava/lang/String;)V
sipush 0
istore 1
loop0:
iload 1
sipush 10
if_icmpge branch0
sipush 10
iload 1
isub
istore 2
aload 0
iload 1
iload 2
iastore
aload 0
iload 1
iaload
istore 3
iload 1
istore 4
getstatic java/lang/System/out Ljava/io/PrintStream;
ldc "value of a["
invokevirtual java/io/PrintStream/print(Ljava/lang/String;)V
getstatic java/lang/System/out Ljava/io/PrintStream;
iload 4
invokevirtual java/io/PrintStream/print(I)V
getstatic java/lang/System/out Ljava/io/PrintStream;
ldc "] is "
invokevirtual java/io/PrintStream/print(Ljava/lang/String;)V
getstatic java/lang/System/out Ljava/io/PrintStream;
iload 3
invokevirtual java/io/PrintStream/print(I)V
getstatic java/lang/System/out Ljava/io/PrintStream;
ldc "
"
invokevirtual java/io/PrintStream/print(Ljava/lang/String;)V
iload 1
sipush 1
iadd
istore 1
goto loop0
branch0:
aload 0
sipush 0
sipush 9
invokestatic C2Bytecode/quicksort([III)V
getstatic java/lang/System/out Ljava/io/PrintStream;
ldc "after quick sort:"
invokevirtual java/io/PrintStream/print(Ljava/lang/String;)V
getstatic java/lang/System/out Ljava/io/PrintStream;
ldc "
"
invokevirtual java/io/PrintStream/print(Ljava/lang/String;)V
sipush 0
istore 1
loop2:
iload 1
sipush 10
if_icmpge branch4
aload 0
iload 1
iaload
istore 3
iload 1
istore 4
getstatic java/lang/System/out Ljava/io/PrintStream;
ldc "value of a["
invokevirtual java/io/PrintStream/print(Ljava/lang/String;)V
getstatic java/lang/System/out Ljava/io/PrintStream;
iload 4
invokevirtual java/io/PrintStream/print(I)V
getstatic java/lang/System/out Ljava/io/PrintStream;
ldc "] is "
invokevirtual java/io/PrintStream/print(Ljava/lang/String;)V
getstatic java/lang/System/out Ljava/io/PrintStream;
iload 3
invokevirtual java/io/PrintStream/print(I)V
getstatic java/lang/System/out Ljava/io/PrintStream;
ldc "
"
invokevirtual java/io/PrintStream/print(Ljava/lang/String;)V
iload 1
sipush 1
iadd
istore 1
goto loop2
branch4:
return
.end method
.method public static quicksort([III)V
sipush 2
newarray int
astore 6
sipush 0
istore 5
sipush 1
istore 5
aload 6
iload 5
sipush 1
iastore
aload 6
sipush 1
iaload
istore 10
getstatic java/lang/System/out Ljava/io/PrintStream;
ldc "before quick sort: "
invokevirtual java/io/PrintStream/print(Ljava/lang/String;)V
getstatic java/lang/System/out Ljava/io/PrintStream;
iload 10
invokevirtual java/io/PrintStream/print(I)V
getstatic java/lang/System/out Ljava/io/PrintStream;
ldc "
"
invokevirtual java/io/PrintStream/print(Ljava/lang/String;)V
sipush 0
istore 9
sipush 0
istore 3
iload 1
sipush 1
isub
istore 3
sipush 0
istore 4
sipush 0
istore 7
sipush 0
istore 8
iload 2
sipush 1
isub
istore 8
iload 1
iload 2
if_icmpge branch1
aload 0
iload 2
iaload
istore 9
iload 1
istore 4
loop1:
iload 4
iload 8
if_icmpgt ibranch1
aload 0
iload 4
iaload
iload 9
if_icmpgt ibranch2
iload 3
sipush 1
iadd
istore 3
aload 0
iload 3
iaload
istore 7
aload 0
iload 3
aload 0
iload 4
iaload
iastore
aload 0
iload 4
iload 7
iastore
ibranch2:
iload 4
sipush 1
iadd
istore 4
goto loop1
ibranch1:
iload 3
sipush 1
iadd
istore 8
aload 0
iload 8
iaload
istore 7
aload 0
iload 8
aload 0
iload 2
iaload
iastore
aload 0
iload 2
iload 7
iastore
iload 8
sipush 1
isub
istore 7
aload 0
iload 1
iload 7
invokestatic C2Bytecode/quicksort([III)V
iload 8
sipush 1
iadd
istore 7
aload 0
iload 7
iload 2
invokestatic C2Bytecode/quicksort([III)V
branch1:
return
.end method
.end class
summary
This code generation and before the interpreter is similar ideas are performed AST or code generation and the corresponding production.
In fact, the main idea is very clear, there are just too many details people get too tangled. This series counted as my own study notes, to which there are thirteen, the next one may write summary officially ended.
Welcome Star!