ゼロからコンパイラ(13)を書く:ASTを横断のコード生成

プロジェクトの完全なコードC2j、コンパイラ

序文

上のJVMの命令の生成を完了するには、実際にコード生成の次のセクションを入力することができます。現代のコンパイラは通常、第一世代のIR、その後、コードの最適化を通じてというように、そして最終的にターゲットプラットフォーム用のコードにコンパイルされています。しかし、限られた時間のレベルは、我々はIRコード最適化しませんでした、直接Javaが生成されたASTを使用してバイトコード

エントランス

コードは、コード生成の入口に生成され、前に説明したのと同様である:ヘッドノードの主な機能を得るために、最初の関数に先頭からノードは、定義され、そして、コードブロックを入力されています

関数定義ノード

ノード関数定義を入力する場合、我々が全体のクラスのためのC言語ファイル、主要公共、主静的他人のための方法として生成対応しているので(Javaバイトコードで定義された対応する機能、すなわち、静的メソッドを生成する必要があります静的メソッドは、構造体)は、別のクラスであります

  • 開始ノードと、対応する機能コマンドパラメータを取得するための関数の定義
  • emitArgs処理パラメータがパラメータに従って対応するJavaバイトコードを生成するために使用されます
  • この機能は、メインである場合には(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;

構造と配列を作成します

配列

ノードはDefGenerate内の構造と配列を作成し、あなたはそれが最初の使用時に構造体の構造を扱っている、通常の変数や配列を扱うここで見ることができます。なお、初期値のためのコード生成操作は処理されません。

  • それが配列の場合、ワインは直接ProgramGeneratorが直接コマンドの配列を作成して生成された呼び出し
  • それに直接割り当てられた通常の変数は、0(変数記号表に従って計算されるキュー内の位置、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;
    }
}

構造

構造を定義するために使用される場合処理構造定義コードUnaryNodeGenerate、すなわちのみ定義されます

  • ノートのinstanceofはArrayValueSetterがgetStructSymbolFromStructArrayに構造体の配列を作成する方法を入力して、構造体の配列で、被写体の下のオブジェクトの現在の構造を返した場合まず、現在のUNARYシンボルを取得します
  • 現在のスコープ範囲の構造を設定します
  • これは、クラスの構造として定義されています
  • その後、ドメイン構造を読みます
  • コード生成は、ポインタをシミュレートしていないため、実際には、ポインタ部分は、無視することができます
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;

単項演算子ノード

このノードには、同じ番号を持っており、インタプリタでは、構造体の操作に加えて、他にも非常に重要な役割であります

  • 数値、文字列または変数および操作のような事前情報は、親ノードと呼ばれる親ノードのプロセスに送信されます
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;

割り当て

  • 電流が配列である場合は、最初にその記号と添字を取得
  • それは構造体の配列でない場合は、配列要素を取得するための添字生成命令は、直接読み取るreadArrayElement
  • 記号はgetLocalVariableIndexを読んで値を持つシンボルである場合
  • それが一定であれば、直接命令を生成IPUSH
  • それはドメイン構造を割り当てることではない場合getLocalVariableIndexは、キュー位置ISTOREを生成して最後に割り当て、直接になるだろう
  • 割り当ては構造体の配列の要素をフィールドする場合、それはassignValueToStructMemberFromArrayコードを生成し呼び出しが、構造が直接生成される場合、コードは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);
    }
}

遂に

このセクションの終了後、次のコード

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

これは、Javaバイトコードの後に​​生成されます

.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

概要

このコード生成及びインタプリタが類似している前のアイデアが実行さASTまたはコード生成および対応する製造。

実際には、主要なアイデアは、人々があまりにも絡まあまりにも多くの詳細がありますが、非常に明確です。このシリーズはどの13があるし、私自身の研究ノートとして数え、次のものが正式に終了要約を書き込むことができます。

ようこそスター!

おすすめ

転載: www.cnblogs.com/secoding/p/11391239.html