Fixes bugs found by xonotic team ('0 0 0' being overlapped with globals, initialisers not being marked as referenced, fixed macro argument expansion to not crash when given long values).

Enables compilation of 'float foo=5;float foo=5;' (similarly functions, fields are never initialised anyway, the dupe is ignored so long as the initialisation is the same).
Fixed an offset bug with arrays stored within typedefed structs.
Fixed int += int to not require an explicit addstore operand.
Added support for ! operator in #if statements, as well as fixing a couple of other issues there, should be much more usable.
Added 'optional' keyword when defining function arguments. All trailing arguments must have it too. This allows stricter type checking with functions that take optional arguments.
Removed warnings with __variant types.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@3921 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2011-11-08 06:00:35 +00:00
parent b8cb5421de
commit 6398930473
4 changed files with 294 additions and 153 deletions

View file

@ -59,7 +59,7 @@ extern int MAX_FUNCTIONS;
#define MAX_DATA_PATH 64
extern int MAX_CONSTANTS;
#define MAXCONSTANTLENGTH 64
#define MAXCONSTANTNAMELENGTH 64
#define MAXCONSTANTPARAMLENGTH 32
#define MAXCONSTANTPARAMS 32
@ -331,6 +331,7 @@ typedef struct QCC_def_s
struct QCC_def_s *nextlocal; //provides a chain of local variables for the opt_locals_marshalling optimisation.
gofs_t ofs;
struct QCC_def_s *scope; // function the var was defined in, or NULL
struct QCC_def_s *deftail; // arrays and structs create multiple globaldef objects providing different types at the different parts of the single object (struct), or alternative names (vectors). this allows us to correctly set the const type based upon how its initialised.
int initialized; // 1 when a declaration included "= immediate"
int constant; // 1 says we can use the value over and over again
@ -407,7 +408,7 @@ extern QCC_pr_info_t pr;
typedef struct
{
char name[MAXCONSTANTLENGTH];
char name[MAXCONSTANTNAMELENGTH];
char *value;
char params[MAXCONSTANTPARAMS][MAXCONSTANTPARAMLENGTH];
int numparams;
@ -441,6 +442,7 @@ extern pbool keyword_break;
extern pbool keyword_case;
extern pbool keyword_class;
extern pbool keyword_const;
extern pbool keyword_optional;
extern pbool keyword_continue;
extern pbool keyword_default;
extern pbool keyword_do;
@ -534,6 +536,7 @@ void QCC_PR_Lex (void);
// reads the next token into pr_token and classifies its type
QCC_type_t *QCC_PR_NewType (char *name, int basictype);
QCC_type_t *QCC_PointerTypeTo(QCC_type_t *type);
QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail);
extern pbool type_inlinefunction;
QCC_type_t *QCC_TypeForName(char *name);
@ -618,6 +621,7 @@ enum {
WARN_SAMENAMEASGLOBAL,
WARN_CONSTANTCOMPARISON,
WARN_UNSAFEFUNCTIONRETURNTYPE,
WARN_MISSINGOPTIONAL,
ERR_PARSEERRORS, //caused by qcc_pr_parseerror being called.

View file

@ -25,6 +25,7 @@ pbool keyword_asm;
pbool keyword_break;
pbool keyword_case;
pbool keyword_class;
pbool keyword_optional;
pbool keyword_const; //fixme
pbool keyword_continue;
pbool keyword_default;
@ -2146,6 +2147,13 @@ QCC_def_t *QCC_PR_Statement (QCC_opcode_t *op, QCC_def_t *var_a, QCC_def_t *var_
var_a = var_c;
var_c = var_a;
break;
case OP_ADDSTORE_I:
op = &pr_opcodes[OP_ADD_I];
var_c = var_b;
var_b = var_a;
var_a = var_c;
var_c = var_a;
break;
case OP_ADDSTORE_FI:
op = &pr_opcodes[OP_ADD_FI];
var_c = var_b;
@ -3574,7 +3582,7 @@ QCC_def_t *QCC_PR_ParseFunctionCall (QCC_def_t *func) //warning, the func could
QCC_PR_ParseErrorPrintDef (ERR_TOOMANYPARAMETERSVARARGS, func, "More than %i parameters on varargs function", MAX_PARMS);
else if (arg >= MAX_PARMS+MAX_EXTRA_PARMS)
QCC_PR_ParseErrorPrintDef (ERR_TOOMANYTOTALPARAMETERS, func, "More than %i parameters", MAX_PARMS+MAX_EXTRA_PARMS);
if (!extraparms && arg >= t->num_parms)
if (!extraparms && arg >= t->num_parms && !p)
{
QCC_PR_ParseWarning (WARN_TOOMANYPARAMETERSFORFUNC, "too many parameters");
QCC_PR_ParsePrintDef(WARN_TOOMANYPARAMETERSFORFUNC, func);
@ -3920,7 +3928,6 @@ QCC_def_t *QCC_MakeTranslateStringConst(char *value)
return QCC_MakeStringConstInternal(value, true);
}
QCC_type_t *QCC_PR_NewType (char *name, int basictype);
QCC_type_t *QCC_PointerTypeTo(QCC_type_t *type)
{
QCC_type_t *newtype;
@ -4922,7 +4929,7 @@ int QCC_canConv(QCC_def_t *from, etype_t to)
}
if (from->type->type == ev_variant)
return 5;
return 3;
/* if (from->type->type == ev_pointer && from->type->aux_type->type == to)
return 1;
@ -5388,11 +5395,21 @@ QCC_def_t *QCC_PR_Expression (int priority, int exprflags)
int QCC_PR_IntConstExpr(void)
{
QCC_def_t *def = QCC_PR_Expression(7, 0);
if (!def->constant)
QCC_PR_ParseError(ERR_BADARRAYSIZE, "Array size is not a constant value");
def = QCC_SupplyConversion(def, ev_integer, true);
return G_INT(def->ofs);
QCC_def_t *def = QCC_PR_Expression(TOP_PRIORITY, 0);
if (def->constant)
{
def->references++;
if (def->type->type == ev_integer)
return G_INT(def->ofs);
if (def->type->type == ev_float)
{
int i = G_FLOAT(def->ofs);
if ((float)i == G_FLOAT(def->ofs))
return i;
}
}
QCC_PR_ParseError(ERR_NOTACONSTANT, "Value is not an integer constant");
return true;
}
void QCC_PR_GotoStatement (QCC_dstatement_t *patch2, char *labelname)
@ -7799,7 +7816,7 @@ QCC_def_t *QCC_PR_DummyDef(QCC_type_t *type, char *name, QCC_def_t *scope, int a
def->scope = scope;
def->saved = saved;
// if (arraysize>1)
//if (type->type = ev_field)
def->constant = true;
if (ofs + type->size*a >= MAX_REGS)
@ -7876,6 +7893,7 @@ QCC_def_t *QCC_PR_DummyDef(QCC_type_t *type, char *name, QCC_def_t *scope, int a
QCC_PR_DummyDef(type_floatfield, newname, scope, 1, ofs + type->size*a+2, referable, false);
}
}
first->deftail = pr.def_tail;
}
if (referable)
@ -8244,9 +8262,6 @@ void QCC_PR_ExpandUnionToFields(QCC_type_t *type, int *fields)
}
/*
def - just debugging
*/
void QCC_PR_ParseInitializerType(int arraysize, QCC_def_t *def, QCC_type_t *type, int offset)
{
QCC_def_t *tmp;
@ -8266,7 +8281,86 @@ void QCC_PR_ParseInitializerType(int arraysize, QCC_def_t *def, QCC_type_t *type
}
else
{
if (type->type == ev_string && QCC_PR_CheckName("_"))
if (type->type == ev_function && pr_token_type == tt_punct)
{
/*begin function special case*/
QCC_def_t *parentfunc = pr_scope;
QCC_function_t *f;
QCC_dfunction_t *df;
QCC_type_t *parm;
tmp = NULL;
def->references++;
pr_scope = def;
if (QCC_PR_CheckToken ("#") || QCC_PR_CheckToken (":"))
{
int binum = 0;
if (pr_token_type == tt_immediate
&& pr_immediate_type == type_float
&& pr_immediate._float == (int)pr_immediate._float)
binum = (int)pr_immediate._float;
else if (pr_token_type == tt_immediate && pr_immediate_type == type_integer)
binum = pr_immediate._int;
else
QCC_PR_ParseError (ERR_BADBUILTINIMMEDIATE, "Bad builtin immediate");
QCC_PR_Lex();
if (def->initialized)
for (i = 0; i < numfunctions; i++)
{
if (functions[i].first_statement == -binum)
{
tmp = QCC_MakeIntConst(i);
break;
}
}
if (!tmp)
{
f = (void *)qccHunkAlloc (sizeof(QCC_function_t));
f->builtin = binum;
locals_start = locals_end = OFS_PARM0; //hmm...
}
else
f = NULL;
}
else
f = QCC_PR_ParseImmediateStatements (type);
if (!tmp)
{
pr_scope = parentfunc;
tmp = QCC_MakeIntConst(numfunctions);
f->def = def;
if (numfunctions >= MAX_FUNCTIONS)
QCC_Error(ERR_INTERNAL, "Too many function defs");
// fill in the dfunction
df = &functions[numfunctions];
numfunctions++;
if (f->builtin)
df->first_statement = -f->builtin;
else
df->first_statement = f->code;
if (f->builtin && opt_function_names)
optres_function_names += strlen(f->def->name);
else
df->s_name = QCC_CopyString (f->def->name);
df->s_file = s_file2;
df->numparms = f->def->type->num_parms;
df->locals = locals_end - locals_start;
df->parm_start = locals_start;
for (i=0,parm = type->param ; i<df->numparms ; i++, parm = parm->next)
{
df->parm_size[i] = parm->size;
}
/*end function special case*/
}
}
else if (type->type == ev_string && QCC_PR_CheckName("_"))
{
char trname[128];
QCC_PR_Expect("(");
@ -8276,66 +8370,15 @@ void QCC_PR_ParseInitializerType(int arraysize, QCC_def_t *def, QCC_type_t *type
QCC_PR_Lex();
QCC_PR_Expect(")");
sprintf(trname, "dotranslate_%i", ++dotranslate_count);
QCC_PR_DummyDef(type_string, trname, pr_scope, 1, offset, true, true)->references = 1;
}
else if (type->type == ev_function && pr_token_type == tt_punct)
{
/*begin function special case*/
QCC_def_t *parentfunc = pr_scope;
QCC_function_t *f;
QCC_dfunction_t *df;
QCC_type_t *parm;
def->references++;
pr_scope = def;
if (QCC_PR_CheckToken ("#") || QCC_PR_CheckToken (":"))
if (!pr_scope || def->constant)
{
int binum = 0;
f = (void *)qccHunkAlloc (sizeof(QCC_function_t));
if (pr_token_type == tt_immediate
&& pr_immediate_type == type_float
&& pr_immediate._float == (int)pr_immediate._float)
binum = (int)pr_immediate._float;
else if (pr_token_type == tt_immediate && pr_immediate_type == type_integer)
binum = pr_immediate._int;
else
QCC_PR_ParseError (ERR_BADBUILTINIMMEDIATE, "Bad builtin immediate");
f->builtin = binum;
QCC_PR_Lex();
locals_start = locals_end = OFS_PARM0; //hmm...
QCC_def_t *dt;
sprintf(trname, "dotranslate_%i", ++dotranslate_count);
dt = QCC_PR_DummyDef(type_string, trname, pr_scope, 1, offset, true, true);
dt->references = 1;
dt->constant = 1;
dt->initialized = 1;
}
else
f = QCC_PR_ParseImmediateStatements (type);
pr_scope = parentfunc;
tmp = QCC_MakeIntConst(numfunctions);
f->def = def;
if (numfunctions >= MAX_FUNCTIONS)
QCC_Error(ERR_INTERNAL, "Too many function defs");
// fill in the dfunction
df = &functions[numfunctions];
numfunctions++;
if (f->builtin)
df->first_statement = -f->builtin;
else
df->first_statement = f->code;
if (f->builtin && opt_function_names)
optres_function_names += strlen(f->def->name);
else
df->s_name = QCC_CopyString (f->def->name);
df->s_file = s_file2;
df->numparms = f->def->type->num_parms;
df->locals = locals_end - locals_start;
df->parm_start = locals_start;
for (i=0,parm = type->param ; i<df->numparms ; i++, parm = parm->next)
{
df->parm_size[i] = parm->size;
}
/*end function special case*/
}
else
{
@ -8362,21 +8405,35 @@ void QCC_PR_ParseInitializerType(int arraysize, QCC_def_t *def, QCC_type_t *type
if (!tmp->constant)
QCC_PR_ParseErrorPrintDef (ERR_BADIMMEDIATETYPE, def, "initializer is not constant");
for (i = 0; (unsigned)i < type->size; i++)
G_INT(offset+i) = G_INT(tmp->ofs+i);
if (def->initialized)
{
for (i = 0; (unsigned)i < type->size; i++)
if (G_INT(offset+i) != G_INT(tmp->ofs+i))
QCC_PR_ParseErrorPrintDef (ERR_REDECLARATION, def, "incompatible redeclaration");
}
else
{
for (i = 0; (unsigned)i < type->size; i++)
G_INT(offset+i) = G_INT(tmp->ofs+i);
}
}
else
{
QCC_def_t lhs, rhs;
if (def->initialized)
QCC_PR_ParseErrorPrintDef (ERR_REDECLARATION, def, "%s initialised twice", def->name);
memset(&lhs, 0, sizeof(lhs));
memset(&rhs, 0, sizeof(rhs));
for (i = 0; (unsigned)i < def->type->size; )
def->references++;
for (i = 0; (unsigned)i < type->size; )
{
rhs.type = lhs.type = type_float;
lhs.ofs = offset+i;
tmp->references++;
rhs.ofs = tmp->ofs+i;
if (def->type->size - i >= 3)
if (type->size - i >= 3)
{
QCC_FreeTemp(QCC_PR_Statement(&pr_opcodes[OP_STORE_V], &rhs, &lhs, NULL));
i+=3;
@ -8835,8 +8892,6 @@ void QCC_PR_ParseDefs (char *classname)
QCC_PR_Expect("(");
type = QCC_PR_ParseFunctionTypeReacc(false, type);
QCC_PR_Expect(";");
if (!stricmp(name, "null"))
printf("null!\n");
def = QCC_PR_GetDef (type, name, NULL, true, 1, false);
if (autoprototype)
@ -8973,36 +9028,8 @@ void QCC_PR_ParseDefs (char *classname)
}
else
{
def = QCC_PR_Expression(TOP_PRIORITY, 0);
if (!def->constant)
QCC_PR_ParseError(ERR_BADARRAYSIZE, "Array size is not a constant value");
else if (def->type->type == ev_integer)
arraysize = G_INT(def->ofs);
else if (def->type->type == ev_float)
{
arraysize = (int)G_FLOAT(def->ofs);
if ((float)arraysize != G_FLOAT(def->ofs))
QCC_PR_ParseError(ERR_BADARRAYSIZE, "Array size is not a constant value");
}
else
QCC_PR_ParseError(ERR_BADARRAYSIZE, "Array size must be of int value");
/* if(pr_token_type == tt_name)
{
def = QCC_PR_GetDef(NULL, QCC_PR_ParseName(), pr_scope, false, 0);
if (def && def->arraysize==1)
{
if (def->type->type == ev_integer)
arraysize = G_INT(def->ofs);
else if (def->type->type == ev_float && (float)(int)G_FLOAT(def->ofs) == G_FLOAT(def->ofs))
arraysize = (int)G_FLOAT(def->ofs);
}
}
else if (pr_token_type == tt_immediate)
{
arraysize = atoi (pr_token);
QCC_PR_Lex();
}
*/ QCC_PR_Expect("]");
arraysize = QCC_PR_IntConstExpr();
QCC_PR_Expect("]");
}
if (arraysize < 1)
@ -9072,13 +9099,12 @@ void QCC_PR_ParseDefs (char *classname)
QCC_PR_ParseError (ERR_INITIALISEDLOCALFUNCTION, "local functions may not be initialised");
}
arraysize = def->arraysize;
d = def; //apply to ALL elements
while(arraysize--)
d = def;
while (d != def->deftail)
{
d = d->next;
d->initialized = 1; //fake function
G_FUNCTION(d->ofs) = 0;
d = d->next;
}
continue;
@ -9095,14 +9121,14 @@ void QCC_PR_ParseDefs (char *classname)
QCC_PR_ParseError (ERR_SHAREDINITIALISED, "shared values may not be assigned an initial value", name);
if (def->initialized == 1)
{
if (def->type->type == ev_function)
{
i = G_FUNCTION(def->ofs);
df = &functions[i];
QCC_PR_ParseErrorPrintDef (ERR_REDECLARATION, def, "%s redeclared, prev instance is in %s", name, strings+df->s_file);
}
else
QCC_PR_ParseErrorPrintDef(ERR_REDECLARATION, def, "%s redeclared", name);
// if (def->type->type == ev_function)
// {
// i = G_FUNCTION(def->ofs);
// df = &functions[i];
// QCC_PR_ParseErrorPrintDef (ERR_REDECLARATION, def, "%s redeclared, prev instance is in %s", name, strings+df->s_file);
// }
// else
// QCC_PR_ParseErrorPrintDef(ERR_REDECLARATION, def, "%s redeclared", name);
}
if (autoprototype)
@ -9163,7 +9189,13 @@ void QCC_PR_ParseDefs (char *classname)
def->constant = isconstant;
}
d = def;
while (d != def->deftail)
{
d = d->next;
d->constant = def->constant;
d->initialized = def->initialized;
}
} while (QCC_PR_CheckToken (","));
if (type->type == ev_function)

View file

@ -237,16 +237,34 @@ int ParsePrecompilerIf(void)
{
CompilerConstant_t *c;
int eval = 0;
//char *start = pr_file_p; //warning: unused variable âstartâ
pbool notted = false;
/*skip whitespace*/
while (*pr_file_p && *pr_file_p <= ' ' && *pr_file_p != '\n')
{
pr_file_p++;
}
if (*pr_file_p == '!')
{
pr_file_p++;
notted = true;
while (*pr_file_p && *pr_file_p <= ' ' && *pr_file_p != '\n')
{
pr_file_p++;
}
}
if (!QCC_PR_SimpleGetToken())
{
if (*pr_file_p == '(')
{
pr_file_p++;
eval = ParsePrecompilerIf();
while (*pr_file_p == ' ' || *pr_file_p == '\t')
pr_file_p++;
if (*pr_file_p != ')')
QCC_PR_ParseError(ERR_EXPECTED, "unclosed bracket condition\n");
pr_file_p++;
}
else
QCC_PR_ParseError(ERR_EXPECTED, "expected bracket or constant\n");
@ -280,6 +298,9 @@ int ParsePrecompilerIf(void)
eval = atoi(c->value);
}
if (notted)
eval = !eval;
QCC_PR_SimpleGetToken();
if (!strcmp(pr_token, "||"))
eval = ParsePrecompilerIf()||eval;
@ -514,7 +535,7 @@ pbool QCC_PR_Precompiler(void)
for (a = 0; a < sizeof(msg)-1 && pr_file_p[a] != '\n' && pr_file_p[a] != '\0'; a++)
msg[a] = pr_file_p[a];
msg[a-1] = '\0';
msg[a] = '\0';
while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line, yes, I KNOW we are going to register an error, and not properly leave this function tree, but...
{
@ -1972,7 +1993,7 @@ CompilerConstant_t *QCC_PR_DefineName(char *name)
// if (numCompilerConstants >= MAX_CONSTANTS)
// QCC_PR_ParseError("Too many compiler constants - %i >= %i", numCompilerConstants, MAX_CONSTANTS);
if (strlen(name) >= MAXCONSTANTLENGTH || !*name)
if (strlen(name) >= MAXCONSTANTNAMELENGTH || !*name)
QCC_PR_ParseError(ERR_NAMETOOLONG, "Compiler constant name length is too long or short");
cnst = pHash_Get(&compconstantstable, name);
@ -2120,6 +2141,43 @@ void QCC_PR_ConditionCompilation(void)
pr_file_p = s;
}
/* *buffer, *bufferlen and *buffermax should be NULL/0 at the start */
static void QCC_PR_ExpandStrCat(char **buffer, int *bufferlen, int *buffermax, char *newdata, int newlen)
{
int newmax = *bufferlen + newlen;
if (newmax < *bufferlen)
{
QCC_PR_ParseWarning(ERR_INTERNAL, "out of memory");
return;
}
if (newmax > *buffermax)
{
char *newbuf;
if (newmax < 64)
newmax = 64;
if (newmax < *bufferlen * 2)
{
newmax = *bufferlen * 2;
if (newmax < *bufferlen) /*overflowed?*/
{
QCC_PR_ParseWarning(ERR_INTERNAL, "out of memory");
return;
}
}
newbuf = realloc(*buffer, newmax);
if (!newbuf)
{
QCC_PR_ParseWarning(ERR_INTERNAL, "out of memory");
return; /*OOM*/
}
*buffer = newbuf;
*buffermax = newmax;
}
memcpy(*buffer + *bufferlen, newdata, newlen);
*bufferlen += newlen;
/*no null terminator, remember to cat one if required*/
}
int QCC_PR_CheakCompConst(void)
{
char *oldpr_file_p = pr_file_p;
@ -2173,7 +2231,10 @@ int QCC_PR_CheakCompConst(void)
{
int p;
char *start;
char buffer[1024];
char *starttok;
char *buffer;
int buffermax;
int bufferlen;
char *paramoffset[MAXCONSTANTPARAMS+1];
int param=0;
int plevel=0;
@ -2228,38 +2289,45 @@ int QCC_PR_CheakCompConst(void)
QCC_PR_ParseError(ERR_TOOFEWPARAMS, "Not enough macro parameters");
paramoffset[param] = start;
*buffer = '\0';
buffer = NULL;
bufferlen = 0;
buffermax = 0;
oldpr_file_p = pr_file_p;
pr_file_p = c->value;
for(;;)
{
whitestart = p = strlen(buffer);
whitestart = bufferlen;
starttok = pr_file_p;
while(*pr_file_p <= ' ') //copy across whitespace
{
if (!*pr_file_p)
break;
buffer[p++] = *pr_file_p++;
pr_file_p++;
}
if (starttok != pr_file_p)
{
QCC_PR_ExpandStrCat(&buffer, &bufferlen, &buffermax, starttok, pr_file_p - starttok);
}
buffer[p] = 0;
if(*pr_file_p == '\"')
{
starttok = pr_file_p;
do
{
buffer[p++] = *pr_file_p;
++pr_file_p;
pr_file_p++;
} while( (pr_file_p[-1] == '\\' || pr_file_p[0] != '\"') && *pr_file_p && *pr_file_p != '\n' );
buffer[p++] = *pr_file_p; // copy the end-quote too
buffer[p] = 0;
++pr_file_p; // and skip it
if(*pr_file_p == '\"')
pr_file_p++;
QCC_PR_ExpandStrCat(&buffer, &bufferlen, &buffermax, starttok, pr_file_p - starttok);
continue;
}
else if (*pr_file_p == '#') //if you ask for #a##b you will be shot. use #a #b instead, or chain macros.
{
if (pr_file_p[1] == '#')
{ //concatinate (srip out whitespace)
buffer[whitestart] = '\0';
{ //concatinate (strip out whitespace before the token)
bufferlen = whitestart;
pr_file_p+=2;
}
else
@ -2273,16 +2341,16 @@ int QCC_PR_CheakCompConst(void)
{
if (!STRCMP(qcc_token, c->params[p]))
{
strcat(buffer, "\"");
strcat(buffer, paramoffset[p]);
strcat(buffer, "\"");
QCC_PR_ExpandStrCat(&buffer, &bufferlen, &buffermax, "\"", 1);
QCC_PR_ExpandStrCat(&buffer, &bufferlen, &buffermax, paramoffset[p], strlen(paramoffset[p]));
QCC_PR_ExpandStrCat(&buffer, &bufferlen, &buffermax, "\"", 1);
break;
}
}
if (p == param)
{
strcat(buffer, "#");
strcat(buffer, qcc_token);
QCC_PR_ExpandStrCat(&buffer, &bufferlen, &buffermax, "#", 1);
QCC_PR_ExpandStrCat(&buffer, &bufferlen, &buffermax, qcc_token, strlen(qcc_token));
//QCC_PR_ParseWarning(0, "Stringification ignored");
}
continue; //already did this one
@ -2297,12 +2365,12 @@ int QCC_PR_CheakCompConst(void)
{
if (!STRCMP(qcc_token, c->params[p]))
{
strcat(buffer, paramoffset[p]);
QCC_PR_ExpandStrCat(&buffer, &bufferlen, &buffermax, paramoffset[p], strlen(paramoffset[p]));
break;
}
}
if (p == param)
strcat(buffer, qcc_token);
QCC_PR_ExpandStrCat(&buffer, &bufferlen, &buffermax, qcc_token, strlen(qcc_token));
}
for (p = 0; p < param-1; p++)
@ -2310,12 +2378,17 @@ int QCC_PR_CheakCompConst(void)
paramoffset[p][strlen(paramoffset[p])] = ')';
pr_file_p = oldpr_file_p;
if (!*buffer)
if (!bufferlen)
expandedemptymacro = true;
QCC_PR_IncludeChunkEx(buffer, true, NULL, c);
else
{
QCC_PR_ExpandStrCat(&buffer, &bufferlen, &buffermax, "\0", 1);
QCC_PR_IncludeChunkEx(buffer, true, NULL, c);
}
free(buffer);
}
else
QCC_PR_ParseError(ERR_TOOFEWPARAMS, "Macro without opening brace");
QCC_PR_ParseError(ERR_TOOFEWPARAMS, "Macro without argument list");
}
else
{
@ -2864,7 +2937,9 @@ int typecmp(QCC_type_t *a, QCC_type_t *b)
if (a->type != b->type)
return 1;
if (a->num_parms != b->num_parms)
{
return 1;
}
if (a->size != b->size)
return 1;
@ -2911,6 +2986,7 @@ QCC_type_t *QCC_PR_DuplicateType(QCC_type_t *in)
op = (op->next = QCC_PR_DuplicateType(ip));
ip = ip->next;
}
out->arraysize = in->arraysize;
out->size = in->size;
out->num_parms = in->num_parms;
out->ofs = in->ofs;
@ -2938,17 +3014,29 @@ char *TypeName(QCC_type_t *type)
if (type->type == ev_function)
{
pbool varg = type->num_parms < 0;
int args = type->num_parms;
if (args < 0)
args = -(args+1);
strcat(ret, type->aux_type->name);
strcat(ret, " (");
type = type->param;
while(type)
{
if (args<=0)
strcat(ret, "optional ");
args--;
strcat(ret, type->name);
type = type->next;
if (type)
if (type || varg)
strcat(ret, ", ");
}
if (varg)
{
strcat(ret, "...");
}
strcat(ret, ")");
}
else if (type->type == ev_entity && type->parentclass)
@ -3082,6 +3170,8 @@ QCC_type_t *QCC_PR_ParseFunctionType (int newtype, QCC_type_t *returntype)
QCC_type_t *ftype, *ptype, *nptype;
char *name;
int definenames = !recursivefunctiontype;
int optional = 0;
int numparms = 0;
recursivefunctiontype++;
@ -3104,10 +3194,20 @@ QCC_type_t *QCC_PR_ParseFunctionType (int newtype, QCC_type_t *returntype)
if (QCC_PR_CheckToken ("..."))
{
ftype->num_parms = (ftype->num_parms * -1) - 1;
if (optional)
numparms = optional-1;
ftype->num_parms = (numparms * -1) - 1;
break;
}
if (QCC_PR_CheckKeyword(keyword_optional, "optional"))
{
if (!optional)
optional = numparms+1;
}
else if (optional)
QCC_PR_ParseWarning(WARN_MISSINGOPTIONAL, "optional not specified on all optional args\n");
nptype = QCC_PR_ParseType(true, false);
if (nptype->type == ev_void)
@ -3129,11 +3229,15 @@ QCC_type_t *QCC_PR_ParseFunctionType (int newtype, QCC_type_t *returntype)
{
name = QCC_PR_ParseName ();
if (definenames)
strcpy (pr_parm_names[ftype->num_parms], name);
strcpy (pr_parm_names[numparms], name);
}
else if (definenames)
strcpy (pr_parm_names[ftype->num_parms], "");
ftype->num_parms++;
strcpy (pr_parm_names[numparms], "");
numparms++;
if (optional)
ftype->num_parms = optional-1;
else
ftype->num_parms = numparms;
} while (QCC_PR_CheckToken (","));
QCC_PR_Expect (")");

View file

@ -183,7 +183,7 @@ optimisations_t optimisations[] =
{&opt_return_only, "ro", 3, FLAG_KILLSDEBUGGERS, "return_only", "Functions ending in a return statement do not need a done statement at the end of the function. This can confuse some decompilers, making functions appear larger than they were."},
{&opt_compound_jumps, "cj", 3, FLAG_KILLSDEBUGGERS, "compound_jumps", "This optimisation plays an effect mostly with nested if/else statements, instead of jumping to an unconditional jump statement, it'll jump to the final destination instead. This will bewilder decompilers."},
// {&opt_comexprremoval, "cer", 4, 0, "expression_removal", "Eliminate common sub-expressions"}, //this would be too hard...
{&opt_stripfunctions, "sf", 3, 0, "strip_functions", "Strips out the 'defs' of functions that were only ever called directly. This does not affect saved games."},
{&opt_stripfunctions, "sf", 4, 0, "strip_functions", "Strips out the 'defs' of functions that were only ever called directly. This does not affect saved games. This can affect FTE_MULTIPROGS."},
{&opt_locals_marshalling, "lm", 4, FLAG_KILLSDEBUGGERS, "locals_marshalling", "Store all locals in one section of the pr_globals. Vastly reducing it. This effectivly does the job of overlaptemps. It's been noticed as buggy by a few, however, and the curcumstances where it causes problems are not yet known."},
{&opt_vectorcalls, "vc", 4, FLAG_KILLSDEBUGGERS, "vectorcalls", "Where a function is called with just a vector, this causes the function call to store three floats instead of one vector. This can save a good number of pr_globals where those vectors contain many duplicate coordinates but do not match entirly."},
{NULL}
@ -214,6 +214,7 @@ compiler_flag_t compiler_flag[] = {
{&keyword_nosave, defaultkeyword, "nosave", "Keyword: nosave", "Disables the 'nosave' keyword."}, //don't write the def to the output.
{&keyword_shared, defaultkeyword, "shared", "Keyword: shared", "Disables the 'shared' keyword."}, //mark global to be copied over when progs changes (part of FTE_MULTIPROGS)
{&keyword_state, nondefaultkeyword,"state", "Keyword: state", "Disables the 'state' keyword."},
{&keyword_optional, defaultkeyword,"optional", "Keyword: optional", "Disables the 'optional' keyword."},
{&keyword_string, defaultkeyword, "string", "Keyword: string", "Disables the 'string' keyword."},
{&keyword_struct, defaultkeyword, "struct", "Keyword: struct", "Disables the 'struct' keyword."},
{&keyword_switch, defaultkeyword, "switch", "Keyword: switch", "Disables the 'switch' keyword."},