diff --git a/ast.c b/ast.c index 5f947b0..117f845 100644 --- a/ast.c +++ b/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); diff --git a/exec.c b/exec.c index c65c6e2..b957a83 100644 --- a/exec.c +++ b/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); diff --git a/execloop.h b/execloop.h index 3b6d666..b75061e 100644 --- a/execloop.h +++ b/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: diff --git a/flags.def b/flags.def index a7387d1..79ab71e 100644 --- a/flags.def +++ b/flags.def @@ -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) diff --git a/gmqcc.h b/gmqcc.h index 4e1c641..b27998b 100644 --- a/gmqcc.h +++ b/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; diff --git a/ir.c b/ir.c index f34cc91..78c97c7 100644 --- a/ir.c +++ b/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; } diff --git a/ir.h b/ir.h index a4dddcb..66336d6 100644 --- a/ir.h +++ b/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); diff --git a/test/ast-macros.h b/test/ast-macros.h index ebb3a5b..580cd7a 100644 --- a/test/ast-macros.h +++ b/test/ast-macros.h @@ -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); \ diff --git a/test/ast-test.c b/test/ast-test.c index 3862144..74800dd 100644 --- a/test/ast-test.c +++ b/test/ast-test.c @@ -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)) {