pr_comp.h:

o	add OP_JUMPB
	o	OP_JUMPB renumberd some opcodes, so up PROG_VERSION
pr_edict.c:
	o	make the version error reporting more informative
pr_exec.c:
	o	implement OP_JUMPB (goto *(ptr + index))
pr_opcode.c: (libs/gamecode/engine)
	o	add OP_JUMPB to the table
expr.h:
	o	ex_uinteger support
	o	some const correctness
	o	prototype new_label_expr
qfcc.h:
	o	uinteger ussport
	o	add pointers for op_jump and op_jumpb
	o	prototype PR_GetArray
emit.c:
	o	general uinteger support
	o	new reference/reloc type 3: absolute statement address
	o	jumpb support (binary goto)
expr.c:
	o	uinteger support
	o	break the label name creation out of new_label_expr into
		new_label_name
	o	some const correctness
pr_def.c:
	o	add PR_GetArray to allocate an array in global space
	o	factor out some code common to PR_GetDef and PR_GetArray that would
		otherwise be duplicated
pr_imm.c:
	o	some const correctness
	o	uinteger support
pr_lex.c:
	o	uinteger support
pr_opcode.c: (tools/qfcc/source)
	o	support jump and jumpb
switch.c:
	o	rewrite the binary search code to support ranges.
This commit is contained in:
Bill Currie 2001-11-13 08:58:54 +00:00
parent 748dc49218
commit 07b59d2f07
13 changed files with 318 additions and 60 deletions

View file

@ -211,6 +211,7 @@ typedef enum {
OP_IFA,
OP_JUMP,
OP_JUMPB,
OP_LT_UI,
OP_GT_UI,
@ -268,7 +269,7 @@ typedef struct
#define PROG_ID_VERSION 6
#define PROG_VERSION 0x00fff001 // MMmmmRRR 0.fff.001 (hex)
#define PROG_VERSION 0x00fff002 // MMmmmRRR 0.fff.002 (hex)
typedef struct
{

View file

@ -1094,9 +1094,23 @@ PR_LoadProgsFile (progs_t * pr, const char *progsname)
((int *) pr->progs)[i] = LittleLong (((int *) pr->progs)[i]);
if (pr->progs->version != PROG_VERSION
&& pr->progs->version != PROG_ID_VERSION)
PR_Error (pr, "%s has unrecognised version number (%08x)",
progsname, pr->progs->version);
&& pr->progs->version != PROG_ID_VERSION) {
if (pr->progs->version < 0x00fff000) {
PR_Error (pr, "%s has unrecognised version number (%d)",
progsname, pr->progs->version);
} else {
PR_Error (pr,
"%s has unrecognised version number (%02x.%03x.%03x)"
" [%02x.%03x.%03x expected]",
progsname,
pr->progs->version >> 24,
(pr->progs->version >> 12) & 0xfff,
pr->progs->version & 0xfff,
PROG_VERSION >> 24,
(PROG_VERSION >> 12) & 0xfff,
PROG_VERSION & 0xfff);
}
}
pr->progs_name = progsname; //XXX is this safe?

View file

@ -623,6 +623,19 @@ PR_ExecuteProgram (progs_t * pr, func_t fnum)
}
st = &pr->pr_statements[OPA.uinteger_var];
break;
case OP_JUMPB:
//FIXME put bounds checking in
pointer = OPA.integer_var + OPB.integer_var;
ptr = pr->pr_globals + pointer;
pointer = ptr->integer_var;
if (pr_boundscheck->int_val
&& (pointer >= pr->progs->numstatements)) {
pr->pr_xstatement = st - pr->pr_statements;
PR_RunError (pr, "Invalid jump destination\n");
return;
}
st = &pr->pr_statements[pointer];
break;
case OP_CALL0:
case OP_CALL1:

View file

