primary function call

This commit is contained in:
Yaossg 2024-11-20 23:44:42 +08:00
parent 653d42ccf3
commit b8108acb2e
2 changed files with 48 additions and 37 deletions

View File

@ -78,7 +78,8 @@ $ sh boot.sh
- 函数和数组不是类型系统的一部分。
- 可以认为数组的类型就是其元素对应的指针类型。
- 函数保存了其返回值的类型,建议仅用于直接调用,其它操作可视为 UB。
- 函数的参数类型和个数不会检查,返回值会参与类型检查。
- 函数名只能被用于调用,函数调用被视为初等表达式。
- 数组只支持一维数组,且数组的元素不能是指针类型。
- 全局变量不能是指针类型。
- 整数和字符字面量的类型是 `int`,字符串字面量的类型是 `char*`
@ -95,7 +96,8 @@ $ sh boot.sh
| 运算符 | 含义 | 结合性 |
| --------------------------------- | ----------------------------------------------- | -------- |
| `++` `--` `()` `[]` | 后缀自增自减 函数调用 数组下标 | 从左到右 |
| `()` | 初等表达式(字面量、标识符、函数调用、括号) | |
| `++` `--` `[]` | 后缀自增自减 数组下标 | 从左到右 |
| `++` `--` `+` `-` `*` `&` `!` `~` | 前缀自增自减 正负号 取地址 解引用 逻辑非 按位非 | 从右到左 |
| `*` `/` `%` | 乘除余 | 从左到右 |
| `+` `-` | 加减 | 从左到右 |
@ -106,7 +108,7 @@ $ sh boot.sh
| `^` | 按位异或 | 从左到右 |
| <code>&#124;</code> | 按位或 | 从左到右 |
| `&&` | 逻辑与 | 从左到右 |
| <code>&#124;&#124;</code> | 逻辑或 | 从左到右 |
| <code>&#124;&#124;</code> | 逻辑或 | 从左到右 |
| `=` | 赋值 | 从右到左 |
- 同级表达式的求值顺序与结合性一致。
@ -116,7 +118,6 @@ $ sh boot.sh
- 逻辑与和逻辑或支持短路求值。
- 表达式没有左值和右值之分。可以认为右值总是存在一个临时的变量中。
- 赋值不检查类型。强制类型转换可以用赋值给特定类型的变量实现。
- 函数的参数类型和个数不会检查,返回值会参与类型检查。
### 其它支持与不支持

76
boot.c
View File

