rework class fields a little - fields now map onto a single underlaying array symbol, which avoids the need for differently sized underlaying arrays per member that were then conflicting between classes.

tweak the decompiler to deal with fte-optimised progs a little better.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5272 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2018-07-18 13:02:03 +00:00
parent a450035e80
commit d474f48fd1
5 changed files with 226 additions and 163 deletions

View File

@ -91,12 +91,12 @@ char *type_names[] =
"ev_quat",
"ev_uinteger"
};
char *typetoname(QCC_type_t *type)
const char *typetoname(QCC_type_t *type)
{
return type->name;
}
char *temp_type (int temp, dstatement_t *start, dfunction_t *df)
const char *temp_type (int temp, dstatement_t *start, dfunction_t *df)
{
int i;
dstatement_t *stat;
@ -452,7 +452,7 @@ static struct {
{80, "infokey", &type_string, {&type_entity, &type_string}, "string(entity e, string key)"},
{81, "stof", &type_float, {&type_string}, "float(string s)"},
{82, "multicast", NULL, {&type_vector, &type_float}, "void(vector where, float set)"},
/*
//these are mvdsv specific
{83, "executecmd", NULL, {NULL}, NULL},
{84, "tokenize", NULL, {&type_string}, NULL},
@ -475,6 +475,50 @@ static struct {
{101, "redirectcmd", NULL, {NULL}, NULL},
{102, "calltimeofday", NULL, {NULL}, NULL},
{103, "forcedemoframe", NULL, {NULL}, NULL},
*/
//some QSG extensions
{83, NULL, NULL, {NULL}, NULL},
{84, NULL, NULL, {NULL}, NULL},
{85, NULL, NULL, {NULL}, NULL},
{86, NULL, NULL, {NULL}, NULL},
{87, NULL, NULL, {NULL}, NULL},
{88, NULL, NULL, {NULL}, NULL},
{89, NULL, NULL, {NULL}, NULL},
{90, "tracebox", NULL, {&type_vector, &type_vector, &type_vector, &type_vector, &type_float, &type_entity}, "void(vector start, vector mins, vector maxs, vector end, float nomonsters, entity ent)"},
{91, "randomvec", &type_vector, {NULL}, "vector()"},
{92, "getlight", &type_vector, {&type_vector}, "vector(vector org)"},
{93, "registercvar", &type_float, {&type_string, &type_string}, "float(string cvarname, string defaultvalue)"},
{94, "min", &type_float, {&type_float,&type_float,&type_float,&type_float,&type_float,&type_float,&type_float,&type_float},"float(float a, float b, ...)"},
{95, "max", &type_float, {&type_float,&type_float,&type_float,&type_float,&type_float,&type_float,&type_float,&type_float},"float(float a, float b, ...)"},
{96, "bound", &type_float, {&type_float,&type_float,&type_float}, "float(float minimum, float val, float maximum)"},
{97, "pow", &type_float, {&type_float,&type_float}, "float(float value, float exp)"},
{98, "findfloat", &type_entity, {&type_entity,&type_field,&type_float}, "entity(entity start, .__variant fld, __variant match)"},
{99, "checkextension",&type_float, {&type_string}, "float(string extname)"},
{100, "builtin_find", &type_float, {&type_string}, "float(string builtinname)"},
{101, "redirectcmd", NULL, {&type_entity,&type_string}, "void(entity to, string str)"},
{102, "anglemod", &type_float, {&type_float}, "float(float value)"},
{103, "cvar_string", &type_string, {&type_string}, "string(string cvarname)"},
{104, "showpic", NULL, {NULL}, "void(string slot, string picname, float x, float y, float zone, optional entity player)"},
{105, "hidepic", NULL, {NULL}, "void(string slot, optional entity player)"},
{106, "movepic", NULL, {NULL}, "void(string slot, float x, float y, float zone, optional entity player)"},
{107, "changepic", NULL, {NULL}, "void(string slot, string picname, optional entity player)"},
{108, "showpicent", NULL, {NULL}, "void(string slot, entity player)"},
{109, "hidepicent", NULL, {NULL}, "void(string slot, entity player)"},
{110, "fopen", &type_float, {&type_string,&type_float}, "filestream(string filename, float mode, optional float mmapminsize)"},
{111, "fclose", NULL, {&type_float}, "void(filestream fhandle)"},
{112, "fgets", &type_string, {&type_float,&type_string}, "string(filestream fhandle)"},
{113, "fputs", NULL, {&type_float,&type_string}, "void(filestream fhandle, string s, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6, optional string s7)"},
{114, "strlen", &type_float, {&type_string}, "float(string s)"},
{115, "strcat", &type_string, {&type_string,&type_string}, "string(string s1, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6, optional string s7, optional string s8)"},
{116, "substring", &type_string, {&type_string,&type_float,&type_float}, "string(string s, float start, float length)"},
{117, "stov", &type_vector, {&type_string}, "vector(string s)"},
{118, "strzone", &type_string, {&type_string}, "string(string s, ...)"},
{119, "strunzone", NULL, {&type_string}, "void(string s)"},
};
char *DecompileValueString(etype_t type, void *val);
@ -1044,11 +1088,12 @@ void DecompileCalcProfiles(void)
*/
for (j = 0, ps = 0; j < df->numparms; j++)
ps += df->parm_size[j];
ps += df->parm_size[j];
if (ps > 0)
{
for (j = df->parm_start; j < (df->parm_start) + ps; j++)
int p;
for (p = 0, j = df->parm_start; j < (df->parm_start) + ps; p++)
{
line[0] = '\0';
par = DecompileGetParameter(j);
@ -1059,16 +1104,31 @@ void DecompileCalcProfiles(void)
{
//Error("Error - No parameter names with offset %i.", j);
// printf("No parameter names with offset %i\n", j);
if (j < (df->parm_start) + ps - 1)
QC_snprintfz(line, sizeof(line), "float par%i, ", j - df->parm_start);
if (p<8)
j += df->parm_size[p];
else
QC_snprintfz(line, sizeof(line), "float par%i", j - df->parm_start);
j += 1;
if (p<8&&df->parm_size[p] == 3)
{
if (j < (df->parm_start) + ps)
QC_snprintfz(line, sizeof(line), "vector par%i, ", p);
else
QC_snprintfz(line, sizeof(line), "vector par%i", p);
}
else
{
if (j < (df->parm_start) + ps)
QC_snprintfz(line, sizeof(line), "__variant par%i, ", p);
else
QC_snprintfz(line, sizeof(line), "__variant par%i", p);
}
}
else
{
if (par->type == ev_vector)
j += 2;
if (j < (df->parm_start) + ps - 1)
j++;
if (j < (df->parm_start) + ps)
{
QC_snprintfz(line, sizeof(line), "%s, ", DecompilePrintParameter(par));
}
@ -1195,7 +1255,7 @@ char *DecompileGlobal(dfunction_t *df, gofs_t ofs, QCC_type_t * req_t)
if (def)
{
if (!strcmp(strings + def->s_name, "IMMEDIATE") || !strcmp(strings + def->s_name, ".imm"))
if (!strcmp(strings + def->s_name, "IMMEDIATE") || !strcmp(strings + def->s_name, ".imm") || !def->s_name)
{
etype_t ty;
if (!req_t)
@ -1363,6 +1423,24 @@ void DecompileImmediate_Insert(dfunction_t *df, gofs_t ofs, char *knew, QCC_type
}
}
void FloatToString(char *out, size_t outsize, float f)
{
char *e;
QC_snprintfz(out, outsize, "%f", f);
//trim any trailing decimals
e = strchr(out, '.');
if (e)
{
e = e+strlen(e);
while (e > out && e[-1] == '0')
e--;
if (e > out && e[-1] == '.')
e--;
*e = 0;
}
}
char *DecompileImmediate_Get(dfunction_t *df, gofs_t ofs, QCC_type_t *req_t)
{
char *res;
@ -1402,16 +1480,21 @@ char *DecompileImmediate_Get(dfunction_t *df, gofs_t ofs, QCC_type_t *req_t)
{
case ev_void: //for lack of any better ideas.
case ev_float:
if ((float)(int)pr_globals[ofs] == pr_globals[ofs])
QC_snprintfz(temp, sizeof(temp), "%i", (int)(pr_globals[ofs]));
else if ((*(int*)&pr_globals[ofs] & 0x7f800000) || !(*(int*)&pr_globals[ofs] & 0x7fffffff))
QC_snprintfz(temp, sizeof(temp), "%f", pr_globals[ofs]);
//denormalised floats need special handling.
if ((0x7fffffff&*(int*)&pr_globals[ofs]) >= 1 && (0x7fffffff&*(int*)&pr_globals[ofs]) < 0x00800000)
{
QC_snprintfz(temp, sizeof(temp), "((float)(__variant)%ii)", *(int*)&pr_globals[ofs]);
// if (req_t && *(int*)&pr_globals[ofs] >= 1 && *(int*)&pr_globals[ofs] < strofs)
// ; //failure to break means we'll print out a trailing /*string*/
// else
break;
}
else
QC_snprintfz(temp, sizeof(temp), "%%%i", *(int*)&pr_globals[ofs]);
if (pr_globals[ofs] == 0 || ((int*)pr_globals)[ofs] < 0 || ((int*)pr_globals)[ofs] >= strofs || strcmp(temp, "0.000000"))
{
FloatToString(temp, sizeof(temp), pr_globals[ofs]);
break;
// printf("Hey! That's not a float! error in %s\n", strings + df->s_name);
// printf("%f could be %s\n", pr_globals[ofs], &strings[((int*)pr_globals)[ofs]]);
}
case ev_string:
{
const char *in;
@ -1495,7 +1578,13 @@ char *DecompileImmediate_Get(dfunction_t *df, gofs_t ofs, QCC_type_t *req_t)
}
break;
case ev_vector:
QC_snprintfz(temp, sizeof(temp), "\'%f %f %f\'", pr_globals[ofs],pr_globals[ofs+1],pr_globals[ofs+2]);
{
char x[64], y[64], z[64];
FloatToString(x, sizeof(x), pr_globals[ofs+0]);
FloatToString(y, sizeof(y), pr_globals[ofs+1]);
FloatToString(z, sizeof(z), pr_globals[ofs+2]);
QC_snprintfz(temp, sizeof(temp), "\'%s %s %s\'", x, y, z);
}
break;
// case ev_quat:
// QC_snprintfz(temp, sizeof(temp), "\'%f %f %f %f\'", pr_globals[ofs],pr_globals[ofs+1],pr_globals[ofs+2],pr_globals[ofs+3]);
@ -2498,57 +2587,15 @@ QCC_ddef_t *DecompileFunctionGlobal(int funcnum)
return NULL;
}
void DecompileFunction(const char *name, int *lastglobal)
void DecompilePreceedingGlobals(int start, int end, const char *name)
{
int i, findex, ps;
dstatement_t *ds, *ts, *altdone;
dfunction_t *df;
QCC_ddef_t *par;
char *arg2;
unsigned short dom, tom;
int j, start, end;
int j;
QCC_ddef_t *ef;
static char line[8192];
dstatement_t *k;
int dum;
size_t startpos;
const char *matchingfield;
for (i = 1; i < numfunctions; i++)
if (!strcmp(name, strings + functions[i].s_name))
break;
if (i == numfunctions)
{
printf("Fatal Error: No function named \"%s\"\n", name);
exit(1);
}
df = functions + i;
altdone = statements + numstatements;
for (j = i+1; j < numfunctions; j++)
{
if (functions[j].first_statement <= 0)
continue;
altdone = statements + functions[j].first_statement;
break;
}
findex = i;
start = *lastglobal;
// if (dfpred->first_statement <= 0 && df->first_statement > 0)
// start -= 1;
end = df->parm_start;
if (!end)
{
par = DecompileFindGlobal(name);
if (par)
end = par - globals;
}
*lastglobal = max(*lastglobal, end + df->locals);
//print globals leading up to the function.
for (j = start; j < end; j++)
{
@ -2584,7 +2631,7 @@ void DecompileFunction(const char *name, int *lastglobal)
}
else if (par->type != ev_pointer)
{
if (strcmp(strings + par->s_name, "IMMEDIATE") && strcmp(strings + par->s_name, ".imm"))
if (strcmp(strings + par->s_name, "IMMEDIATE") && strcmp(strings + par->s_name, ".imm") && par->s_name)
{
if (par->type == ev_field)
@ -2656,8 +2703,58 @@ void DecompileFunction(const char *name, int *lastglobal)
}
}
}
}
void DecompileFunction(const char *name, int *lastglobal)
{
int i, findex, ps;
dstatement_t *ds, *ts, *altdone;
dfunction_t *df;
QCC_ddef_t *par;
char *arg2;
unsigned short dom, tom;
int j, start, end;
static char line[8192];
dstatement_t *k;
int dum;
size_t startpos;
for (i = 1; i < numfunctions; i++)
if (!strcmp(name, strings + functions[i].s_name))
break;
if (i == numfunctions)
{
printf("Fatal Error: No function named \"%s\"\n", name);
exit(1);
}
df = functions + i;
altdone = statements + numstatements;
for (j = i+1; j < numfunctions; j++)
{
if (functions[j].first_statement <= 0)
continue;
altdone = statements + functions[j].first_statement;
break;
}
findex = i;
start = *lastglobal;
// if (dfpred->first_statement <= 0 && df->first_statement > 0)
// start -= 1;
end = df->parm_start;
if (!end)
{
par = DecompileFindGlobal(name);
if (par)
end = par - globals;
}
*lastglobal = max(*lastglobal, end + df->locals);
DecompilePreceedingGlobals(start, end, name);
/*
* Check ''local globals''
* Check ''local globals''
*/
if (df->first_statement <= 0)
@ -2967,6 +3064,7 @@ void DecompileDecompileFunctions(const char *origcopyright)
vfile_t *f;
char fname[512];
int lastglob = 1;
QCC_ddef_t *def;
DecompileCalcProfiles();
@ -2985,6 +3083,27 @@ void DecompileDecompileFunctions(const char *origcopyright)
QCC_CatVFile(Decompileprogssrc, "//#pragma copyright \"%s\"\n", origcopyright);
QCC_CatVFile(Decompileprogssrc, "\n", origcopyright);
def = DecompileFindGlobal("end_sys_fields");
lastglob = def?def->ofs+1:1;
if (lastglob != 1)
{
QC_snprintfz(synth_name, sizeof(synth_name), "sysdefs.qc");
QC_snprintfz(fname, sizeof(fname), synth_name);
if (!DecompileAlreadySeen(fname, &f))
{
printf("decompiling %s\n", fname);
compilecb();
QCC_CatVFile(Decompileprogssrc, "%s\n", fname);
}
if (!f)
{
printf("Fatal Error - Could not open \"%s\" for output.\n", fname);
exit(1);
}
Decompileofile = f;
DecompilePreceedingGlobals(1, lastglob, "");
}
for (i = 1; i < numfunctions; i++)
{

View File

@ -975,6 +975,7 @@ void QCC_PR_NewLine (pbool incomment);
#define GDF_USED 64 //don't strip this, ever.
#define GDF_BASICTYPE 128 //don't care about #merge types not being known correctly.
#define GDF_SCANLOCAL 256 //don't use the locals hash table
#define GDF_POSTINIT 512 //field must be initialised at the end of the compile (allows arrays to be extended later)
QCC_def_t *QCC_PR_GetDef (QCC_type_t *type, const char *name, struct QCC_function_s *scope, pbool allocate, int arraysize, unsigned int flags);
QCC_sref_t QCC_PR_GetSRef (QCC_type_t *type, const char *name, struct QCC_function_s *scope, pbool allocate, int arraysize, unsigned int flags);
void QCC_FreeTemp(QCC_sref_t t);

View File

@ -6826,94 +6826,6 @@ QCC_def_t *QCC_MemberInParentClass(char *name, QCC_type_t *clas)
return QCC_MemberInParentClass(name, clas->parentclass);
}
#if 0
//create fields for the types, instanciate the members to the fields.
//we retouch the parents each time to guarentee polymorphism works.
//FIXME: virtual methods will not work properly. Need to trace down to see if a parent already defined it
void QCC_PR_EmitFieldsForMembers(QCC_type_t *clas, int *basictypefield)
{
//we created fields for each class when we defined the actual classes.
//we need to go through each member and match it to the offset of it's parent class, if overloaded, or create a new field if not..
//basictypefield is cleared before we do this
//we emit the parent's fields first (every time), thus ensuring that we don't reuse parent fields on a child class.
char membername[2048];
unsigned int p;
int a;
unsigned int o;
QCC_type_t *mt, *ft;
QCC_def_t *f, *m;
extern pbool verbose;
if (clas->parentclass != type_entity) //parents MUST have all their fields set or inheritance would go crazy.
QCC_PR_EmitFieldsForMembers(clas->parentclass, basictypefield);
for (p = 0; p < clas->num_parms; p++)
{
mt = clas->params[p].type;
QC_snprintfz(membername, sizeof(membername), "%s::"MEMBERFIELDNAME, clas->name, clas->params[p].paramname);
m = QCC_PR_GetDef(NULL, membername, NULL, false, 0, false);
f = QCC_MemberInParentClass(clas->params[p].paramname, clas->parentclass);
if (f)
{
if (f->type->type != ev_field || typecmp(f->type->aux_type, mt))
{
char ct[256];
char pt[256];
TypeName(f->type->aux_type, pt, sizeof(pt));
TypeName(mt, ct, sizeof(ct));
QCC_PR_Warning(0, NULL, 0, "type mismatch on inheritance of %s::%s. %s vs %s", clas->name, clas->params[p].paramname, ct, pt);
}
if (!m)
{
basictypefield[mt->type] += 1;
continue;
}
if (m->arraysize)
QCC_Error(ERR_INTERNAL, "FTEQCC does not support overloaded arrays of members");
a=0;
for (o = 0; o < m->type->size; o++)
((int *)qcc_pr_globals)[o+a*mt->size+m->ofs] = ((int *)qcc_pr_globals)[o+a*mt->size+f->ofs];
continue;
}
//came from parent class instead?
if (!m)
QCC_Error(ERR_INTERNAL, "field def missing for class member (%s::%s)", clas->name, clas->params[p].paramname);
for (a = 0; a < (m->arraysize?m->arraysize:1); a++)
{
/*if it was already set, don't go recursive and generate 500 fields for a one-member class that was inheritted from 500 times*/
if (((int *)qcc_pr_globals)[0+a*mt->size+m->ofs])
{
++basictypefield[mt->type];
continue;
}
//we need the type in here so saved games can still work without saving ints as floats. (would be evil)
ft = QCC_PR_FieldType(*basictypes[mt->type]);
QC_snprintfz(membername, sizeof(membername), "::%s%i", basictypenames[mt->type], ++basictypefield[mt->type]);
f = QCC_PR_GetDef(ft, membername, NULL, false, 0, GDF_CONST);
if (!f)
{
//give it a location if this is the first class that uses this fieldspace
f = QCC_PR_GetDef(ft, membername, NULL, true, 0, GDF_CONST);
for (o = 0; o < m->type->size; o++)
((int *)qcc_pr_globals)[o+f->ofs] = pr.size_fields + o;
pr.size_fields += o;
}
for (o = 0; o < m->type->size; o++)
((int *)qcc_pr_globals)[o+a*mt->size+m->ofs] = ((int *)qcc_pr_globals)[o+f->ofs];
if (verbose)
QCC_PR_Note(0, NULL, 0, "%s maps to %s", m->name, f->name);
f->references++;
}
}
}
#endif
void QCC_PR_EmitClassFunctionTable(QCC_type_t *clas, QCC_type_t *childclas, QCC_sref_t ed)
{ //go through clas, do the virtual thing only if the child class does not override.
@ -13641,11 +13553,14 @@ QCC_def_t *QCC_PR_DummyDef(QCC_type_t *type, const char *name, QCC_function_t *s
if (!rootsymbol)
{
rootsymbol = first;
rootsymbol->symboldata = qccHunkAlloc ((def->arraysize?def->arraysize:1) * type->size * sizeof(float));
if (flags & GDF_POSTINIT)
rootsymbol->symboldata = NULL;
else
rootsymbol->symboldata = qccHunkAlloc ((def->arraysize?def->arraysize:1) * type->size * sizeof(float));
}
def->symbolheader = rootsymbol;
def->symboldata = rootsymbol->symboldata + def->ofs;
def->symboldata = (rootsymbol->symboldata?rootsymbol->symboldata + def->ofs:NULL);
def->symbolsize = (def->arraysize?def->arraysize:1) * type->size;
if (type->type == ev_struct && (!arraysize || a>=0))

View File

@ -5619,19 +5619,24 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
d = QCC_PR_GetDef(NULL, parmname, NULL, 0, 0, GDF_CONST);
if (!d)
{ //don't go all weird with unioning generic fields
QC_snprintfz(membername, sizeof(membername), "::%s%i", basictypenames[newparm->type], basicindex+1);
QC_snprintfz(membername, sizeof(membername), "::*%s", basictypenames[newparm->type]);
d = QCC_PR_GetDef(NULL, membername, NULL, 0, 0, GDF_CONST);
if (!d)
{
d = QCC_PR_GetDef(QCC_PR_FieldType(*basictypes[newparm->type]), membername, NULL, 2, arraysize, GDF_CONST);
for (i = 0; (unsigned int)i < newparm->size*(arraysize?arraysize:1); i++)
d->symboldata[i]._int = pr.size_fields+i;
pr.size_fields += i;
d = QCC_PR_GetDef(QCC_PR_FieldType(*basictypes[newparm->type]), membername, NULL, 2, arraysize, GDF_CONST|GDF_POSTINIT);
// for (i = 0; (unsigned int)i < newparm->size*(arraysize?arraysize:1); i++)
// d->symboldata[i]._int = pr.size_fields+i;
// pr.size_fields += i;
d->referenced = true; //always referenced, so you can inherit safely.
}
else if (d->arraysize != arraysize)
QCC_PR_ParseError(ERR_INTERNAL, "array members are kinda limited, sorry. try rearranging them or adding padding for alignment\n"); //FIXME: add relocs to cope with this all of a type can then be contiguous and thus allow arrays.
if (d->arraysize < basicindex+(arraysize?arraysize:1))
{
if (d->symboldata)
QCC_PR_ParseError(ERR_INTERNAL, "array members are kinda limited, sorry. try rearranging them or adding padding for alignment\n"); //FIXME: add relocs to cope with this all of a type can then be contiguous and thus allow arrays.
else
d->arraysize = basicindex+(arraysize?arraysize:1);
}
}
QCC_FreeDef(d);
@ -5639,7 +5644,7 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
//actually, that seems pointless.
QC_snprintfz(membername, sizeof(membername), "%s::"MEMBERFIELDNAME, classname, parmname);
// printf("define %s -> %s\n", membername, d->name);
d = QCC_PR_DummyDef(fieldtype, membername, pr_scope, arraysize, d, 0, true, (isnull?0:GDF_CONST)|(opt_classfields?GDF_STRIP:0));
d = QCC_PR_DummyDef(fieldtype, membername, pr_scope, arraysize, d, basicindex, true, (isnull?0:GDF_CONST)|(opt_classfields?GDF_STRIP:0));
d->referenced = true; //always referenced, so you can inherit safely.
}

View File

@ -3145,6 +3145,27 @@ void QCC_PR_BeginCompilation (void *memory, int memsize)
QCC_PrioritiseOpcodes();
}
void QCC_PR_FinishFieldDef(QCC_def_t *d)
{
int i;
if (d->symboldata)
return; //nothing to finish
d->symbolsize = (d->arraysize?d->arraysize:1) * d->type->size;
if (d->symbolheader != d)
{
QCC_PR_FinishFieldDef(d->symbolheader);
d->symboldata = d->symbolheader->symboldata + d->ofs;
}
else
{
d->symboldata = qccHunkAlloc (d->symbolsize * sizeof(float));
for (i = 0; i < d->symbolsize; i++)
d->symboldata[i]._int = pr.size_fields++;
}
}
/*
==============
PR_FinishCompilation
@ -3172,6 +3193,8 @@ int QCC_PR_FinishCompilation (void)
// check to make sure all functions prototyped have code
for (d=pr.def_head.next ; d ; d=d->next)
{
if (d->type->type == ev_field && !d->symboldata)
QCC_PR_FinishFieldDef(d);
if (d->type->type == ev_function && d->constant)// function parms are ok
{
// f = G_FUNCTION(d->ofs);