@ -166,6 +166,7 @@ opcode_t pr_opcodes[] = {
{"<GOTO>", "goto", OP_GOTO, false, ev_integer, ev_void, ev_void, PROG_ID_VERSION},
{"<JUMP>", "jump", OP_JUMP, false, ev_integer, ev_void, ev_void, PROG_VERSION},
{"<JUMPB>", "jumpb", OP_JUMPB, false, ev_pointer, ev_integer, ev_void, PROG_VERSION},
{"&&", "and", OP_AND, false, ev_float, ev_float, ev_integer, PROG_ID_VERSION},
{"||", "or", OP_OR, false, ev_float, ev_float, ev_integer, PROG_ID_VERSION},

View file

@ -16,12 +16,13 @@ typedef enum {
ex_pointer,
ex_quaternion,
ex_integer,
ex_uinteger,
} expr_type;
typedef struct {
statref_t *refs;
dstatement_t *statement;
char *name;
const char *name;
} elabel_t;
typedef struct {
@ -56,7 +57,7 @@ typedef struct expr_s {
def_t *def;
temp_t temp;
char *string_val;
const char *string_val;
float float_val;
float vector_val[3];
int entity_val;
@ -65,6 +66,7 @@ typedef struct expr_s {
int pointer_val;
float quaternion_val[4];
int integer_val;
int uinteger_val;
} e;
} expr_t;
@ -76,6 +78,7 @@ type_t *get_type (expr_t *e);
etype_t extract_type (expr_t *e);
expr_t *new_expr (void);
const char *new_label_name (void);
expr_t *new_label_expr (void);
expr_t *new_block_expr (void);
expr_t *new_binary_expr (int op, expr_t *e1, expr_t *e2);

View file

@ -342,6 +342,7 @@ extern type_t type_pointer;
extern type_t type_floatfield;
extern type_t type_quaternion;
extern type_t type_integer;
extern type_t type_uinteger;
extern def_t def_void;
extern def_t def_string;
@ -353,6 +354,7 @@ extern def_t def_function;
extern def_t def_pointer;
extern def_t def_quaternion;
extern def_t def_integer;
extern def_t def_uinteger;
struct function_s
{
@ -397,6 +399,8 @@ extern opcode_t *op_ifae;
extern opcode_t *op_ifa;
extern opcode_t *op_state;
extern opcode_t *op_goto;
extern opcode_t *op_jump;
extern opcode_t *op_jumpb;
statref_t *PR_NewStatref (dstatement_t *st, int field);
void PR_AddStatementRef (def_t *def, dstatement_t *st, int field);
@ -466,6 +470,9 @@ extern def_t *pr_scope;
extern int pr_error_count;
void PR_NewLine (void);
def_t *PR_GetArray (type_t *etype, const char *name, int size, def_t *scope,
int *allocate);
def_t *PR_GetDef (type_t *type, const char *name, def_t *scope,
int *allocate);
def_t *PR_NewDef (type_t *type, const char *name, def_t *scope);

View file

@ -288,6 +288,7 @@ emit_sub_expr (expr_t *e, def_t *dest)
case ex_pointer:
case ex_quaternion:
case ex_integer:
case ex_uinteger:
d = PR_ReuseConstant (e, 0);
break;
}
@ -319,6 +320,9 @@ emit_expr (expr_t *e)
case 2:
ref->statement->c = label->statement - ref->statement;
break;
case 3:
*(int*)ref->statement = label->statement - statements;
break;
default:
abort();
}
@ -366,6 +370,11 @@ emit_expr (expr_t *e)
}
e->e.expr.e2->e.temp.def = emit_sub_expr (e->e.expr.e1, e->e.expr.e2->e.temp.def);
break;
case 'g':
def_a = emit_sub_expr (e->e.expr.e1, 0);
def_b = emit_sub_expr (e->e.expr.e2, 0);
emit_statement (e->line, op_jumpb, def_a, def_b, 0);
break;
default:
warning (e, "Ignoring useless expression");
break;
@ -399,6 +408,7 @@ emit_expr (expr_t *e)
case ex_pointer:
case ex_quaternion:
case ex_integer:
case ex_uinteger:
warning (e, "Ignoring useless expression");
break;
case ex_nil:

View file

