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