From 65ca335e8774eec1d4d7e8e957fe148aaede109a Mon Sep 17 00:00:00 2001 From: Jim Huang Date: Sun, 3 Aug 2025 07:01:17 +0800 Subject: [PATCH] Support multiple declarators in struct member decl This commit allows struct members to be declared with multiple variables on the same line, matching standard C syntax. For example: struct node { struct node *next, *prev; // Now supported int value; }; The fix handles comma-separated declarators by parsing additional variables after the first one, inheriting the base type while parsing pointer levels and array dimensions independently for each declarator. --- lib/c.c | 3 +-- src/defs.h | 24 ++++++++--------------- src/parser.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++ tests/driver.sh | 14 ++++++++++++++ 4 files changed, 74 insertions(+), 18 deletions(-) diff --git a/lib/c.c b/lib/c.c index a5983962..f4db49a3 100644 --- a/lib/c.c +++ b/lib/c.c @@ -576,8 +576,7 @@ int fputc(int c, FILE *stream) #define IS_CHUNK_GET_FREED(size) (size & CHUNK_SIZE_FREED_MASK) typedef struct chunk { - struct chunk *next; - struct chunk *prev; + struct chunk *next, *prev; int size; } chunk_t; diff --git a/src/defs.h b/src/defs.h index 96887397..63da2e01 100644 --- a/src/defs.h +++ b/src/defs.h @@ -266,8 +266,7 @@ typedef struct { typedef struct ref_block ref_block_t; struct ref_block_list { - ref_block_t *head; - ref_block_t *tail; + ref_block_t *head, *tail; }; typedef struct ref_block_list ref_block_list_t; @@ -276,8 +275,7 @@ typedef struct insn insn_t; typedef struct use_chain_node { insn_t *insn; - struct use_chain_node *next; - struct use_chain_node *prev; + struct use_chain_node *next, *prev; } use_chain_t; typedef struct var var_t; @@ -306,8 +304,7 @@ struct var { int subscripts_idx; rename_t rename; ref_block_list_t ref_block_list; /* blocks which kill variable */ - use_chain_t *users_head; - use_chain_t *users_tail; + use_chain_t *users_head, *users_tail; struct insn *last_assign; int consumed; bool is_ternary_ret; @@ -408,8 +405,7 @@ struct phi_operand { typedef struct phi_operand phi_operand_t; struct insn { - struct insn *next; - struct insn *prev; + struct insn *next, *prev; int idx; opcode_t opcode; var_t *rd; @@ -423,13 +419,11 @@ struct insn { }; typedef struct { - insn_t *head; - insn_t *tail; + insn_t *head, *tail; } insn_list_t; typedef struct { - ph2_ir_t *head; - ph2_ir_t *tail; + ph2_ir_t *head, *tail; } ph2_ir_list_t; typedef enum { NEXT, ELSE, THEN } bb_connection_type_t; @@ -448,8 +442,7 @@ struct symbol { typedef struct symbol symbol_t; typedef struct { - symbol_t *head; - symbol_t *tail; + symbol_t *head, *tail; } symbol_list_t; struct basic_block { @@ -519,8 +512,7 @@ struct func { }; typedef struct { - func_t *head; - func_t *tail; + func_t *head, *tail; } func_list_t; typedef struct { diff --git a/src/parser.c b/src/parser.c index be032d18..8a41aeb7 100644 --- a/src/parser.c +++ b/src/parser.c @@ -2870,6 +2870,31 @@ void read_global_statement(void) read_full_var_decl(v, 0, 1); v->offset = size; size += size_var(v); + + /* Handle multiple variable declarations with same base type */ + while (lex_accept(T_comma)) { + if (i >= MAX_FIELDS) + error("Too many struct fields"); + + var_t *nv = &type->fields[i++]; + nv->type = v->type; + nv->var_name[0] = '\0'; + nv->is_ptr = 0; + nv->is_func = false; + nv->is_global = false; + nv->array_size = 0; + nv->offset = 0; + nv->init_val = 0; + nv->liveness = 0; + nv->in_loop = 0; + nv->base = NULL; + nv->subscript = 0; + nv->subscripts_idx = 0; + read_inner_var_decl(nv, 0, 1); + nv->offset = size; + size += size_var(nv); + } + lex_expect(T_semicolon); } while (!lex_accept(T_close_curly)); @@ -2922,6 +2947,32 @@ void read_global_statement(void) read_full_var_decl(v, 0, 1); v->offset = size; size += size_var(v); + + /* Handle multiple variable declarations with same base type + */ + while (lex_accept(T_comma)) { + if (i >= MAX_FIELDS) + error("Too many struct fields"); + + var_t *nv = &type->fields[i++]; + nv->type = v->type; + nv->var_name[0] = '\0'; + nv->is_ptr = 0; + nv->is_func = false; + nv->is_global = false; + nv->array_size = 0; + nv->offset = 0; + nv->init_val = 0; + nv->liveness = 0; + nv->in_loop = 0; + nv->base = NULL; + nv->subscript = 0; + nv->subscripts_idx = 0; + read_inner_var_decl(nv, 0, 1); + nv->offset = size; + size += size_var(nv); + } + lex_expect(T_semicolon); } while (!lex_accept(T_close_curly)); } diff --git a/tests/driver.sh b/tests/driver.sh index fc1bbfed..650b962a 100755 --- a/tests/driver.sh +++ b/tests/driver.sh @@ -423,6 +423,20 @@ int main() { } EOF +# struct with multiple pointer declarations in same line +try_ 42 << EOF +typedef struct chunk { + struct chunk *next, *prev; + int size; +} chunk_t; + +int main() { + chunk_t c; + c.size = 42; + return c.size; +} +EOF + # arrays try_ 12 << EOF int nth_of(int *a, int i) {