mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-23 12:52:46 +00:00
Rework build_switch to use initialize_def.
This required support for label reference expressions, whose purpose is to represent the address of a label.
This commit is contained in:
parent
48fe9f729d
commit
9095e1eabc
7 changed files with 78 additions and 21 deletions
|
@ -45,6 +45,7 @@ typedef enum {
|
|||
ex_state, ///< state expression (::ex_state_t)
|
||||
ex_bool, ///< short circuit boolean logic expression (::ex_bool_t)
|
||||
ex_label, ///< goto/branch label (::ex_label_t)
|
||||
ex_labelref, ///< label reference (::ex_labelref_t)
|
||||
ex_block, ///< statement block expression (::ex_block_t)
|
||||
ex_expr, ///< binary expression (::ex_expr_t)
|
||||
ex_uexpr, ///< unary expression (::ex_expr_t)
|
||||
|
@ -69,13 +70,17 @@ typedef struct ex_expr_s {
|
|||
} ex_expr_t;
|
||||
|
||||
typedef struct ex_label_s {
|
||||
struct ex_label_s *next; ///< next label in global list of labels
|
||||
struct ex_label_s *next;
|
||||
struct reloc_s *refs; ///< relocations associated with this label
|
||||
struct sblock_s *dest; ///< the location of this label if known
|
||||
const char *name; ///< the name of this label
|
||||
int used; ///< label is used as a target
|
||||
} ex_label_t;
|
||||
|
||||
typedef struct {
|
||||
ex_label_t *label;
|
||||
} ex_labelref_t;
|
||||
|
||||
typedef struct {
|
||||
struct expr_s *head; ///< the first expression in the block
|
||||
struct expr_s **tail; ///< last expression in the block, for appending
|
||||
|
@ -179,6 +184,7 @@ typedef struct expr_s {
|
|||
unsigned rvalue:1; ///< the expression is on the right side of =
|
||||
union {
|
||||
ex_label_t label; ///< label expression
|
||||
ex_labelref_t labelref; ///< label reference expression (&)
|
||||
ex_state_t state; ///< state expression
|
||||
ex_bool_t bool; ///< boolean logic expression
|
||||
ex_block_t block; ///< statement block expression
|
||||
|
@ -253,13 +259,21 @@ const char *new_label_name (void);
|
|||
|
||||
/** Create a new label expression node.
|
||||
|
||||
The label name is set using new_label_name(), and the label is linked
|
||||
into the global list of labels for later resolution.
|
||||
The label name is set using new_label_name().
|
||||
|
||||
\return The new label expression (::ex_label_t) node.
|
||||
*/
|
||||
expr_t *new_label_expr (void);
|
||||
|
||||
/** Create a new label reference expression node.
|
||||
|
||||
Used for taking the address of a label (eg. jump tables).
|
||||
The label's \a used field is incremented.
|
||||
|
||||
\return The new label reference expression (::ex_labelref_t) node.
|
||||
*/
|
||||
expr_t *new_label_ref (ex_label_t *label);
|
||||
|
||||
/** Create a new state expression node.
|
||||
|
||||
The label name is set using new_label_name(), and the label is linked
|
||||
|
|
|
@ -1469,7 +1469,7 @@ fold_constants (expr_t *e)
|
|||
if (e2->type == ex_error)
|
||||
return e2;
|
||||
|
||||
if (e2->type == ex_label)
|
||||
if (e2->type == ex_label || e2->type == ex_labelref)
|
||||
return e;
|
||||
|
||||
t2 = extract_type (e2);
|
||||
|
|
|
@ -277,6 +277,12 @@ init_elements (struct def_s *def, expr_t *eles)
|
|||
}
|
||||
init_elements (&elements[i], c);
|
||||
continue;
|
||||
} else if (c->type == ex_labelref) {
|
||||
def_t loc;
|
||||
loc.space = elements[i].space;
|
||||
loc.offset = elements[i].offset;
|
||||
reloc_def_op (c->e.labelref.label, &loc);
|
||||
continue;
|
||||
} else if (c->type == ex_value) {
|
||||
if (c->e.value.type == ev_integer
|
||||
&& elements[i].type->type == ev_float)
|
||||
|
|
|
@ -155,6 +155,19 @@ print_label (expr_t *e, int level, int id)
|
|||
e->e.label.name, e->line);
|
||||
}
|
||||
|
||||
static void
|
||||
print_labelref (expr_t *e, int level, int id)
|
||||
{
|
||||
int indent = level * 2 + 2;
|
||||
|
||||
if (e->next)
|
||||
printf ("%*s\"e_%p\" -> \"e_%p\" "
|
||||
"[constraint=false,style=dashed];\n", indent, "",
|
||||
e, e->next);
|
||||
printf ("%*s\"e_%p\" [label=\"&%s\\n%d\"];\n", indent, "", e,
|
||||
e->e.label.name, e->line);
|
||||
}
|
||||
|
||||
static void
|
||||
print_block (expr_t *e, int level, int id)
|
||||
{
|
||||
|
@ -364,6 +377,7 @@ _print_expr (expr_t *e, int level, int id)
|
|||
print_state,
|
||||
print_bool,
|
||||
print_label,
|
||||
print_labelref,
|
||||
print_block,
|
||||
print_subexpr,
|
||||
print_uexpr,
|
||||
|
|
|
@ -140,6 +140,8 @@ get_type (expr_t *e)
|
|||
{
|
||||
convert_name (e);
|
||||
switch (e->type) {
|
||||
case ex_labelref:
|
||||
return &type_void;
|
||||
case ex_label:
|
||||
case ex_error:
|
||||
return 0; // something went very wrong
|
||||
|
@ -306,6 +308,8 @@ copy_expr (expr_t *e)
|
|||
case ex_label:
|
||||
/// Create a fresh label
|
||||
return new_label_expr ();
|
||||
case ex_labelref:
|
||||
return new_label_ref (e->e.labelref.label);
|
||||
case ex_block:
|
||||
n = new_expr ();
|
||||
*n = *e;
|
||||
|
@ -407,6 +411,18 @@ new_label_expr (void)
|
|||
return l;
|
||||
}
|
||||
|
||||
expr_t *
|
||||
new_label_ref (ex_label_t *label)
|
||||
{
|
||||
|
||||
expr_t *l = new_expr ();
|
||||
|
||||
l->type = ex_labelref;
|
||||
l->e.labelref.label = label;
|
||||
label->used++;
|
||||
return l;
|
||||
}
|
||||
|
||||
expr_t *
|
||||
new_block_expr (void)
|
||||
{
|
||||
|
@ -607,7 +623,7 @@ new_short_expr (short short_val)
|
|||
int
|
||||
is_constant (expr_t *e)
|
||||
{
|
||||
if (e->type == ex_nil || e->type == ex_value
|
||||
if (e->type == ex_nil || e->type == ex_value || e->type == ex_labelref
|
||||
|| (e->type == ex_symbol && e->e.symbol->sy_type == sy_const)
|
||||
|| (e->type == ex_symbol && e->e.symbol->sy_type == sy_var
|
||||
&& e->e.symbol->s.def->constant))
|
||||
|
@ -624,7 +640,7 @@ constant_expr (expr_t *e)
|
|||
|
||||
if (!is_constant (e))
|
||||
return e;
|
||||
if (e->type == ex_nil || e->type == ex_value)
|
||||
if (e->type == ex_nil || e->type == ex_value || e->type == ex_labelref)
|
||||
return e;
|
||||
if (e->type != ex_symbol)
|
||||
return e;
|
||||
|
@ -1623,6 +1639,7 @@ unary_expr (int op, expr_t *e)
|
|||
case ex_value: // should be handled above
|
||||
case ex_error:
|
||||
case ex_label:
|
||||
case ex_labelref:
|
||||
case ex_state:
|
||||
internal_error (e, 0);
|
||||
case ex_uexpr:
|
||||
|
@ -1685,6 +1702,7 @@ unary_expr (int op, expr_t *e)
|
|||
case ex_value: // should be handled above
|
||||
case ex_error:
|
||||
case ex_label:
|
||||
case ex_labelref:
|
||||
case ex_state:
|
||||
internal_error (e, 0);
|
||||
case ex_bool:
|
||||
|
@ -1742,6 +1760,7 @@ unary_expr (int op, expr_t *e)
|
|||
case ex_value: // should be handled above
|
||||
case ex_error:
|
||||
case ex_label:
|
||||
case ex_labelref:
|
||||
case ex_state:
|
||||
internal_error (e, 0);
|
||||
case ex_uexpr:
|
||||
|
@ -2217,6 +2236,8 @@ address_expr (expr_t *e1, expr_t *e2, type_t *t)
|
|||
return error (e1, "invalid type for unary &");
|
||||
e1->e.block.result = address_expr (e1->e.block.result, e2, t);
|
||||
return e1;
|
||||
case ex_label:
|
||||
return new_label_ref (&e1->e.label);
|
||||
default:
|
||||
return error (e1, "invalid type for unary &");
|
||||
}
|
||||
|
|
|
@ -830,6 +830,7 @@ statement_subexpr (sblock_t *sblock, expr_t *e, operand_t **op)
|
|||
0, // ex_state
|
||||
0, // ex_bool
|
||||
0, // ex_label
|
||||
0, // ex_labelref
|
||||
expr_block, // ex_block
|
||||
expr_expr,
|
||||
expr_uexpr,
|
||||
|
@ -1107,6 +1108,7 @@ statement_slist (sblock_t *sblock, expr_t *e)
|
|||
statement_state,
|
||||
statement_bool,
|
||||
statement_label,
|
||||
0, // ex_labelref
|
||||
statement_block,
|
||||
statement_expr,
|
||||
statement_uexpr,
|
||||
|
|
|
@ -327,18 +327,25 @@ build_switch (expr_t *sw, case_node_t *tree, int op, expr_t *sw_val,
|
|||
} else {
|
||||
int low = expr_integer (tree->low);
|
||||
int high = expr_integer (tree->high);
|
||||
symbol_t *sym;
|
||||
expr_t *table;
|
||||
const char *name = new_label_name ();
|
||||
symbol_t *table_sym;
|
||||
expr_t *table_expr;
|
||||
expr_t *table_init;
|
||||
const char *table_name = new_label_name ();
|
||||
int i;
|
||||
expr_t *range = binary_expr ('-', tree->high, tree->low);
|
||||
|
||||
range = fold_constants (range);
|
||||
|
||||
sym = make_symbol (name, array_type (&type_integer, high - low + 1),
|
||||
pr.near_data, st_static);
|
||||
table = new_symbol_expr (sym);
|
||||
table = new_alias_expr (&type_integer, table);
|
||||
table_init = new_block_expr ();
|
||||
for (i = 0; i <= high - low; i++) {
|
||||
tree->labels[i]->e.label.used++;
|
||||
append_expr (table_init, address_expr (tree->labels[i], 0, 0));
|
||||
}
|
||||
table_sym = new_symbol (table_name);
|
||||
initialize_def (table_sym, array_type (&type_integer, high - low + 1),
|
||||
table_init, pr.near_data, st_static);
|
||||
table_expr = new_symbol_expr (table_sym);
|
||||
table_expr = new_alias_expr (&type_integer, table_expr);
|
||||
|
||||
if (tree->left) {
|
||||
branch = branch_expr (IFB, temp, low_label);
|
||||
|
@ -348,7 +355,7 @@ build_switch (expr_t *sw, case_node_t *tree, int op, expr_t *sw_val,
|
|||
cast_expr (&type_uinteger, range));
|
||||
branch = branch_expr ('i', test, high_label);
|
||||
append_expr (sw, branch);
|
||||
branch = new_binary_expr ('g', table, temp);
|
||||
branch = new_binary_expr ('g', table_expr, temp);
|
||||
append_expr (sw, branch);
|
||||
if (tree->left) {
|
||||
append_expr (sw, low_label);
|
||||
|
@ -358,13 +365,6 @@ build_switch (expr_t *sw, case_node_t *tree, int op, expr_t *sw_val,
|
|||
append_expr (sw, high_label);
|
||||
build_switch (sw, tree->right, op, sw_val, temp, default_label);
|
||||
}
|
||||
for (i = 0; i <= high - low; i++) {
|
||||
def_t loc;
|
||||
loc.space = sym->s.def->space;
|
||||
loc.offset = sym->s.def->offset + i;
|
||||
tree->labels[i]->e.label.used++;
|
||||
reloc_def_op (&tree->labels[i]->e.label, &loc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue