用LLVM来开发自己的编译器(二)——流程控制

增加新的类型和运算

这里先增加char型和bool型。char型代表一个unicode字符,因为c的wchar_t是32位的,所以这里用i32来实现char型。char可以看成是32位整型,可以和long型或double型互相转换,可以进行数值的运算。bool型代表真假值,这里用i1来实现,只有两个值true和false。
例子:

char c = 'A'; //普通字符
c = '\t';     //转义字符
c = '\u4e2d'; //unicode码
bool b = true;
b = false;

数值型(char,long,double)的运算原来只有+、-、*、/,这里增加%(求余)、>、<、==、!=、>=、<=等运算。bool型支持逻辑运算&&、||、!和比较运算==、!=。

if-else分支

定义if-else的语法如下:

if (expression) {
    .....
} else {
    .....
}
if (expression) {
    .....
}

ir的br指令是实现流程控制的最重要指令,使用它来进行基本块间的跳转。br可以直接跳转,如br label %bb1,执行过程跳转到基本块bb1上;br也可以是有条件跳转,如br i1 %cond, label %then, label %else,如果cond等于1就跳转到基本块then上,如果等于0就跳到else上。这样代码和ir的对应关系如下:
在此输入图片描述

使用irBuilder.CreateCondBr(condVal, thenBB, elseBB)irBuilder.CreateBr(outBB)可以生成对应的指令。

for循环

定义for循环的语法如下:

for(statement; expression; statement){
    .....
}

for循环也是用br来实现。它的对应比if-else的要稍微复杂些:
在此输入图片描述

局部变量

for和if-else的代码块都应该产生新的作用域,里面定义的变量外面是不可见的。在代码块里定义的变量需要分配新的内存,但显然不能在for的里面出现alloca指令,因为这样会不断的申请栈上的内存。这里的策略是把所有的栈内存分配都放在函数的开头(clang也是这样做的),所以函数的开头要有一个alloc基本块,用来插入alloca指令,这样就可以在代码块内重复的使用对应的内存。例如:
在此输入图片描述

完整代码

https://github.com/linlifengx/step2

例子

test.sp

long main(){
    printL(fibonacci(10));println(); //55
    printL(fibonacci(20));println(); //6765

    printC('\u4e60');
    printC('\u8fd1');
    printC('\u5e73');
    println();
    return 0;
}

long fibonacci(long n){
    if(n < 0)
        return 0;
    if(n == 0)
        return 0;
    else if(n == 1)
        return 1;
    else
        return fibonacci(n-1)+fibonacci(n-2);
}

你可能感兴趣的:(流程控制,编译器,llvm)