@ -61,6 +61,7 @@ etype_t qc_types[] = {
ev_pointer, // ex_pointer
ev_quaternion, // ex_quaternion
ev_integer, // ex_integer
ev_uinteger, // ex_uinteger
};
type_t *types[] = {
@ -74,6 +75,7 @@ type_t *types[] = {
&type_pointer,
&type_quaternion,
&type_integer,
&type_uinteger,
};
expr_type expr_types[] = {
@ -87,6 +89,7 @@ expr_type expr_types[] = {
ex_pointer, // ev_pointer
ex_quaternion, // ev_quaternion
ex_integer, // ev_integer
ex_uinteger, // ev_uinteger
};
type_t *
@ -122,6 +125,7 @@ get_type (expr_t *e)
case ex_func:
case ex_pointer:
case ex_quaternion:
case ex_uinteger:
return types[qc_types[e->type]];
}
return 0;
@ -287,20 +291,27 @@ num_digits (int val)
return num;
}
expr_t *
new_label_expr (void)
const char *
new_label_name (void)
{
static int label = 0;
int lnum = ++label;
const char *fname = current_func->def->name;
int len = 1 + strlen (fname) + 1 + num_digits (lnum) + 1;
char *lname = malloc (len);
if (!lname)
Sys_Error ("new_label_expr: Memory Allocation Failure\n");
sprintf (lname, "$%s_%d", fname, lnum);
return lname;
}
expr_t *
new_label_expr (void)
{
expr_t *l = new_expr ();
l->type = ex_label;
l->e.label.name = malloc (len);
if (!l->e.label.name)
Sys_Error ("new_label_expr: Memory Allocation Failure\n");
sprintf (l->e.label.name, "$%s_%d", fname, lnum);
l->e.label.name = new_label_name ();
return l;
}
@ -482,7 +493,7 @@ do_op_string (int op, expr_t *e1, expr_t *e2)
{
int len;
char *buf;
char *s1, *s2;
const char *s1, *s2;
s1 = e1->e.string_val ? e1->e.string_val : "";
s2 = e2->e.string_val ? e2->e.string_val : "";

View file

@ -52,17 +52,10 @@ defs_get_key (void *_def, void *_tab)
return "";
}
/*
PR_GetDef
If type is NULL, it will match any type
If allocate is true, a new def will be allocated if it can't be found
*/
def_t *
PR_GetDef (type_t *type, const char *name, def_t *scope, int *allocate)
static def_t *
check_for_name (type_t *type, const char *name, def_t *scope, int *allocate)
{
def_t *def;
char element[MAX_NAME];
if (!defs_by_name) {
defs_by_name = Hash_NewTable (16381, defs_get_key, 0, &defs_by_name);
@ -77,9 +70,49 @@ PR_GetDef (type_t *type, const char *name, def_t *scope, int *allocate)
if (!allocate || def->scope == scope)
return def;
}
return 0;
}
if (!allocate)
return NULL;
static inline type_t *
find_type (type_t *type, type_t *aux_type)
{
type_t new;
memset (&new, 0, sizeof (new));
new.type = type->type;
new.aux_type = aux_type;
return PR_FindType (&new);
}
def_t *
PR_GetArray (type_t *etype, const char *name, int size, def_t *scope,
int *allocate)
{
type_t *type = find_type (&type_pointer, etype);
def_t *def = check_for_name (type, name, scope, allocate);
if (def || !allocate)
return def;
def = PR_NewDef (type, name, scope);
def->ofs = *allocate;
*allocate += pr_type_size [type->type] * size + 1;
pr_global_defs[def->ofs] = def;
G_INT (def->ofs) = def->ofs + 1;
return def;
}
/*
PR_GetDef
If type is NULL, it will match any type
If allocate is true, a new def will be allocated if it can't be found
*/
def_t *
PR_GetDef (type_t *type, const char *name, def_t *scope, int *allocate)
{
def_t *def = check_for_name (type, name, scope, allocate);
char element[MAX_NAME];
if (def || !allocate)
return def;
// allocate a new def
def = PR_NewDef (type, name, scope);

View file

@ -87,7 +87,8 @@ def_t *
PR_ReuseConstant (expr_t *expr, def_t *def)
{
def_t *cn = 0;
char rep[60], *r = rep;
char rep[60];
const char *r = rep;
hashtab_t *tab = 0;
type_t *type;
expr_t e = *expr;
@ -131,13 +132,17 @@ PR_ReuseConstant (expr_t *expr, def_t *def)
type = &type_pointer;
break;
case ex_integer:
case ex_uinteger:
if (!def || def->type != &type_float) {
sprintf (rep, "\001integer:%08X\001", e.e.integer_val);
tab = integer_imm_defs;
type = &type_integer;
break;
}
e.e.float_val = e.e.integer_val;
if (e.type == ex_uinteger)
e.e.float_val = e.e.uinteger_val;
else
e.e.float_val = e.e.integer_val;
case ex_float:
sprintf (rep, "\001float:%08X\001", e.e.integer_val);
tab = float_imm_defs;

View file

@ -65,6 +65,7 @@ type_t type_function = { ev_func, &def_function, NULL, &type_void };
type_t type_pointer = { ev_pointer, &def_pointer };
type_t type_quaternion = { ev_quaternion, &def_quaternion };
type_t type_integer = { ev_integer, &def_integer };
type_t type_uinteger = { ev_uinteger, &def_uinteger };
type_t type_floatfield = { ev_field, &def_field, NULL, &type_float };
@ -78,6 +79,7 @@ def_t def_function = { &type_function, "temp" };
def_t def_pointer = { &type_pointer, "temp" };
def_t def_quaternion = { &type_quaternion, "temp"};
def_t def_integer = { &type_integer, "temp"};
def_t def_uinteger = { &type_uinteger, "temp"};
def_t def_ret, def_parms[MAX_PARMS];

View file

@ -40,6 +40,8 @@ opcode_t *op_ifae;
opcode_t *op_ifa;
opcode_t *op_state;
opcode_t *op_goto;
opcode_t *op_jump;
opcode_t *op_jumpb;
statref_t *
PR_NewStatref (dstatement_t *st, int field)
@ -167,6 +169,10 @@ PR_Opcode_Init_Tables (void)
op_state = op;
} else if (!strcmp (op->name, "<GOTO>")) {
op_goto = op;
} else if (!strcmp (op->name, "<JUMP>")) {
op_jump = op;
} else if (!strcmp (op->name, "<JUMPB>")) {
op_jumpb = op;
}
}
}

