Compiler 是一个基于 LLVM 的编译器,用于编译自创的静态类型编程语言 lyris 。
- xmake xmake 是一个基于Lua的轻量级跨平台自动构建工具,并自带强大的包管理和集成功能。
- clang 本项目将 lyris 代码编译为 LLVM IR,由 clang 将 IR 编译链接成可执行文件。
- llvm 部分代码需要使用 llvm 工具链,windows 上的 mingw 自带 llvm 工具链。
操作系统支持:windows,linux
拉取代码后,在项目根目录输入以下命令编译项目:
xmake
编译时需要安装 llvm、boost 等依赖库,若出现提示请输入 y。如果下载因网络问题失败,考虑使用 VPN,并参考 官方文档
编译完成后,输入以下命令即可运行项目:
xmake run compiler -o bin/main code/main.txt
这条命令会编译 code/main.txt 代码文件,并在 bin 目录下生成名为 main 的可执行文件。随后运行可执行文件,将看到输出 hello world!
要了解更多用法,使用以下命令打印编译器帮助列表
xmake run compiler --help
在项目根目录输入以下命令开始测试
xmake test
在 test/code 目录下有用于测试的代码文件,这些代码文件可以帮助理解 lyris 的使用。
要安装 Compiler,首先需要在项目根目录下运行以下命令
xmake f --dev=false
xmake install -o <install directory>
第二条命令中的 <install directory> 替换为安装目录。
安装完成后将在安装目录看到以下结构的文件
./compiler/
├── bin
│ └── compiler
├── include
│ └── io
└── lib
└── libio.a
bin:存放编译器的可执行文件
include:保存 lyris 需要的标准库函数
lib:标准库函数的依赖库,包含标准库函数的具体实现
将 bin 目录加入到 PATH 环境变量中,就可以像 gcc、clang 一样使用 Compiler 了。
lyris 是一门静态类型的编译型语言。它有三个基本类型:int, boolean, string,这三个基本类型可以组成数组和结构体。lyris 支持条件语句、循环语句、函数、嵌套作用域、导入库函数。lyris 没有类型转换,编译器会检查类型的使用是否正确。
以下是使用 lyris 输出 hello world! 的代码:
import io;
func main() -> int {
printf("hello world!\n");
return 0;
}
import io 表明要导入 io 库函数。io 库中声明了 printf 函数,这个函数的用法和 C 语言中的一样。
func 关键字用于指示函数声明或函数定义。这里定义了一个 main 函数,箭头(->)后的 int 表示返回类型。一份 lyris 代码必须包含 main 函数。
lyris 使用 let 关键字声明变量,随后是变量名,后面是类型名称,最后是可选的初始化。
lyris 支持自动类型推导,当变量被初始化时,可以省略变量类型。
变量之间可以赋值,前提是赋值运算符两侧的操作数类型一致。
func main() -> int {
let a : int;
let b : int = 10;
let c = 30;
let d : boolean = true;
let e : string = "hello";
e = "world!";
return 0;
}
lyris 使用 if 和 else 实现条件语句,这一点和 C 语言一样,不同之处在于 if 条件只能是 boolean 类型。
import io;
func main() -> int {
let x = input();
if (x < 10) {
printf("x is less than 10\n");
} else if (x > 10) {
printf("x is greater than 10\n");
} else {
printf("x is 10\n");
}
return 0;
}
lyris 支持 for 循环和 while 循环,语法和 C 语言相同。
func main() -> int {
for (let i = 0; i < 10; i++) {
println(i);
}
return 0;
}
lyris 支持结构体。结构体有多个成员组成,成员类型可以是基本类型,也可以是结构体,但不能是数组。一个结构体最多有 255 个成员。
struct Pair {
let x : int;
let y : int;
}
结构体成员并不是变量声明,所以不能初始化,也不能省略类型。
使用 . 访问结构体变量的成员
func main() -> int {
let pair : Pair;
pair.x = 10;
pair.y = 20;
println(pair.y);
return 0;
}
结构体之间可以直接赋值。
数组可以看成由一个或多个连续存放的变量。lyris 中定义数组只需在类型名后用中括号和数字指定数组大小。
func main() -> int {
let a : int[10];
let b : boolean[2];
return 0;
}
数组大小只能是整型字面量,不能是变量,且数组类型的变量不能初始化。
数组元素可以是基本类型,也可以是结构体。
数组类型由元素类型和数组大小构成,因此不同大小的数组是不同的类型。
数组之间无法赋值。
使用中括号和整数访问数组元素
func main() -> int {
let a : int[10];
a[0] = 1;
a[1] = a[0];
return 0;
}
函数必须有返回值,且函数体必须有 return。
函数可以返回结构体,但不能返回数组。
函数可以接收最多 255 个参数,参数类型可以是结构体,但不能是数组。lyris 中函数参数都是值传递,函数无法修改实参。
struct Pair {
let x : int;
let y : int;
}
func make_pair(int x, int y) -> Pair {
let p : Pair;
p.x = x;
p.y = y;
return p;
}
func swap(Pair x) -> Pair {
let p : Pair;
p.x = x.y;
p.y = x.x;
return p;
}
内置函数:
print打印一个整数println打印一个整数并换行input从标准输入接收一个整数,并返回puts输出字符串并返回printf格式化输出字符串print_boolean打印布尔值并换行