mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-02-25 21:21:14 +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;
|
const expr_t *false_expr;
|
||||||
} ex_cond_t;
|
} 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)
|
#define POINTER_VAL(p) (((p).def ? (p).def->offset : 0) + (p).val)
|
||||||
|
|
||||||
typedef struct expr_s {
|
typedef struct expr_s {
|
||||||
|
@ -378,6 +390,8 @@ typedef struct expr_s {
|
||||||
ex_type_t typ; ///< type expression
|
ex_type_t typ; ///< type expression
|
||||||
ex_incop_t incop; ///< incop expression
|
ex_incop_t incop; ///< incop expression
|
||||||
ex_cond_t cond; ///< ?: conditional expression
|
ex_cond_t cond; ///< ?: conditional expression
|
||||||
|
ex_field_t field; ///< field reference expression
|
||||||
|
ex_array_t array; ///< array index expression
|
||||||
};
|
};
|
||||||
} expr_t;
|
} 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_incop_expr (int op, const expr_t *e, bool postop);
|
||||||
expr_t *new_cond_expr (const expr_t *test, const expr_t *true_expr,
|
expr_t *new_cond_expr (const expr_t *test, const expr_t *true_expr,
|
||||||
const expr_t *false_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
|
/** Create an expression of the correct type that references the specified
|
||||||
parameter slot.
|
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(type) ///< type expression for generics
|
||||||
EX_EXPR(incop) ///< pre or post increment/decrement (::ex_incop_t)
|
EX_EXPR(incop) ///< pre or post increment/decrement (::ex_incop_t)
|
||||||
EX_EXPR(cond) ///< ?: conditional expression (::ex_cond_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
|
#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,
|
//FIXME true_expr and false_expr need to have the same type,
|
||||||
//unless one is nil
|
//unless one is nil
|
||||||
return get_type (e->cond.true_expr);
|
return get_type (e->cond.true_expr);
|
||||||
|
case ex_field:
|
||||||
|
return e->field.type;
|
||||||
|
case ex_array:
|
||||||
|
return e->array.type;
|
||||||
case ex_count:
|
case ex_count:
|
||||||
internal_error (e, "invalid expression");
|
internal_error (e, "invalid expression");
|
||||||
}
|
}
|
||||||
|
@ -1949,6 +1953,11 @@ has_function_call (const expr_t *e)
|
||||||
return (has_function_call (e->cond.test)
|
return (has_function_call (e->cond.test)
|
||||||
|| has_function_call (e->cond.true_expr)
|
|| has_function_call (e->cond.true_expr)
|
||||||
|| has_function_call (e->cond.false_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:
|
case ex_count:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -2505,6 +2514,29 @@ new_cond_expr (const expr_t *test, const expr_t *true_expr,
|
||||||
return cond;
|
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 *
|
const expr_t *
|
||||||
incop_expr (int op, const expr_t *e, int postop)
|
incop_expr (int op, const expr_t *e, int postop)
|
||||||
|
|
|
@ -136,6 +136,10 @@ is_lvalue (const expr_t *expr)
|
||||||
case ex_cond:
|
case ex_cond:
|
||||||
return (is_lvalue (expr->cond.true_expr)
|
return (is_lvalue (expr->cond.true_expr)
|
||||||
&& is_lvalue (expr->cond.false_expr));
|
&& is_lvalue (expr->cond.false_expr));
|
||||||
|
case ex_field:
|
||||||
|
return 1;
|
||||||
|
case ex_array:
|
||||||
|
return 1;
|
||||||
case ex_count:
|
case ex_count:
|
||||||
internal_error (expr, "invalid expression");
|
internal_error (expr, "invalid expression");
|
||||||
}
|
}
|
||||||
|
|
|
@ -189,6 +189,20 @@ edag_add_expr (const expr_t *expr)
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
break;
|
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);
|
DARRAY_APPEND (&expr_dag, expr);
|
||||||
|
|
|
@ -75,6 +75,28 @@ proc_symbol (const expr_t *expr)
|
||||||
return 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 *
|
static const expr_t *
|
||||||
proc_value (const expr_t *expr)
|
proc_value (const expr_t *expr)
|
||||||
{
|
{
|
||||||
|
@ -92,15 +114,59 @@ proc_compound (const expr_t *expr)
|
||||||
return comp;
|
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 *
|
const expr_t *
|
||||||
expr_process (const expr_t *expr)
|
expr_process (const expr_t *expr)
|
||||||
{
|
{
|
||||||
static process_f funcs[ex_count] = {
|
static process_f funcs[ex_count] = {
|
||||||
[ex_expr] = proc_expr,
|
[ex_expr] = proc_expr,
|
||||||
[ex_uexpr] = proc_uexpr,
|
[ex_uexpr] = proc_uexpr,
|
||||||
|
[ex_symbol] = proc_symbol,
|
||||||
|
[ex_vector] = proc_vector,
|
||||||
[ex_value] = proc_value,
|
[ex_value] = proc_value,
|
||||||
[ex_compound] = proc_compound,
|
[ex_compound] = proc_compound,
|
||||||
[ex_symbol] = proc_symbol,
|
[ex_assign] = proc_assign,
|
||||||
|
[ex_branch] = proc_branch,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (expr->type >= ex_count) {
|
if (expr->type >= ex_count) {
|
||||||
|
|
|
@ -323,15 +323,15 @@ postfix_expression
|
||||||
: primary_exprsssion
|
: primary_exprsssion
|
||||||
| postfix_expression '[' integer_expression ']'
|
| postfix_expression '[' integer_expression ']'
|
||||||
{
|
{
|
||||||
$$ = array_expr ($1, $3);
|
$$ = new_array_expr ($1, $3);
|
||||||
}
|
}
|
||||||
| function_call
|
| function_call
|
||||||
| postfix_expression '.' IDENTIFIER/*FIELD_SELECTION*/
|
| postfix_expression '.' IDENTIFIER/*FIELD_SELECTION*/
|
||||||
{
|
{
|
||||||
auto sym = new_symbol_expr ($3);
|
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
|
integer_expression
|
||||||
|
@ -354,7 +354,7 @@ function_call_or_method
|
||||||
auto func = exprs[count - 1];
|
auto func = exprs[count - 1];
|
||||||
auto args = new_list_expr (nullptr);
|
auto args = new_list_expr (nullptr);
|
||||||
list_gather (&args->list, exprs, count - 1);
|
list_gather (&args->list, exprs, count - 1);
|
||||||
$$ = function_expr (func, args);
|
$$ = call_expr (func, args, nullptr);
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -402,7 +402,7 @@ function_identifier
|
||||||
|
|
||||||
unary_expression
|
unary_expression
|
||||||
: postfix_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); }
|
| unary_operator unary_expression { $$ = new_unary_expr ($1, $2); }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -1041,7 +1041,7 @@ statement
|
||||||
|
|
||||||
simple_statement
|
simple_statement
|
||||||
: declaration_statement
|
: declaration_statement
|
||||||
| expression_statement
|
| expression_statement { $$ = expr_process ($1); }//FIXME shouldn't be here
|
||||||
| selection_statement
|
| selection_statement
|
||||||
| switch_statement
|
| switch_statement
|
||||||
| case_label
|
| 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);
|
make_function (sym, 0, pr.symtab->space, sc_extern);
|
||||||
}
|
}
|
||||||
*op = def_operand (sym->metafunc->func->def, 0, e);
|
*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 {
|
} else {
|
||||||
internal_error (e, "unexpected symbol type: %s for %s",
|
internal_error (e, "unexpected symbol type: %s for %s",
|
||||||
symtype_str (sym->sy_type), sym->name);
|
symtype_str (sym->sy_type), sym->name);
|
||||||
|
|
Loading…
Reference in a new issue