mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-02-25 13:11:00 +00:00
[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:
parent
feca9bd5cb
commit
a7639a685e
8 changed files with 146 additions and 7 deletions
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue