mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-03-23 10:50:58 +00:00
[qfcc] Support compound init in assignment and params
foo({...}) and bar = {...}
This commit is contained in:
parent
023a920a51
commit
b6439e8dc1
10 changed files with 381 additions and 174 deletions
|
@ -85,16 +85,18 @@ typedef struct {
|
|||
ex_label_t *label;
|
||||
} ex_labelref_t;
|
||||
|
||||
typedef struct ex_initele_s {
|
||||
struct ex_initele_s *next; ///< next in chain
|
||||
struct symbol_s *symbol; ///< for labeled initializers
|
||||
typedef struct element_s {
|
||||
struct element_s *next; ///< next in chain
|
||||
int offset;
|
||||
struct type_s *type;
|
||||
struct expr_s *expr; ///< initializer expression
|
||||
} ex_initele_t;
|
||||
struct symbol_s *symbol; ///< for labeled initializers
|
||||
} element_t;
|
||||
|
||||
typedef struct ex_cmpinit_s {
|
||||
ex_initele_t *head;
|
||||
ex_initele_t **tail;
|
||||
} ex_cmpinit_t;
|
||||
typedef struct element_chain_s {
|
||||
element_t *head;
|
||||
element_t **tail;
|
||||
} element_chain_t;
|
||||
|
||||
typedef struct {
|
||||
struct expr_s *head; ///< the first expression in the block
|
||||
|
@ -222,7 +224,7 @@ typedef struct expr_s {
|
|||
ex_temp_t temp; ///< temporary variable expression
|
||||
ex_vector_t vector; ///< vector expression list
|
||||
ex_value_t *value; ///< constant value
|
||||
ex_cmpinit_t compound; ///< compound initializer
|
||||
element_chain_t compound; ///< compound initializer
|
||||
} e;
|
||||
} expr_t;
|
||||
|
||||
|
@ -361,9 +363,15 @@ expr_t *new_block_expr (void);
|
|||
*/
|
||||
expr_t *build_block_expr (expr_t *expr_list);
|
||||
|
||||
ex_initele_t *new_initele (expr_t *expr, struct symbol_s *symbol);
|
||||
element_t *new_element (expr_t *expr, struct symbol_s *symbol);
|
||||
expr_t *new_compound_init (void);
|
||||
expr_t *append_element (expr_t *compound, ex_initele_t *element);
|
||||
expr_t *append_element (expr_t *compound, element_t *element);
|
||||
expr_t *initialized_temp_expr (struct type_s *type, expr_t *compound);
|
||||
void assign_elements (expr_t *local_expr, expr_t *ptr,
|
||||
element_chain_t *element_chain);
|
||||
void build_element_chain (element_chain_t *element_chain, struct type_s *type,
|
||||
expr_t *eles, int base_offset);
|
||||
void free_element_chain (element_chain_t *element_chain);
|
||||
|
||||
/** Create a new binary expression node node.
|
||||
|
||||
|
|
|
@ -41,7 +41,8 @@ bin_SCRIPTS= qfpreqcc
|
|||
common_src=\
|
||||
class.c codespace.c constfold.c cpp.c dags.c debug.c def.c defspace.c \
|
||||
diagnostic.c dot.c dot_dag.c dot_expr.c dot_flow.c dot_sblock.c emit.c \
|
||||
expr.c expr_assign.c expr_binary.c expr_bool.c flow.c function.c grab.c \
|
||||
expr.c expr_assign.c expr_binary.c expr_bool.c expr_compound.c \
|
||||
flow.c function.c grab.c \
|
||||
idstuff.c \
|
||||
linker.c method.c \
|
||||
obj_file.c \
|
||||
|
|
|
@ -62,37 +62,7 @@
|
|||
#include "type.h"
|
||||
#include "value.h"
|
||||
|
||||
typedef struct element_s {
|
||||
struct element_s *next;
|
||||
int offset;
|
||||
type_t *type;
|
||||
expr_t *expr;
|
||||
} element_t;
|
||||
|
||||
typedef struct element_chain_s {
|
||||
element_t *head;
|
||||
element_t **tail;
|
||||
} element_chain_t;
|
||||
|
||||
static def_t *defs_freelist;
|
||||
static element_t *elements_freelist;
|
||||
|
||||
static element_t *
|
||||
new_element (void)
|
||||
{
|
||||
element_t *element;
|
||||
ALLOC (256, element_t, elements, element);
|
||||
return element;
|
||||
}
|
||||
|
||||
static element_t *
|
||||
append_init_element (element_chain_t *element_chain, element_t *element)
|
||||
{
|
||||
element->next = 0;
|
||||
*element_chain->tail = element;
|
||||
element_chain->tail = &element->next;
|
||||
return element;
|
||||
}
|
||||
|
||||
static void
|
||||
set_storage_bits (def_t *def, storage_class_t storage)
|
||||
|
@ -367,65 +337,6 @@ init_elements_nil (def_t *def)
|
|||
// it's a global, so already initialized to 0
|
||||
}
|
||||
|
||||
static void
|
||||
build_element_chain (element_chain_t *element_chain, type_t *type,
|
||||
expr_t *eles, int base_offset)
|
||||
{
|
||||
ex_initele_t *ele = eles->e.compound.head;
|
||||
|
||||
if (is_array (type)) {
|
||||
type_t *array_type = type->t.array.type;
|
||||
int array_size = type->t.array.size;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < array_size; i++) {
|
||||
int offset = base_offset + i * type_size (array_type);
|
||||
if (ele->expr && ele->expr->type == ex_compound) {
|
||||
build_element_chain (element_chain, array_type,
|
||||
ele->expr, offset);
|
||||
} else {
|
||||
element_t *element = new_element ();
|
||||
element->type = array_type;
|
||||
element->offset = offset;
|
||||
element->expr = ele->expr; // null will be treated as nil
|
||||
append_init_element (element_chain, element);
|
||||
}
|
||||
if (ele) {
|
||||
ele = ele->next;
|
||||
}
|
||||
}
|
||||
} else if (is_struct (type) || is_vector (type) || is_quaternion (type)) {
|
||||
symtab_t *symtab = type->t.symtab;
|
||||
symbol_t *field;
|
||||
|
||||
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 (ele->expr && ele->expr->type == ex_compound) {
|
||||
build_element_chain (element_chain, field->type,
|
||||
ele->expr, offset);
|
||||
} else {
|
||||
element_t *element = new_element ();
|
||||
element->type = field->type;
|
||||
element->offset = offset;
|
||||
element->expr = ele->expr; // null will be treated as nil
|
||||
append_init_element (element_chain, element);
|
||||
}
|
||||
if (ele) {
|
||||
ele = ele->next;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
error (eles, "invalid initializer");
|
||||
}
|
||||
if (ele && ele->next && options.warnings.initializer) {
|
||||
warning (eles, "excessive elements in initializer");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
init_elements (struct def_s *def, expr_t *eles)
|
||||
{
|
||||
|
@ -444,21 +355,8 @@ init_elements (struct def_s *def, expr_t *eles)
|
|||
build_element_chain (&element_chain, def->type, eles, 0);
|
||||
|
||||
if (def->local && local_expr) {
|
||||
for (element = element_chain.head; element; element = element->next) {
|
||||
int offset = element->offset;
|
||||
type_t *type = element->type;
|
||||
expr_t *ptr = new_pointer_expr (offset, type, def);
|
||||
|
||||
if (element->expr) {
|
||||
c = constant_expr (element->expr);
|
||||
} else {
|
||||
c = new_nil_expr ();
|
||||
}
|
||||
if (c->type == ex_nil) {
|
||||
c = convert_nil (c, type);
|
||||
}
|
||||
append_expr (local_expr, assign_expr (unary_expr ('.', ptr), c));
|
||||
}
|
||||
expr_t *ptr = new_pointer_expr (0, def->type, def);
|
||||
assign_elements (local_expr, pointer_expr (ptr), &element_chain);
|
||||
} else {
|
||||
def_t dummy = *def;
|
||||
for (element = element_chain.head; element; element = element->next) {
|
||||
|
@ -502,8 +400,7 @@ init_elements (struct def_s *def, expr_t *eles)
|
|||
}
|
||||
}
|
||||
|
||||
*element_chain.tail = elements_freelist;
|
||||
elements_freelist = element_chain.head;
|
||||
free_element_chain (&element_chain);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -432,8 +432,8 @@ copy_expr (expr_t *e)
|
|||
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));
|
||||
for (element_t *i = e->e.compound.head; i; i = i->next) {
|
||||
append_element (n, new_element (i->expr, i->symbol));
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
@ -551,46 +551,6 @@ new_block_expr (void)
|
|||
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 *
|
||||
new_binary_expr (int op, expr_t *e1, expr_t *e2)
|
||||
{
|
||||
|
@ -1731,6 +1691,7 @@ expr_t *
|
|||
build_function_call (expr_t *fexpr, const type_t *ftype, expr_t *params)
|
||||
{
|
||||
expr_t *e;
|
||||
expr_t *p;
|
||||
int arg_count = 0, parm_count = 0;
|
||||
int i;
|
||||
expr_t *args = 0, **a = &args;
|
||||
|
@ -1770,8 +1731,18 @@ build_function_call (expr_t *fexpr, const type_t *ftype, expr_t *params)
|
|||
parm_count = ftype->t.func.num_params;
|
||||
}
|
||||
for (i = arg_count - 1, e = params; i >= 0; i--, e = e->next) {
|
||||
type_t *t = get_type (e);
|
||||
type_t *t;
|
||||
|
||||
if (e->type == ex_compound) {
|
||||
if (i < parm_count) {
|
||||
t = ftype->t.func.param_types[i];
|
||||
} else {
|
||||
return error (e, "cannot pass compound initializer "
|
||||
"through ...");
|
||||
}
|
||||
} else {
|
||||
t = get_type (e);
|
||||
}
|
||||
if (!t) {
|
||||
return e;
|
||||
}
|
||||
|
@ -1827,7 +1798,11 @@ build_function_call (expr_t *fexpr, const type_t *ftype, expr_t *params)
|
|||
|
||||
call = expr_file_line (new_block_expr (), fexpr);
|
||||
call->e.block.is_call = 1;
|
||||
for (e = params, i = 0; e; e = e->next, i++) {
|
||||
for (p = params, i = 0; p; p = p->next, i++) {
|
||||
expr_t *e = p;
|
||||
if (e->type == ex_compound) {
|
||||
e = expr_file_line (initialized_temp_expr (arg_types[i], e), e);
|
||||
}
|
||||
if (has_function_call (e)) {
|
||||
expr_t *cast = cast_expr (arg_types[i], convert_vector (e));
|
||||
expr_t *tmp = new_temp_def_expr (arg_types[i]);
|
||||
|
|
|
@ -313,10 +313,16 @@ assign_expr (expr_t *dst, expr_t *src)
|
|||
}
|
||||
|
||||
dst_type = get_type (dst);
|
||||
src_type = get_type (src);
|
||||
if (!dst_type) {
|
||||
internal_error (dst, "dst_type broke in assign_expr");
|
||||
}
|
||||
if (src->type == ex_compound) {
|
||||
src = initialized_temp_expr (dst_type, src);
|
||||
if (src->type == ex_error) {
|
||||
return src;
|
||||
}
|
||||
}
|
||||
src_type = get_type (src);
|
||||
if (!src_type) {
|
||||
internal_error (src, "src_type broke in assign_expr");
|
||||
}
|
||||
|
|
209
tools/qfcc/source/expr_compound.c
Normal file
209
tools/qfcc/source/expr_compound.c
Normal file
|
@ -0,0 +1,209 @@
|
|||
/*
|
||||
expr_compound.c
|
||||
|
||||
compound intializer expression construction and manipulations
|
||||
|
||||
Copyright (C) 2020 Bill Currie <bill@taniwha.org>
|
||||
|
||||
Author: Bill Currie <bill@taniwha.org>
|
||||
Date: 2020/03/11
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
|
||||
Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA
|
||||
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
# include <string.h>
|
||||
#endif
|
||||
#ifdef HAVE_STRINGS_H
|
||||
# include <strings.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "QF/alloc.h"
|
||||
#include "QF/dstring.h"
|
||||
#include "QF/mathlib.h"
|
||||
#include "QF/sys.h"
|
||||
#include "QF/va.h"
|
||||
|
||||
#include "diagnostic.h"
|
||||
#include "expr.h"
|
||||
#include "options.h"
|
||||
#include "symtab.h"
|
||||
#include "type.h"
|
||||
|
||||
static element_t *elements_freelist;
|
||||
|
||||
element_t *
|
||||
new_element (expr_t *expr, symbol_t *symbol)
|
||||
{
|
||||
element_t *element;
|
||||
ALLOC (256, element_t, elements, element);
|
||||
element->expr = expr;
|
||||
element->symbol = symbol;
|
||||
return element;
|
||||
}
|
||||
|
||||
static element_t *
|
||||
append_init_element (element_chain_t *element_chain, element_t *element)
|
||||
{
|
||||
element->next = 0;
|
||||
*element_chain->tail = element;
|
||||
element_chain->tail = &element->next;
|
||||
return element;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void
|
||||
build_element_chain (element_chain_t *element_chain, type_t *type,
|
||||
expr_t *eles, int base_offset)
|
||||
{
|
||||
element_t *ele = eles->e.compound.head;
|
||||
|
||||
if (is_array (type)) {
|
||||
type_t *array_type = type->t.array.type;
|
||||
int array_size = type->t.array.size;
|
||||
int i;
|
||||
|
||||
for (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;
|
||||
}
|
||||
}
|
||||
} else if (is_struct (type) || is_vector (type) || is_quaternion (type)) {
|
||||
symtab_t *symtab = type->t.symtab;
|
||||
symbol_t *field;
|
||||
|
||||
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 (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);
|
||||
}
|
||||
if (ele) {
|
||||
ele = ele->next;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
error (eles, "invalid initializer");
|
||||
}
|
||||
if (ele && ele->next && options.warnings.initializer) {
|
||||
warning (eles, "excessive elements in initializer");
|
||||
}
|
||||
}
|
||||
|
||||
void free_element_chain (element_chain_t *element_chain)
|
||||
{
|
||||
*element_chain->tail = elements_freelist;
|
||||
elements_freelist = element_chain->head;
|
||||
element_chain->head = 0;
|
||||
element_chain->tail = &element_chain->head;
|
||||
}
|
||||
|
||||
expr_t *
|
||||
append_element (expr_t *compound, element_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");
|
||||
}
|
||||
append_init_element (&compound->e.compound, element);
|
||||
return compound;
|
||||
}
|
||||
|
||||
void
|
||||
assign_elements (expr_t *local_expr, expr_t *init,
|
||||
element_chain_t *element_chain)
|
||||
{
|
||||
element_t *element;
|
||||
|
||||
for (element = element_chain->head; element; element = element->next) {
|
||||
int offset = element->offset;
|
||||
type_t *type = element->type;
|
||||
expr_t *alias = new_offset_alias_expr (type, init, offset);
|
||||
|
||||
expr_t *c;
|
||||
|
||||
if (element->expr) {
|
||||
c = constant_expr (element->expr);
|
||||
} else {
|
||||
c = new_nil_expr ();
|
||||
}
|
||||
if (c->type == ex_nil) {
|
||||
c = convert_nil (c, type);
|
||||
}
|
||||
append_expr (local_expr, assign_expr (alias, c));
|
||||
}
|
||||
}
|
||||
|
||||
expr_t *
|
||||
initialized_temp_expr (type_t *type, expr_t *compound)
|
||||
{
|
||||
element_chain_t element_chain;
|
||||
expr_t *temp = new_temp_def_expr (type);
|
||||
expr_t *block = new_block_expr ();
|
||||
|
||||
element_chain.head = 0;
|
||||
element_chain.tail = &element_chain.head;
|
||||
build_element_chain (&element_chain, type, compound, 0);
|
||||
assign_elements (block, temp, &element_chain);
|
||||
block->e.block.result = temp;
|
||||
free_element_chain (&element_chain);
|
||||
return block;
|
||||
}
|
|
@ -98,7 +98,7 @@ int yylex (void);
|
|||
void *pointer; // for ensuring pointer values are null
|
||||
struct type_s *type;
|
||||
struct expr_s *expr;
|
||||
struct ex_initele_s *element;
|
||||
struct element_s *element;
|
||||
struct function_s *function;
|
||||
struct switch_block_s *switch_block;
|
||||
struct param_s *param;
|
||||
|
@ -188,7 +188,8 @@ int yylex (void);
|
|||
%type <expr> optional_state_expr texpr vector_expr
|
||||
%type <expr> statement statements compound_statement
|
||||
%type <expr> else bool_label break_label continue_label
|
||||
%type <expr> unary_expr ident_expr cast_expr opt_arg_list arg_list
|
||||
%type <expr> unary_expr ident_expr cast_expr expr_list
|
||||
%type <expr> opt_arg_list arg_list arg_expr
|
||||
%type <expr> init_var_decl_list init_var_decl
|
||||
%type <switch_block> switch_block
|
||||
%type <symbol> identifier label
|
||||
|
@ -1183,8 +1184,8 @@ element_list
|
|||
;
|
||||
|
||||
element
|
||||
: compound_init { $$ = new_initele ($1, 0); }
|
||||
| expr { $$ = new_initele ($1, 0); }
|
||||
: compound_init { $$ = new_element ($1, 0); }
|
||||
| expr { $$ = new_element ($1, 0); }
|
||||
;
|
||||
|
||||
optional_comma
|
||||
|
@ -1473,7 +1474,7 @@ ident_expr
|
|||
;
|
||||
|
||||
vector_expr
|
||||
: '[' expr ',' arg_list ']'
|
||||
: '[' expr ',' expr_list ']'
|
||||
{
|
||||
expr_t *t = $4;
|
||||
while (t->next)
|
||||
|
@ -1494,6 +1495,7 @@ cast_expr
|
|||
expr
|
||||
: cast_expr
|
||||
| expr '=' expr { $$ = assign_expr ($1, $3); }
|
||||
| expr '=' compound_init { $$ = assign_expr ($1, $3); }
|
||||
| expr ASX expr { $$ = asx_expr ($2, $1, $3); }
|
||||
| expr '?' expr ':' expr { $$ = conditional_expr ($1, $3, $5); }
|
||||
| expr AND bool_label expr { $$ = bool_expr (AND, $3, $1, $4); }
|
||||
|
@ -1522,7 +1524,7 @@ texpr
|
|||
;
|
||||
|
||||
comma_expr
|
||||
: arg_list
|
||||
: expr_list
|
||||
{
|
||||
if ($1->next) {
|
||||
expr_t *res = $1;
|
||||
|
@ -1533,20 +1535,34 @@ comma_expr
|
|||
}
|
||||
;
|
||||
|
||||
expr_list
|
||||
: expr
|
||||
| expr_list ',' expr
|
||||
{
|
||||
$3->next = $1;
|
||||
$$ = $3;
|
||||
}
|
||||
;
|
||||
|
||||
opt_arg_list
|
||||
: /* emtpy */ { $$ = 0; }
|
||||
| arg_list { $$ = $1; }
|
||||
;
|
||||
|
||||
arg_list
|
||||
: expr
|
||||
| arg_list ',' expr
|
||||
: arg_expr
|
||||
| arg_list ',' arg_expr
|
||||
{
|
||||
$3->next = $1;
|
||||
$$ = $3;
|
||||
}
|
||||
;
|
||||
|
||||
arg_expr
|
||||
: expr
|
||||
| compound_init
|
||||
;
|
||||
|
||||
const
|
||||
: VALUE
|
||||
| NIL { $$ = new_nil_expr (); }
|
||||
|
|
|
@ -35,6 +35,7 @@ test_progs_dat=\
|
|||
chewed-alias.dat \
|
||||
chewed-return.dat \
|
||||
comma-expr.dat \
|
||||
compound.dat \
|
||||
deadbool.dat \
|
||||
double.dat \
|
||||
enum.dat \
|
||||
|
@ -158,6 +159,15 @@ comma-expr.run: Makefile build-run
|
|||
include ./$(DEPDIR)/comma-expr.Qo # am--include-marker
|
||||
r_depfiles_remade += ./$(DEPDIR)/comma-expr.Qo
|
||||
|
||||
compound_dat_SOURCES=compound.r
|
||||
compound_obj=$(compound_dat_SOURCES:.r=.qfo)
|
||||
compound.dat$(EXEEXT): $(compound_obj) $(QFCC_DEP)
|
||||
$(QFCC) $(QCFLAGS) -o $@ $(compound_obj)
|
||||
compound.run: Makefile build-run
|
||||
@$(srcdir)/build-run $@
|
||||
include ./$(DEPDIR)/compound.Qo # am--include-marker
|
||||
r_depfiles_remade += ./$(DEPDIR)/compound.Qo
|
||||
|
||||
deadbool_dat_SOURCES=deadbool.r
|
||||
deadbool_obj=$(deadbool_dat_SOURCES:.r=.qfo)
|
||||
deadbool.dat$(EXEEXT): $(deadbool_obj) $(QFCC_DEP)
|
||||
|
|
72
tools/qfcc/test/compound.r
Normal file
72
tools/qfcc/test/compound.r
Normal file
|
@ -0,0 +1,72 @@
|
|||
#include "test-harness.h"
|
||||
|
||||
typedef struct Point {
|
||||
int x;
|
||||
int y;
|
||||
} Point;
|
||||
|
||||
typedef struct Size {
|
||||
int width;
|
||||
int height;
|
||||
} Size;
|
||||
|
||||
typedef struct Rect {
|
||||
Point origin;
|
||||
Size size;
|
||||
} Rect;
|
||||
|
||||
int test_simple_param (Point p, int x, int y)
|
||||
{
|
||||
int ret = !(p.x == x && p.y == y);
|
||||
if (ret) {
|
||||
printf ("simple param: {%d, %d} != {%d, %d}\n", p.x, p.y, x, y);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int test_nested_param (Rect r, int x, int y, int w, int h)
|
||||
{
|
||||
int ret = !(r.origin.x == x && r.origin.y == y
|
||||
&& r.size.width == w && r.size.height == h);
|
||||
if (ret) {
|
||||
printf ("nested param: {{%d, %d}, {%d, %d}} != ",
|
||||
r.origin.x, r.origin.y, r.size.width, r.size.height);
|
||||
printf ("{{%d, %d}, {%d, %d}}\n", x, y, w, h);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int test_simple_assign (int x, int y)
|
||||
{
|
||||
Point p;
|
||||
p = { x, y };
|
||||
int ret = !(p.x == x && p.y == y);
|
||||
if (ret) {
|
||||
printf ("simple assign: {%d, %d} != {%d, %d}\n", p.x, p.y, x, y);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int test_nested_assign (int x, int y, int w, int h)
|
||||
{
|
||||
Rect r;
|
||||
r = {{x, y}, {w, h}};
|
||||
int ret = !(r.origin.x == x && r.origin.y == y
|
||||
&& r.size.width == w && r.size.height == h);
|
||||
if (ret) {
|
||||
printf ("nested assign: {{%d, %d}, {%d, %d}} != ",
|
||||
r.origin.x, r.origin.y, r.size.width, r.size.height);
|
||||
printf ("{{%d, %d}, {%d, %d}}\n", x, y, w, h);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
int ret = 0;
|
||||
ret |= test_simple_param ({1, 2}, 1, 2);
|
||||
ret |= test_nested_param ({{1, 2}, {3, 4}}, 1, 2, 3, 4);
|
||||
ret |= test_simple_assign (1, 2);
|
||||
ret |= test_nested_assign (1, 2, 3, 4);
|
||||
return ret;
|
||||
}
|
|
@ -16,6 +16,12 @@ typedef struct Rect_s {
|
|||
|
||||
void *foo (Rect *obj, void *cmd, Rect *o, Point pos, Rect r);
|
||||
|
||||
void *baz (Rect *obj, void *cmd, Rect *o, Point pos)
|
||||
{
|
||||
Rect rect = { {1, 2}, {3, 4} };
|
||||
return foo (obj, cmd, o, pos, rect);
|
||||
}
|
||||
|
||||
void *bar (Rect *obj, void *cmd, Rect *o, Point pos)
|
||||
{
|
||||
Rect rect = { {}, obj.extent };
|
||||
|
@ -33,12 +39,19 @@ Rect o = { { 5, 6}, {7, 8} };
|
|||
|
||||
int main (void)
|
||||
{
|
||||
int ret = 1;
|
||||
int ret = 0;
|
||||
bar(&obj, nil, &o, obj.offset);
|
||||
printf ("%d %d %d %d\n", o.offset.x, o.offset.y,
|
||||
o.extent.width, o.extent.height);
|
||||
if (o.offset.x == 0 && o.offset.y == 0
|
||||
if not (o.offset.x == 0 && o.offset.y == 0
|
||||
&& o.extent.width == 3 && o.extent.height == 4)
|
||||
ret = 0;
|
||||
ret |= 1;
|
||||
|
||||
baz(&obj, nil, &o, obj.offset);
|
||||
printf ("%d %d %d %d\n", o.offset.x, o.offset.y,
|
||||
o.extent.width, o.extent.height);
|
||||
if not (o.offset.x == 1 && o.offset.y == 2
|
||||
&& o.extent.width == 3 && o.extent.height == 4)
|
||||
ret |= 1;
|
||||
return ret;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue