mirror of
https://github.com/DarkPlacesEngine/gmqcc.git
synced 2025-03-23 11:11:22 +00:00
Merging master to handle vector members, fields, and members of vector fields
This commit is contained in:
commit
d68d19dbfd
9 changed files with 401 additions and 37 deletions
44
ast.c
44
ast.c
|
@ -94,6 +94,15 @@ static ast_value* ast_value_copy(const ast_value *self)
|
|||
return cp;
|
||||
}
|
||||
|
||||
static ast_expression* ast_shallow_type(lex_ctx ctx, int vtype)
|
||||
{
|
||||
ast_instantiate(ast_expression, ctx, ast_expression_delete_full);
|
||||
self->expression.codegen = NULL;
|
||||
self->expression.next = NULL;
|
||||
self->expression.vtype = vtype;
|
||||
return self;
|
||||
}
|
||||
|
||||
static ast_expression* ast_type_copy(lex_ctx ctx, const ast_expression *ex)
|
||||
{
|
||||
size_t i;
|
||||
|
@ -306,10 +315,22 @@ ast_member* ast_member_new(lex_ctx ctx, ast_expression *owner, unsigned int fiel
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (owner->expression.vtype != TYPE_FLOAT &&
|
||||
owner->expression.vtype != TYPE_FIELD) {
|
||||
printf("ast_member on an invalid owner of type %i\n", (int)owner->expression.vtype);
|
||||
mem_d(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_member_codegen);
|
||||
|
||||
self->expression.vtype = TYPE_FLOAT;
|
||||
self->expression.next = NULL;
|
||||
if (owner->expression.vtype == TYPE_VECTOR) {
|
||||
self->expression.vtype = TYPE_FLOAT;
|
||||
self->expression.next = NULL;
|
||||
} else {
|
||||
self->expression.vtype = TYPE_FIELD;
|
||||
self->expression.next = ast_shallow_type(ctx, TYPE_FLOAT);
|
||||
}
|
||||
|
||||
self->owner = owner;
|
||||
self->field = field;
|
||||
|
@ -628,6 +649,18 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir)
|
|||
return true;
|
||||
}
|
||||
|
||||
if (self->expression.vtype == TYPE_FIELD) {
|
||||
v = ir_builder_create_field(ir, self->name, self->expression.next->expression.vtype);
|
||||
if (!v)
|
||||
return false;
|
||||
if (self->isconst) {
|
||||
printf("TODO: constant field pointers with value\n");
|
||||
goto error;
|
||||
}
|
||||
self->ir_v = v;
|
||||
return true;
|
||||
}
|
||||
|
||||
v = ir_builder_create_global(ir, self->name, self->expression.vtype);
|
||||
if (!v) {
|
||||
printf("ir_builder_create_global failed\n");
|
||||
|
@ -954,14 +987,17 @@ bool ast_entfield_codegen(ast_entfield *self, ast_function *func, bool lvalue, i
|
|||
bool ast_member_codegen(ast_member *self, ast_function *func, bool lvalue, ir_value **out)
|
||||
{
|
||||
ast_expression_codegen *cgen;
|
||||
ir_value *vec, *field;
|
||||
ir_value *vec;
|
||||
|
||||
cgen = self->owner->expression.codegen;
|
||||
if (!(*cgen)((ast_expression*)(self->owner), func, true, &vec))
|
||||
return false;
|
||||
|
||||
if (vec->vtype != TYPE_VECTOR)
|
||||
if (vec->vtype != TYPE_VECTOR &&
|
||||
!(vec->vtype == TYPE_FIELD && self->owner->expression.next->expression.vtype == TYPE_VECTOR))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
*out = ir_value_vector_member(vec, self->field);
|
||||
|
||||
|
|
140
exec.c
140
exec.c
|
@ -13,6 +13,7 @@ MEM_VEC_FUN_APPEND(qc_program, char, strings)
|
|||
MEM_VEC_FUN_RESIZE(qc_program, char, strings)
|
||||
MEM_VEC_FUNCTIONS(qc_program, qcint, globals)
|
||||
MEM_VEC_FUNCTIONS(qc_program, qcint, entitydata)
|
||||
MEM_VEC_FUNCTIONS(qc_program, bool, entitypool)
|
||||
|
||||
MEM_VEC_FUNCTIONS(qc_program, qcint, localstack)
|
||||
MEM_VEC_FUN_APPEND(qc_program, qcint, localstack)
|
||||
|
@ -34,10 +35,20 @@ static void loaderror(const char *fmt, ...)
|
|||
printf(": %s\n", strerror(err));
|
||||
}
|
||||
|
||||
static void printvmerr(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vprintf(fmt, ap);
|
||||
va_end(ap);
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
qc_program* prog_load(const char *filename)
|
||||
{
|
||||
qc_program *prog;
|
||||
prog_header header;
|
||||
size_t i;
|
||||
FILE *file;
|
||||
|
||||
file = fopen(filename, "rb");
|
||||
|
@ -108,6 +119,19 @@ qc_program* prog_load(const char *filename)
|
|||
if (!qc_program_strings_resize(prog, prog->strings_count + 16*1024))
|
||||
goto error;
|
||||
|
||||
/* spawn the world entity */
|
||||
if (!qc_program_entitypool_add(prog, true)) {
|
||||
loaderror("failed to allocate world entity\n");
|
||||
goto error;
|
||||
}
|
||||
for (i = 0; i < prog->entityfields; ++i) {
|
||||
if (!qc_program_entitydata_add(prog, 0)) {
|
||||
loaderror("failed to allocate world data\n");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
prog->entities = 1;
|
||||
|
||||
return prog;
|
||||
|
||||
error:
|
||||
|
@ -119,6 +143,7 @@ error:
|
|||
if (prog->strings) mem_d(prog->strings);
|
||||
if (prog->globals) mem_d(prog->globals);
|
||||
if (prog->entitydata) mem_d(prog->entitydata);
|
||||
if (prog->entitypool) mem_d(prog->entitypool);
|
||||
mem_d(prog);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -133,6 +158,7 @@ void prog_delete(qc_program *prog)
|
|||
MEM_VECTOR_CLEAR(prog, strings);
|
||||
MEM_VECTOR_CLEAR(prog, globals);
|
||||
MEM_VECTOR_CLEAR(prog, entitydata);
|
||||
MEM_VECTOR_CLEAR(prog, entitypool);
|
||||
MEM_VECTOR_CLEAR(prog, localstack);
|
||||
MEM_VECTOR_CLEAR(prog, stack);
|
||||
MEM_VECTOR_CLEAR(prog, profile);
|
||||
|
@ -177,7 +203,58 @@ prog_section_def* prog_getdef(qc_program *prog, qcint off)
|
|||
|
||||
qcany* prog_getedict(qc_program *prog, qcint e)
|
||||
{
|
||||
return (qcany*)(prog->entitydata + (prog->entityfields + e));
|
||||
if (e >= prog->entitypool_count) {
|
||||
prog->vmerror++;
|
||||
printf("Accessing out of bounds edict %i\n", (int)e);
|
||||
e = 0;
|
||||
}
|
||||
return (qcany*)(prog->entitydata + (prog->entityfields * e));
|
||||
}
|
||||
|
||||
qcint prog_spawn_entity(qc_program *prog)
|
||||
{
|
||||
size_t i;
|
||||
qcint e;
|
||||
for (e = 0; e < (qcint)prog->entitypool_count; ++e) {
|
||||
if (!prog->entitypool[e]) {
|
||||
char *data = (char*)(prog->entitydata + (prog->entityfields * e));
|
||||
memset(data, 0, prog->entityfields * sizeof(qcint));
|
||||
return e;
|
||||
}
|
||||
}
|
||||
if (!qc_program_entitypool_add(prog, true)) {
|
||||
prog->vmerror++;
|
||||
printf("Failed to allocate entity\n");
|
||||
return 0;
|
||||
}
|
||||
prog->entities++;
|
||||
for (i = 0; i < prog->entityfields; ++i) {
|
||||
if (!qc_program_entitydata_add(prog, 0)) {
|
||||
printf("Failed to allocate entity\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
void prog_free_entity(qc_program *prog, qcint e)
|
||||
{
|
||||
if (!e) {
|
||||
prog->vmerror++;
|
||||
printf("Trying to free world entity\n");
|
||||
return;
|
||||
}
|
||||
if (e >= prog->entitypool_count) {
|
||||
prog->vmerror++;
|
||||
printf("Trying to free out of bounds entity\n");
|
||||
return;
|
||||
}
|
||||
if (!prog->entitypool[e]) {
|
||||
prog->vmerror++;
|
||||
printf("Double free on entity\n");
|
||||
return;
|
||||
}
|
||||
prog->entitypool[e] = false;
|
||||
}
|
||||
|
||||
qcint prog_tempstring(qc_program *prog, const char *_str)
|
||||
|
@ -439,6 +516,8 @@ bool prog_exec(qc_program *prog, prog_section_function *func, size_t flags, long
|
|||
long jumpcount = 0;
|
||||
prog_section_statement *st;
|
||||
|
||||
prog->vmerror = 0;
|
||||
|
||||
st = prog->code + prog_enterfunction(prog, func);
|
||||
--st;
|
||||
switch (flags)
|
||||
|
@ -477,6 +556,8 @@ bool prog_exec(qc_program *prog, prog_section_function *func, size_t flags, long
|
|||
cleanup:
|
||||
prog->localstack_count = 0;
|
||||
prog->stack_count = 0;
|
||||
if (prog->vmerror)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -488,16 +569,66 @@ cleanup:
|
|||
bool opts_debug = false;
|
||||
bool opts_memchk = false;
|
||||
|
||||
#define CheckArgs(num) do { \
|
||||
if (prog->argc != (num)) { \
|
||||
prog->vmerror++; \
|
||||
printf("ERROR: invalid number of arguments for %s: %i, expected %i\n", \
|
||||
__FUNCTION__, prog->argc, (num)); \
|
||||
return -1; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define GetGlobal(idx) ((qcany*)(prog->globals + (idx)))
|
||||
#define GetArg(num) GetGlobal(OFS_PARM0 + 3*(num))
|
||||
#define Return(any) *(GetGlobal(OFS_RETURN)) = (any)
|
||||
|
||||
static int qc_print(qc_program *prog)
|
||||
{
|
||||
qcany *str = (qcany*)(prog->globals + OFS_PARM0);
|
||||
printf("%s", prog_getstring(prog, str->string));
|
||||
size_t i;
|
||||
for (i = 0; i < prog->argc; ++i) {
|
||||
qcany *str = (qcany*)(prog->globals + OFS_PARM0 + 3*i);
|
||||
printf("%s", prog_getstring(prog, str->string));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qc_ftos(qc_program *prog)
|
||||
{
|
||||
char buffer[512];
|
||||
qcany *num;
|
||||
qcany str;
|
||||
CheckArgs(1);
|
||||
num = GetArg(0);
|
||||
snprintf(buffer, sizeof(buffer), "%g", num->_float);
|
||||
str.string = prog_tempstring(prog, buffer);
|
||||
Return(str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qc_spawn(qc_program *prog)
|
||||
{
|
||||
qcany ent;
|
||||
CheckArgs(0);
|
||||
ent.edict = prog_spawn_entity(prog);
|
||||
Return(ent);
|
||||
return (ent.edict ? 0 : -1);
|
||||
}
|
||||
|
||||
static int qc_kill(qc_program *prog)
|
||||
{
|
||||
qcany *ent;
|
||||
CheckArgs(1);
|
||||
ent = GetArg(0);
|
||||
prog_free_entity(prog, ent->edict);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static prog_builtin qc_builtins[] = {
|
||||
NULL,
|
||||
&qc_print
|
||||
&qc_print,
|
||||
&qc_ftos,
|
||||
&qc_spawn,
|
||||
&qc_kill
|
||||
};
|
||||
static size_t qc_builtins_count = sizeof(qc_builtins) / sizeof(qc_builtins[0]);
|
||||
|
||||
|
@ -528,6 +659,7 @@ int main(int argc, char **argv)
|
|||
if (!strcmp(name, "main"))
|
||||
fnmain = (qcint)i;
|
||||
}
|
||||
printf("Entity field space: %i\n", (int)prog->entityfields);
|
||||
if (fnmain > 0)
|
||||
{
|
||||
prog_exec(prog, &prog->functions[fnmain], VMXF_TRACE, VM_JUMPS_DEFAULT);
|
||||
|
|
10
execloop.h
10
execloop.h
|
@ -16,7 +16,7 @@
|
|||
#endif
|
||||
|
||||
#if !defined(PRVM_ERROR)
|
||||
# define PRVM_ERROR printf
|
||||
# define PRVM_ERROR prog->vmerror++, printvmerr
|
||||
#endif
|
||||
|
||||
#if !defined(PRVM_NAME)
|
||||
|
@ -216,7 +216,7 @@
|
|||
ptr->_int = OPA->_int;
|
||||
break;
|
||||
case INSTR_STOREP_V:
|
||||
if (OPB->_int < 0 || OPB->_int + 3 >= prog->entitydata_count)
|
||||
if (OPB->_int < 0 || OPB->_int + 2 >= prog->entitydata_count)
|
||||
{
|
||||
PRVM_ERROR("%s attempted to write to an out of bounds edict (%i)", PRVM_NAME, OPB->_int);
|
||||
goto cleanup;
|
||||
|
@ -232,7 +232,7 @@
|
|||
case INSTR_ADDRESS:
|
||||
if (OPA->edict < 0 || OPA->edict >= prog->entities)
|
||||
{
|
||||
PRVM_ERROR ("%s Progs attempted to address an out of bounds edict number", PRVM_NAME);
|
||||
PRVM_ERROR ("%s Progs attempted to address an out of bounds edict number %i", PRVM_NAME, OPA->edict);
|
||||
goto cleanup;
|
||||
}
|
||||
if ((unsigned int)(OPB->_int) >= (unsigned int)(prog->entityfields))
|
||||
|
@ -271,7 +271,7 @@
|
|||
PRVM_ERROR ("%s Progs attempted to read an out of bounds edict number", PRVM_NAME);
|
||||
goto cleanup;
|
||||
}
|
||||
if (OPB->_int < 0 || OPB->_int + 3 >= prog->entityfields)
|
||||
if (OPB->_int < 0 || OPB->_int + 3 > prog->entityfields)
|
||||
{
|
||||
PRVM_ERROR("%s attempted to read an invalid field in an edict (%i)", PRVM_NAME, OPB->_int);
|
||||
goto cleanup;
|
||||
|
@ -357,6 +357,8 @@
|
|||
}
|
||||
else
|
||||
st = prog->code + PROG_ENTERFUNCTION(newf);
|
||||
if (prog->vmerror)
|
||||
goto cleanup;
|
||||
break;
|
||||
|
||||
case INSTR_DONE:
|
||||
|
|
|
@ -5,3 +5,4 @@
|
|||
GMQCC_DEFINE_FLAG(OVERLAP_LOCALS)
|
||||
GMQCC_DEFINE_FLAG(DARKPLACES_STRING_TABLE_BUG)
|
||||
GMQCC_DEFINE_FLAG(OMIT_NULL_BYTES)
|
||||
GMQCC_DEFINE_FLAG(ADJUST_VECTOR_FIELDS)
|
||||
|
|
1
gmqcc.h
1
gmqcc.h
|
@ -885,6 +885,7 @@ typedef struct qc_program_s {
|
|||
MEM_VECTOR_MAKE(char, strings);
|
||||
MEM_VECTOR_MAKE(qcint, globals);
|
||||
MEM_VECTOR_MAKE(qcint, entitydata);
|
||||
MEM_VECTOR_MAKE(bool, entitypool);
|
||||
|
||||
size_t tempstring_start;
|
||||
size_t tempstring_at;
|
||||
|
|
138
ir.c
138
ir.c
|
@ -559,6 +559,8 @@ void ir_value_code_setaddr(ir_value *self, int32_t gaddr)
|
|||
|
||||
int32_t ir_value_code_addr(const ir_value *self)
|
||||
{
|
||||
if (self->store == store_return)
|
||||
return OFS_RETURN + self->code.addroffset;
|
||||
return self->code.globaladdr + self->code.addroffset;
|
||||
}
|
||||
|
||||
|
@ -594,13 +596,29 @@ ir_value* ir_value_vector_member(ir_value *self, unsigned int member)
|
|||
if (self->members[member])
|
||||
return self->members[member];
|
||||
|
||||
m = ir_value_var(self->name, self->store, TYPE_FLOAT);
|
||||
if (!m)
|
||||
return NULL;
|
||||
m->context = self->context;
|
||||
if (self->vtype == TYPE_VECTOR)
|
||||
{
|
||||
m = ir_value_var(self->name, self->store, TYPE_FLOAT);
|
||||
if (!m)
|
||||
return NULL;
|
||||
m->context = self->context;
|
||||
|
||||
self->members[member] = m;
|
||||
m->code.addroffset = member;
|
||||
self->members[member] = m;
|
||||
m->code.addroffset = member;
|
||||
}
|
||||
else if (self->vtype == TYPE_FIELD)
|
||||
{
|
||||
if (self->fieldtype != TYPE_VECTOR)
|
||||
return NULL;
|
||||
m = ir_value_var(self->name, self->store, TYPE_FIELD);
|
||||
if (!m)
|
||||
return NULL;
|
||||
m->fieldtype = TYPE_FLOAT;
|
||||
m->context = self->context;
|
||||
|
||||
self->members[member] = m;
|
||||
m->code.addroffset = member;
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
@ -694,6 +712,15 @@ bool ir_value_set_matrix(ir_value *self, matrix v)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool ir_value_set_field(ir_value *self, ir_value *fld)
|
||||
{
|
||||
if (self->vtype != TYPE_FIELD)
|
||||
return false;
|
||||
self->constval.vpointer = fld;
|
||||
self->isconst = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ir_value_set_string(ir_value *self, const char *str)
|
||||
{
|
||||
if (self->vtype != TYPE_STRING)
|
||||
|
@ -945,22 +972,26 @@ bool ir_values_overlap(const ir_value *a, const ir_value *b)
|
|||
|
||||
bool ir_block_create_store_op(ir_block *self, int op, ir_value *target, ir_value *what)
|
||||
{
|
||||
if (target->store == store_value) {
|
||||
ir_instr *in = ir_instr_new(self, op);
|
||||
if (!in)
|
||||
return false;
|
||||
|
||||
if (target->store == store_value &&
|
||||
(op < INSTR_STOREP_F || op > INSTR_STOREP_FNC))
|
||||
{
|
||||
fprintf(stderr, "cannot store to an SSA value\n");
|
||||
fprintf(stderr, "trying to store: %s <- %s\n", target->name, what->name);
|
||||
fprintf(stderr, "instruction: %s\n", asm_instr[op].m);
|
||||
return false;
|
||||
} else {
|
||||
ir_instr *in = ir_instr_new(self, op);
|
||||
if (!in)
|
||||
return false;
|
||||
if (!ir_instr_op(in, 0, target, true) ||
|
||||
!ir_instr_op(in, 1, what, false) ||
|
||||
!ir_block_instr_add(self, in) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!ir_instr_op(in, 0, target, true) ||
|
||||
!ir_instr_op(in, 1, what, false) ||
|
||||
!ir_block_instr_add(self, in) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ir_block_create_store(ir_block *self, ir_value *target, ir_value *what)
|
||||
|
@ -980,6 +1011,11 @@ bool ir_block_create_store(ir_block *self, ir_value *target, ir_value *what)
|
|||
#endif
|
||||
op = type_store_instr[vtype];
|
||||
|
||||
if (OPTS_FLAG(ADJUST_VECTOR_FIELDS)) {
|
||||
if (op == INSTR_STORE_FLD && what->fieldtype == TYPE_VECTOR)
|
||||
op = INSTR_STORE_V;
|
||||
}
|
||||
|
||||
return ir_block_create_store_op(self, op, target, what);
|
||||
}
|
||||
|
||||
|
@ -997,6 +1033,11 @@ bool ir_block_create_storep(ir_block *self, ir_value *target, ir_value *what)
|
|||
vtype = what->vtype;
|
||||
|
||||
op = type_storep_instr[vtype];
|
||||
if (OPTS_FLAG(ADJUST_VECTOR_FIELDS)) {
|
||||
if (op == INSTR_STOREP_FLD && what->fieldtype == TYPE_VECTOR)
|
||||
op = INSTR_STOREP_V;
|
||||
}
|
||||
|
||||
return ir_block_create_store_op(self, op, target, what);
|
||||
}
|
||||
|
||||
|
@ -2178,10 +2219,18 @@ static bool gen_global_field(ir_value *global)
|
|||
|
||||
/* copy the field's value */
|
||||
ir_value_code_setaddr(global, code_globals_add(code_globals_data[fld->code.globaladdr]));
|
||||
if (global->fieldtype == TYPE_VECTOR) {
|
||||
code_globals_add(code_globals_data[fld->code.globaladdr]+1);
|
||||
code_globals_add(code_globals_data[fld->code.globaladdr]+2);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ir_value_code_setaddr(global, code_globals_add(0));
|
||||
if (global->fieldtype == TYPE_VECTOR) {
|
||||
code_globals_add(0);
|
||||
code_globals_add(0);
|
||||
}
|
||||
}
|
||||
if (global->code.globaladdr < 0)
|
||||
return false;
|
||||
|
@ -2408,8 +2457,10 @@ tailcall:
|
|||
stmt.o1.u1 = stmt.o3.u1;
|
||||
stmt.o3.u1 = 0;
|
||||
}
|
||||
else if (stmt.opcode >= INSTR_STORE_F &&
|
||||
stmt.opcode <= INSTR_STORE_FNC)
|
||||
else if ((stmt.opcode >= INSTR_STORE_F &&
|
||||
stmt.opcode <= INSTR_STORE_FNC) ||
|
||||
(stmt.opcode >= INSTR_STOREP_F &&
|
||||
stmt.opcode <= INSTR_STOREP_FNC))
|
||||
{
|
||||
/* 2-operand instructions with A -> B */
|
||||
stmt.o2.u1 = stmt.o3.u1;
|
||||
|
@ -2622,13 +2673,42 @@ static bool ir_builder_gen_field(ir_builder *self, ir_value *field)
|
|||
|
||||
def.type = field->vtype;
|
||||
def.offset = code_globals_elements;
|
||||
def.name = field->code.name = code_genstring(field->name);
|
||||
|
||||
/* create a global named the same as the field */
|
||||
if (opts_standard == COMPILER_GMQCC) {
|
||||
/* in our standard, the global gets a dot prefix */
|
||||
size_t len = strlen(field->name);
|
||||
char name[1024];
|
||||
|
||||
/* we really don't want to have to allocate this, and 1024
|
||||
* bytes is more than enough for a variable/field name
|
||||
*/
|
||||
if (len+2 >= sizeof(name)) {
|
||||
printf("invalid field name size: %u\n", (unsigned int)len);
|
||||
return false;
|
||||
}
|
||||
|
||||
name[0] = '.';
|
||||
strcpy(name+1, field->name); /* no strncpy - we used strlen above */
|
||||
name[len+1] = 0;
|
||||
|
||||
def.name = code_genstring(name);
|
||||
fld.name = def.name + 1; /* we reuse that string table entry */
|
||||
} else {
|
||||
/* in plain QC, there cannot be a global with the same name,
|
||||
* and so we also name the global the same.
|
||||
* FIXME: fteqcc should create a global as well
|
||||
* check if it actually uses the same name. Probably does
|
||||
*/
|
||||
def.name = code_genstring(field->name);
|
||||
fld.name = def.name;
|
||||
}
|
||||
|
||||
field->code.name = def.name;
|
||||
|
||||
if (code_defs_add(def) < 0)
|
||||
return false;
|
||||
|
||||
fld.name = def.name;
|
||||
fld.offset = code_fields_elements;
|
||||
fld.type = field->fieldtype;
|
||||
|
||||
if (fld.type == TYPE_VOID) {
|
||||
|
@ -2636,13 +2716,21 @@ static bool ir_builder_gen_field(ir_builder *self, ir_value *field)
|
|||
return false;
|
||||
}
|
||||
|
||||
fld.offset = code_alloc_field(type_sizeof[field->fieldtype]);
|
||||
|
||||
if (code_fields_add(fld) < 0)
|
||||
return false;
|
||||
|
||||
if (!code_globals_add(code_alloc_field(type_sizeof[field->fieldtype])))
|
||||
ir_value_code_setaddr(field, code_globals_elements);
|
||||
if (!code_globals_add(fld.offset))
|
||||
return false;
|
||||
if (fld.type == TYPE_VECTOR) {
|
||||
if (!code_globals_add(fld.offset+1))
|
||||
return false;
|
||||
if (!code_globals_add(fld.offset+2))
|
||||
return false;
|
||||
}
|
||||
|
||||
ir_value_code_setaddr(field, code_globals_add(fld.offset));
|
||||
return field->code.globaladdr >= 0;
|
||||
}
|
||||
|
||||
|
|
1
ir.h
1
ir.h
|
@ -97,6 +97,7 @@ bool GMQCC_WARN ir_value_set_int(ir_value*, int i);
|
|||
#endif
|
||||
bool GMQCC_WARN ir_value_set_string(ir_value*, const char *s);
|
||||
bool GMQCC_WARN ir_value_set_vector(ir_value*, vector v);
|
||||
bool GMQCC_WARN ir_value_set_field(ir_value*, ir_value *fld);
|
||||
/*bool ir_value_set_pointer_v(ir_value*, ir_value* p); */
|
||||
/*bool ir_value_set_pointer_i(ir_value*, int i); */
|
||||
bool GMQCC_WARN ir_value_set_quaternion(ir_value*, quaternion v);
|
||||
|
|
|
@ -21,6 +21,17 @@ name = ast_value_new(ctx, #varname, type)
|
|||
#define MKGLOBAL(name) \
|
||||
assert(globals_add(name) >= 0)
|
||||
|
||||
#define FIELD(type, name) \
|
||||
name = ast_value_new(ctx, #name, TYPE_FIELD); \
|
||||
do { \
|
||||
ast_value *field_##name = ast_value_new(ctx, #name, type); \
|
||||
name->expression.next = (ast_expression*)field_##name; \
|
||||
MKFIELD(name); \
|
||||
} while (0)
|
||||
|
||||
#define MKFIELD(name) \
|
||||
assert(fields_add(name) >= 0)
|
||||
|
||||
#define MKCONSTFLOAT(name, value) \
|
||||
do { \
|
||||
name->isconst = true; \
|
||||
|
@ -35,6 +46,15 @@ do { \
|
|||
MKGLOBAL(name); \
|
||||
} while(0)
|
||||
|
||||
#define MKCONSTVECTOR(name, valx, valy, valz) \
|
||||
do { \
|
||||
name->isconst = true; \
|
||||
name->constval.vvec.x = (valx); \
|
||||
name->constval.vvec.y = (valy); \
|
||||
name->constval.vvec.z = (valz); \
|
||||
MKGLOBAL(name); \
|
||||
} while(0)
|
||||
|
||||
#define STATE(a) \
|
||||
do { \
|
||||
ast_expression *exp = (ast_expression*)(a); \
|
||||
|
@ -47,6 +67,12 @@ do { \
|
|||
#define BIN(op, a, b) \
|
||||
(ast_expression*)ast_binary_new(ctx, INSTR_##op, (ast_expression*)(a), (ast_expression*)(b))
|
||||
|
||||
#define ENTFIELD(a, b) \
|
||||
(ast_expression*)ast_entfield_new(ctx, (ast_expression*)(a), (ast_expression*)(b))
|
||||
|
||||
#define VECMEM(vec, mem) \
|
||||
(ast_expression*)ast_member_new(ctx, (ast_expression*)(vec), (mem))
|
||||
|
||||
#define CALL(what) \
|
||||
do { \
|
||||
ast_call *call = ast_call_new(ctx, (ast_expression*)what); \
|
||||
|
@ -58,6 +84,13 @@ do { \
|
|||
STATE(call); \
|
||||
} while(0)
|
||||
|
||||
#define ENDCALLWITH(as, where) \
|
||||
{ \
|
||||
ast_expression *as = (ast_expression*)call; \
|
||||
where; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define WHILE(cond) \
|
||||
do { \
|
||||
ast_expression *wh_cond = (ast_expression*)(cond); \
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#define assert(x) do { if ( !(x) ) { printf("Assertion failed: %s\n", #x); abort(); } } while(0)
|
||||
|
||||
VECTOR_MAKE(ast_value*, globals);
|
||||
VECTOR_MAKE(ast_value*, fields);
|
||||
VECTOR_MAKE(ast_function*, functions);
|
||||
|
||||
uint32_t opts_flags[1 + (COUNT_FLAGS / 32)];
|
||||
|
@ -36,13 +37,30 @@ int main()
|
|||
DEFVAR(f0);
|
||||
DEFVAR(f1);
|
||||
DEFVAR(f5);
|
||||
DEFVAR(cv3x4x5);
|
||||
DEFVAR(cv1x1x1);
|
||||
DEFVAR(sHello);
|
||||
DEFVAR(sNL);
|
||||
DEFVAR(print);
|
||||
DEFVAR(ftos);
|
||||
DEFVAR(spawn);
|
||||
|
||||
DEFVAR(mema);
|
||||
DEFVAR(memb);
|
||||
DEFVAR(memv);
|
||||
DEFVAR(pawn);
|
||||
|
||||
/* opts_debug = true; */
|
||||
|
||||
BUILTIN(print, TYPE_VOID, -1);
|
||||
PARAM(TYPE_STRING, text);
|
||||
ENDBUILTIN();
|
||||
|
||||
BUILTIN(ftos, TYPE_STRING, -2);
|
||||
PARAM(TYPE_FLOAT, value);
|
||||
ENDBUILTIN();
|
||||
|
||||
BUILTIN(spawn, TYPE_ENTITY, -3);
|
||||
ENDBUILTIN();
|
||||
|
||||
TESTINIT();
|
||||
|
@ -50,21 +68,36 @@ VAR(TYPE_FLOAT, f0);
|
|||
VAR(TYPE_FLOAT, f1);
|
||||
VAR(TYPE_FLOAT, f5);
|
||||
VAR(TYPE_STRING, sHello);
|
||||
VAR(TYPE_STRING, sNL);
|
||||
VAR(TYPE_VECTOR, cv3x4x5);
|
||||
VAR(TYPE_VECTOR, cv1x1x1);
|
||||
|
||||
FIELD(TYPE_FLOAT, mema);
|
||||
FIELD(TYPE_FLOAT, memb);
|
||||
FIELD(TYPE_VECTOR, memv);
|
||||
|
||||
MKCONSTFLOAT(f0, 0.0);
|
||||
MKCONSTFLOAT(f1, 1.0);
|
||||
MKCONSTFLOAT(f5, 5.0);
|
||||
MKCONSTSTRING(sHello, "Hello, World\n");
|
||||
MKCONSTSTRING(sNL, "\n");
|
||||
MKCONSTVECTOR(cv3x4x5, 3, 4, 5);
|
||||
MKCONSTVECTOR(cv1x1x1, 1, 1, 1);
|
||||
|
||||
FUNCTION(foo, TYPE_VOID);
|
||||
ENDFUNCTION(foo);
|
||||
|
||||
#define PRINTNL() do { CALL(print) CALLPARAM(sNL) ENDCALL(); } while(0)
|
||||
|
||||
FUNCTION(main, TYPE_VOID);
|
||||
|
||||
VAR(TYPE_FLOAT, vi);
|
||||
VAR(TYPE_FLOAT, vx);
|
||||
VAR(TYPE_ENTITY, pawn);
|
||||
|
||||
MKLOCAL(vi);
|
||||
MKLOCAL(vx);
|
||||
MKLOCAL(pawn);
|
||||
|
||||
STATE(ASSIGN(STORE_F, vi, f0));
|
||||
WHILE(BIN(LT, vi, f5));
|
||||
|
@ -76,11 +109,48 @@ FUNCTION(main, TYPE_VOID);
|
|||
CALLPARAM(sHello)
|
||||
ENDCALL();
|
||||
|
||||
CALL(spawn)
|
||||
ENDCALLWITH(newent, STATE(ASSIGN(STORE_ENT, pawn, newent)));
|
||||
|
||||
STATE(ASSIGN(STOREP_F, ENTFIELD(pawn, mema), f5));
|
||||
STATE(ASSIGN(STOREP_F, ENTFIELD(pawn, memb), f1));
|
||||
STATE(ASSIGN(STOREP_V, ENTFIELD(pawn, memv), cv3x4x5));
|
||||
CALL(ftos)
|
||||
CALLPARAM(ENTFIELD(pawn, mema))
|
||||
ENDCALLWITH(output,
|
||||
CALL(print)
|
||||
CALLPARAM(output)
|
||||
CALLPARAM(sNL)
|
||||
ENDCALL();
|
||||
);
|
||||
CALL(ftos)
|
||||
CALLPARAM(ENTFIELD(pawn, memb))
|
||||
ENDCALLWITH(output,
|
||||
CALL(print)
|
||||
CALLPARAM(output)
|
||||
CALLPARAM(sNL)
|
||||
ENDCALL();
|
||||
);
|
||||
CALL(ftos)
|
||||
CALLPARAM(ENTFIELD(pawn, VECMEM(memv, 2)))
|
||||
ENDCALLWITH(output,
|
||||
CALL(print)
|
||||
CALLPARAM(output)
|
||||
CALLPARAM(sNL)
|
||||
ENDCALL();
|
||||
);
|
||||
|
||||
ENDFUNCTION(main);
|
||||
|
||||
ir = ir_builder_new("ast_test");
|
||||
assert(ir);
|
||||
|
||||
/* gen fields */
|
||||
for (i = 0; i < fields_elements; ++i) {
|
||||
if (!ast_global_codegen(fields_data[i], ir)) {
|
||||
assert(!"failed to generate field");
|
||||
}
|
||||
}
|
||||
/* gen globals */
|
||||
for (i = 0; i < globals_elements; ++i) {
|
||||
if (!ast_global_codegen(globals_data[i], ir)) {
|
||||
|
|
Loading…
Reference in a new issue