这个系列算做我本身的学习笔记,到如今已经有十三篇了,加上这篇一共十四篇。一步一步的从词法分析到语法分析、语义分析,再到代码生成,准备在这一篇作一个总结收尾和一个这个系列之前文章的索引。html
(另外,因为我如今的这个主题不能对markdown的一级标题做目录,因此这个系列文章的目录都是有问题的)java
从零写一个编译器(一):输入系统和词法分析markdown
对于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这个节点的操做可能就是找到这个存储这个变量的寄存器,而后生成对这个寄存器赋值的指令
在这个过程有一个很是重要的数据结构,即符号表,不管是直接解释执行仍是代码生成都会用到。它的主要用来标识和存储源代码的变量、函数等。在符号表中,源程序中的每一个标识符都和它的声明或使用信息绑定在一块儿,好比其数据类型、做用域以及内存地址。
一个玩具型编译器的主体思路是很明确的,可是在实际实现当中须要考虑的细节也不少,因此才让实现过于繁琐