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);