mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-01-19 07:20:50 +00:00
[qfcc] Create a compound initializer expression type
This fixes the problem of using the return value of a function as an element in a compound initializer. The cause of the problem is that compound initializers were represented by block expressions, but function calls are contained within block expressions, so def initialization saw the block expression and thought it was a nested compound initializer. Technically, it was a bug in the nested element parsing code in that it wasn't checking the result value of the block expression, but using a whole new expression type makes things much cleaner and the work done paves the way for labeled initializers and compound assignments.
This commit is contained in:
parent
f10f9e157d
commit
d1e83b9d48
5 changed files with 109 additions and 44 deletions
|
@ -55,6 +55,7 @@ typedef enum {
|
||||||
|
|
||||||
ex_nil, ///< umm, nil, null. nuff said (0 of any type)
|
ex_nil, ///< umm, nil, null. nuff said (0 of any type)
|
||||||
ex_value, ///< constant value (::ex_value_t)
|
ex_value, ///< constant value (::ex_value_t)
|
||||||
|
ex_compound, ///< compound initializer
|
||||||
} expr_type;
|
} expr_type;
|
||||||
|
|
||||||
/** Binary and unary expressions.
|
/** Binary and unary expressions.
|
||||||
|
@ -84,6 +85,17 @@ typedef struct {
|
||||||
ex_label_t *label;
|
ex_label_t *label;
|
||||||
} ex_labelref_t;
|
} ex_labelref_t;
|
||||||
|
|
||||||
|
typedef struct ex_initele_s {
|
||||||
|
struct ex_initele_s *next; ///< next in chain
|
||||||
|
struct symbol_s *symbol; ///< for labeled initializers
|
||||||
|
struct expr_s *expr; ///< initializer expression
|
||||||
|
} ex_initele_t;
|
||||||
|
|
||||||
|
typedef struct ex_cmpinit_s {
|
||||||
|
ex_initele_t *head;
|
||||||
|
ex_initele_t **tail;
|
||||||
|
} ex_cmpinit_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
struct expr_s *head; ///< the first expression in the block
|
struct expr_s *head; ///< the first expression in the block
|
||||||
struct expr_s **tail; ///< last expression in the block, for appending
|
struct expr_s **tail; ///< last expression in the block, for appending
|
||||||
|
@ -210,6 +222,7 @@ typedef struct expr_s {
|
||||||
ex_temp_t temp; ///< temporary variable expression
|
ex_temp_t temp; ///< temporary variable expression
|
||||||
ex_vector_t vector; ///< vector expression list
|
ex_vector_t vector; ///< vector expression list
|
||||||
ex_value_t *value; ///< constant value
|
ex_value_t *value; ///< constant value
|
||||||
|
ex_cmpinit_t compound; ///< compound initializer
|
||||||
} e;
|
} e;
|
||||||
} expr_t;
|
} expr_t;
|
||||||
|
|
||||||
|
@ -348,6 +361,10 @@ expr_t *new_block_expr (void);
|
||||||
*/
|
*/
|
||||||
expr_t *build_block_expr (expr_t *expr_list);
|
expr_t *build_block_expr (expr_t *expr_list);
|
||||||
|
|
||||||
|
ex_initele_t *new_initele (expr_t *expr, struct symbol_s *symbol);
|
||||||
|
expr_t *new_compound_init (void);
|
||||||
|
expr_t *append_element (expr_t *compound, ex_initele_t *element);
|
||||||
|
|
||||||
/** Create a new binary expression node node.
|
/** Create a new binary expression node node.
|
||||||
|
|
||||||
If either \a e1 or \a e2 are error expressions, then that expression will
|
If either \a e1 or \a e2 are error expressions, then that expression will
|
||||||
|
|
|
@ -86,7 +86,7 @@ new_element (void)
|
||||||
}
|
}
|
||||||
|
|
||||||
static element_t *
|
static element_t *
|
||||||
append_element (element_chain_t *element_chain, element_t *element)
|
append_init_element (element_chain_t *element_chain, element_t *element)
|
||||||
{
|
{
|
||||||
element->next = 0;
|
element->next = 0;
|
||||||
*element_chain->tail = element;
|
*element_chain->tail = element;
|
||||||
|
@ -371,7 +371,7 @@ static void
|
||||||
build_element_chain (element_chain_t *element_chain, type_t *type,
|
build_element_chain (element_chain_t *element_chain, type_t *type,
|
||||||
expr_t *eles, int base_offset)
|
expr_t *eles, int base_offset)
|
||||||
{
|
{
|
||||||
expr_t *e = eles->e.block.head;
|
ex_initele_t *ele = eles->e.compound.head;
|
||||||
|
|
||||||
if (is_array (type)) {
|
if (is_array (type)) {
|
||||||
type_t *array_type = type->t.array.type;
|
type_t *array_type = type->t.array.type;
|
||||||
|
@ -380,17 +380,18 @@ build_element_chain (element_chain_t *element_chain, type_t *type,
|
||||||
|
|
||||||
for (i = 0; i < array_size; i++) {
|
for (i = 0; i < array_size; i++) {
|
||||||
int offset = base_offset + i * type_size (array_type);
|
int offset = base_offset + i * type_size (array_type);
|
||||||
if (e && e->type == ex_block) {
|
if (ele->expr && ele->expr->type == ex_compound) {
|
||||||
build_element_chain (element_chain, array_type, e, offset);
|
build_element_chain (element_chain, array_type,
|
||||||
|
ele->expr, offset);
|
||||||
} else {
|
} else {
|
||||||
element_t *element = new_element ();
|
element_t *element = new_element ();
|
||||||
element->type = array_type;
|
element->type = array_type;
|
||||||
element->offset = offset;
|
element->offset = offset;
|
||||||
element->expr = e; // null will be treated as nil
|
element->expr = ele->expr; // null will be treated as nil
|
||||||
append_element (element_chain, element);
|
append_init_element (element_chain, element);
|
||||||
}
|
}
|
||||||
if (e) {
|
if (ele) {
|
||||||
e = e->next;
|
ele = ele->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (is_struct (type) || is_vector (type) || is_quaternion (type)) {
|
} else if (is_struct (type) || is_vector (type) || is_quaternion (type)) {
|
||||||
|
@ -403,23 +404,24 @@ build_element_chain (element_chain_t *element_chain, type_t *type,
|
||||||
|| field->visibility == vis_anonymous) {
|
|| field->visibility == vis_anonymous) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (e && e->type == ex_block) {
|
if (ele->expr && ele->expr->type == ex_compound) {
|
||||||
build_element_chain (element_chain, field->type, e, offset);
|
build_element_chain (element_chain, field->type,
|
||||||
|
ele->expr, offset);
|
||||||
} else {
|
} else {
|
||||||
element_t *element = new_element ();
|
element_t *element = new_element ();
|
||||||
element->type = field->type;
|
element->type = field->type;
|
||||||
element->offset = offset;
|
element->offset = offset;
|
||||||
element->expr = e; // null will be treated as nil
|
element->expr = ele->expr; // null will be treated as nil
|
||||||
append_element (element_chain, element);
|
append_init_element (element_chain, element);
|
||||||
}
|
}
|
||||||
if (e) {
|
if (ele) {
|
||||||
e = e->next;
|
ele = ele->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
error (eles, "invalid initializer");
|
error (eles, "invalid initializer");
|
||||||
}
|
}
|
||||||
if (e && e->next && options.warnings.initializer) {
|
if (ele && ele->next && options.warnings.initializer) {
|
||||||
warning (eles, "excessive elements in initializer");
|
warning (eles, "excessive elements in initializer");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -652,7 +654,7 @@ initialize_def (symbol_t *sym, expr_t *init, defspace_t *space,
|
||||||
}
|
}
|
||||||
if (!sym->s.def) {
|
if (!sym->s.def) {
|
||||||
if (is_array (sym->type) && !type_size (sym->type)
|
if (is_array (sym->type) && !type_size (sym->type)
|
||||||
&& init->type == ex_block && !init->e.block.result) {
|
&& init->type == ex_compound) {
|
||||||
sym->type = array_type (sym->type->t.array.type,
|
sym->type = array_type (sym->type->t.array.type,
|
||||||
num_elements (init));
|
num_elements (init));
|
||||||
}
|
}
|
||||||
|
@ -676,7 +678,7 @@ initialize_def (symbol_t *sym, expr_t *init, defspace_t *space,
|
||||||
return;
|
return;
|
||||||
if ((is_array (sym->type) || is_struct (sym->type)
|
if ((is_array (sym->type) || is_struct (sym->type)
|
||||||
|| sym->type == &type_vector || sym->type == &type_quaternion)
|
|| sym->type == &type_vector || sym->type == &type_quaternion)
|
||||||
&& ((init->type == ex_block && !init->e.block.result)
|
&& ((init->type == ex_compound)
|
||||||
|| init->type == ex_nil)) {
|
|| init->type == ex_nil)) {
|
||||||
init_elements (sym->s.def, init);
|
init_elements (sym->s.def, init);
|
||||||
sym->s.def->initialized = 1;
|
sym->s.def->initialized = 1;
|
||||||
|
|
|
@ -217,6 +217,7 @@ get_type (expr_t *e)
|
||||||
return &type_void;
|
return &type_void;
|
||||||
case ex_label:
|
case ex_label:
|
||||||
case ex_error:
|
case ex_error:
|
||||||
|
case ex_compound:
|
||||||
return 0; // something went very wrong
|
return 0; // something went very wrong
|
||||||
case ex_bool:
|
case ex_bool:
|
||||||
if (options.code.progsversion == PROG_ID_VERSION)
|
if (options.code.progsversion == PROG_ID_VERSION)
|
||||||
|
@ -420,14 +421,21 @@ copy_expr (expr_t *e)
|
||||||
n = new_expr ();
|
n = new_expr ();
|
||||||
n->e.vector.type = e->e.vector.type;
|
n->e.vector.type = e->e.vector.type;
|
||||||
n->e.vector.list = copy_expr (e->e.vector.list);
|
n->e.vector.list = copy_expr (e->e.vector.list);
|
||||||
n = n->e.vector.list;
|
|
||||||
t = e->e.vector.list;
|
t = e->e.vector.list;
|
||||||
|
e = n->e.vector.list;
|
||||||
while (t->next) {
|
while (t->next) {
|
||||||
n->next = copy_expr (t->next);
|
e->next = copy_expr (t->next);
|
||||||
n = n->next;
|
e = e->next;
|
||||||
t = t->next;
|
t = t->next;
|
||||||
}
|
}
|
||||||
return n;
|
return n;
|
||||||
|
case ex_compound:
|
||||||
|
n = new_expr ();
|
||||||
|
*n = *e;
|
||||||
|
for (ex_initele_t *i = e->e.compound.head; i; i = i->next) {
|
||||||
|
append_element (n, new_initele (i->expr, i->symbol));
|
||||||
|
}
|
||||||
|
return n;
|
||||||
}
|
}
|
||||||
internal_error (e, "invalid expression");
|
internal_error (e, "invalid expression");
|
||||||
}
|
}
|
||||||
|
@ -543,6 +551,46 @@ new_block_expr (void)
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ex_initele_t *
|
||||||
|
new_initele (expr_t *expr, symbol_t *symbol)
|
||||||
|
{
|
||||||
|
ex_initele_t *i = calloc (1, sizeof (*i));
|
||||||
|
i->expr = expr;
|
||||||
|
i->symbol = symbol;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
expr_t *
|
||||||
|
new_compound_init (void)
|
||||||
|
{
|
||||||
|
expr_t *c = new_expr ();
|
||||||
|
c->type = ex_compound;
|
||||||
|
c->e.compound.head = 0;
|
||||||
|
c->e.compound.tail = &c->e.compound.head;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
expr_t *
|
||||||
|
append_element (expr_t *compound, ex_initele_t *element)
|
||||||
|
{
|
||||||
|
if (compound->type != ex_compound) {
|
||||||
|
internal_error (compound, "not a compound expression");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!element || (element->expr && element->expr->type == ex_error)) {
|
||||||
|
return compound;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (element->next) {
|
||||||
|
internal_error (compound, "append_element: element loop detected");
|
||||||
|
}
|
||||||
|
|
||||||
|
*compound->e.compound.tail = element;
|
||||||
|
compound->e.compound.tail = &element->next;
|
||||||
|
|
||||||
|
return compound;
|
||||||
|
}
|
||||||
|
|
||||||
expr_t *
|
expr_t *
|
||||||
new_binary_expr (int op, expr_t *e1, expr_t *e2)
|
new_binary_expr (int op, expr_t *e1, expr_t *e2)
|
||||||
{
|
{
|
||||||
|
@ -1499,6 +1547,7 @@ unary_expr (int op, expr_t *e)
|
||||||
case ex_label:
|
case ex_label:
|
||||||
case ex_labelref:
|
case ex_labelref:
|
||||||
case ex_state:
|
case ex_state:
|
||||||
|
case ex_compound:
|
||||||
internal_error (e, 0);
|
internal_error (e, 0);
|
||||||
case ex_uexpr:
|
case ex_uexpr:
|
||||||
if (e->e.expr.op == '-')
|
if (e->e.expr.op == '-')
|
||||||
|
@ -1565,6 +1614,7 @@ unary_expr (int op, expr_t *e)
|
||||||
case ex_label:
|
case ex_label:
|
||||||
case ex_labelref:
|
case ex_labelref:
|
||||||
case ex_state:
|
case ex_state:
|
||||||
|
case ex_compound:
|
||||||
internal_error (e, 0);
|
internal_error (e, 0);
|
||||||
case ex_bool:
|
case ex_bool:
|
||||||
return new_bool_expr (e->e.bool.false_list,
|
return new_bool_expr (e->e.bool.false_list,
|
||||||
|
@ -1630,6 +1680,7 @@ unary_expr (int op, expr_t *e)
|
||||||
case ex_label:
|
case ex_label:
|
||||||
case ex_labelref:
|
case ex_labelref:
|
||||||
case ex_state:
|
case ex_state:
|
||||||
|
case ex_compound:
|
||||||
internal_error (e, 0);
|
internal_error (e, 0);
|
||||||
case ex_uexpr:
|
case ex_uexpr:
|
||||||
if (e->e.expr.op == '~')
|
if (e->e.expr.op == '~')
|
||||||
|
|
|
@ -123,6 +123,7 @@ check_valid_lvalue (expr_t *expr)
|
||||||
return check_valid_lvalue (expr->e.expr.e1);
|
return check_valid_lvalue (expr->e.expr.e1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case ex_compound:
|
||||||
case ex_state:
|
case ex_state:
|
||||||
case ex_bool:
|
case ex_bool:
|
||||||
case ex_label:
|
case ex_label:
|
||||||
|
|
|
@ -98,6 +98,7 @@ int yylex (void);
|
||||||
void *pointer; // for ensuring pointer values are null
|
void *pointer; // for ensuring pointer values are null
|
||||||
struct type_s *type;
|
struct type_s *type;
|
||||||
struct expr_s *expr;
|
struct expr_s *expr;
|
||||||
|
struct ex_initele_s *element;
|
||||||
struct function_s *function;
|
struct function_s *function;
|
||||||
struct switch_block_s *switch_block;
|
struct switch_block_s *switch_block;
|
||||||
struct param_s *param;
|
struct param_s *param;
|
||||||
|
@ -181,7 +182,9 @@ int yylex (void);
|
||||||
%type <symbol> methoddef
|
%type <symbol> methoddef
|
||||||
%type <expr> opt_initializer var_initializer local_def
|
%type <expr> opt_initializer var_initializer local_def
|
||||||
|
|
||||||
%type <expr> opt_init opt_expr cexpr expr element_list element
|
%type <expr> opt_init opt_expr cexpr expr
|
||||||
|
%type <expr> compound_init element_list
|
||||||
|
%type <element> element
|
||||||
%type <expr> optional_state_expr texpr vector_expr
|
%type <expr> optional_state_expr texpr vector_expr
|
||||||
%type <expr> statement statements compound_statement
|
%type <expr> statement statements compound_statement
|
||||||
%type <expr> else bool_label break_label continue_label
|
%type <expr> else bool_label break_label continue_label
|
||||||
|
@ -1148,17 +1151,20 @@ opt_initializer
|
||||||
|
|
||||||
var_initializer
|
var_initializer
|
||||||
: '=' expr { $$ = $2; }
|
: '=' expr { $$ = $2; }
|
||||||
| '=' '{' { $<spec>$ = $<spec>-1; }
|
| '=' compound_init
|
||||||
element_list optional_comma '}' { $$ = $4; }
|
|
||||||
| '=' '{' '}'
|
|
||||||
{
|
{
|
||||||
if (is_scalar ($<spec>-1.type)) {
|
if (!$2 && is_scalar ($<spec>-1.type)) {
|
||||||
error (0, "empty scalar initializer");
|
error (0, "empty scalar initializer");
|
||||||
}
|
}
|
||||||
$$ = new_nil_expr ();
|
$$ = $2 ? $2 : new_nil_expr ();
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
compound_init
|
||||||
|
: '{' element_list optional_comma '}' { $$ = $2; }
|
||||||
|
| '{' '}' { $$ = 0; }
|
||||||
|
;
|
||||||
|
|
||||||
optional_state_expr
|
optional_state_expr
|
||||||
: /* emtpy */ { $$ = 0; }
|
: /* emtpy */ { $$ = 0; }
|
||||||
| vector_expr { $$ = build_state_expr ($1); }
|
| vector_expr { $$ = build_state_expr ($1); }
|
||||||
|
@ -1167,30 +1173,18 @@ optional_state_expr
|
||||||
element_list
|
element_list
|
||||||
: element
|
: element
|
||||||
{
|
{
|
||||||
$$ = new_block_expr ();
|
$$ = new_compound_init ();
|
||||||
append_expr ($$, $1);
|
append_element ($$, $1);
|
||||||
}
|
}
|
||||||
| element_list ',' {$<spec>$ = $<spec>0; } element
|
| element_list ',' element
|
||||||
{
|
{
|
||||||
append_expr ($$, $4);
|
append_element ($$, $3);
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
element
|
element
|
||||||
: '{' { $<spec>$ = $<spec>0; }
|
: compound_init { $$ = new_initele ($1, 0); }
|
||||||
element_list optional_comma '}' { $$ = $3; }
|
| expr { $$ = new_initele ($1, 0); }
|
||||||
| '{' '}'
|
|
||||||
{
|
|
||||||
// FIXME doesn't check the right type (does prove the inherited
|
|
||||||
// attributes have been passed down correctly though). The problem
|
|
||||||
// is that the type of the sub elements needs to be extracted if
|
|
||||||
// possible
|
|
||||||
if (is_scalar ($<spec>0.type)) {
|
|
||||||
error (0, "empty scalar initializer");
|
|
||||||
}
|
|
||||||
$$ = new_nil_expr ();
|
|
||||||
}
|
|
||||||
| expr { $$ = $1; }
|
|
||||||
;
|
;
|
||||||
|
|
||||||
optional_comma
|
optional_comma
|
||||||
|
|
Loading…
Reference in a new issue