Write a compiler (13) from zero: code generation of traversing AST

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!

Guess you like

Origin www.cnblogs.com/secoding/p/11391239.html