View file

@ -38,6 +38,14 @@ static const char rcsid[] =
#include "scope.h"
#include "qc-parse.h"
typedef struct case_node_s {
expr_t *low;
expr_t *high;
expr_t **labels;
expr_t *_label;
struct case_node_s *left, *right;
} case_node_t;
static unsigned long
get_hash (void *_cl, void *unused)
{
@ -80,7 +88,6 @@ case_label_expr (switch_block_t *switch_block, expr_t *value)
return 0;
}
cl->value = value;
print_expr(value);puts("");
if (Hash_FindElement (switch_block->labels, cl)) {
error (value, "duplicate %s", value ? "case" : "default");
free (cl);
@ -128,18 +135,118 @@ label_compare (const void *_a, const void *_b)
}
}
static void
build_binary_jump_table (expr_t *sw, case_label_t **labels, int op, int base, int count, expr_t *sw_val, expr_t *temp, expr_t *default_label)
static case_node_t *
new_case_node (expr_t *low, expr_t *high)
{
case_node_t *node = malloc (sizeof (case_node_t));
if (!node)
Sys_Error ("out of memory");
node->low = low;
node->high = high;
if (low == high) {
node->labels = &node->_label;
node->_label = 0;
} else {
int size;
if (low->type != ex_integer) {
error (low, "switch: internal error");
abort ();
}
size = high->e.integer_val - low->e.integer_val + 1;
node->labels = calloc (size, sizeof (case_node_t *));
}
node->left = node->right = 0;
return node;
}
static case_node_t *
balance_case_tree (case_node_t **nodes, int base, int count)
{
case_node_t *node;
int index = count / 2;
if (!count)
return 0;
node = nodes[base + index];
node->left = balance_case_tree (nodes, base, index);
base += index + 1;
count -= index + 1;
node->right = balance_case_tree (nodes, base, count);
return node;
}
static case_node_t *
build_case_tree (case_label_t **labels, int count)
{
case_node_t **nodes;
int i, j, k;
int num_nodes = 0;
qsort (labels, count, sizeof (*labels), label_compare);
nodes = (case_node_t **) malloc (count * sizeof (case_node_t*));
if (!nodes)
Sys_Error ("out of memory");
if (labels[0]->value->type == ex_integer) {
for (i = 0; i < count - 1; i = j, num_nodes++) {
for (j = i + 1; j < count; j++) {
if (labels[j]->value->e.integer_val
- labels[j - 1]->value->e.integer_val > 1)
break;
}
nodes[num_nodes] = new_case_node (labels[i]->value,
labels[j - 1]->value);
for (k = i; k < j; k++)
nodes[num_nodes]->labels[labels[k]->value->e.integer_val
- labels[i]->value->e.integer_val]
= labels[k]->label;
}
if (i < count) {
nodes[num_nodes] = new_case_node (labels[i]->value,
labels[i]->value);
nodes[num_nodes]->labels[0] = labels[i]->label;
num_nodes++;
}
} else {
for (i = 0; i < count; i++, num_nodes++) {
nodes[num_nodes] = new_case_node (labels[i]->value,
labels[i]->value);
nodes[num_nodes]->labels[0] = labels[i]->label;
}
}
return balance_case_tree (nodes, 0, num_nodes);
}
static void
build_switch (expr_t *sw, case_node_t *tree, int op, expr_t *sw_val,
expr_t *temp, expr_t *default_label)
{
case_label_t *l;
expr_t *test;
expr_t *branch;
int index;
expr_t *high_label = default_label;
expr_t *low_label = default_label;
index = count / 2;
l = labels [base + index];
if (!tree)
return;
test = binary_expr (op, l->value, sw_val);
if (tree->right) {
high_label = new_label_expr ();
high_label->line = sw_val->line;
high_label->file = sw_val->file;
}
if (tree->left) {
low_label = new_label_expr ();
low_label->line = sw_val->line;
low_label->file = sw_val->file;
}
test = binary_expr (op, sw_val, tree->low);
test->line = sw_val->line;
test->file = sw_val->file;
@ -147,37 +254,81 @@ build_binary_jump_table (expr_t *sw, case_label_t **labels, int op, int base, in
test->line = sw_val->line;
test->file = sw_val->file;
branch = new_binary_expr ('n', test, l->label);
branch->line = sw_val->line;
branch->file = sw_val->file;
append_expr (sw, branch);
if (index) {
expr_t *high_label;
if (count - (index + 1)) {
high_label = new_label_expr ();
high_label->line = sw_val->line;
high_label->file = sw_val->file;
} else {
high_label = default_label;
}
branch = new_binary_expr (IFA, temp, high_label);
if (tree->low == tree->high) {
printf ("%3d\n", tree->low->e.integer_val);
branch = new_binary_expr ('n', test, tree->labels[0]);
branch->line = sw_val->line;
branch->file = sw_val->file;
append_expr (sw, branch);
build_binary_jump_table (sw, labels, op, base, index, sw_val, temp, default_label);
if (tree->left) {
branch = new_binary_expr (IFA, temp, high_label);
branch->line = sw_val->line;
branch->file = sw_val->file;
append_expr (sw, branch);
if (count - (index + 1))
build_switch (sw, tree->left, op, sw_val, temp, default_label);
if (tree->right)
append_expr (sw, high_label);
}
if (tree->right)
build_switch (sw, tree->right, op, sw_val, temp, default_label);
} else {
expr_t *utemp = new_temp_def_expr (&type_uinteger);
int low = tree->low->e.integer_val;
int high = tree->high->e.integer_val;
def_t *def;
expr_t *table = new_expr ();
const char *name = new_label_name ();
int i;
expr_t *range = binary_expr ('-', tree->high, tree->low);
printf ("%3d %3d\n", low, high);
def = PR_GetArray (&type_uinteger, name, high - low + 1, 0,
&numpr_globals);
table->type = ex_def;
table->e.def = def;
append_expr (sw, test);
if (tree->left) {
branch = new_binary_expr (IFB, temp, low_label);
branch->line = sw_val->line;
branch->file = sw_val->file;
append_expr (sw, branch);
}
tree->high->type = ex_uinteger;
append_expr (sw, new_binary_expr ('b', temp, utemp));
test = binary_expr (GT, utemp, range);
test->line = sw_val->line;
test->file = sw_val->file;
branch = new_binary_expr ('i', test, high_label);
branch->line = sw_val->line;
branch->file = sw_val->file;
append_expr (sw, branch);
branch = new_binary_expr ('g', table, temp);
branch->line = sw_val->line;
branch->file = sw_val->file;
append_expr (sw, branch);
if (tree->left) {
append_expr (sw, low_label);
build_switch (sw, tree->left, op, sw_val, temp, default_label);
}
if (tree->right) {
append_expr (sw, high_label);
build_switch (sw, tree->right, op, sw_val, temp, default_label);
}
for (i = 0; i <= high - low; i++) {
dstatement_t *st;
statref_t *ref;
st = (dstatement_t *) &pr_globals[G_INT (def->ofs) + i];
ref = PR_NewStatref (st, 3);
ref->next = tree->labels[i]->e.label.refs;
tree->labels[i]->e.label.refs = ref;
}
}
base += index + 1;
count -= index + 1;
if (count)
build_binary_jump_table (sw, labels, op, base, count, sw_val, temp, default_label);
}
struct expr_s *
@ -229,12 +380,13 @@ switch_expr (switch_block_t *switch_block, expr_t *break_label,
} else {
expr_t *temp;
int op;
case_node_t *case_tree;
if (type == &type_string)
temp = new_temp_def_expr (&type_integer);
else
temp = new_temp_def_expr (type);
qsort (labels, num_labels, sizeof (*labels), label_compare);
case_tree = build_case_tree (labels, num_labels);
switch (type->type) {
case ev_string:
op = NE;
@ -249,7 +401,7 @@ switch_expr (switch_block_t *switch_block, expr_t *break_label,
error (0, "internal compiler error in switch");
abort ();
}
build_binary_jump_table (sw, labels, op, 0, num_labels, sw_val, temp, default_label->label);
build_switch (sw, case_tree, op, sw_val, temp, default_label->label);
}
append_expr (sw, default_expr);
append_expr (sw, statements);