mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-02-25 13:11:00 +00:00
[qfcc] Add xvalue expressions and symbols
xvalue symbols refer to two expressions: an lvalue and an rvalue. They are meant to be used with xvalue expressions. xvalue expressions are useful when a distinction must be made between the behavior of something (eg, a pascal function symbol) must change depending on whether it's an lvalue (assignment of the function's return value) or an rvalue (a call to the function, especially when the function takes no parameters).
This commit is contained in:
parent
ed984e6eae
commit
1e19335b44
9 changed files with 83 additions and 0 deletions
|
@ -397,6 +397,11 @@ typedef struct {
|
||||||
const expr_t *end_value; ///< for case value ranges (otherwise null)
|
const expr_t *end_value; ///< for case value ranges (otherwise null)
|
||||||
} ex_caselabel_t;
|
} ex_caselabel_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const expr_t *expr;
|
||||||
|
bool lvalue; ///< rvalue if false
|
||||||
|
} ex_xvalue_t;
|
||||||
|
|
||||||
typedef struct expr_s {
|
typedef struct expr_s {
|
||||||
expr_t *next;
|
expr_t *next;
|
||||||
rua_loc_t loc; ///< source location of expression
|
rua_loc_t loc; ///< source location of expression
|
||||||
|
@ -449,6 +454,7 @@ typedef struct expr_s {
|
||||||
ex_intrinsic_t intrinsic; ///< intrinsic intruction expression
|
ex_intrinsic_t intrinsic; ///< intrinsic intruction expression
|
||||||
ex_switch_t switchblock; ///< switch block expression
|
ex_switch_t switchblock; ///< switch block expression
|
||||||
ex_caselabel_t caselabel; ///< case label expression
|
ex_caselabel_t caselabel; ///< case label expression
|
||||||
|
ex_xvalue_t xvalue; ///< lvalue/rvalue specific expression
|
||||||
};
|
};
|
||||||
} expr_t;
|
} expr_t;
|
||||||
|
|
||||||
|
@ -1015,6 +1021,7 @@ expr_t *new_intrinsic_expr (const expr_t *expr_list);
|
||||||
expr_t *new_switch_expr (const expr_t *test, const expr_t *body,
|
expr_t *new_switch_expr (const expr_t *test, const expr_t *body,
|
||||||
const expr_t *break_label);
|
const expr_t *break_label);
|
||||||
expr_t *new_caselabel_expr (const expr_t *value, const expr_t *end_value);
|
expr_t *new_caselabel_expr (const expr_t *value, const expr_t *end_value);
|
||||||
|
expr_t *new_xvalue_expr (const expr_t *expr, bool lvalue);
|
||||||
|
|
||||||
/** 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.
|
||||||
|
|
|
@ -80,6 +80,7 @@ EX_EXPR(select) ///< select construct expression (::ex_select_t)
|
||||||
EX_EXPR(intrinsic) ///< intrinsic instruction expression (::ex_intrinsic_t)
|
EX_EXPR(intrinsic) ///< intrinsic instruction expression (::ex_intrinsic_t)
|
||||||
EX_EXPR(switch) ///< switch expression (::ex_switch_t)
|
EX_EXPR(switch) ///< switch expression (::ex_switch_t)
|
||||||
EX_EXPR(caselabel) ///< case expression (::ex_caselabel_t)
|
EX_EXPR(caselabel) ///< case expression (::ex_caselabel_t)
|
||||||
|
EX_EXPR(xvalue) ///< xvalue expression (::ex_xvalue_t)
|
||||||
|
|
||||||
#undef EX_EXPR
|
#undef EX_EXPR
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,7 @@ SY_TYPE(convert) ///< symbol refers to a conversion function
|
||||||
SY_TYPE(macro) ///< symbol refers to a macro definition
|
SY_TYPE(macro) ///< symbol refers to a macro definition
|
||||||
SY_TYPE(namespace) ///< symbol refers to a namespace definition
|
SY_TYPE(namespace) ///< symbol refers to a namespace definition
|
||||||
SY_TYPE(list)
|
SY_TYPE(list)
|
||||||
|
SY_TYPE(xvalue) ///< symbol has different lvalue and rvalue
|
||||||
|
|
||||||
#undef SY_TYPE
|
#undef SY_TYPE
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,11 @@ typedef struct symconv_s {
|
||||||
void *data;
|
void *data;
|
||||||
} symconv_t;
|
} symconv_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const expr_t *lvalue;
|
||||||
|
const expr_t *rvalue;
|
||||||
|
} sy_xvalue_t;
|
||||||
|
|
||||||
typedef struct var_s {
|
typedef struct var_s {
|
||||||
enum storage_class_e storage;
|
enum storage_class_e storage;
|
||||||
} var_t;
|
} var_t;
|
||||||
|
@ -87,6 +92,7 @@ typedef struct symbol_s {
|
||||||
struct rua_macro_s *macro; ///< sy_macro
|
struct rua_macro_s *macro; ///< sy_macro
|
||||||
struct symtab_s *namespace; ///< sy_namespace
|
struct symtab_s *namespace; ///< sy_namespace
|
||||||
ex_list_t list; ///< sy_list
|
ex_list_t list; ///< sy_list
|
||||||
|
sy_xvalue_t xvalue; ///< sy_xvalue
|
||||||
};
|
};
|
||||||
} symbol_t;
|
} symbol_t;
|
||||||
|
|
||||||
|
|
|
@ -472,6 +472,20 @@ print_intrinsic (dstring_t *dstr, const expr_t *e, int level, int id,
|
||||||
"@intrinsic", e->loc.line);
|
"@intrinsic", e->loc.line);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_xvalue (dstring_t *dstr, const expr_t *e, int level, int id,
|
||||||
|
const expr_t *next)
|
||||||
|
{
|
||||||
|
int indent = level * 2 + 2;
|
||||||
|
|
||||||
|
_print_expr (dstr, e->xvalue.expr, level, id, next);
|
||||||
|
dasprintf (dstr, "%*se_%p -> \"e_%p\";\n", indent, "", e, e->xvalue.expr);
|
||||||
|
const char *b = e->xvalue.lvalue ? "Q" : "";
|
||||||
|
const char *a = e->xvalue.lvalue ? "" : "Q";
|
||||||
|
dasprintf (dstr, "%*se_%p [label=\"%s%c%s\\n%d\"];\n", indent, "", e,
|
||||||
|
b, '=', a, e->loc.line);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
print_subexpr (dstring_t *dstr, const expr_t *e, int level, int id, const expr_t *next)
|
print_subexpr (dstring_t *dstr, const expr_t *e, int level, int id, const expr_t *next)
|
||||||
{
|
{
|
||||||
|
@ -932,6 +946,7 @@ _print_expr (dstring_t *dstr, const expr_t *e, int level, int id,
|
||||||
[ex_loop] = nullptr,
|
[ex_loop] = nullptr,
|
||||||
[ex_select] = print_select,
|
[ex_select] = print_select,
|
||||||
[ex_intrinsic] = print_intrinsic,
|
[ex_intrinsic] = print_intrinsic,
|
||||||
|
[ex_xvalue] = print_xvalue,
|
||||||
};
|
};
|
||||||
int indent = level * 2 + 2;
|
int indent = level * 2 + 2;
|
||||||
|
|
||||||
|
|
|
@ -81,6 +81,9 @@ get_type (const expr_t *e)
|
||||||
}
|
}
|
||||||
type = get_type (e->inout.out);
|
type = get_type (e->inout.out);
|
||||||
break;
|
break;
|
||||||
|
case ex_xvalue:
|
||||||
|
bug (e, "should xvalue happen here?");
|
||||||
|
return get_type (e->xvalue.expr);
|
||||||
case ex_branch:
|
case ex_branch:
|
||||||
type = e->branch.ret_type;
|
type = e->branch.ret_type;
|
||||||
break;
|
break;
|
||||||
|
@ -1991,6 +1994,9 @@ has_function_call (const expr_t *e)
|
||||||
|| has_function_call (e->array.index));
|
|| has_function_call (e->array.index));
|
||||||
case ex_switch:
|
case ex_switch:
|
||||||
return has_function_call (e->switchblock.test);
|
return has_function_call (e->switchblock.test);
|
||||||
|
case ex_xvalue:
|
||||||
|
bug (e, "should xvalue happen here?");
|
||||||
|
return has_function_call (e->xvalue.expr);
|
||||||
case ex_count:
|
case ex_count:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -2304,6 +2310,18 @@ new_caselabel_expr (const expr_t *value, const expr_t *end_value)
|
||||||
return cl;
|
return cl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
expr_t *
|
||||||
|
new_xvalue_expr (const expr_t *expr, bool lvalue)
|
||||||
|
{
|
||||||
|
auto xv = new_expr ();
|
||||||
|
xv->type = ex_xvalue;
|
||||||
|
xv->xvalue = (ex_xvalue_t) {
|
||||||
|
.expr = expr,
|
||||||
|
.lvalue = lvalue,
|
||||||
|
};
|
||||||
|
return xv;
|
||||||
|
}
|
||||||
|
|
||||||
expr_t *
|
expr_t *
|
||||||
new_decl (symbol_t *sym, const expr_t *init)
|
new_decl (symbol_t *sym, const expr_t *init)
|
||||||
{
|
{
|
||||||
|
|
|
@ -148,6 +148,12 @@ is_lvalue (const expr_t *expr)
|
||||||
return true;
|
return true;
|
||||||
case ex_array:
|
case ex_array:
|
||||||
return true;
|
return true;
|
||||||
|
case ex_xvalue:
|
||||||
|
bug (expr, "should xvalue happen here?");
|
||||||
|
if (expr->xvalue.lvalue) {
|
||||||
|
return is_lvalue (expr->xvalue.expr);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
case ex_count:
|
case ex_count:
|
||||||
internal_error (expr, "invalid expression");
|
internal_error (expr, "invalid expression");
|
||||||
}
|
}
|
||||||
|
|
|
@ -210,6 +210,16 @@ edag_add_expr (const expr_t *expr)
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case ex_xvalue:
|
||||||
|
bug (expr, "should xvalue happen here?");
|
||||||
|
if (e->xvalue.expr == expr->xvalue.expr
|
||||||
|
&& e->xvalue.lvalue == expr->xvalue.lvalue) {
|
||||||
|
// never dag an lvalue
|
||||||
|
if (!e->xvalue.lvalue) {
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DARRAY_APPEND (&expr_dag, expr);
|
DARRAY_APPEND (&expr_dag, expr);
|
||||||
|
|
|
@ -644,6 +644,24 @@ proc_caselabel (const expr_t *expr, rua_ctx_t *ctx)
|
||||||
return current_target.proc_caselabel (expr, ctx);
|
return current_target.proc_caselabel (expr, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const expr_t *
|
||||||
|
proc_xvalue (const expr_t *expr, rua_ctx_t *ctx)
|
||||||
|
{
|
||||||
|
auto xvalue = expr->xvalue.expr;
|
||||||
|
if (xvalue->type == ex_symbol && xvalue->symbol->sy_type == sy_xvalue) {
|
||||||
|
if (expr->xvalue.lvalue) {
|
||||||
|
auto xv = xvalue->symbol->xvalue.lvalue;
|
||||||
|
if (!xv || !is_lvalue (xv)) {
|
||||||
|
return error (xv, "invalid lvalue");
|
||||||
|
}
|
||||||
|
xvalue = xv;
|
||||||
|
} else {
|
||||||
|
xvalue = xvalue->symbol->xvalue.rvalue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return expr_process (xvalue, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
const expr_t *
|
const expr_t *
|
||||||
expr_process (const expr_t *expr, rua_ctx_t *ctx)
|
expr_process (const expr_t *expr, rua_ctx_t *ctx)
|
||||||
{
|
{
|
||||||
|
@ -677,6 +695,7 @@ expr_process (const expr_t *expr, rua_ctx_t *ctx)
|
||||||
[ex_intrinsic] = proc_intrinsic,
|
[ex_intrinsic] = proc_intrinsic,
|
||||||
[ex_switch] = proc_switch,
|
[ex_switch] = proc_switch,
|
||||||
[ex_caselabel] = proc_caselabel,
|
[ex_caselabel] = proc_caselabel,
|
||||||
|
[ex_xvalue] = proc_xvalue,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (expr->type >= ex_count) {
|
if (expr->type >= ex_count) {
|
||||||
|
|
Loading…
Reference in a new issue