Compare commits
No commits in common. "66505c1389f418523d28809083d695119e9b88a2" and "b8108acb2ebc0a42937cc7caa4bc038000b2c956" have entirely different histories.
66505c1389
...
b8108acb2e
22
README.md
22
README.md
@ -1,6 +1,6 @@
|
|||||||
# RVBTCC
|
# RVBTCC
|
||||||
|
|
||||||
- 约 1800 行的轻量级自举编译器。
|
- 约 1500 行的轻量级自举编译器。
|
||||||
- 编译器和自举编译器行为一致。
|
- 编译器和自举编译器行为一致。
|
||||||
- 语法类似 C,输出 RISC-V 汇编。
|
- 语法类似 C,输出 RISC-V 汇编。
|
||||||
- 依赖几个 libc 函数用于输入输出。
|
- 依赖几个 libc 函数用于输入输出。
|
||||||
@ -64,21 +64,7 @@ $ sh boot.sh
|
|||||||
|
|
||||||
本语言包含的关键字即为支持的标量类型的关键字和流程控制的关键字,还有 `const`。
|
本语言包含的关键字即为支持的标量类型的关键字和流程控制的关键字,还有 `const`。
|
||||||
|
|
||||||
### `const` 关键字
|
`const` 关键字可以在类型中使用,但会被直接忽略。支持它是为了更好兼容 C 程序。
|
||||||
|
|
||||||
`const` 关键字可以在类型中使用,在大部分情况下会被直接忽略。支持它是为了更好兼容 C 程序。
|
|
||||||
|
|
||||||
但是当在出现
|
|
||||||
|
|
||||||
- 全局,标量(即不是数组)
|
|
||||||
- 类型为 `const int` 或 `const int const`
|
|
||||||
- 带有初始化
|
|
||||||
|
|
||||||
的声明时,将会被解析为整数常量。
|
|
||||||
|
|
||||||
整数常量在使用的时候会被直接替换为对应的右值,失去作为全局变量左值的性质。
|
|
||||||
|
|
||||||
使用 `int const` 或 `int` 可以避免这样的特殊处理。
|
|
||||||
|
|
||||||
### 支持六个基本类型
|
### 支持六个基本类型
|
||||||
|
|
||||||
@ -89,11 +75,13 @@ $ sh boot.sh
|
|||||||
| `int` | `int*` |
|
| `int` | `int*` |
|
||||||
|
|
||||||
- 注意指针类型不是复合得来的,而是被视作整体。因此也不存在二重指针。
|
- 注意指针类型不是复合得来的,而是被视作整体。因此也不存在二重指针。
|
||||||
|
|
||||||
- 函数和数组不是类型系统的一部分。
|
- 函数和数组不是类型系统的一部分。
|
||||||
- 可以认为数组的类型就是其元素对应的指针类型。
|
- 可以认为数组的类型就是其元素对应的指针类型。
|
||||||
- 函数的参数类型和个数不会检查,返回值会参与类型检查。
|
- 函数的参数类型和个数不会检查,返回值会参与类型检查。
|
||||||
- 函数名只能被用于调用,函数调用被视为初等表达式。
|
- 函数名只能被用于调用,函数调用被视为初等表达式。
|
||||||
- 数组只支持一维数组,且数组的元素不能是指针类型。
|
- 数组只支持一维数组,且数组的元素不能是指针类型。
|
||||||
|
- 全局变量不能是指针类型。
|
||||||
- 整数和字符字面量的类型是 `int`,字符串字面量的类型是 `char*`
|
- 整数和字符字面量的类型是 `int`,字符串字面量的类型是 `char*`
|
||||||
|
|
||||||
### 支持的流程控制
|
### 支持的流程控制
|
||||||
@ -128,6 +116,8 @@ $ sh boot.sh
|
|||||||
- 算术运算的结果总是被提升为 `int` 类型。布尔值用 `int` 类型表示。
|
- 算术运算的结果总是被提升为 `int` 类型。布尔值用 `int` 类型表示。
|
||||||
- 由于空指针就是 `0`,因此指针和整数之间的比较运算没有禁止。
|
- 由于空指针就是 `0`,因此指针和整数之间的比较运算没有禁止。
|
||||||
- 逻辑与和逻辑或支持短路求值。
|
- 逻辑与和逻辑或支持短路求值。
|
||||||
|
- 表达式没有左值和右值之分。可以认为右值总是存在一个临时的变量中。
|
||||||
|
- 赋值不检查类型。强制类型转换可以用赋值给特定类型的变量实现。
|
||||||
|
|
||||||
### 其它支持与不支持
|
### 其它支持与不支持
|
||||||
|
|
||||||
|
2
boot.sh
2
boot.sh
@ -5,7 +5,7 @@ gcc ../boot.c ../boot-lib.c -o gcc.out &&
|
|||||||
riscv64-linux-gnu-gcc-12 -static boot1.s ../boot-lib.c -o boot1.out &&
|
riscv64-linux-gnu-gcc-12 -static boot1.s ../boot-lib.c -o boot1.out &&
|
||||||
qemu-riscv64 boot1.out < boot-all.c > boot2.s &&
|
qemu-riscv64 boot1.out < boot-all.c > boot2.s &&
|
||||||
riscv64-linux-gnu-gcc-12 -static boot2.s ../boot-lib.c -o boot2.out &&
|
riscv64-linux-gnu-gcc-12 -static boot2.s ../boot-lib.c -o boot2.out &&
|
||||||
qemu-riscv64 boot2.out < boot-all.c > boot3.s
|
qemu-riscv64 boot2.out < boot-all.c > boot3.s &&
|
||||||
cmp --silent boot1.s boot2.s && echo "boot1.s == boot2.s" || echo "boot1.s != boot2.s"
|
cmp --silent boot1.s boot2.s && echo "boot1.s == boot2.s" || echo "boot1.s != boot2.s"
|
||||||
cmp --silent boot2.s boot3.s && echo "boot2.s == boot3.s" || echo "boot2.s != boot3.s"
|
cmp --silent boot2.s boot3.s && echo "boot2.s == boot3.s" || echo "boot2.s != boot3.s"
|
||||||
cmp --silent boot1.s boot3.s && echo "boot1.s == boot3.s" || echo "boot1.s != boot3.s"
|
cmp --silent boot1.s boot3.s && echo "boot1.s == boot3.s" || echo "boot1.s != boot3.s"
|
||||||
|
17
demo/add.c
17
demo/add.c
@ -1,17 +0,0 @@
|
|||||||
int printf(const char format[], ...);
|
|
||||||
int scanf(const char format[], ...);
|
|
||||||
int putchar(int ch);
|
|
||||||
|
|
||||||
int* p;
|
|
||||||
int f1() {
|
|
||||||
int a = 1;
|
|
||||||
return *(a+(a+(a+(a+(a+(a+(a+(a+(a+(a+(p))))))))))); // a[10]
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
int a[15];
|
|
||||||
p = a;
|
|
||||||
for (int i = 0; i < 15; ++i) a[i] = i;
|
|
||||||
return f1();
|
|
||||||
}
|
|
47
demo/lut.c
47
demo/lut.c
@ -1,47 +0,0 @@
|
|||||||
int printf(const char format[], ...);
|
|
||||||
int getchar();
|
|
||||||
|
|
||||||
char string_table[65536];
|
|
||||||
int string_offset;
|
|
||||||
int string_lut[4096];
|
|
||||||
int string_lut_size;
|
|
||||||
|
|
||||||
int parse_string() {
|
|
||||||
int offset = string_offset;
|
|
||||||
int ch;
|
|
||||||
while ((ch = getchar()) != '"') {
|
|
||||||
if (ch == -1 || ch == '\n') {
|
|
||||||
printf("expecting '\"'\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
string_table[string_offset++] = ch;
|
|
||||||
}
|
|
||||||
string_table[string_offset++] = 0;
|
|
||||||
string_lut[string_lut_size] = offset;
|
|
||||||
return string_lut_size++;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int streq(const char* s1, const char* s2) {
|
|
||||||
while (*s1 && *s2 && *s1 == *s2) {
|
|
||||||
s1++;
|
|
||||||
s2++;
|
|
||||||
}
|
|
||||||
return *s1 == *s2;
|
|
||||||
}
|
|
||||||
|
|
||||||
void dump_string_table() {
|
|
||||||
printf(".data\n");
|
|
||||||
for (int i = 0; i < string_lut_size; ++i) {
|
|
||||||
char* id = string_table + string_lut[i];
|
|
||||||
printf(".LC%d: .string \"%s\", const: %d\n",
|
|
||||||
i, id, streq(id, "const"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
char ch;
|
|
||||||
while ((ch = getchar()) == '"') parse_string();
|
|
||||||
dump_string_table();
|
|
||||||
return 0;
|
|
||||||
}
|
|
19
demo/parse.c
19
demo/parse.c
@ -1,19 +0,0 @@
|
|||||||
int getchar();
|
|
||||||
|
|
||||||
|
|
||||||
int is_digit(int ch) {
|
|
||||||
return '0' <= ch && ch <= '9';
|
|
||||||
}
|
|
||||||
|
|
||||||
int parse_int(int ch) {
|
|
||||||
int num = ch - '0';
|
|
||||||
while (is_digit(ch = getchar())) {
|
|
||||||
num = num * 10;
|
|
||||||
num = num + ch - '0';
|
|
||||||
}
|
|
||||||
return num;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
return parse_int(getchar());
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
int printf(const char* format, ...);
|
|
||||||
|
|
||||||
int strcmp(const char* s1, const char* s2) {
|
|
||||||
while (*s1 && *s2 && *s1 == *s2) {
|
|
||||||
s1++;
|
|
||||||
s2++;
|
|
||||||
}
|
|
||||||
return *s1 - *s2;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
const char* s1 = "helloworld";
|
|
||||||
const char* s2 = "world";
|
|
||||||
printf("%d\n", strcmp(s1, s2));
|
|
||||||
printf("%d\n", strcmp(s1 + 5, s2));
|
|
||||||
return 0;
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user