mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-04-05 17:01:11 +00:00
[qfcc] Implement designated initializers
Conforms fairly closely to GCC's C implementation.
This commit is contained in:
parent
04e26a7b9f
commit
5d9823af30
6 changed files with 201 additions and 63 deletions
|
@ -74,12 +74,18 @@ typedef struct {
|
|||
ex_label_t *label;
|
||||
} ex_labelref_t;
|
||||
|
||||
typedef struct designator_s {
|
||||
struct designator_s *next;
|
||||
struct expr_s *field;
|
||||
struct expr_s *index;
|
||||
} designator_t;
|
||||
|
||||
typedef struct element_s {
|
||||
struct element_s *next; ///< next in chain
|
||||
int offset;
|
||||
struct type_s *type;
|
||||
struct expr_s *expr; ///< initializer expression
|
||||
struct symbol_s *symbol; ///< for labeled initializers
|
||||
designator_t *designator; ///< for labeled initializers
|
||||
} element_t;
|
||||
|
||||
typedef struct element_chain_s {
|
||||
|
@ -448,7 +454,8 @@ expr_t *new_block_expr (void);
|
|||
*/
|
||||
expr_t *build_block_expr (expr_t *expr_list);
|
||||
|
||||
element_t *new_element (expr_t *expr, struct symbol_s *symbol);
|
||||
designator_t *new_designator (expr_t *field, expr_t *index);
|
||||
element_t *new_element (expr_t *expr, designator_t *designator);
|
||||
expr_t *new_compound_init (void);
|
||||
expr_t *append_element (expr_t *compound, element_t *element);
|
||||
expr_t *initialized_temp_expr (const struct type_s *type, expr_t *compound);
|
||||
|
|
|
@ -72,6 +72,7 @@ typedef struct symbol_s {
|
|||
sy_type_e sy_type; ///< symbol type
|
||||
struct type_s *type; ///< type of object to which symbol refers
|
||||
struct param_s *params; ///< the parameters if a function
|
||||
unsigned no_auto_init; ///< skip for non-designated initializers
|
||||
union {
|
||||
int offset; ///< sy_var (in a struct/union)
|
||||
struct def_s *def; ///< sy_var
|
||||
|
|
|
@ -370,7 +370,7 @@ copy_expr (expr_t *e)
|
|||
n = new_expr ();
|
||||
*n = *e;
|
||||
for (element_t *i = e->e.compound.head; i; i = i->next) {
|
||||
append_element (n, new_element (i->expr, i->symbol));
|
||||
append_element (n, new_element (i->expr, i->designator));
|
||||
}
|
||||
return n;
|
||||
case ex_memset:
|
||||
|
|
|
@ -53,14 +53,31 @@
|
|||
#include "tools/qfcc/include/type.h"
|
||||
|
||||
ALLOC_STATE (element_t, elements);
|
||||
ALLOC_STATE (designator_t, designators);
|
||||
|
||||
designator_t *
|
||||
new_designator (expr_t *field, expr_t *index)
|
||||
{
|
||||
if ((!field && !index) || (field && index)) {
|
||||
internal_error (0, "exactly one of field or index is required");
|
||||
}
|
||||
if (field && field->type != ex_symbol) {
|
||||
internal_error (field, "invalid field designator");
|
||||
}
|
||||
designator_t *des;
|
||||
ALLOC (256, designator_t, designators, des);
|
||||
des->field = field;
|
||||
des->index = index;
|
||||
return des;
|
||||
}
|
||||
|
||||
element_t *
|
||||
new_element (expr_t *expr, symbol_t *symbol)
|
||||
new_element (expr_t *expr, designator_t *designator)
|
||||
{
|
||||
element_t *element;
|
||||
ALLOC (256, element_t, elements, element);
|
||||
element->expr = expr;
|
||||
element->symbol = symbol;
|
||||
element->designator = designator;
|
||||
return element;
|
||||
}
|
||||
|
||||
|
@ -83,29 +100,99 @@ new_compound_init (void)
|
|||
return c;
|
||||
}
|
||||
|
||||
static element_t *
|
||||
build_array_element_chain(element_chain_t *element_chain,
|
||||
int array_size, type_t *array_type,
|
||||
element_t *ele,
|
||||
int base_offset)
|
||||
static symbol_t *
|
||||
designator_field (const designator_t *des, const type_t *type)
|
||||
{
|
||||
for (int i = 0; i < array_size; i++) {
|
||||
int offset = base_offset + i * type_size (array_type);
|
||||
if (ele && ele->expr && ele->expr->type == ex_compound) {
|
||||
build_element_chain (element_chain, array_type,
|
||||
ele->expr, offset);
|
||||
} else {
|
||||
element_t *element = new_element (0, 0);
|
||||
element->type = array_type;
|
||||
element->offset = offset;
|
||||
element->expr = ele ? ele->expr : 0; // null -> nil
|
||||
append_init_element (element_chain, element);
|
||||
}
|
||||
if (ele) {
|
||||
ele = ele->next;
|
||||
}
|
||||
if (des->index) {
|
||||
error (des->index, "designator index in non-array");
|
||||
return 0;
|
||||
}
|
||||
return ele;
|
||||
symtab_t *symtab = type->t.symtab;
|
||||
symbol_t *sym = des->field->e.symbol;
|
||||
symbol_t *field = symtab_lookup (symtab, sym->name);;
|
||||
if (!field) {
|
||||
const char *name = type->name;
|
||||
if (!strncmp (name, "tag ", 4)) {
|
||||
name += 4;
|
||||
}
|
||||
error (des->field, "'%s' has no member named '%s'", name, sym->name);
|
||||
return 0;
|
||||
}
|
||||
return field;
|
||||
}
|
||||
|
||||
static int
|
||||
designator_index (const designator_t *des, int ele_size, int array_size)
|
||||
{
|
||||
if (des->field) {
|
||||
error (des->field, "field designator in array initializer");
|
||||
return -1;
|
||||
} else if (!is_constant (des->index)) {
|
||||
error (des->index, "non-constant designator index");
|
||||
return -1;
|
||||
} else if (!is_integral (get_type (des->index))) {
|
||||
error (des->index, "invalid designator index type");
|
||||
return -1;
|
||||
}
|
||||
int index = expr_integral (des->index);
|
||||
if (index <= 0 || index >= array_size) {
|
||||
error (des->index, "designator index out of bounds");
|
||||
return -1;
|
||||
}
|
||||
return index * ele_size;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
type_t *type;
|
||||
symbol_t *field;
|
||||
int offset;
|
||||
} initstate_t;
|
||||
|
||||
static initstate_t
|
||||
get_designated_offset (const type_t *type, const designator_t *des)
|
||||
{
|
||||
int offset = -1;
|
||||
type_t *ele_type = 0;
|
||||
symbol_t *field = 0;
|
||||
|
||||
if (is_struct (type) || is_union (type)) {
|
||||
field = designator_field (des, type);
|
||||
offset = field->s.offset;
|
||||
ele_type = field->type;
|
||||
} else if (is_array (type)) {
|
||||
int array_size = type->t.array.size;
|
||||
ele_type = type->t.array.type;
|
||||
offset = designator_index (des, type_size (ele_type), array_size);
|
||||
} else if (is_nonscalar (type)) {
|
||||
ele_type = ev_types[type->type];
|
||||
if (type->t.symtab && des->field) {
|
||||
field = designator_field (des, type);
|
||||
offset = field->s.offset;
|
||||
} else {
|
||||
int vec_width = type_width (type);
|
||||
offset = designator_index (des, type_size (ele_type), vec_width);
|
||||
}
|
||||
} else {
|
||||
error (0, "invalid initializer");
|
||||
}
|
||||
if (ele_type && des->next) {
|
||||
__auto_type state = get_designated_offset (ele_type, des->next);
|
||||
ele_type = state.type;
|
||||
offset += state.offset;
|
||||
}
|
||||
return (initstate_t) { .type = ele_type, .field = field, .offset = offset};
|
||||
}
|
||||
|
||||
static int
|
||||
skip_field (symbol_t *field)
|
||||
{
|
||||
if (field->sy_type != sy_var) {
|
||||
return 1;
|
||||
}
|
||||
if (field->no_auto_init) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -116,50 +203,64 @@ build_element_chain (element_chain_t *element_chain, const type_t *type,
|
|||
|
||||
type = unalias_type (type);
|
||||
|
||||
if (is_array (type)) {
|
||||
type_t *array_type = type->t.array.type;
|
||||
int array_size = type->t.array.size;
|
||||
ele = build_array_element_chain (element_chain, array_size, array_type,
|
||||
ele, base_offset);
|
||||
} else if (is_struct (type) || (is_nonscalar (type) && type->t.symtab)) {
|
||||
symtab_t *symtab = type->t.symtab;
|
||||
symbol_t *field;
|
||||
initstate_t state = {};
|
||||
if (is_struct (type) || is_union (type)
|
||||
|| (is_nonscalar (type) && type->t.symtab)) {
|
||||
state.field = type->t.symtab->symbols;
|
||||
while (skip_field (state.field)) {
|
||||
state.field = state.field->next;
|
||||
}
|
||||
state.type = state.field->type;
|
||||
state.offset = state.field->s.offset;
|
||||
} else if (is_array (type)) {
|
||||
state.type = type->t.array.type;
|
||||
} else {
|
||||
internal_error (eles, "invalid initialization");
|
||||
}
|
||||
while (ele) {
|
||||
if (ele->designator) {
|
||||
state = get_designated_offset (type, ele->designator);
|
||||
}
|
||||
if (!state.type) {
|
||||
break;
|
||||
}
|
||||
|
||||
for (field = symtab->symbols; field; field = field->next) {
|
||||
int offset = base_offset + field->s.offset;
|
||||
if (field->sy_type != sy_var
|
||||
|| field->visibility == vis_anonymous) {
|
||||
continue;
|
||||
if (state.offset >= type_size (type)) {
|
||||
if (options.warnings.initializer) {
|
||||
warning (eles, "excessive elements in initializer");
|
||||
}
|
||||
if (ele && ele->expr && ele->expr->type == ex_compound) {
|
||||
build_element_chain (element_chain, field->type,
|
||||
ele->expr, offset);
|
||||
} else {
|
||||
element_t *element = new_element (0, 0);
|
||||
element->type = field->type;
|
||||
element->offset = offset;
|
||||
element->expr = ele ? ele->expr : 0; // null -> nil
|
||||
append_init_element (element_chain, element);
|
||||
break;
|
||||
}
|
||||
|
||||
if (ele->expr && ele->expr->type == ex_compound) {
|
||||
build_element_chain (element_chain, state.type, ele->expr,
|
||||
state.offset);
|
||||
} else {
|
||||
element_t *element = new_element (0, 0);
|
||||
element->type = state.type;
|
||||
element->offset = base_offset + state.offset;
|
||||
element->expr = ele->expr; // null -> nil
|
||||
append_init_element (element_chain, element);
|
||||
}
|
||||
|
||||
state.offset += type_size (state.type);
|
||||
if (state.field) {
|
||||
state.field = state.field->next;
|
||||
while (state.field && skip_field (state.field)) {
|
||||
state.field = state.field->next;
|
||||
}
|
||||
if (ele) {
|
||||
ele = ele->next;
|
||||
if (state.field) {
|
||||
state.type = state.field->type;
|
||||
state.offset = state.field->s.offset;
|
||||
}
|
||||
}
|
||||
} else if (is_nonscalar (type)) {
|
||||
// vector type with unnamed components
|
||||
int vec_width = type_width (type);
|
||||
type_t *vec_type = ev_types[type->type];
|
||||
ele = build_array_element_chain (element_chain, vec_width, vec_type,
|
||||
ele, base_offset);
|
||||
} else {
|
||||
error (eles, "invalid initializer");
|
||||
}
|
||||
if (ele && ele->next && options.warnings.initializer) {
|
||||
warning (eles, "excessive elements in initializer");
|
||||
|
||||
ele = ele->next;
|
||||
}
|
||||
}
|
||||
|
||||
void free_element_chain (element_chain_t *element_chain)
|
||||
void
|
||||
free_element_chain (element_chain_t *element_chain)
|
||||
{
|
||||
*element_chain->tail = elements_freelist;
|
||||
elements_freelist = element_chain->head;
|
||||
|
@ -200,6 +301,8 @@ assign_elements (expr_t *local_expr, expr_t *init,
|
|||
|
||||
expr_t *c;
|
||||
|
||||
if (type_size (type) == 0)
|
||||
internal_error (init, "wtf");
|
||||
if (element->expr) {
|
||||
c = constant_expr (element->expr);
|
||||
} else {
|
||||
|
|
|
@ -114,6 +114,7 @@ int yylex (void);
|
|||
struct symbol_s *symbol;
|
||||
struct symtab_s *symtab;
|
||||
struct attribute_s *attribute;
|
||||
struct designator_s *designator;
|
||||
}
|
||||
|
||||
// these tokens are common between qc and qp
|
||||
|
@ -194,6 +195,7 @@ int yylex (void);
|
|||
|
||||
%type <expr> opt_init_semi opt_expr comma_expr expr
|
||||
%type <expr> compound_init element_list
|
||||
%type <designator> designator designator_spec
|
||||
%type <element> element
|
||||
%type <expr> ose optional_state_expr texpr vector_expr
|
||||
%type <expr> statement statements compound_statement
|
||||
|
@ -1146,6 +1148,9 @@ struct_defs
|
|||
component_decl_list
|
||||
: component_decl_list2
|
||||
| component_decl_list2 component_decl
|
||||
{
|
||||
warning (0, "no semicolon at end of struct or union");
|
||||
}
|
||||
;
|
||||
|
||||
component_decl_list2
|
||||
|
@ -1405,10 +1410,31 @@ element_list
|
|||
;
|
||||
|
||||
element
|
||||
: compound_init { $$ = new_element ($1, 0); }
|
||||
: designator '=' compound_init { $$ = new_element ($3, $1); }
|
||||
| designator '=' expr { $$ = new_element ($3, $1); }
|
||||
| compound_init { $$ = new_element ($1, 0); }
|
||||
| expr { $$ = new_element ($1, 0); }
|
||||
;
|
||||
|
||||
designator
|
||||
: designator_spec
|
||||
| designator designator_spec
|
||||
{
|
||||
designator_t *des = $1;
|
||||
while (des->next) {
|
||||
des = des->next;
|
||||
}
|
||||
des->next = $2;
|
||||
$$ = $1;
|
||||
}
|
||||
;
|
||||
|
||||
designator_spec
|
||||
: '.' ident_expr { $$ = new_designator ($2, 0); }
|
||||
| '.' NAME { $$ = new_designator (new_symbol_expr ($2), 0); }
|
||||
| '[' expr ']' { $$ = new_designator (0, $2); }
|
||||
;
|
||||
|
||||
optional_comma
|
||||
: /* empty */
|
||||
| ','
|
||||
|
|
|
@ -202,6 +202,7 @@ build_struct (int su, symbol_t *tag, symtab_t *symtab, type_t *type, int base)
|
|||
s = s->next;
|
||||
s->s.offset += offset;
|
||||
s->table = symtab;
|
||||
s->no_auto_init = 1;
|
||||
Hash_Add (symtab->tab, s);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue