從零寫一個編譯器(完結):總結和系列索引

前言

這個系列算做我本身的學習筆記,到如今已經有十三篇了,加上這篇一共十四篇。一步一步的從詞法分析到語法分析、語義分析,再到代碼生成,準備在這一篇作一個總結收尾和一個這個系列之前文章的索引。html

(另外,因爲我如今的這個主題不能對markdown的一級標題做目錄,因此這個系列文章的目錄都是有問題的)java

索引

從零寫一個編譯器(一):輸入系統和詞法分析markdown

從零寫一個編譯器(二):語法分析以前置知識數據結構

從零寫一個編譯器(三):語法分析之幾個基礎數據結構函數

從零寫一個編譯器(四):語法分析之構造有限狀態自動機oop

從零寫一個編譯器(五):語法分析之自動機的缺陷和改進學習

從零寫一個編譯器(六):語法分析之表驅動語法分析ui

從零寫一個編譯器(七):語義分析之符號表的數據結構code

從零寫一個編譯器(八):語義分析之構造符號表htm

從零寫一個編譯器(九):語義分析之構造抽象語法樹(AST)

從零寫一個編譯器(十):編譯前傳之直接解釋執行

從零寫一個編譯器(十一):代碼生成之Java字節碼基礎

從零寫一個編譯器(十二):代碼生成之生成邏輯

從零寫一個編譯器(十三):代碼生成之遍歷AST

示例

對於C語言的一個快速排序

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

解釋執行

就直接在控制檯輸出

代碼生成

會在當前目錄生成一個C2Bytecode.j字節碼文件,再通過字節碼的彙編器就能夠在JVM上運行

.class public C2Bytecode
.super java/lang/Object

.method public static main([Ljava/lang/String;)V
    sipush  10
    newarray    int
    astore  0
    sipush  0
    istore  2
    sipush  0
    istore  1
    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  2

loop0:
    iload   2
    sipush  10
if_icmpge branch0
    sipush  10
    iload   2
    isub
    istore  1
    aload   0
    iload   2
    iload   1
    iastore
    aload   0
    iload   2
    iaload
    istore  3
    iload   2
    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   2
    sipush  1
    iadd
    istore  2
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  2

loop2:
    iload   2
    sipush  10
if_icmpge branch4
    aload   0
    iload   2
    iaload
    istore  3
    iload   2
    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   2
    sipush  1
    iadd
    istore  2
goto loop2
branch4:
    return
.end method
.method public static quicksort([III)V
    sipush  0
    istore  5
    sipush  0
    istore  6
    iload   1
    sipush  1
    isub
    istore  6
    sipush  0
    istore  7
    sipush  0
    istore  3
    sipush  0
    istore  4
    iload   2
    sipush  1
    isub
    istore  4
    iload   1
    iload   2
if_icmpge branch1

    aload   0
    iload   2
    iaload
    istore  5
    iload   1
    istore  7

loop1:

    iload   7
    iload   4
if_icmpgt ibranch1

    aload   0
    iload   7
    iaload
    iload   5
if_icmpgt ibranch2

    iload   6
    sipush  1
    iadd
    istore  6
    aload   0
    iload   6
    iaload
    istore  3
    aload   0
    iload   6
    aload   0
    iload   7
    iaload
    iastore
    aload   0
    iload   7
    iload   3
    iastore
ibranch2:

    iload   7
    sipush  1
    iadd
    istore  7
goto loop1

ibranch1:

    iload   6
    sipush  1
    iadd
    istore  4
    aload   0
    iload   4
    iaload
    istore  3
    aload   0
    iload   4
    aload   0
    iload   2
    iaload
    iastore
    aload   0
    iload   2
    iload   3
    iastore
    iload   4
    sipush  1
    isub
    istore  3
    aload   0
    iload   1
    iload   3
    invokestatic    C2Bytecode/quicksort([III)V
    iload   4
    sipush  1
    iadd
    istore  3
    aload   0
    iload   3
    iload   2
    invokestatic    C2Bytecode/quicksort([III)V
branch1:

    return
.end method

.end class

總結

  • 詞法分析

通常用有限狀態自動機或者手工編寫來實現,這一步輸出的是token序列

  • 語法分析

主要分爲自頂向下和自底向上的語法分析,通常有遞歸降低,LL(1),LR(1),LALR(1)幾種方法實現。這一步輸出的是語法樹

  • 語義分析

語義分析主要任務是生成符號表,而且發現不符合語義的語句,這一步輸出的仍是AST

  • 代碼生成

這裏通常會生成一個與平臺無關的較爲貼近底層的中間語言(IR),這一步輸入AST,輸出的是IR

這個編譯過程在第一篇的時候就有提起,如今主要想總結的是解釋執行和代碼生成部分,也就是遍歷AST的過程

  • 首先抽象語法樹AST的構造就像是把全部代碼分割成一塊一塊,可是其中塊和塊之間又有邏輯關係,而後把它們組成一棵樹

  • 正是有這顆樹咱們才得以對代碼進行邏輯的解釋,從葉子節點開始,再存儲處理後的信息,傳遞至父節點

  • 好比對於a = 0節點,咱們先遞歸至子節點,求出a和0的值而且保存在本身的節點,而父節點a = 0就能夠利用子節點的信息來對a賦值,好比若是是生成代碼的話,a = 0這個節點的操做可能就是找到這個存儲這個變量的寄存器,而後生成對這個寄存器賦值的指令

  • 在這個過程有一個很是重要的數據結構,即符號表,不管是直接解釋執行仍是代碼生成都會用到。它的主要用來標識和存儲源代碼的變量、函數等。在符號表中,源程序中的每一個標識符都和它的聲明或使用信息綁定在一塊兒,好比其數據類型、做用域以及內存地址。

  • 一個玩具型編譯器的主體思路是很明確的,可是在實際實現當中須要考慮的細節也不少,因此才讓實現過於繁瑣

相關文章
相關標籤/搜索