From 05cce1404f0be28eb72fcacfe775bbb3768cd352 Mon Sep 17 00:00:00 2001 From: Lumynous Date: Sun, 18 May 2025 11:59:07 +0800 Subject: [PATCH 1/4] Allow parameter list to be a single "void" A parameter list is either a single keyword "void" or a comma-separated list of parameters according to the standard. Previously, only the latter is supported, and the former leads to unexpected token errors. --- src/parser.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/parser.c b/src/parser.c index 42b97087..3932be9e 100644 --- a/src/parser.c +++ b/src/parser.c @@ -728,6 +728,17 @@ void read_parameter_list_decl(func_t *func, int anon) { int vn = 0; lex_expect(T_open_bracket); + + char token[MAX_TYPE_LEN]; + if (lex_peek(T_identifier, token) && !strncmp(token, "void", 4)) { + next_token = lex_token(); + if (lex_accept(T_close_bracket)) + return; + func->param_defs[vn].type = TY_void; + read_inner_var_decl(&func->param_defs[vn++], anon, 1); + lex_accept(T_comma); + } + while (lex_peek(T_identifier, NULL) == 1) { read_full_var_decl(&func->param_defs[vn++], anon, 1); lex_accept(T_comma); From 059a771b3d9615ea7ff77135495225713429b039 Mon Sep 17 00:00:00 2001 From: Lumynous Date: Mon, 19 May 2025 21:34:56 +0800 Subject: [PATCH 2/4] Fix non-only or named "void" in parameter lists 'void' must be the only parameter and unnamed to indicate no parameters. Previously, the check for functions with first parameter of void pointer, etc. didn't consider the illegal forms, so those could pass compilation. --- src/parser.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/parser.c b/src/parser.c index 3932be9e..69e4909d 100644 --- a/src/parser.c +++ b/src/parser.c @@ -735,7 +735,11 @@ void read_parameter_list_decl(func_t *func, int anon) if (lex_accept(T_close_bracket)) return; func->param_defs[vn].type = TY_void; - read_inner_var_decl(&func->param_defs[vn++], anon, 1); + read_inner_var_decl(&func->param_defs[vn], anon, 1); + if (!func->param_defs[vn].is_ptr && !func->param_defs[vn].is_func && + !func->param_defs[vn].array_size) + error("'void' must be the only parameter and unnamed"); + vn++; lex_accept(T_comma); } From e539092e95178156df23b297d8483b61d93fab71 Mon Sep 17 00:00:00 2001 From: Lumynous Date: Mon, 19 May 2025 22:29:08 +0800 Subject: [PATCH 3/4] Add tests for void parameter --- tests/driver.sh | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/driver.sh b/tests/driver.sh index b01400bb..9b35a317 100755 --- a/tests/driver.sh +++ b/tests/driver.sh @@ -267,6 +267,12 @@ int main() { return 0; } EOF # functions +try_ 0 << EOF +int main(void) { + return 0; +} +EOF + try_ 55 << EOF int sum(int m, int n) { int acc; @@ -319,6 +325,14 @@ int main() { } EOF +try_compile_error << EOF +int main(void v) {} +EOF + +try_compile_error << EOF +int main(void, int i) {} +EOF + # Unreachable declaration should not cause prog seg-falut (prog should leave normally with exit code 0) try_ 0 << EOF int main() From fb762cd27857ad093d9a80f7dcbc505dfc37dc9f Mon Sep 17 00:00:00 2001 From: Lumynous Date: Tue, 20 May 2025 11:59:26 +0800 Subject: [PATCH 4/4] Use explicit "void" parameter instead Adds the keyword "void" to the parameter lists of functions. This helps validation of the implementation of "void" parameter lists in the bootstrapping process. Especially K&R style exists until C23, though it's not implemented in shecc now, shecc is first built by another compiler such as gcc and is written in C99 (as per Makefile). Suggested-by: Yu-En Hsiao --- lib/c.c | 8 ++++---- src/arm-codegen.c | 4 ++-- src/arm.c | 2 +- src/elf.c | 6 +++--- src/globals.c | 8 ++++---- src/lexer.c | 6 +++--- src/parser.c | 20 ++++++++++---------- src/peephole.c | 2 +- src/reg-alloc.c | 4 ++-- src/riscv-codegen.c | 4 ++-- src/riscv.c | 6 +++--- src/ssa.c | 34 +++++++++++++++++----------------- 12 files changed, 52 insertions(+), 52 deletions(-) diff --git a/lib/c.c b/lib/c.c index 7ec2dbb8..0c2ff7bb 100644 --- a/lib/c.c +++ b/lib/c.c @@ -45,7 +45,7 @@ typedef int FILE; -void abort(); +void abort(void); int strlen(char *str) { @@ -458,7 +458,7 @@ int snprintf(char *buffer, int n, char *str, ...) return fmtbuf.len; } -int __free_all(); +int __free_all(void); void exit(int exit_code) { @@ -466,7 +466,7 @@ void exit(int exit_code) __syscall(__syscall_exit, exit_code); } -void abort() +void abort(void) { printf("Abnormal program termination\n"); exit(-1); @@ -698,7 +698,7 @@ void __rfree(void *ptr, int size) __syscall(__syscall_munmap, ptr, size); } -int __free_all() +int __free_all(void) { if (!__freelist_head && !__alloc_head) return 0; diff --git a/src/arm-codegen.c b/src/arm-codegen.c index 1f624f2b..ded8b0cd 100644 --- a/src/arm-codegen.c +++ b/src/arm-codegen.c @@ -130,7 +130,7 @@ void update_elf_offset(ph2_ir_t *ph2_ir) } } -void cfg_flatten() +void cfg_flatten(void) { func_t *func = find_func("__syscall"); func->bbs->elf_offset = 44; /* offset of start + exit in codegen */ @@ -447,7 +447,7 @@ void emit_ph2_ir(ph2_ir_t *ph2_ir) } } -void code_generate() +void code_generate(void) { elf_data_start = elf_code_start + elf_offset; diff --git a/src/arm.c b/src/arm.c index 4271cbf6..3fae60b7 100644 --- a/src/arm.c +++ b/src/arm.c @@ -126,7 +126,7 @@ int arm_encode(arm_cond_t cond, int opcode, int rn, int rd, int op2) return (cond << 28) + (opcode << 20) + (rn << 16) + (rd << 12) + op2; } -int __svc() +int __svc(void) { return arm_encode(__AL, 240, 0, 0, 0); } diff --git a/src/elf.c b/src/elf.c index deed1d9d..d17c324e 100644 --- a/src/elf.c +++ b/src/elf.c @@ -47,7 +47,7 @@ void elf_write_blk(strbuf_t *elf_array, void *blk, int sz) strbuf_putc(elf_array, ptr[i]); } -void elf_generate_header() +void elf_generate_header(void) { elf32_hdr_t hdr; /* @@ -173,7 +173,7 @@ void elf_generate_header() elf_write_blk(elf_header, &phdr, sizeof(elf32_phdr_t)); } -void elf_generate_sections() +void elf_generate_sections(void) { /* symtab section */ for (int b = 0; b < elf_symtab->size; b++) @@ -310,7 +310,7 @@ void elf_generate_sections() elf_write_blk(elf_section, &shdr, sizeof(elf32_shdr_t)); } -void elf_align() +void elf_align(void) { while (elf_data->size & 3) elf_write_byte(elf_data, 0); diff --git a/src/globals.c b/src/globals.c index b861103e..7e200bfa 100644 --- a/src/globals.c +++ b/src/globals.c @@ -600,7 +600,7 @@ int find_macro_param_src_idx(char *name, block_t *parent) return 0; } -type_t *add_type() +type_t *add_type(void) { return &TYPES[types_idx++]; } @@ -970,7 +970,7 @@ void strbuf_free(strbuf_t *src) /* This routine is required because the global variable initializations are * not supported now. */ -void global_init() +void global_init(void) { elf_code_start = ELF_START + elf_header_len; @@ -994,7 +994,7 @@ void global_init() elf_section = strbuf_create(MAX_SECTION); } -void global_release() +void global_release(void) { free(MACROS); free(TYPES); @@ -1286,7 +1286,7 @@ void dump_bb_insn_by_dom(func_t *func, basic_block_t *bb, bool *at_func_start) } } -void dump_insn() +void dump_insn(void) { printf("====\n"); diff --git a/src/lexer.c b/src/lexer.c index 8064d1e8..e2854f34 100644 --- a/src/lexer.c +++ b/src/lexer.c @@ -63,7 +63,7 @@ bool is_numeric(char buffer[]) return true; } -void skip_whitespace() +void skip_whitespace(void) { while (true) { if (is_linebreak(next_char)) { @@ -533,13 +533,13 @@ token_t lex_token_internal(bool aliasing) /* Lex next token and returns its token type. To disable aliasing on next * token, use 'lex_token_internal'. */ -token_t lex_token() +token_t lex_token(void) { return lex_token_internal(true); } /* Skip the content. We only need the index where the macro body begins. */ -void skip_macro_body() +void skip_macro_body(void) { while (!is_newline(next_char)) next_token = lex_token(); diff --git a/src/parser.c b/src/parser.c index 69e4909d..47314578 100644 --- a/src/parser.c +++ b/src/parser.c @@ -108,7 +108,7 @@ void opstack_push(var_t *var) operand_stack[operand_stack_idx++] = var; } -var_t *opstack_pop() +var_t *opstack_pop(void) { return operand_stack[--operand_stack_idx]; } @@ -179,7 +179,7 @@ int get_unary_operator_prio(opcode_t op) } } -opcode_t get_operator() +opcode_t get_operator(void) { opcode_t op = OP_generic; if (lex_accept(T_plus)) @@ -317,7 +317,7 @@ int read_numeric_constant(char buffer[]) return value; } -int read_constant_expr_operand() +int read_constant_expr_operand(void) { char buffer[MAX_ID_LEN]; int value; @@ -449,7 +449,7 @@ int read_constant_infix_expr(int precedence) return lhs; } -int read_constant_expr() +int read_constant_expr(void) { return read_constant_infix_expr(0); } @@ -457,7 +457,7 @@ int read_constant_expr() /* Skips lines where preprocessor match is false, this will stop once next * token is either 'T_cppd_elif', 'T_cppd_else' or 'cppd_endif'. */ -void cppd_control_flow_skip_lines() +void cppd_control_flow_skip_lines(void) { while (!lex_peek(T_cppd_elif, NULL) && !lex_peek(T_cppd_else, NULL) && !lex_peek(T_cppd_endif, NULL)) { @@ -472,7 +472,7 @@ void check_def(char *alias, bool expected) preproc_match = true; } -void read_defined_macro() +void read_defined_macro(void) { char lookup_alias[MAX_TOKEN_LEN]; @@ -487,7 +487,7 @@ void read_defined_macro() /* read preprocessor directive at each potential positions: e.g., * global statement / body statement */ -bool read_preproc_directive() +bool read_preproc_directive(void) { char token[MAX_ID_LEN]; @@ -1969,7 +1969,7 @@ bool read_body_assignment(char *token, return false; } -int read_primary_constant() +int read_primary_constant(void) { /* return signed constant */ int isneg = 0, res; @@ -2834,7 +2834,7 @@ void read_global_decl(block_t *block) error("Syntax error in global declaration"); } -void read_global_statement() +void read_global_statement(void) { char token[MAX_ID_LEN]; block_t *block = GLOBAL_BLOCK; /* global block */ @@ -2953,7 +2953,7 @@ void read_global_statement() error("Syntax error in global statement"); } -void parse_internal() +void parse_internal(void) { /* set starting point of global stack manually */ GLOBAL_FUNC = add_func("", true); diff --git a/src/peephole.c b/src/peephole.c index 80a3074b..aca6ca7a 100644 --- a/src/peephole.c +++ b/src/peephole.c @@ -146,7 +146,7 @@ bool insn_fusion(ph2_ir_t *ph2_ir) return false; } -void peephole() +void peephole(void) { for (func_t *func = FUNC_LIST.head; func; func = func->next) { for (basic_block_t *bb = func->bbs; bb; bb = bb->rpo_next) { diff --git a/src/reg-alloc.c b/src/reg-alloc.c index d130a21b..f60c5c00 100644 --- a/src/reg-alloc.c +++ b/src/reg-alloc.c @@ -240,7 +240,7 @@ void extend_liveness(basic_block_t *bb, insn_t *insn, var_t *var, int offset) var->consumed = insn->idx + offset; } -void reg_alloc() +void reg_alloc(void) { /* TODO: .bss and .data section */ for (insn_t *global_insn = GLOBAL_FUNC->bbs->insn_list.head; global_insn; @@ -649,7 +649,7 @@ void reg_alloc() } } -void dump_ph2_ir() +void dump_ph2_ir(void) { for (int i = 0; i < ph2_ir_idx; i++) { ph2_ir_t *ph2_ir = PH2_IR_FLATTEN[i]; diff --git a/src/riscv-codegen.c b/src/riscv-codegen.c index db5f1824..27df288b 100644 --- a/src/riscv-codegen.c +++ b/src/riscv-codegen.c @@ -104,7 +104,7 @@ void update_elf_offset(ph2_ir_t *ph2_ir) } } -void cfg_flatten() +void cfg_flatten(void) { func_t *func = find_func("__syscall"); func->bbs->elf_offset = 48; /* offset of start + exit in codegen */ @@ -426,7 +426,7 @@ void emit_ph2_ir(ph2_ir_t *ph2_ir) } } -void code_generate() +void code_generate(void) { elf_data_start = elf_code_start + elf_offset; diff --git a/src/riscv.c b/src/riscv.c index da1b861f..3ea8b57e 100644 --- a/src/riscv.c +++ b/src/riscv.c @@ -372,17 +372,17 @@ int __auipc(rv_reg rd, int imm) return rv_encode_U(rv_auipc, rd, imm); } -int __ecall() +int __ecall(void) { return rv_encode_I(rv_ecall, __zero, __zero, 0); } -int __ebreak() +int __ebreak(void) { return rv_encode_I(rv_ebreak, __zero, __zero, 1); } -int __nop() +int __nop(void) { return __addi(__zero, __zero, 0); } diff --git a/src/ssa.c b/src/ssa.c index 62d97a29..cdbee2d8 100644 --- a/src/ssa.c +++ b/src/ssa.c @@ -102,7 +102,7 @@ void bb_build_rpo(func_t *func, basic_block_t *bb) prev->rpo_next = bb; } -void build_rpo() +void build_rpo(void) { bb_traversal_args_t *args = calloc(1, sizeof(bb_traversal_args_t)); for (func_t *func = FUNC_LIST.head; func; func = func->next) { @@ -146,7 +146,7 @@ basic_block_t *intersect(basic_block_t *i, basic_block_t *j) * Cooper, Keith D.; Harvey, Timothy J.; Kennedy, Ken (2001). * "A Simple, Fast Dominance Algorithm" */ -void build_idom() +void build_idom(void) { for (func_t *func = FUNC_LIST.head; func; func = func->next) { bool changed; @@ -219,7 +219,7 @@ void bb_build_dom(func_t *func, basic_block_t *bb) } } -void build_dom() +void build_dom(void) { bb_traversal_args_t *args = calloc(1, sizeof(bb_traversal_args_t)); for (func_t *func = FUNC_LIST.head; func; func = func->next) { @@ -254,7 +254,7 @@ void bb_build_df(func_t *func, basic_block_t *bb) } } -void build_df() +void build_df(void) { bb_traversal_args_t *args = calloc(1, sizeof(bb_traversal_args_t)); for (func_t *func = FUNC_LIST.head; func; func = func->next) { @@ -279,7 +279,7 @@ basic_block_t *reverse_intersect(basic_block_t *i, basic_block_t *j) return i; } -void build_r_idom() +void build_r_idom(void) { for (func_t *func = FUNC_LIST.head; func; func = func->next) { bool changed; @@ -349,7 +349,7 @@ void bb_build_rdom(func_t *func, basic_block_t *bb) } } -void build_rdom() +void build_rdom(void) { bb_traversal_args_t *args = calloc(1, sizeof(bb_traversal_args_t)); for (func_t *func = FUNC_LIST.head; func; func = func->next) { @@ -394,7 +394,7 @@ void bb_build_rdf(func_t *func, basic_block_t *bb) } } -void build_rdf() +void build_rdf(void) { bb_traversal_args_t *args = calloc(1, sizeof(bb_traversal_args_t)); for (func_t *func = FUNC_LIST.head; func; func = func->next) { @@ -442,7 +442,7 @@ void use_chain_delete(use_chain_t *u, var_t *var) free(u); } -void use_chain_build() +void use_chain_build(void) { for (func_t *func = FUNC_LIST.head; func; func = func->next) { for (basic_block_t *bb = func->bbs; bb; bb = bb->rpo_next) { @@ -547,7 +547,7 @@ void bb_solve_globals(func_t *func, basic_block_t *bb) } } -void solve_globals() +void solve_globals(void) { bb_traversal_args_t *args = calloc(1, sizeof(bb_traversal_args_t)); for (func_t *func = FUNC_LIST.head; func; func = func->next) { @@ -610,7 +610,7 @@ bool insert_phi_insn(basic_block_t *bb, var_t *var) return true; } -void solve_phi_insertion() +void solve_phi_insertion(void) { for (func_t *func = FUNC_LIST.head; func; func = func->next) { for (symbol_t *sym = func->global_sym_list.head; sym; sym = sym->next) { @@ -794,7 +794,7 @@ void bb_solve_phi_params(basic_block_t *bb) } } -void solve_phi_params() +void solve_phi_params(void) { for (func_t *func = FUNC_LIST.head; func; func = func->next) { for (int i = 0; i < func->num_params; i++) { @@ -866,7 +866,7 @@ void bb_unwind_phi(func_t *func, basic_block_t *bb) insn->prev = NULL; } -void unwind_phi() +void unwind_phi(void) { bb_traversal_args_t *args = calloc(1, sizeof(bb_traversal_args_t)); for (func_t *func = FUNC_LIST.head; func; func = func->next) { @@ -1212,7 +1212,7 @@ void dump_dom(char name[]) } #endif -void ssa_build() +void ssa_build(void) { build_rpo(); build_idom(); @@ -1499,7 +1499,7 @@ void dce_insn(basic_block_t *bb) } } -void dce_sweep() +void dce_sweep(void) { for (func_t *func = FUNC_LIST.head; func; func = func->next) { for (basic_block_t *bb = func->bbs; bb; bb = bb->rpo_next) { @@ -1540,7 +1540,7 @@ void dce_sweep() void build_reversed_rpo(); -void optimize() +void optimize(void) { /* build rdf information for DCE */ build_reversed_rpo(); @@ -1607,7 +1607,7 @@ void bb_build_reversed_rpo(func_t *func, basic_block_t *bb) prev->rpo_r_next = bb; } -void build_reversed_rpo() +void build_reversed_rpo(void) { bb_traversal_args_t *args = calloc(1, sizeof(bb_traversal_args_t)); for (func_t *func = FUNC_LIST.head; func; func = func->next) { @@ -1757,7 +1757,7 @@ bool recompute_live_out(basic_block_t *bb) return false; } -void liveness_analysis() +void liveness_analysis(void) { bb_traversal_args_t *args = calloc(1, sizeof(bb_traversal_args_t)); for (func_t *func = FUNC_LIST.head; func; func = func->next) {