[qfcc] Add field and array expression types

And implement enough AST processing to compile fstrianglest.vert

Plenty of code-gen issues, though.
This commit is contained in:
Bill Currie 2024-10-02 02:01:33 +09:00
parent feca9bd5cb
commit a7639a685e
8 changed files with 146 additions and 7 deletions

View file

@ -333,6 +333,18 @@ typedef struct {
const expr_t *false_expr;
} ex_cond_t;
typedef struct {
const expr_t *object;
const expr_t *member;
const type_t *type;
} ex_field_t;
typedef struct {
const expr_t *base;
const expr_t *index;
const type_t *type;
} ex_array_t;
#define POINTER_VAL(p) (((p).def ? (p).def->offset : 0) + (p).val)
typedef struct expr_s {
@ -378,6 +390,8 @@ typedef struct expr_s {
ex_type_t typ; ///< type expression
ex_incop_t incop; ///< incop expression
ex_cond_t cond; ///< ?: conditional expression
ex_field_t field; ///< field reference expression
ex_array_t array; ///< array index expression
};
} expr_t;
@ -889,6 +903,8 @@ expr_t *new_with_expr (int mode, int reg, const expr_t *val);
expr_t *new_incop_expr (int op, const expr_t *e, bool postop);
expr_t *new_cond_expr (const expr_t *test, const expr_t *true_expr,
const expr_t *false_expr);
expr_t *new_field_expr (const expr_t *object, const expr_t *member);
expr_t *new_array_expr (const expr_t *base, const expr_t *index);
/** Create an expression of the correct type that references the specified
parameter slot.

View file

@ -71,6 +71,8 @@ EX_EXPR(list) ///< non-invasive list of expressions (::ex_list_t)
EX_EXPR(type) ///< type expression for generics
EX_EXPR(incop) ///< pre or post increment/decrement (::ex_incop_t)
EX_EXPR(cond) ///< ?: conditional expression (::ex_cond_t)
EX_EXPR(field) ///< field reference expression (::ex_field_t)
EX_EXPR(array) ///< array index ex_field_t (::ex_array_t)
#undef EX_EXPR

View file

@ -212,6 +212,10 @@ get_type (const expr_t *e)
//FIXME true_expr and false_expr need to have the same type,
//unless one is nil
return get_type (e->cond.true_expr);
case ex_field:
return e->field.type;
case ex_array:
return e->array.type;
case ex_count:
internal_error (e, "invalid expression");
}
@ -1949,6 +1953,11 @@ has_function_call (const expr_t *e)
return (has_function_call (e->cond.test)
|| has_function_call (e->cond.true_expr)
|| has_function_call (e->cond.false_expr));
case ex_field:
return has_function_call (e->field.object);
case ex_array:
return (has_function_call (e->array.base)
|| has_function_call (e->array.index));
case ex_count:
break;
}
@ -2505,6 +2514,29 @@ new_cond_expr (const expr_t *test, const expr_t *true_expr,
return cond;
}
expr_t *
new_field_expr (const expr_t *object, const expr_t *member)
{
auto field = new_expr ();
field->type = ex_field;
field->field = (ex_field_t) {
.object = object,
.member = member,
};
return field;
}
expr_t *
new_array_expr (const expr_t *base, const expr_t *index)
{
auto array = new_expr ();
array->type = ex_array;
array->array = (ex_array_t) {
.base = base,
.index = index,
};
return array;
}
const expr_t *
incop_expr (int op, const expr_t *e, int postop)

View file

@ -136,6 +136,10 @@ is_lvalue (const expr_t *expr)
case ex_cond:
return (is_lvalue (expr->cond.true_expr)
&& is_lvalue (expr->cond.false_expr));
case ex_field:
return 1;
case ex_array:
return 1;
case ex_count:
internal_error (expr, "invalid expression");
}

View file

@ -189,6 +189,20 @@ edag_add_expr (const expr_t *expr)
return e;
}
break;
case ex_field:
if (e->field.type == expr->field.type
&& e->field.object == expr->field.object
&& e->field.member == expr->field.member) {
return e;
}
break;
case ex_array:
if (e->array.type == expr->array.type
&& e->array.base == expr->array.base
&& e->array.index == expr->array.index) {
return e;
}
break;
}
}
DARRAY_APPEND (&expr_dag, expr);

View file

@ -75,6 +75,28 @@ proc_symbol (const expr_t *expr)
return expr;
}
static void
proc_do_list (ex_list_t *out, const ex_list_t *in)
{
int count = list_count (in);
const expr_t *exprs[count + 1];
list_scatter (in, exprs);
for (int i = 0; i < count; i++) {
exprs[i] = expr_process (exprs[i]);
}
list_gather (out, exprs, count);
}
static const expr_t *
proc_vector (const expr_t *expr)
{
auto vec = new_expr ();
vec->type = ex_vector;
vec->vector.type = expr->vector.type;
proc_do_list (&vec->vector.list, &expr->vector.list);
return vec;
}
static const expr_t *
proc_value (const expr_t *expr)
{
@ -92,15 +114,59 @@ proc_compound (const expr_t *expr)
return comp;
}
static const expr_t *
proc_assign (const expr_t *expr)
{
auto dst = expr_process (expr->assign.dst);
auto src = expr_process (expr->assign.src);
if (is_error (src)) {
return src;
}
if (is_error (src)) {
return src;
}
return assign_expr (dst, src);
}
static const expr_t *
proc_branch (const expr_t *expr)
{
if (expr->branch.type == pr_branch_call) {
auto args = new_list_expr (nullptr);
proc_do_list (&args->list, &expr->branch.args->list);
return function_expr (expr->branch.target, args);
} else {
auto branch = new_expr ();
branch->type = ex_branch;
branch->branch = expr->branch;
branch->branch.target = expr_process (expr->branch.target);
branch->branch.index = expr_process (expr->branch.index);
branch->branch.test = expr_process (expr->branch.test);
if (is_error (branch->branch.target)) {
return branch->branch.target;
}
if (is_error (branch->branch.index)) {
return branch->branch.index;
}
if (is_error (branch->branch.test)) {
return branch->branch.test;
}
return branch;
}
}
const expr_t *
expr_process (const expr_t *expr)
{
static process_f funcs[ex_count] = {
[ex_expr] = proc_expr,
[ex_uexpr] = proc_uexpr,
[ex_symbol] = proc_symbol,
[ex_vector] = proc_vector,
[ex_value] = proc_value,
[ex_compound] = proc_compound,
[ex_symbol] = proc_symbol,
[ex_assign] = proc_assign,
[ex_branch] = proc_branch,
};
if (expr->type >= ex_count) {

View file

@ -323,15 +323,15 @@ postfix_expression
: primary_exprsssion
| postfix_expression '[' integer_expression ']'
{
$$ = array_expr ($1, $3);
$$ = new_array_expr ($1, $3);
}
| function_call
| postfix_expression '.' IDENTIFIER/*FIELD_SELECTION*/
{
auto sym = new_symbol_expr ($3);
$$ = field_expr ($1, sym);
$$ = new_field_expr ($1, sym);
}
| postfix_expression INCOP { $$ = incop_expr ($2, $1, 1); }
| postfix_expression INCOP { $$ = new_incop_expr ($2, $1, 1); }
;
integer_expression
@ -354,7 +354,7 @@ function_call_or_method
auto func = exprs[count - 1];
auto args = new_list_expr (nullptr);
list_gather (&args->list, exprs, count - 1);
$$ = function_expr (func, args);
$$ = call_expr (func, args, nullptr);
}
;
@ -402,7 +402,7 @@ function_identifier
unary_expression
: postfix_expression
| INCOP unary_expression { $$ = incop_expr ($1, $2, 0); }
| INCOP unary_expression { $$ = new_incop_expr ($1, $2, 0); }
| unary_operator unary_expression { $$ = new_unary_expr ($1, $2); }
;
@ -1041,7 +1041,7 @@ statement
simple_statement
: declaration_statement
| expression_statement
| expression_statement { $$ = expr_process ($1); }//FIXME shouldn't be here
| selection_statement
| switch_statement
| case_label

View file

@ -2078,6 +2078,11 @@ expr_symbol (sblock_t *sblock, const expr_t *e, operand_t **op)
make_function (sym, 0, pr.symtab->space, sc_extern);
}
*op = def_operand (sym->metafunc->func->def, 0, e);
} else if (sym->sy_type == sy_convert) {
e = sym->convert.conv (sym, sym->convert.data);
return statement_subexpr (sblock, e, op);
} else if (sym->sy_type == sy_expr) {
return statement_subexpr (sblock, sym->expr, op);
} else {
internal_error (e, "unexpected symbol type: %s for %s",
symtype_str (sym->sy_type), sym->name);