mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-01-18 15:01:41 +00:00
start on actually generating code. doesn't work yet (getting a weird type
redeclaration error and not all expressions are handled yet).
This commit is contained in:
parent
e99796c4cf
commit
c1753046a9
8 changed files with 378 additions and 6 deletions
|
@ -55,3 +55,5 @@ void print_expr (expr_t *e);
|
|||
expr_t *binary_expr (int op, expr_t *e1, expr_t *e2);
|
||||
expr_t *unary_expr (int op, expr_t *e);
|
||||
expr_t *function_expr (expr_t *e1, expr_t *e2);
|
||||
|
||||
void emit_expr (expr_t *e);
|
||||
|
|
|
@ -329,6 +329,7 @@ extern type_t type_field;
|
|||
extern type_t type_function;
|
||||
extern type_t type_pointer;
|
||||
extern type_t type_floatfield;
|
||||
extern type_t type_quaternion;
|
||||
|
||||
extern def_t def_void;
|
||||
extern def_t def_string;
|
||||
|
@ -338,6 +339,7 @@ extern def_t def_entity;
|
|||
extern def_t def_field;
|
||||
extern def_t def_function;
|
||||
extern def_t def_pointer;
|
||||
extern def_t def_quaternion;
|
||||
|
||||
struct function_s
|
||||
{
|
||||
|
@ -390,6 +392,8 @@ extern opcode_t *op_ifnot;
|
|||
extern opcode_t *op_state;
|
||||
extern opcode_t *op_goto;
|
||||
|
||||
statref_t *PR_NewStatref (dstatement_t *st, int field);
|
||||
void PR_AddStatementRef (def_t *def, dstatement_t *st, int field);
|
||||
def_t *PR_Statement (opcode_t *op, def_t *var_a, def_t *var_b);
|
||||
opcode_t *PR_Opcode_Find (const char *name, int priority,
|
||||
def_t *var_a, def_t *var_b, def_t *var_c);
|
||||
|
@ -398,6 +402,8 @@ void PR_Opcode_Init (void);
|
|||
|
||||
//============================================================================
|
||||
|
||||
#include "expr.h"
|
||||
|
||||
|
||||
extern qboolean pr_dumpasm;
|
||||
|
||||
|
@ -426,6 +432,7 @@ void PR_LexString (void);
|
|||
type_t *PR_ParseType (void);
|
||||
char *PR_ParseName (void);
|
||||
def_t *PR_ParseImmediate (def_t *def);
|
||||
def_t *PR_ReuseConstant (expr_t *expr, def_t *def);
|
||||
|
||||
qboolean PR_Check (token_type_t type, const char *string);
|
||||
void PR_Expect (token_type_t type, const char *string);
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#include <QF/mathlib.h>
|
||||
#include <QF/va.h>
|
||||
|
||||
#include "qfcc.h"
|
||||
#include "expr.h"
|
||||
#include "scope.h"
|
||||
#include "qc-parse.h"
|
||||
|
||||
|
@ -34,6 +34,17 @@ static type_t *types[] = {
|
|||
&type_pointer,
|
||||
};
|
||||
|
||||
static expr_type expr_types[] = {
|
||||
ex_label, // ev_void (ick)
|
||||
ex_string, // ev_string
|
||||
ex_float, // ev_float
|
||||
ex_vector, // ev_vector
|
||||
ex_label, // ev_entity (ick)
|
||||
ex_label, // ev_field (ick)
|
||||
ex_label, // ev_func (ick)
|
||||
ex_label, // ev_pointer (ick)
|
||||
};
|
||||
|
||||
static etype_t
|
||||
get_type (expr_t *e)
|
||||
{
|
||||
|
@ -630,3 +641,242 @@ function_expr (expr_t *e1, expr_t *e2)
|
|||
e->e.expr.e2 = e2;
|
||||
return e;
|
||||
}
|
||||
|
||||
def_t *
|
||||
emit_statement (opcode_t *op, def_t *var_a, def_t *var_b, def_t *var_c)
|
||||
{
|
||||
dstatement_t *statement;
|
||||
|
||||
statement = &statements[numstatements];
|
||||
numstatements++;
|
||||
statement_linenums[statement - statements] = pr_source_line;
|
||||
statement->op = op->opcode;
|
||||
statement->a = var_a ? var_a->ofs : 0;
|
||||
statement->b = var_b ? var_b->ofs : 0;
|
||||
if (op->type_c == &def_void || op->right_associative) {
|
||||
// ifs, gotos, and assignments don't need vars allocated
|
||||
var_c = NULL;
|
||||
statement->c = 0;
|
||||
} else { // allocate result space
|
||||
if (!var_c)
|
||||
var_c = PR_GetTempDef (op->type_c->type, pr_scope);
|
||||
statement->c = var_c->ofs;
|
||||
}
|
||||
PR_AddStatementRef (var_a, statement, 0);
|
||||
PR_AddStatementRef (var_b, statement, 1);
|
||||
PR_AddStatementRef (var_c, statement, 2);
|
||||
|
||||
if (op->right_associative)
|
||||
return var_a;
|
||||
return var_c;
|
||||
}
|
||||
|
||||
def_t *emit_sub_expr (expr_t *e, def_t *dest);
|
||||
|
||||
def_t *
|
||||
emit_function_call (expr_t *e, def_t *dest)
|
||||
{
|
||||
def_t *func = emit_sub_expr (e->e.expr.e1, 0);
|
||||
def_t *arg;
|
||||
expr_t *earg;
|
||||
opcode_t *op;
|
||||
int count = 0, ind;
|
||||
|
||||
for (earg = e->e.expr.e2; earg; earg = earg->next)
|
||||
count++;
|
||||
ind = count;
|
||||
for (earg = e->e.expr.e2; earg; earg = earg->next) {
|
||||
ind--;
|
||||
arg = emit_sub_expr (earg, 0);
|
||||
def_parms[ind].type = arg->type;
|
||||
op = PR_Opcode_Find ("=", 5, arg, &def_parms[ind], &def_parms[ind]);
|
||||
emit_statement (op, arg, &def_parms[ind], 0);
|
||||
}
|
||||
op = PR_Opcode_Find (va ("<CALL%d>", count), -1, &def_function, &def_void, &def_void);
|
||||
emit_statement (op, func, 0, dest);
|
||||
|
||||
def_ret.type = func->type->aux_type;
|
||||
return &def_ret;
|
||||
}
|
||||
|
||||
def_t *
|
||||
emit_sub_expr (expr_t *e, def_t *dest)
|
||||
{
|
||||
opcode_t *op;
|
||||
char *operator;
|
||||
def_t *def_a, *def_b;
|
||||
int priority;
|
||||
|
||||
if (e->type == ex_expr && e->e.expr.op == 'c')
|
||||
return emit_function_call (e, dest);
|
||||
|
||||
switch (e->type) {
|
||||
default:
|
||||
case ex_label:
|
||||
case ex_block:
|
||||
abort ();
|
||||
case ex_expr:
|
||||
def_a = emit_sub_expr (e->e.expr.e1, 0);
|
||||
def_b = emit_sub_expr (e->e.expr.e2, 0);
|
||||
switch (e->e.expr.op) {
|
||||
case AND:
|
||||
operator = "&&";
|
||||
priority = 6;
|
||||
break;
|
||||
case OR:
|
||||
operator = "||";
|
||||
priority = 6;
|
||||
break;
|
||||
case '=':
|
||||
operator = "=";
|
||||
priority = 6;
|
||||
break;
|
||||
case EQ:
|
||||
operator = "==";
|
||||
priority = 4;
|
||||
break;
|
||||
case NE:
|
||||
operator = "!=";
|
||||
priority = 4;
|
||||
break;
|
||||
case LE:
|
||||
operator = "<=";
|
||||
priority = 4;
|
||||
break;
|
||||
case GE:
|
||||
operator = ">=";
|
||||
priority = 4;
|
||||
break;
|
||||
case LT:
|
||||
operator = "<";
|
||||
priority = 4;
|
||||
break;
|
||||
case GT:
|
||||
operator = ">";
|
||||
priority = 4;
|
||||
break;
|
||||
case '+':
|
||||
operator = "+";
|
||||
priority = 3;
|
||||
break;
|
||||
case '-':
|
||||
operator = "-";
|
||||
priority = 3;
|
||||
break;
|
||||
case '*':
|
||||
operator = "*";
|
||||
priority = 2;
|
||||
break;
|
||||
case '/':
|
||||
operator = "/";
|
||||
priority = 2;
|
||||
break;
|
||||
case '&':
|
||||
operator = "&";
|
||||
priority = 2;
|
||||
break;
|
||||
case '|':
|
||||
operator = "|";
|
||||
priority = 2;
|
||||
break;
|
||||
case '.':
|
||||
operator = ".";
|
||||
priority = 1;
|
||||
break;
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
op = PR_Opcode_Find (operator, priority, def_a, def_b, dest);
|
||||
return emit_statement (op, def_a, def_b, dest);
|
||||
case ex_uexpr:
|
||||
if (e->e.expr.op == '!') {
|
||||
operator = "!";
|
||||
priority = -1;
|
||||
def_a = emit_sub_expr (e->e.expr.e1, 0);
|
||||
def_b = &def_void;
|
||||
} else if (e->e.expr.op == '-') {
|
||||
static expr_t zero;
|
||||
|
||||
zero.type = expr_types[get_type (e->e.expr.e1)];
|
||||
|
||||
operator = "-";
|
||||
priority = 3;
|
||||
def_a = PR_ReuseConstant (&zero, 0);
|
||||
def_b = emit_sub_expr (e->e.expr.e1, 0);
|
||||
} else {
|
||||
abort ();
|
||||
}
|
||||
op = PR_Opcode_Find (operator, priority, def_a, def_b, dest);
|
||||
return emit_statement (op, def_a, def_b, dest);
|
||||
case ex_def:
|
||||
return e->e.def;
|
||||
case ex_int:
|
||||
case ex_float:
|
||||
case ex_string:
|
||||
case ex_vector:
|
||||
case ex_quaternion:
|
||||
return PR_ReuseConstant (e, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
emit_expr (expr_t *e)
|
||||
{
|
||||
def_t *def;
|
||||
statref_t *ref;
|
||||
dstatement_t *st;
|
||||
|
||||
switch (e->type) {
|
||||
case ex_label:
|
||||
break;
|
||||
case ex_block:
|
||||
for (e = e->e.block.head; e; e = e->next)
|
||||
emit_expr (e);
|
||||
break;
|
||||
case ex_expr:
|
||||
switch (e->e.expr.op) {
|
||||
case '=':
|
||||
break;
|
||||
case 'n':
|
||||
break;
|
||||
case 'i':
|
||||
break;
|
||||
case 'c':
|
||||
break;
|
||||
default:
|
||||
fprintf (stderr,
|
||||
"%s:%d: warning: unused expression ignored\n",
|
||||
strings + s_file, pr_source_line);
|
||||
}
|
||||
break;
|
||||
case ex_uexpr:
|
||||
switch (e->e.expr.op) {
|
||||
case 'r':
|
||||
def = 0;
|
||||
if (e->e.expr.e1)
|
||||
def = emit_sub_expr (e->e.expr.e1, 0);
|
||||
PR_Statement (op_return, def, 0);
|
||||
return;
|
||||
case 'g':
|
||||
st = &statements[numstatements];
|
||||
PR_Statement (op_goto, 0, 0);
|
||||
if (e->e.label.statement) {
|
||||
st->a = e->e.label.statement - st;
|
||||
} else {
|
||||
ref = PR_NewStatref (st, 0);
|
||||
ref->next = e->e.label.refs;
|
||||
e->e.label.refs = ref;
|
||||
}
|
||||
return;
|
||||
}
|
||||
case ex_def:
|
||||
case ex_int:
|
||||
case ex_float:
|
||||
case ex_string:
|
||||
case ex_vector:
|
||||
case ex_quaternion:
|
||||
fprintf (stderr, "%s:%d: warning: unused expression ignored\n",
|
||||
strings + s_file, pr_source_line);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
static hashtab_t *string_imm_defs;
|
||||
static hashtab_t *float_imm_defs;
|
||||
static hashtab_t *vector_imm_defs;
|
||||
static hashtab_t *quaternion_imm_defs;
|
||||
|
||||
static const char *
|
||||
string_imm_get_key (void *_def, void *unused)
|
||||
|
@ -54,6 +55,17 @@ vector_imm_get_key (void *_def, void *unused)
|
|||
return rep;
|
||||
}
|
||||
|
||||
static const char *
|
||||
quaternion_imm_get_key (void *_def, void *unused)
|
||||
{
|
||||
def_t *def = (def_t*)_def;
|
||||
static char rep[60];
|
||||
sprintf (rep, "\001quaternion:%08X\001%08X\001%08X\001%08X\001",
|
||||
G_INT(def->ofs), G_INT(def->ofs+1),
|
||||
G_INT(def->ofs+2), G_INT(def->ofs+3));
|
||||
return rep;
|
||||
}
|
||||
|
||||
/*
|
||||
PR_ParseImmediate
|
||||
|
||||
|
@ -131,3 +143,90 @@ PR_ParseImmediate (def_t *def)
|
|||
|
||||
return cn;
|
||||
}
|
||||
|
||||
def_t *
|
||||
PR_ReuseConstant (expr_t *e, def_t *def)
|
||||
{
|
||||
def_t *cn = 0;
|
||||
char rep[60];
|
||||
hashtab_t *tab = 0;
|
||||
type_t *type;
|
||||
|
||||
if (!string_imm_defs) {
|
||||
string_imm_defs = Hash_NewTable (16381, string_imm_get_key, 0, 0);
|
||||
float_imm_defs = Hash_NewTable (16381, float_imm_get_key, 0, 0);
|
||||
vector_imm_defs = Hash_NewTable (16381, vector_imm_get_key, 0, 0);
|
||||
quaternion_imm_defs = Hash_NewTable (16381, quaternion_imm_get_key, 0, 0);
|
||||
}
|
||||
switch (e->type) {
|
||||
case ex_int:
|
||||
e->e.float_val = e->e.int_val; //FIXME
|
||||
case ex_float:
|
||||
sprintf (rep, "\001float:%08X\001", *(int*)&pr_immediate._float);
|
||||
cn = (def_t*) Hash_Find (float_imm_defs, rep);
|
||||
tab = float_imm_defs;
|
||||
type = &type_float;
|
||||
//printf ("%f\n",pr_immediate._float);
|
||||
break;
|
||||
case ex_string:
|
||||
cn = (def_t*) Hash_Find (string_imm_defs, pr_immediate_string);
|
||||
tab = string_imm_defs;
|
||||
type = &type_string;
|
||||
//printf ("%s\n",pr_immediate_string);
|
||||
break;
|
||||
case ex_vector:
|
||||
sprintf (rep, "\001vector:%08X\001%08X\001%08X\001",
|
||||
*(int*)&e->e.vector_val[0],
|
||||
*(int*)&e->e.vector_val[1],
|
||||
*(int*)&e->e.vector_val[2]);
|
||||
cn = (def_t*) Hash_Find (vector_imm_defs, rep);
|
||||
tab = vector_imm_defs;
|
||||
type = &type_vector;
|
||||
//printf ("%f %f %f\n",pr_immediate.vector[0], pr_immediate.vector[1], pr_immediate.vector[2]);
|
||||
break;
|
||||
case ex_quaternion:
|
||||
sprintf (rep, "\001quaternion:%08X\001%08X\001%08X\001%08X\001",
|
||||
*(int*)&e->e.quaternion_val[0],
|
||||
*(int*)&e->e.quaternion_val[1],
|
||||
*(int*)&e->e.quaternion_val[2],
|
||||
*(int*)&e->e.quaternion_val[3]);
|
||||
cn = (def_t*) Hash_Find (quaternion_imm_defs, rep);
|
||||
tab = vector_imm_defs;
|
||||
type = &type_quaternion;
|
||||
//printf ("%f %f %f\n",pr_immediate.vector[0], pr_immediate.vector[1], pr_immediate.vector[2]);
|
||||
break;
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
if (cn) {
|
||||
//printf("found\n");
|
||||
if (def) {
|
||||
PR_FreeLocation (def);
|
||||
def->ofs = cn->ofs;
|
||||
def->initialized = 1;
|
||||
cn = def;
|
||||
}
|
||||
return cn;
|
||||
}
|
||||
// allocate a new one
|
||||
// always share immediates
|
||||
if (def) {
|
||||
cn = def;
|
||||
} else {
|
||||
cn = PR_NewDef (pr_immediate_type, "IMMEDIATE", 0);
|
||||
cn->ofs = PR_NewLocation (pr_immediate_type);
|
||||
pr_global_defs[cn->ofs] = cn;
|
||||
}
|
||||
cn->initialized = 1;
|
||||
// copy the immediate to the global area
|
||||
if (e->type == ex_string)
|
||||
e->e.int_val = CopyString (e->e.string_val);
|
||||
|
||||
memcpy (pr_globals + cn->ofs, &e->e, 4 * type_size[type->type]);
|
||||
|
||||
Hash_Add (tab, cn);
|
||||
|
||||
PR_Lex ();
|
||||
|
||||
return cn;
|
||||
}
|
||||
|
|
|
@ -60,6 +60,7 @@ type_t type_field = { ev_field, &def_field };
|
|||
// type_function is a void() function used for state defs
|
||||
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_floatfield = { ev_field, &def_field, NULL, &type_float };
|
||||
|
||||
|
@ -73,6 +74,7 @@ def_t def_entity = { &type_entity, "temp" };
|
|||
def_t def_field = { &type_field, "temp" };
|
||||
def_t def_function = { &type_function, "temp" };
|
||||
def_t def_pointer = { &type_pointer, "temp" };
|
||||
def_t def_quaternion = { &type_quaternion, "temp"};
|
||||
|
||||
def_t def_ret, def_parms[MAX_PARMS];
|
||||
|
||||
|
@ -684,7 +686,9 @@ PR_ParseError (const char *error, ...)
|
|||
|
||||
printf ("%s:%i:%s\n", strings + s_file, pr_source_line, string);
|
||||
|
||||
#ifndef NEW_PARSER
|
||||
longjmp (pr_parse_abort, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -131,15 +131,22 @@ opcode_t pr_opcodes[] = {
|
|||
{"|", "BITOR", OP_BITOR, 2, false, &def_float, &def_float, &def_float, PROG_ID_VERSION},
|
||||
};
|
||||
|
||||
statref_t *
|
||||
PR_NewStatref (dstatement_t *st, int field)
|
||||
{
|
||||
statref_t *ref = calloc (1, sizeof (statref_t));
|
||||
ref->statement = st;
|
||||
ref->field = field;
|
||||
return ref;
|
||||
}
|
||||
|
||||
void
|
||||
PR_AddStatementRef (def_t *def, dstatement_t *st, int field)
|
||||
{
|
||||
if (def) {
|
||||
statref_t *ref = calloc (1, sizeof (statref_t));
|
||||
statref_t *ref = PR_NewStatref (st, field);
|
||||
ref->next = def->refs;
|
||||
def->refs = ref;
|
||||
ref->statement = st;
|
||||
ref->field = field;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
%{
|
||||
#include <QF/hash.h>
|
||||
#include "qfcc.h"
|
||||
#include "expr.h"
|
||||
#include "scope.h"
|
||||
#include "qc-parse.h"
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
%{
|
||||
#include "qfcc.h"
|
||||
#include "expr.h"
|
||||
|
||||
#define YYDEBUG 1
|
||||
#define YYERROR_VERBOSE 1
|
||||
|
@ -538,6 +537,11 @@ build_function (function_t *f)
|
|||
void
|
||||
emit_function (function_t *f, expr_t *e)
|
||||
{
|
||||
pr_scope = f->def;
|
||||
while (e) {
|
||||
emit_expr (e);
|
||||
e = e->next;
|
||||
}
|
||||
/*PR_PrintType (f->def->type);
|
||||
printf (" %s =\n", f->def->name);
|
||||
while (e) {
|
||||
|
|
Loading…
Reference in a new issue