mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-04-19 07:51:08 +00:00
[qfcc] Use non-invasive lists for function arguments
This allows expressions to be repeated (by reference) in function argument lists, which will allow for expression dags.
This commit is contained in:
parent
81b544c362
commit
f974192177
9 changed files with 114 additions and 118 deletions
|
@ -381,10 +381,12 @@ etype_t extract_type (expr_t *e);
|
|||
ex_listitem_t *new_listitem (expr_t *e);
|
||||
int list_count (ex_list_t *list) __attribute__((pure));
|
||||
void list_scatter (ex_list_t *list, expr_t **exprs);
|
||||
void list_scatter_rev (ex_list_t *list, expr_t **exprs);
|
||||
void list_gather (ex_list_t *dst, expr_t **exprs, int count);
|
||||
expr_t *new_list_expr (expr_t *first);
|
||||
expr_t *list_append_expr (expr_t *list, expr_t *expr);
|
||||
expr_t *list_prepend_expr (expr_t *list, expr_t *expr);
|
||||
expr_t *list_append_list (expr_t *list, ex_list_t *append);
|
||||
expr_t *list_prepend_list (expr_t *list, ex_list_t *prepend);
|
||||
|
||||
/** Create a new expression node.
|
||||
|
@ -843,7 +845,6 @@ expr_t *convert_name (expr_t *e)__attribute__((warn_unused_result));
|
|||
expr_t *append_expr (expr_t *block, expr_t *e);
|
||||
expr_t *prepend_expr (expr_t *block, expr_t *e);
|
||||
|
||||
expr_t *reverse_expr_list (expr_t *e);
|
||||
void print_expr (expr_t *e);
|
||||
void dump_dot_expr (void *e, const char *filename);
|
||||
|
||||
|
|
|
@ -1637,6 +1637,7 @@ class_finish_module (void)
|
|||
init_sym = function_symbol (init_sym, 0, 1);
|
||||
|
||||
module_expr = address_expr (new_symbol_expr (module_sym), 0);
|
||||
module_expr = new_list_expr (module_expr);
|
||||
|
||||
init_expr = new_block_expr ();
|
||||
append_expr (init_expr,
|
||||
|
|
|
@ -204,7 +204,8 @@ get_type (expr_t *e)
|
|||
return e->multivec.type;
|
||||
case ex_list:
|
||||
if (e->list.head) {
|
||||
return get_type ((*e->list.tail)->expr);
|
||||
auto last = (ex_listitem_t *) e->list.tail;
|
||||
return get_type (last->expr);
|
||||
}
|
||||
return 0;
|
||||
case ex_count:
|
||||
|
@ -296,6 +297,14 @@ list_prepend_expr (expr_t *list, expr_t *expr)
|
|||
return list;
|
||||
}
|
||||
|
||||
expr_t *
|
||||
list_append_list (expr_t *list, ex_list_t *append)
|
||||
{
|
||||
*list->list.tail = append->head;
|
||||
list->list.tail = append->tail;
|
||||
return list;
|
||||
}
|
||||
|
||||
expr_t *
|
||||
list_prepend_list (expr_t *list, ex_list_t *prepend)
|
||||
{
|
||||
|
@ -338,6 +347,15 @@ list_scatter (ex_list_t *list, expr_t **exprs)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
list_scatter_rev (ex_list_t *list, expr_t **exprs)
|
||||
{
|
||||
int count = list_count (list);
|
||||
for (auto li = list->head; li; li = li->next) {
|
||||
exprs[--count] = li->expr;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
list_gather (ex_list_t *list, expr_t **exprs, int count)
|
||||
{
|
||||
|
@ -2216,29 +2234,29 @@ vararg_integer (expr_t *e)
|
|||
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, param_count = 0;
|
||||
int i;
|
||||
expr_t *args = 0, **a = &args;
|
||||
int arg_expr_count = 0;
|
||||
int emit_args = 0;
|
||||
int param_count = 0;
|
||||
expr_t *assign;
|
||||
expr_t *call;
|
||||
expr_t *err = 0;
|
||||
|
||||
for (e = params; e; e = e->next) {
|
||||
if (e->type == ex_error)
|
||||
int arg_count = params ? list_count (¶ms->list) :0;
|
||||
expr_t *arguments[arg_count];
|
||||
if (params) {
|
||||
list_scatter_rev (¶ms->list, arguments);
|
||||
}
|
||||
|
||||
for (int i = 0; i < arg_count; i++) {
|
||||
auto e = arguments[i];
|
||||
if (e->type == ex_error) {
|
||||
return e;
|
||||
arg_count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (options.code.progsversion < PROG_VERSION
|
||||
&& arg_count > PR_MAX_PARAMS) {
|
||||
return error (fexpr, "more than %d parameters", PR_MAX_PARAMS);
|
||||
}
|
||||
type_t *arg_types[arg_count];
|
||||
expr_t *arg_exprs[arg_count][2];
|
||||
|
||||
if (ftype->t.func.num_params < -1) {
|
||||
if (-arg_count > ftype->t.func.num_params + 1) {
|
||||
if (!options.traditional)
|
||||
|
@ -2258,11 +2276,11 @@ build_function_call (expr_t *fexpr, const type_t *ftype, expr_t *params)
|
|||
}
|
||||
param_count = ftype->t.func.num_params;
|
||||
}
|
||||
if (ftype->t.func.num_params < 0) {
|
||||
emit_args = !ftype->t.func.no_va_list;
|
||||
}
|
||||
|
||||
type_t *arg_types[arg_count];
|
||||
// params is reversed (a, b, c) -> c, b, a
|
||||
for (i = arg_count - 1, e = params; i >= 0; i--, e = e->next) {
|
||||
for (int i = 0; i < arg_count; i++) {
|
||||
auto e = arguments[i];
|
||||
type_t *t;
|
||||
|
||||
if (e->type == ex_compound) {
|
||||
|
@ -2324,21 +2342,29 @@ build_function_call (expr_t *fexpr, const type_t *ftype, expr_t *params)
|
|||
}
|
||||
vararg_integer (e);
|
||||
}
|
||||
arg_types[arg_count - 1 - i] = t;
|
||||
arg_types[i] = t;
|
||||
}
|
||||
if (err)
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
bool emit_args = false;
|
||||
if (ftype->t.func.num_params < 0) {
|
||||
emit_args = !ftype->t.func.no_va_list;
|
||||
}
|
||||
call = expr_file_line (new_block_expr (), fexpr);
|
||||
call->block.is_call = 1;
|
||||
int arg_expr_count = 0;
|
||||
expr_t *arg_exprs[arg_count][2];
|
||||
expr_t *args = new_list_expr (0);
|
||||
// args is built in reverse order so it matches params
|
||||
for (p = params, i = 0; p; p = p->next, i++) {
|
||||
if (emit_args && arg_count - i == param_count) {
|
||||
emit_args = 0;
|
||||
*a = new_args_expr ();
|
||||
a = &(*a)->next;
|
||||
for (int i = 0; i < arg_count; i++) {
|
||||
if (emit_args && i == param_count) {
|
||||
list_prepend_expr (args, new_args_expr ());
|
||||
emit_args = false;
|
||||
}
|
||||
expr_t *e = p;
|
||||
|
||||
auto e = arguments[i];
|
||||
if (e->type == ex_compound) {
|
||||
e = expr_file_line (initialized_temp_expr (arg_types[i], e), e);
|
||||
}
|
||||
|
@ -2348,32 +2374,34 @@ build_function_call (expr_t *fexpr, const type_t *ftype, expr_t *params)
|
|||
if (has_function_call (e)) {
|
||||
expr_t *cast = cast_expr (arg_types[i], e);
|
||||
expr_t *tmp = new_temp_def_expr (arg_types[i]);
|
||||
*a = expr_file_line (tmp, e);
|
||||
tmp = expr_file_line (tmp, e);
|
||||
list_prepend_expr (args, tmp);
|
||||
|
||||
arg_exprs[arg_expr_count][0] = expr_file_line (cast, e);
|
||||
arg_exprs[arg_expr_count][1] = *a;
|
||||
arg_exprs[arg_expr_count][1] = tmp;
|
||||
arg_expr_count++;
|
||||
} else {
|
||||
*a = expr_file_line (cast_expr (arg_types[i], e), e);
|
||||
e = expr_file_line (cast_expr (arg_types[i], e), e);
|
||||
list_prepend_expr (args, e);
|
||||
}
|
||||
a = &(*a)->next;
|
||||
}
|
||||
if (emit_args) {
|
||||
emit_args = 0;
|
||||
*a = new_args_expr ();
|
||||
a = &(*a)->next;
|
||||
emit_args = false;
|
||||
list_prepend_expr (args, new_args_expr ());
|
||||
}
|
||||
for (i = 0; i < arg_expr_count - 1; i++) {
|
||||
for (int i = 0; i < arg_expr_count - 1; i++) {
|
||||
assign = assign_expr (arg_exprs[i][1], arg_exprs[i][0]);
|
||||
append_expr (call, expr_file_line (assign, arg_exprs[i][0]));
|
||||
}
|
||||
if (arg_expr_count) {
|
||||
e = assign_expr (arg_exprs[arg_expr_count - 1][1],
|
||||
arg_exprs[arg_expr_count - 1][0]);
|
||||
auto e = assign_expr (arg_exprs[arg_expr_count - 1][1],
|
||||
arg_exprs[arg_expr_count - 1][0]);
|
||||
e = expr_file_line (e, arg_exprs[arg_expr_count - 1][0]);
|
||||
append_expr (call, e);
|
||||
}
|
||||
e = expr_file_line (call_expr (fexpr, args, ftype->t.func.type), fexpr);
|
||||
call->block.result = e;
|
||||
type_t *ret_type = ftype->t.func.type;
|
||||
call->block.result = expr_file_line (call_expr (fexpr, args, ret_type),
|
||||
fexpr);
|
||||
return call;
|
||||
}
|
||||
|
||||
|
@ -3153,17 +3181,3 @@ sizeof_expr (expr_t *expr, struct type_s *type)
|
|||
}
|
||||
return expr;
|
||||
}
|
||||
|
||||
expr_t *
|
||||
reverse_expr_list (expr_t *e)
|
||||
{
|
||||
expr_t *r = 0;
|
||||
|
||||
while (e) {
|
||||
expr_t *t = e->next;
|
||||
e->next = r;
|
||||
r = e;
|
||||
e = t;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
|
|
@ -180,7 +180,6 @@ super_expr (class_type_t *class_type)
|
|||
expr_t *
|
||||
message_expr (expr_t *receiver, keywordarg_t *message)
|
||||
{
|
||||
expr_t *args = 0, **a = &args;
|
||||
expr_t *selector = selector_expr (message);
|
||||
expr_t *call;
|
||||
keywordarg_t *m;
|
||||
|
@ -226,16 +225,15 @@ message_expr (expr_t *receiver, keywordarg_t *message)
|
|||
if (method)
|
||||
return_type = method->type->t.func.type;
|
||||
|
||||
expr_t *args = expr_file_line (new_list_expr (0), receiver);
|
||||
for (m = message; m; m = m->next) {
|
||||
*a = m->expr;
|
||||
while ((*a)) {
|
||||
expr_file_line (selector, *a);
|
||||
a = &(*a)->next;
|
||||
if (m->expr && m->expr->list.head) {
|
||||
list_append_list (args, &m->expr->list);
|
||||
expr_file_line (selector, m->expr);
|
||||
}
|
||||
}
|
||||
*a = selector;
|
||||
a = &(*a)->next;
|
||||
*a = receiver;
|
||||
list_append_expr (args, selector);
|
||||
list_append_expr (args, receiver);
|
||||
|
||||
send_msg = expr_file_line (send_message (super), receiver);
|
||||
if (method) {
|
||||
|
|
|
@ -349,30 +349,32 @@ func_compare (const void *a, const void *b)
|
|||
expr_t *
|
||||
find_function (expr_t *fexpr, expr_t *params)
|
||||
{
|
||||
expr_t *e;
|
||||
int i, j, func_count, parm_count, reported = 0;
|
||||
overloaded_function_t *f, dummy, *best = 0;
|
||||
type_t type;
|
||||
type_t type = {};
|
||||
void **funcs, *dummy_p = &dummy;
|
||||
|
||||
if (fexpr->type != ex_symbol)
|
||||
return fexpr;
|
||||
|
||||
memset (&type, 0, sizeof (type));
|
||||
type.type = ev_func;
|
||||
|
||||
for (e = params; e; e = e->next) {
|
||||
if (e->type == ex_error)
|
||||
return e;
|
||||
type.t.func.num_params++;
|
||||
type.t.func.num_params = params ? list_count (¶ms->list) : 0;
|
||||
expr_t *args[type.t.func.num_params];
|
||||
if (params) {
|
||||
list_scatter_rev (¶ms->list, args);
|
||||
}
|
||||
i = type.t.func.num_params * sizeof (type_t);
|
||||
type.t.func.param_types = alloca(i);
|
||||
memset (type.t.func.param_types, 0, i);
|
||||
for (i = 0, e = params; e; i++, e = e->next) {
|
||||
type.t.func.param_types[type.t.func.num_params - 1 - i] = get_type (e);
|
||||
if (e->type == ex_error)
|
||||
|
||||
for (int i = 0; i < type.t.func.num_params; i++) {
|
||||
auto e = args[i];
|
||||
if (e->type == ex_error) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
type_t *arg_types[type.t.func.num_params];
|
||||
type.t.func.param_types = arg_types;
|
||||
for (int i = 0; i < type.t.func.num_params; i++) {
|
||||
auto e = args[i];
|
||||
type.t.func.param_types[i] = get_type (e);
|
||||
}
|
||||
funcs = Hash_FindList (function_map, fexpr->symbol->name);
|
||||
if (!funcs)
|
||||
|
|
|
@ -703,32 +703,26 @@ clear_selectors (void)
|
|||
expr_t *
|
||||
method_check_params (method_t *method, expr_t *args)
|
||||
{
|
||||
int i, count, param_count;
|
||||
expr_t *a, **arg_list, *err = 0;
|
||||
int i, param_count;
|
||||
expr_t *err = 0;
|
||||
type_t *mtype = method->type;
|
||||
|
||||
if (mtype->t.func.num_params == -1)
|
||||
return 0;
|
||||
|
||||
for (count = 0, a = args; a; a = a->next)
|
||||
count++;
|
||||
|
||||
if (count > PR_MAX_PARAMS)
|
||||
return error (args, "more than %d parameters", PR_MAX_PARAMS);
|
||||
|
||||
if (mtype->t.func.num_params >= 0)
|
||||
param_count = mtype->t.func.num_params;
|
||||
else
|
||||
param_count = -mtype->t.func.num_params - 1;
|
||||
|
||||
int count = list_count (&args->list);
|
||||
if (count < param_count)
|
||||
return error (args, "too few arguments");
|
||||
if (mtype->t.func.num_params >= 0 && count > mtype->t.func.num_params)
|
||||
return error (args, "too many arguments");
|
||||
|
||||
arg_list = malloc (count * sizeof (expr_t *));
|
||||
for (i = count - 1, a = args; a; a = a->next)
|
||||
arg_list[i--] = a;
|
||||
expr_t *arg_list[count];
|
||||
list_scatter_rev (&args->list, arg_list);
|
||||
for (i = 2; i < count; i++) {
|
||||
expr_t *e = arg_list[i];
|
||||
type_t *arg_type = mtype->t.func.param_types[i];
|
||||
|
@ -752,6 +746,5 @@ method_check_params (method_t *method, expr_t *args)
|
|||
vararg_integer (e);
|
||||
}
|
||||
}
|
||||
free (arg_list);
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -1799,12 +1799,8 @@ opt_arg_list
|
|||
;
|
||||
|
||||
arg_list
|
||||
: arg_expr
|
||||
| arg_list ',' arg_expr
|
||||
{
|
||||
$3->next = $1;
|
||||
$$ = $3;
|
||||
}
|
||||
: arg_expr { $$ = new_list_expr ($1); }
|
||||
| arg_list ',' arg_expr { $$ = list_prepend_expr ($1, $3); }
|
||||
;
|
||||
|
||||
arg_expr
|
||||
|
|
|
@ -458,12 +458,8 @@ procedure_statement
|
|||
;
|
||||
|
||||
expression_list
|
||||
: expression
|
||||
| expression_list ',' expression
|
||||
{
|
||||
$$ = $3;
|
||||
$$->next = $1;
|
||||
}
|
||||
: expression { $$ = new_list_expr ($1); }
|
||||
| expression_list ',' expression { $$ = list_prepend_expr ($1, $3); }
|
||||
;
|
||||
|
||||
unary_expr
|
||||
|
|
|
@ -1068,7 +1068,6 @@ expr_call_v6p (sblock_t *sblock, expr_t *call, operand_t **op)
|
|||
{
|
||||
expr_t *func = call->branch.target;
|
||||
expr_t *args = call->branch.args;
|
||||
expr_t *a;
|
||||
expr_t *param;
|
||||
operand_t *arguments[2] = {0, 0};
|
||||
int count = 0;
|
||||
|
@ -1079,7 +1078,8 @@ expr_call_v6p (sblock_t *sblock, expr_t *call, operand_t **op)
|
|||
operand_t *use = 0;
|
||||
|
||||
// function arguments are in reverse order
|
||||
for (a = args; a; a = a->next) {
|
||||
for (auto li = args->list.head; li; li = li->next) {
|
||||
auto a = li->expr;
|
||||
if (a->type == ex_args) {
|
||||
// v6p uses callN and pr_argc
|
||||
continue;
|
||||
|
@ -1087,7 +1087,8 @@ expr_call_v6p (sblock_t *sblock, expr_t *call, operand_t **op)
|
|||
count++;
|
||||
}
|
||||
ind = count;
|
||||
for (a = args; a; a = a->next) {
|
||||
for (auto li = args->list.head; li; li = li->next) {
|
||||
auto a = li->expr;
|
||||
if (a->type == ex_args) {
|
||||
// v6p uses callN and pr_argc
|
||||
continue;
|
||||
|
@ -1157,7 +1158,6 @@ expr_call (sblock_t *sblock, expr_t *call, operand_t **op)
|
|||
}
|
||||
defspace_t *arg_space = current_func->arguments;
|
||||
expr_t *func = call->branch.target;
|
||||
expr_t **args = 0;
|
||||
expr_t *args_va_list = 0; // .args (...) parameter
|
||||
expr_t *args_params = 0; // first arg in ...
|
||||
operand_t *use = 0;
|
||||
|
@ -1166,17 +1166,9 @@ expr_call (sblock_t *sblock, expr_t *call, operand_t **op)
|
|||
|
||||
defspace_reset (arg_space);
|
||||
|
||||
int num_args = 0;
|
||||
for (expr_t *a = call->branch.args; a; a = a->next) {
|
||||
num_args++;
|
||||
}
|
||||
if (num_args) {
|
||||
int i = num_args;
|
||||
args = alloca (num_args * sizeof (expr_t *));
|
||||
for (expr_t *a = call->branch.args; a; a = a->next) {
|
||||
args[--i] = a;
|
||||
}
|
||||
}
|
||||
int num_args = list_count (&call->branch.args->list);
|
||||
expr_t *args[num_args];
|
||||
list_scatter_rev (&call->branch.args->list, args);
|
||||
int arg_num = 0;
|
||||
for (int i = 0; i < num_args; i++) {
|
||||
expr_t *a = args[i];
|
||||
|
@ -2590,12 +2582,15 @@ search_for_super_dealloc (sblock_t *sblock)
|
|||
}
|
||||
// function arguments are in reverse order, and the selector
|
||||
// is the second argument (or second last in the list)
|
||||
expr_t *arg;
|
||||
for (arg = st->expr->branch.args;
|
||||
arg && arg->next && arg->next->next; arg = arg->next) {
|
||||
expr_t *arg = 0;
|
||||
auto arguments = st->expr->branch.args;
|
||||
for (auto li = arguments->list.head; li; li = li->next) {
|
||||
if (li->next && !li->next->next) {
|
||||
arg = li->expr;
|
||||
}
|
||||
}
|
||||
if (arg && arg->next && is_selector (arg)) {
|
||||
selector_t *sel = get_selector (st->expr->branch.args);
|
||||
if (arg && is_selector (arg)) {
|
||||
selector_t *sel = get_selector (arg);
|
||||
if (sel && strcmp (sel->name, "dealloc") == 0) {
|
||||
op = pseudo_operand (super_dealloc, st->expr);
|
||||
statement_add_def (st, op);
|
||||
|
|
Loading…
Reference in a new issue