[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:
Bill Currie 2023-09-24 20:44:50 +09:00
parent 81b544c362
commit f974192177
9 changed files with 114 additions and 118 deletions

View file

@ -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);

View file

@ -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,

View file

@ -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 (&params->list) :0;
expr_t *arguments[arg_count];
if (params) {
list_scatter_rev (&params->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;
}

View file

@ -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) {

View file

@ -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 (&params->list) : 0;
expr_t *args[type.t.func.num_params];
if (params) {
list_scatter_rev (&params->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)

View file

@ -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;
}

View file

@ -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

View file

@ -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

View file

@ -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);