@ -80,7 +80,6 @@ const int TYPE_INT_PTR = 17;
const int TYPE_CHAR_PTR = 18;
const int TYPE_PTR_MASK = 16;
const int TYPE_FUNC_MASK = 32;
const int TYPE_TOKEN_MASK = 128;
int parse_int(int ch) {
@ -436,6 +435,7 @@ int max_local_id = 2;
const int MARKER_TEMP = 0;
const int MARKER_SCALAR = 1;
const int MARKER_ARRAY = 2;
const int MARKER_FUNCTION = 3;
int local_marker[4096];
int global_marker[4096];
@ -552,7 +552,7 @@ void load(int rd, int id) {
const char* op = "lw"; // int
if (type == TYPE_CHAR) {
op = "lb";
} else if (type & TYPE_PTR_MASK || type & TYPE_FUNC_MASK) {
} else if (type & TYPE_PTR_MASK) {
op = "ld";
}
printf(" %s t%d, 0(t%d) # id: type %d\n", op, rd, rd, type);
@ -564,7 +564,7 @@ void store_t0(int id) {
const char* op = "sw"; // int
if (type == TYPE_CHAR) {
op = "sb";
} else if (type & TYPE_PTR_MASK || type & TYPE_FUNC_MASK) {
} else if (type & TYPE_PTR_MASK) {
op = "sd";
}
printf(" %s t0, 0(t1) # id: type %d\n", op, type);
@ -593,6 +593,10 @@ int lookup(int id) {
}
const char* name = id_table + id_lut[id];
if (global_marker[id]) {
if (global_marker[id] == MARKER_FUNCTION) {
eprintf("function name must not appear outside function call: %s\n", name);
exit(1);
}
printf(" la t0, %s # id: %d\n", name, id);
int reg = materialize_t0(global_type[id] | TYPE_PTR_MASK);
if (global_marker[id] == MARKER_SCALAR) {
@ -631,7 +635,7 @@ int asm_r(const char* op, int rs1) {
}
int asm_r_arith(const char* op, int rs1) {
if (local_type[rs1] & TYPE_PTR_MASK || local_type[rs1] & TYPE_FUNC_MASK) {
if (local_type[rs1] & TYPE_PTR_MASK) {
eprintf("pointer cannot be arithmetically operated by %s\n", op);
exit(1);
}
@ -654,8 +658,7 @@ int asm_rr(const char* op, int rs1, int rs2) {
}
int asm_rr_arith(const char* op, int rs1, int rs2) {
if (local_type[rs1] & TYPE_PTR_MASK || local_type[rs2] & TYPE_PTR_MASK
|| local_type[rs1] & TYPE_FUNC_MASK || local_type[rs2] & TYPE_FUNC_MASK) {
if (local_type[rs1] & TYPE_PTR_MASK || local_type[rs2] & TYPE_PTR_MASK) {
eprintf("pointer cannot be arithmetically operated by %s\n", op);
exit(1);
}
@ -778,29 +781,12 @@ int asm_sub(int lhs, int rhs) {
// parser
int parse_expr();
int parse_primary_expr() {
next_token();
if (token_type == TOKEN_EOF) {
exit(1);
} else if (token_type == TOKEN_NUMBER) {
printf(" li t0, %d\n", token_data);
return materialize_t0(TYPE_INT);
} else if (token_type == TOKEN_ID) {
return lookup(token_data);
} else if (token_type == TOKEN_STRING) {
printf(" la t0, .LC%d\n", token_data);
return materialize_t0(TYPE_CHAR_PTR);
} else if (token_type == TOKEN_PAREN_LEFT) {
int reg = parse_expr();
expect_token(TOKEN_PAREN_RIGHT);
return reg;
} else {
eprintf("unexpected token in primary expression: %d\n", token_type);
int parse_function_call(int id) {
const char* name = id_table + id_lut[id];
if (global_marker[id] != MARKER_FUNCTION) {
eprintf("not a function name: %s\n", name);
exit(1);
}
}
int parse_function_call(int func) {
int arg = 0;
int args[8];
while (1) {
@ -828,9 +814,8 @@ int parse_function_call(int func) {
load(0, args[i]);
printf(" mv a%d, t0\n", i);
}
load_address(0, func);
printf(" jalr t0\n");
int type = local_type[func];
printf(" call %s\n", name);
int type = global_type[id];
if (type != TYPE_VOID) {
printf(" mv t0, a0\n");
return materialize_t0(type);
@ -838,6 +823,33 @@ int parse_function_call(int func) {
return -1;
}
int parse_primary_expr() {
next_token();
if (token_type == TOKEN_EOF) {
exit(1);
} else if (token_type == TOKEN_NUMBER) {
printf(" li t0, %d\n", token_data);
return materialize_t0(TYPE_INT);
} else if (token_type == TOKEN_ID) {
next_token();
if (token_type == TOKEN_PAREN_LEFT) {
return parse_function_call(token_data);
}
unget_token();
return lookup(token_data);
} else if (token_type == TOKEN_STRING) {
printf(" la t0, .LC%d\n", token_data);
return materialize_t0(TYPE_CHAR_PTR);
} else if (token_type == TOKEN_PAREN_LEFT) {
int reg = parse_expr();
expect_token(TOKEN_PAREN_RIGHT);
return reg;
} else {
eprintf("unexpected token in primary expression: %d\n", token_type);
exit(1);
}
}
int parse_postfix_expr() {
int lhs = parse_primary_expr();
while (1) {
@ -862,8 +874,6 @@ int parse_postfix_expr() {
int rhs = parse_expr();
expect_token(TOKEN_BRACKET_RIGHT);
lhs = dereference(asm_add(lhs, rhs));
} else if (token_type == TOKEN_PAREN_LEFT) {
lhs = parse_function_call(lhs);
} else {
unget_token();
break;
@ -1440,7 +1450,7 @@ void parse_global_declaration() {
char* name = id_table + id_lut[id];
next_token();
if (token_type == TOKEN_PAREN_LEFT) {
declare_global(id, MARKER_SCALAR, type | TYPE_FUNC_MASK);
declare_global(id, MARKER_FUNCTION, type);
parse_function(name);
} else {
declare_global(id, MARKER_SCALAR, type);