diff --git a/include/QF/pr_comp.h b/include/QF/pr_comp.h index 0467927cb..d2047ed8c 100644 --- a/include/QF/pr_comp.h +++ b/include/QF/pr_comp.h @@ -39,6 +39,7 @@ typedef enum { ev_integer, ev_uinteger, ev_short, // value is embedded in the opcode + ev_struct, ev_type_count // not a type, gives number of types } etype_t; @@ -236,6 +237,8 @@ typedef enum { OP_STOREBI_FNC, OP_STOREBI_I, OP_STOREBI_P, + + OP_LEAI, } pr_opcode_e; typedef struct diff --git a/include/QF/progs.h b/include/QF/progs.h index c7d6cd60d..a351dc9b7 100644 --- a/include/QF/progs.h +++ b/include/QF/progs.h @@ -161,7 +161,7 @@ void ED_Count (progs_t *pr); void PR_Profile (progs_t *pr); char *PR_GlobalString (progs_t *pr, int ofs, etype_t type); -char *PR_GlobalStringNoContents (progs_t *pr, int ofs); +char *PR_GlobalStringNoContents (progs_t *pr, int ofs, etype_t type); pr_type_t *GetEdictFieldValue(progs_t *pr, edict_t *ed, const char *field); diff --git a/libs/gamecode/engine/pr_edict.c b/libs/gamecode/engine/pr_edict.c index a1f1d4b2a..953e3d6e1 100644 --- a/libs/gamecode/engine/pr_edict.c +++ b/libs/gamecode/engine/pr_edict.c @@ -40,7 +40,6 @@ static const char rcsid[] = #include #include "QF/cmd.h" -#include "compat.h" #include "QF/crc.h" #include "QF/cvar.h" #include "QF/hash.h" @@ -52,6 +51,8 @@ static const char rcsid[] = #include "QF/va.h" #include "QF/vfs.h" +#include "compat.h" + cvar_t *pr_boundscheck; cvar_t *pr_deadbeef_ents; cvar_t *pr_deadbeef_locals; @@ -69,6 +70,7 @@ int pr_type_size[ev_type_count] = { 1, 1, 0, // value in opcode + 1, // variable }; const char *type_name[ev_type_count] = { @@ -84,6 +86,7 @@ const char *type_name[ev_type_count] = { "integer", "uinteger", "short", + "struct", }; ddef_t *ED_FieldAtOfs (progs_t * pr, int ofs); @@ -512,12 +515,16 @@ PR_GlobalString (progs_t * pr, int ofs, etype_t type) } char * -PR_GlobalStringNoContents (progs_t * pr, int ofs) +PR_GlobalStringNoContents (progs_t * pr, int ofs, etype_t type) { int i; ddef_t *def = 0; static char line[128]; + if (type == ev_short) { + snprintf (line, sizeof (line), "%-20d", (short) ofs); + return line; + } if (pr_debug->int_val && pr->debug) def = PR_Get_Local_Def (pr, ofs); if (!def) diff --git a/libs/gamecode/engine/pr_exec.c b/libs/gamecode/engine/pr_exec.c index 1fb87ebf0..63dc2ef3e 100644 --- a/libs/gamecode/engine/pr_exec.c +++ b/libs/gamecode/engine/pr_exec.c @@ -86,13 +86,15 @@ PR_PrintStatement (progs_t * pr, dstatement_t *s) if (op->type_c != ev_void) Sys_Printf ("%s", PR_GlobalString (pr, s->b, op->type_b)); else - Sys_Printf ("%s", PR_GlobalStringNoContents (pr, s->b)); + Sys_Printf ("%s", PR_GlobalStringNoContents (pr, s->b, + op->type_b)); } if (op->type_c != ev_void) { if (op->type_b == ev_pointer && op->type_c == ev_integer) Sys_Printf ("%s", PR_GlobalString (pr, s->c, op->type_c)); else - Sys_Printf ("%s", PR_GlobalStringNoContents (pr, s->c)); + Sys_Printf ("%s", PR_GlobalStringNoContents (pr, s->c, + op->type_c)); } } Sys_Printf ("\n"); @@ -598,6 +600,11 @@ PR_ExecuteProgram (progs_t * pr, func_t fnum) OPC.integer_var = pointer; break; + case OP_LEAI: + pointer = OPA.integer_var + (short) st->b; + OPC.integer_var = pointer; + break; + case OP_STOREB_F: case OP_STOREB_S: case OP_STOREB_ENT: diff --git a/libs/gamecode/engine/pr_opcode.c b/libs/gamecode/engine/pr_opcode.c index 4158a2f0c..e6a233ea0 100644 --- a/libs/gamecode/engine/pr_opcode.c +++ b/libs/gamecode/engine/pr_opcode.c @@ -121,7 +121,8 @@ opcode_t pr_opcodes[] = { {"&", "address.i", OP_ADDRESS_I, false, ev_integer, ev_void, ev_pointer, PROG_VERSION}, {"&", "address.p", OP_ADDRESS_P, false, ev_pointer, ev_void, ev_pointer, PROG_VERSION}, - {"&", "lea", OP_LEA, false, ev_pointer, ev_integer, ev_pointer, PROG_VERSION}, + {"&", "lea", OP_LEA, false, ev_pointer, ev_integer, ev_pointer, PROG_VERSION}, + {"&", "leai", OP_LEAI, false, ev_pointer, ev_short, ev_pointer, PROG_VERSION}, {"=", "store.f", OP_STORE_F, true, ev_float, ev_float, ev_void, PROG_ID_VERSION}, {"=", "store.v", OP_STORE_V, true, ev_vector, ev_vector, ev_void, PROG_ID_VERSION}, diff --git a/tools/gl_stub/build b/tools/gl_stub/build index 050d47595..83ee23acf 100755 --- a/tools/gl_stub/build +++ b/tools/gl_stub/build @@ -1,3 +1,3 @@ #! /bin/sh -gcc -o GLstub.so -shared -O3 -ffast-math -funroll-loops -fomit-frame-pointer -fexpensive-optimizations gl_stub.c +gcc -o GLstub.so -fPIC -shared -O3 -ffast-math -funroll-loops -fomit-frame-pointer -fexpensive-optimizations gl_stub.c diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index 74e0b6910..ccf4a2ca5 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -6,6 +6,7 @@ typedef enum { ex_def, ex_temp, // temporary variable ex_nil, // umm, nil, null. nuff said + ex_name, ex_string, ex_float, diff --git a/tools/qfcc/include/qfcc.h b/tools/qfcc/include/qfcc.h index 794b0dee5..ecfb755b7 100644 --- a/tools/qfcc/include/qfcc.h +++ b/tools/qfcc/include/qfcc.h @@ -283,10 +283,13 @@ typedef struct type_s etype_t type; struct def_s *def; // a def that points to this type struct type_s *next; -// function types are more complex +// function/pointer/struct types are more complex struct type_s *aux_type; // return type or field type int num_parms; // -1 = variable args struct type_s *parm_types[MAX_PARMS]; // only [num_parms] allocated + struct hashtab_s *struct_fields; + struct struct_field_s *struct_head; + struct struct_field_s **struct_tail; } type_t; typedef struct statref_s { @@ -359,6 +362,7 @@ extern type_t type_quaternion; extern type_t type_integer; extern type_t type_uinteger; extern type_t type_short; +extern type_t type_struct; extern def_t def_void; extern def_t def_string; @@ -372,6 +376,7 @@ extern def_t def_quaternion; extern def_t def_integer; extern def_t def_uinteger; extern def_t def_short; +extern def_t def_struct; struct function_s { diff --git a/tools/qfcc/source/Makefile.am b/tools/qfcc/source/Makefile.am index a5f6bb4e1..04ceabe5e 100644 --- a/tools/qfcc/source/Makefile.am +++ b/tools/qfcc/source/Makefile.am @@ -33,5 +33,5 @@ YFLAGS = -d bin_PROGRAMS= qfcc -qfcc_SOURCES= cmdlib.c debug.c pr_comp.c pr_def.c pr_imm.c pr_lex.c pr_opcode.c qfcc.c qc-parse.y qc-lex.l emit.c expr.c switch.c getopt.c getopt1.c +qfcc_SOURCES= cmdlib.c debug.c pr_comp.c pr_def.c pr_imm.c pr_lex.c pr_opcode.c qfcc.c qc-parse.y qc-lex.l emit.c expr.c struct.c switch.c getopt.c getopt1.c qfcc_LDADD= -lQFgamecode -lQFutil diff --git a/tools/qfcc/source/emit.c b/tools/qfcc/source/emit.c index 3eea295c9..2c5cce9dd 100644 --- a/tools/qfcc/source/emit.c +++ b/tools/qfcc/source/emit.c @@ -77,6 +77,8 @@ emit_statement (int sline, opcode_t *op, def_t *var_a, def_t *var_b, if (op->type_c == ev_void) { var_c = NULL; statement->c = 0; + } else { + statement->c = var_c->ofs; } ret = var_a; } else { // allocate result space @@ -249,6 +251,7 @@ emit_sub_expr (expr_t *e, def_t *dest) emit_expr (e); break; } + case ex_name: case ex_nil: case ex_label: error (e, "internal error"); @@ -299,6 +302,24 @@ emit_sub_expr (expr_t *e, def_t *dest) dest = PR_GetTempDef (e->e.expr.type, pr_scope); dest->users += 2; } + } else if (e->e.expr.op == '&') { + static expr_t zero; + def_t *tmp = 0; + + zero.type = ex_short; + + operator = "&"; + if (e->e.expr.e1->type == ex_expr + && e->e.expr.e1->e.expr.op == '.') { + tmp = PR_GetTempDef (e->e.expr.type, pr_scope); + tmp->users += 2; + } + def_a = emit_sub_expr (e->e.expr.e1, tmp); + def_b = emit_sub_expr (&zero, 0); + if (!dest) { + dest = PR_GetTempDef (e->e.expr.type, pr_scope); + dest->users += 2; + } } else { abort (); } @@ -335,6 +356,7 @@ emit_sub_expr (expr_t *e, def_t *dest) d = PR_NewDef (&type_short, 0, pr_scope); d->ofs = e->e.short_val; d->absolute = 1; + d->users = 1; break; } PR_FreeTempDefs (); @@ -454,6 +476,7 @@ emit_expr (expr_t *e) warning (e, "Ignoring useless expression"); break; case ex_nil: + case ex_name: error (e, "internal error"); abort (); } diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 9908be90b..5ef0e0217 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -38,6 +38,7 @@ static const char rcsid[] = #include "qfcc.h" #include "scope.h" +#include "struct.h" #include "qc-parse.h" @@ -51,6 +52,7 @@ etype_t qc_types[] = { ev_void, // ex_def ev_void, // ex_temp ev_void, // ex_nil + ev_void, // ex_name ev_string, // ex_string ev_float, // ex_float @@ -93,13 +95,31 @@ expr_type expr_types[] = { ex_integer, // ev_integer ex_uinteger, // ev_uinteger ex_short, // ev_short + ex_nil, // ev_struct FIXME??? }; +void +convert_name (expr_t *e) +{ + if (e->type == ex_name) { + const char * name = e->e.string_val; + + e->type = ex_def; + e->e.def = PR_GetDef (NULL, name, pr_scope, false); + if (!e->e.def) { + error (e, "Undeclared variable \"%s\".", name); + e->e.def = &def_float; + } + } +} + type_t * get_type (expr_t *e) { + convert_name (e); switch (e->type) { case ex_label: + case ex_name: return 0; // something went very wrong case ex_nil: return &type_void; @@ -487,6 +507,7 @@ print_expr (expr_t *e) printf ("NULL"); break; case ex_string: + case ex_name: printf ("\"%s\"", e->e.string_val); break; case ex_float: @@ -798,8 +819,36 @@ field_expr (expr_t *e1, expr_t *e2) { etype_t t1, t2; expr_t *e; + type_t *strct; + struct_field_t *field; t1 = extract_type (e1); + if (t1 == ev_struct) { + strct = get_type (e1); + if (e2->type != ex_name) + return error (e2, "structure field name expected"); + field = struct_find_field (strct, e2->e.string_val); + if (!field) + return error (e2, "structure has no field %s", e2->e.string_val); + e2->type = ex_short; + e2->e.short_val = field->offset; + e = new_binary_expr ('.', unary_expr ('&', e1), e2); + e->e.expr.type = field->type; + return e; + } + if (t1 == ev_pointer + && (strct = get_type(e1)->aux_type)->type == ev_struct) { + if (e2->type != ex_name) + return error (e2, "structure field name expected"); + field = struct_find_field (strct, e2->e.string_val); + if (!field) + return error (e2, "structure has no field %s", e2->e.string_val); + e2->type = ex_short; + e2->e.short_val = field->offset; + e = new_binary_expr ('.', e1, e2); + e->e.expr.type = field->type; + return e; + } t2 = extract_type (e2); if ((t1 != ev_entity || t2 != ev_field) @@ -831,8 +880,7 @@ test_expr (expr_t *e, int test) error (e, "internal error"); abort (); case ev_void: - error (e, "void has no value"); - break; + return error (e, "void has no value"); case ev_string: new = new_expr (); new->type = ex_string; @@ -871,6 +919,8 @@ test_expr (expr_t *e, int test) new = new_expr (); new->type = ex_quaternion; break; + case ev_struct: + return error (e, "struct cannot be tested"); } new->line = e->line; new->file = e->file; @@ -894,9 +944,9 @@ binary_expr (int op, expr_t *e1, expr_t *e2) type_t *type = 0; expr_t *e; + convert_name (e1); if (op != '=') check_initialized (e1); - check_initialized (e2); if (op == '=' && e1->type == ex_def) PR_DefInitialized (e1->e.def); @@ -911,6 +961,9 @@ binary_expr (int op, expr_t *e1, expr_t *e2) if (op == '.') return field_expr (e1, e2); + convert_name (e2); + check_initialized (e2); + if (op == OR || op == AND) { e1 = test_expr (e1, true); e2 = test_expr (e2, true); @@ -1028,11 +1081,13 @@ asx_expr (int op, expr_t *e1, expr_t *e2) expr_t * unary_expr (int op, expr_t *e) { + convert_name (e); check_initialized (e); switch (op) { case '-': switch (e->type) { case ex_label: + case ex_name: error (e, "internal error"); abort (); case ex_uexpr: @@ -1084,6 +1139,8 @@ unary_expr (int op, expr_t *e) case '!': switch (e->type) { case ex_label: + case ex_name: + error (e, "internal error"); abort (); case ex_block: if (!e->e.block.result) @@ -1142,13 +1199,15 @@ unary_expr (int op, expr_t *e) case '~': switch (e->type) { case ex_label: + case ex_name: + error (e, "internal error"); abort (); case ex_uexpr: if (e->e.expr.op == '~') return e->e.expr.e1; case ex_block: if (!e->e.block.result) - return error (e, "invalid type for unary -"); + return error (e, "invalid type for unary ~"); case ex_expr: case ex_def: case ex_temp: @@ -1183,8 +1242,54 @@ unary_expr (int op, expr_t *e) return error (e, "invalid type for unary ~"); } break; - default: - abort (); + case '&': + switch (e->type) { + case ex_label: + case ex_name: + error (e, "internal error"); + abort (); + case ex_def: + { + type_t new; + expr_t *n = new_unary_expr (op, e); + + memset (&new, 0, sizeof (new)); + new.type = ev_pointer; + new.aux_type = e->e.def->type; + n->e.expr.type = PR_FindType (&new); + return n; + } + case ex_expr: + if (e->e.expr.op == '.') { + expr_t *e1 = e->e.expr.e1; + if (get_type (e1) == &type_entity) { + type_t new; + + memset (&new, 0, sizeof (new)); + new.type = ev_pointer; + new.aux_type = e->e.expr.type; + e->e.expr.type = PR_FindType (&new); + return e; + } + } + case ex_uexpr: + case ex_block: + case ex_temp: + case ex_short: + case ex_integer: + case ex_uinteger: + case ex_float: + case ex_nil: + case ex_string: + case ex_vector: + case ex_quaternion: + case ex_entity: + case ex_field: + case ex_func: + case ex_pointer: + return error (e, "invalid type for unary &"); + } + break; } error (e, "internal error"); abort (); diff --git a/tools/qfcc/source/pr_def.c b/tools/qfcc/source/pr_def.c index 4b3535737..45b30199a 100644 --- a/tools/qfcc/source/pr_def.c +++ b/tools/qfcc/source/pr_def.c @@ -102,6 +102,14 @@ PR_GetArray (type_t *etype, const char *name, int size, def_t *scope, return def; } +int +PR_GetTypeSize (type_t *type) +{ + if (type->type == ev_struct) + return type->num_parms; + return pr_type_size[type->type]; +} + /* PR_GetDef @@ -113,6 +121,7 @@ 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]; + int size; if (def || !allocate) return def; @@ -147,7 +156,7 @@ PR_GetDef (type_t *type, const char *name, def_t *scope, int *allocate) d->used = 1; d->parent = def; } else { - *allocate += pr_type_size[type->type]; + *allocate += PR_GetTypeSize(type); } if (type->type == ev_field) { @@ -171,13 +180,15 @@ PR_GetDef (type_t *type, const char *name, def_t *scope, int *allocate) d->used = 1; // always `used' d->parent = def; } else if (type->aux_type->type == ev_pointer) { - pr.size_fields += type->aux_type->num_parms - * pr_type_size[type->aux_type->aux_type->type]; + size = PR_GetTypeSize (type->aux_type->aux_type); + pr.size_fields += type->aux_type->num_parms * size; } else { - pr.size_fields += pr_type_size[type->aux_type->type]; + size = PR_GetTypeSize (type->aux_type); + pr.size_fields += size; } } else if (type->type == ev_pointer) { - *allocate += type->num_parms * pr_type_size[type->aux_type->type]; + size = PR_GetTypeSize (type->aux_type); + *allocate += type->num_parms * size; def->initialized = def->constant = 1; } diff --git a/tools/qfcc/source/pr_lex.c b/tools/qfcc/source/pr_lex.c index 671f590c4..60a831f7d 100644 --- a/tools/qfcc/source/pr_lex.c +++ b/tools/qfcc/source/pr_lex.c @@ -68,6 +68,7 @@ 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_short = { ev_short, &def_short }; +type_t type_struct = { ev_struct, &def_struct }; type_t type_floatfield = { ev_field, &def_field, NULL, &type_float }; @@ -83,6 +84,7 @@ def_t def_quaternion = { &type_quaternion, "temp" }; def_t def_integer = { &type_integer, "temp" }; def_t def_uinteger = { &type_uinteger, "temp" }; def_t def_short = { &type_short, "temp" }; +def_t def_struct = { &type_struct, "temp" }; def_t def_ret, def_parms[MAX_PARMS]; @@ -304,8 +306,7 @@ PR_FindType (type_t *type) // allocate a generic def for the type, so fields can reference it def = malloc (sizeof (def_t)); - - if (!check) + if (!def) Sys_Error ("PR_FindType: Memory Allocation Failure\n"); def->name = "COMPLEX TYPE"; def->type = check; diff --git a/tools/qfcc/source/qc-lex.l b/tools/qfcc/source/qc-lex.l index 0ac85e03d..89203862f 100644 --- a/tools/qfcc/source/qc-lex.l +++ b/tools/qfcc/source/qc-lex.l @@ -35,6 +35,7 @@ static const char rcsid[] = #include #include "qfcc.h" #include "scope.h" +#include "struct.h" #include "qc-parse.h" #define YY_NO_UNPUT @@ -227,6 +228,7 @@ static keyword_t keywords[] = { {"case", CASE, 0, PROG_ID_VERSION}, {"default", DEFAULT, 0, PROG_ID_VERSION}, {"NIL", NIL, 0, PROG_ID_VERSION}, + {"struct", STRUCT, 0, PROG_VERSION}, }; static const char * @@ -238,23 +240,27 @@ keyword_get_key (void *kw, void *unused) int type_or_name (char *token) { - static int initialized = 0; static hashtab_t *keyword_tab; - keyword_t *keyword; + keyword_t *keyword; + type_t *type; - if (!initialized) { + if (!keyword_tab) { int i; keyword_tab = Hash_NewTable (1021, keyword_get_key, 0, 0); for (i = 0; i < sizeof (keywords) / sizeof (keywords[0]); i++) if (keywords[i].version <= options.code.progsversion) Hash_Add (keyword_tab, &keywords[i]); - initialized = 1; } keyword = Hash_Find (keyword_tab, token); if (keyword) { yylval.type = keyword->type; return keyword->value; } + type = find_struct (token); + if (type) { + yylval.type = type; + return TYPE; + } yylval.string_val = strdup (token); return NAME; } diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index c3798c187..d22ea4eac 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -35,6 +35,7 @@ static const char rcsid[] = #include #include +#include "struct.h" #include "switch.h" #define YYDEBUG 1 @@ -110,7 +111,7 @@ typedef struct { %token LOCAL RETURN WHILE DO IF ELSE FOR BREAK CONTINUE ELIPSIS NIL %token IFBE IFB IFAE IFA -%token SWITCH CASE DEFAULT +%token SWITCH CASE DEFAULT STRUCT %token TYPE %type type opt_func func_parms array_decl @@ -137,6 +138,7 @@ expr_t *local_expr; expr_t *break_label; expr_t *continue_label; switch_block_t *switch_block; +type_t *struct_type; def_t *pr_scope; // the function being parsed, or NULL string_t s_file; // filename for function definition @@ -157,6 +159,22 @@ def { current_type = build_type ($1, $4); } var_def_list | opt_field TYPE { current_type = $2; } func_parms { current_type = build_type ($1, $4); } func_def_list + | STRUCT NAME + { struct_type = new_struct ($2); } '=' '{' struct_defs '}' + ; + +struct_defs + : /* empty */ + | struct_defs struct_def ';' + ; + +struct_def + : opt_field TYPE + { current_type = build_type ($1, $2); } struct_def_list + | opt_field TYPE { current_type = $2; } array_decl + { current_type = build_type ($1, $4); } struct_def_list + | opt_field TYPE { current_type = $2; } func_parms + { current_type = build_type ($1, $4); } struct_def_list ; opt_field @@ -218,6 +236,15 @@ array_decl | '[' ']' { $$ = build_array_type (0); } ; +struct_def_list + : struct_def_list ',' struct_def_item + | struct_def_item + ; + +struct_def_item + : NAME { new_struct_field (struct_type, current_type, $1); } + ; + var_def_list : var_def_list ',' var_def_item | var_def_item @@ -683,12 +710,8 @@ expr | NAME { $$ = new_expr (); - $$->type = ex_def; - $$->e.def = PR_GetDef (NULL, $1, pr_scope, false); - if (!$$->e.def) { - error (0, "Undeclared variable \"%s\".", $1); - $$->e.def = &def_float; - } + $$->type = ex_name; + $$->e.string_val = $1; } | const { $$ = $1; } | '(' expr ')' { $$ = $2; $$->paren = 1; } @@ -805,6 +828,14 @@ build_type (int is_field, type_t *type) new.type = ev_field; new.aux_type = type; return PR_FindType (&new); + } else if (type->type == ev_struct) { + type_t new; + + memset (&new, 0, sizeof (new)); + new.type = ev_pointer; + new.aux_type = type; + new.num_parms = 1; + return PR_FindType (&new); } else { return type; } diff --git a/tools/qfcc/source/struct.c b/tools/qfcc/source/struct.c index 529cc786e..f804d2f01 100644 --- a/tools/qfcc/source/struct.c +++ b/tools/qfcc/source/struct.c @@ -37,7 +37,8 @@ new_struct_field (type_t *strct, type_t *type, const char *name) field->next = 0; *strct->struct_tail = field; strct->struct_tail = &field->next; - return 0; + Hash_Add (strct->struct_fields, field); + return field; } struct_field_t *