Add __deprecated keyword. Add strlen intrinsic.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5696 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
parent
80474cc3be
commit
53deb25340
3 changed files with 117 additions and 26 deletions
|
@ -440,6 +440,7 @@ typedef struct QCC_def_s
|
||||||
pbool initialized:1; //true when a declaration included "= immediate".
|
pbool initialized:1; //true when a declaration included "= immediate".
|
||||||
pbool isextern:1; //fteqw-specific lump entry
|
pbool isextern:1; //fteqw-specific lump entry
|
||||||
pbool isparameter:1; //its an engine parameter (thus preinitialised).
|
pbool isparameter:1; //its an engine parameter (thus preinitialised).
|
||||||
|
const char *deprecated; //reason its deprecated (or empty for no reason given)
|
||||||
|
|
||||||
int fromstatement; //statement that it is valid from.
|
int fromstatement; //statement that it is valid from.
|
||||||
temp_t *temp;
|
temp_t *temp;
|
||||||
|
@ -748,7 +749,7 @@ char *QCC_NameForWarning(int idx);
|
||||||
enum {
|
enum {
|
||||||
WARN_DEBUGGING,
|
WARN_DEBUGGING,
|
||||||
WARN_ERROR,
|
WARN_ERROR,
|
||||||
WARN_DEPRECATEDWARNING, //to silence warnings about old warnings.
|
WARN_REMOVEDWARNING, //to silence warnings about old warnings.
|
||||||
WARN_WRITTENNOTREAD,
|
WARN_WRITTENNOTREAD,
|
||||||
WARN_READNOTWRITTEN,
|
WARN_READNOTWRITTEN,
|
||||||
WARN_NOTREFERENCED,
|
WARN_NOTREFERENCED,
|
||||||
|
@ -805,6 +806,7 @@ enum {
|
||||||
WARN_IDENTICALPRECOMPILER,
|
WARN_IDENTICALPRECOMPILER,
|
||||||
WARN_FORMATSTRING, //sprintf
|
WARN_FORMATSTRING, //sprintf
|
||||||
WARN_DEPRECACTEDSYNTAX, //triggered when syntax is used that I'm trying to kill
|
WARN_DEPRECACTEDSYNTAX, //triggered when syntax is used that I'm trying to kill
|
||||||
|
WARN_DEPRECATEDVARIABLE, //triggered from usage of a symbol that someone tried to kill
|
||||||
WARN_GMQCC_SPECIFIC, //extension created by gmqcc that conflicts or isn't properly implemented.
|
WARN_GMQCC_SPECIFIC, //extension created by gmqcc that conflicts or isn't properly implemented.
|
||||||
WARN_FTE_SPECIFIC, //extension that only FTEQCC will have a clue about.
|
WARN_FTE_SPECIFIC, //extension that only FTEQCC will have a clue about.
|
||||||
WARN_EXTENSION_USED, //extension that frikqcc also understands
|
WARN_EXTENSION_USED, //extension that frikqcc also understands
|
||||||
|
|
|
@ -5438,6 +5438,20 @@ static QCC_sref_t QCC_PR_Inline(QCC_sref_t fdef, QCC_ref_t **arglist, unsigned i
|
||||||
return ctx.result;
|
return ctx.result;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
pbool QCC_Intrinsic_strlen(QCC_sref_t *result, const QCC_eval_t *a)
|
||||||
|
{
|
||||||
|
const char *str = &strings[a->string];
|
||||||
|
size_t l = 0;
|
||||||
|
for (l = 0; str[l]; l++)
|
||||||
|
{ //don't shortcut it when its an extended char. we don't know what the engine's strlen function would return.
|
||||||
|
if ((unsigned char)str[l] & 0x80)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (l > 1u<<24) //wait, what?
|
||||||
|
return false; //too big for a float.
|
||||||
|
*result = QCC_MakeFloatConst(l);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
QCC_sref_t QCC_PR_GenerateFunctionCallRef (QCC_sref_t newself, QCC_sref_t func, QCC_ref_t **arglist, unsigned int argcount) //warning, the func could have no name set if it's a field call.
|
QCC_sref_t QCC_PR_GenerateFunctionCallRef (QCC_sref_t newself, QCC_sref_t func, QCC_ref_t **arglist, unsigned int argcount) //warning, the func could have no name set if it's a field call.
|
||||||
{
|
{
|
||||||
QCC_sref_t d, oself, self, retval;
|
QCC_sref_t d, oself, self, retval;
|
||||||
|
@ -5478,6 +5492,9 @@ QCC_sref_t QCC_PR_GenerateFunctionCallRef (QCC_sref_t newself, QCC_sref_t func,
|
||||||
return QCC_MakeFloatConst(sqrt(a->_float));
|
return QCC_MakeFloatConst(sqrt(a->_float));
|
||||||
// if (!strcmp(funcname, "ftos"))
|
// if (!strcmp(funcname, "ftos"))
|
||||||
// return QCC_MakeStringConst(ftos(a->_float)); //engines differ too much in their ftos implementation for this to be worthwhile
|
// return QCC_MakeStringConst(ftos(a->_float)); //engines differ too much in their ftos implementation for this to be worthwhile
|
||||||
|
|
||||||
|
if (!strcmp(funcname, "strlen") && QCC_Intrinsic_strlen(&d, a))
|
||||||
|
return d;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (opt_constantarithmatic && argcount == 2 && arglist[0]->type == REF_GLOBAL && arglist[1]->type == REF_GLOBAL)
|
else if (opt_constantarithmatic && argcount == 2 && arglist[0]->type == REF_GLOBAL && arglist[1]->type == REF_GLOBAL)
|
||||||
|
@ -6068,36 +6085,63 @@ static QCC_sref_t QCC_PR_ParseFunctionCall (QCC_ref_t *funcref) //warning, the f
|
||||||
{
|
{
|
||||||
int sz;
|
int sz;
|
||||||
int oldstcount = numstatements;
|
int oldstcount = numstatements;
|
||||||
#if 1
|
|
||||||
QCC_ref_t refbuf, *r;
|
QCC_ref_t refbuf, *r;
|
||||||
r = QCC_PR_RefExpression(&refbuf, TOP_PRIORITY, 0);
|
r = QCC_PR_RefExpression(&refbuf, TOP_PRIORITY, 0);
|
||||||
// r = QCC_PR_ParseRefValue(&refbuf, pr_classtype, false, false, false);
|
if (r->type == REF_GLOBAL && r->base.sym->type == type_string && !strcmp(r->base.sym->name, "IMMEDIATE"))
|
||||||
if (r->type == REF_ARRAYHEAD && !r->index.cast)
|
sz = strlen(&strings[QCC_SRef_EvalConst(r->base)->string]) + 1; //sizeof("hello") includes the null, and is bytes not codepoints
|
||||||
{
|
|
||||||
e = r->base;
|
|
||||||
sz = e.sym->arraysize;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
sz = 1;
|
{
|
||||||
|
sz = 4; //4 bytes per word. we don't support char/short (our string type is logically char*)
|
||||||
|
if (r->type == REF_ARRAYHEAD && !r->index.cast)
|
||||||
|
sz *= r->base.sym->arraysize;
|
||||||
sz *= r->cast->size;
|
sz *= r->cast->size;
|
||||||
|
}
|
||||||
|
QCC_FreeTemp(r->base);
|
||||||
|
if (r->index.cast)
|
||||||
|
QCC_FreeTemp(r->index);
|
||||||
|
//the term should not have side effects, or generate any actual statements.
|
||||||
|
numstatements = oldstcount;
|
||||||
|
QCC_PR_Expect(")");
|
||||||
|
return QCC_MakeIntConst(sz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!strcmp(funcname, "_length"))
|
||||||
|
{ //for compat with gmqcc
|
||||||
|
QCC_type_t *t;
|
||||||
|
func.sym->unused = true;
|
||||||
|
func.sym->referenced = true;
|
||||||
|
QCC_FreeTemp(func);
|
||||||
|
t = QCC_PR_ParseType(false, true);
|
||||||
|
if (t)
|
||||||
|
{
|
||||||
|
QCC_PR_Expect(")");
|
||||||
|
return QCC_PR_Statement(&pr_opcodes[OP_ADD_PIW], QCC_MakeIntConst(0), QCC_MakeIntConst(t->size), NULL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int sz = 0;
|
||||||
|
int oldstcount = numstatements;
|
||||||
|
QCC_ref_t refbuf, *r;
|
||||||
|
r = QCC_PR_RefExpression(&refbuf, TOP_PRIORITY, 0);
|
||||||
|
if (r->type == REF_ARRAYHEAD)
|
||||||
|
sz = r->base.sym->arraysize;
|
||||||
|
else if (r->cast == type_string)
|
||||||
|
{
|
||||||
|
QCC_sref_t d = QCC_RefToDef(r, false);
|
||||||
|
const QCC_eval_t *c = QCC_SRef_EvalConst(d);
|
||||||
|
if (c)
|
||||||
|
sz = strlen(&strings[c->string]); //_length("hello") does NOT include the null (like strlen), but is bytes not codepoints
|
||||||
|
}
|
||||||
|
else if (r->cast == type_vector)
|
||||||
|
sz = 3; //might as well. considering that vectors can be indexed as an array.
|
||||||
|
else
|
||||||
|
QCC_PR_ParseError (ERR_TYPEMISMATCHPARM, "_length() unsupported argument type for intrinsic");
|
||||||
QCC_FreeTemp(r->base);
|
QCC_FreeTemp(r->base);
|
||||||
if (r->index.cast)
|
if (r->index.cast)
|
||||||
QCC_FreeTemp(r->index);
|
QCC_FreeTemp(r->index);
|
||||||
#else
|
|
||||||
e = QCC_PR_ParseValue(pr_classtype, false, true, false);
|
|
||||||
if (!e)
|
|
||||||
QCC_PR_ParseErrorPrintSRef (ERR_NOTAFUNCTION, func, "sizeof term not supported");
|
|
||||||
if (!e->arraysize)
|
|
||||||
sz = 1;
|
|
||||||
else
|
|
||||||
sz = e->arraysize;
|
|
||||||
sz *= e->type->size;
|
|
||||||
QCC_FreeTemp(e);
|
|
||||||
#endif
|
|
||||||
//the term should not have side effects, or generate any actual statements.
|
//the term should not have side effects, or generate any actual statements.
|
||||||
numstatements = oldstcount;
|
numstatements = oldstcount;
|
||||||
QCC_PR_Expect(")");
|
QCC_PR_Expect(")");
|
||||||
sz *= 4; //4 bytes per word
|
|
||||||
return QCC_MakeIntConst(sz);
|
return QCC_MakeIntConst(sz);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8047,7 +8091,8 @@ QCC_ref_t *QCC_PR_ParseRefValue (QCC_ref_t *refbuf, QCC_type_t *assumeclass, pbo
|
||||||
if (!strcmp(name, "nil"))
|
if (!strcmp(name, "nil"))
|
||||||
d = QCC_MakeIntConst(0);
|
d = QCC_MakeIntConst(0);
|
||||||
else if ( (!strcmp(name, "randomv")) ||
|
else if ( (!strcmp(name, "randomv")) ||
|
||||||
(!strcmp(name, "sizeof")) ||
|
(!strcmp(name, "sizeof")) || //FIXME: sizeof should be an operator, not a function (ie: 'sizeof foo' should work just like 'sizeof(foo)' does)
|
||||||
|
(!strcmp(name, "_length")) ||
|
||||||
(!strcmp(name, "alloca")) ||
|
(!strcmp(name, "alloca")) ||
|
||||||
(!strcmp(name, "entnum")) ||
|
(!strcmp(name, "entnum")) ||
|
||||||
(!strcmp(name, "autocvar")) ||
|
(!strcmp(name, "autocvar")) ||
|
||||||
|
@ -14314,6 +14359,13 @@ QCC_sref_t QCC_PR_GetSRef (QCC_type_t *type, const char *name, QCC_function_t *s
|
||||||
sr.sym = def;
|
sr.sym = def;
|
||||||
sr.cast = def->type;
|
sr.cast = def->type;
|
||||||
sr.ofs = 0;
|
sr.ofs = 0;
|
||||||
|
if (def->deprecated)
|
||||||
|
{
|
||||||
|
if (*def->deprecated) //we have a reason for it
|
||||||
|
QCC_PR_ParseWarning(WARN_DEPRECATEDVARIABLE, "Variable \"%s\" is deprecated: %s", def->name, def->deprecated);
|
||||||
|
else //we don't have any reason for it.
|
||||||
|
QCC_PR_ParseWarning(WARN_DEPRECATEDVARIABLE, "Variable \"%s\" is deprecated", def->name);
|
||||||
|
}
|
||||||
return sr;
|
return sr;
|
||||||
}
|
}
|
||||||
return nullsref;
|
return nullsref;
|
||||||
|
@ -15171,6 +15223,7 @@ void QCC_PR_ParseDefs (char *classname, pbool fatal)
|
||||||
pbool doweak = false;
|
pbool doweak = false;
|
||||||
pbool forceused = false;
|
pbool forceused = false;
|
||||||
pbool accumulate = false;
|
pbool accumulate = false;
|
||||||
|
const char *deprecated = NULL;
|
||||||
int arraysize;
|
int arraysize;
|
||||||
unsigned int gd_flags;
|
unsigned int gd_flags;
|
||||||
const char *aliasof = NULL;
|
const char *aliasof = NULL;
|
||||||
|
@ -15411,6 +15464,22 @@ void QCC_PR_ParseDefs (char *classname, pbool fatal)
|
||||||
doweak = true;
|
doweak = true;
|
||||||
else if (QCC_PR_CheckKeyword(keyword_accumulate, "accumulate"))
|
else if (QCC_PR_CheckKeyword(keyword_accumulate, "accumulate"))
|
||||||
accumulate = true;
|
accumulate = true;
|
||||||
|
else if (QCC_PR_CheckKeyword(false, "deprecated"))
|
||||||
|
{
|
||||||
|
if (!QCC_PR_CheckToken("("))
|
||||||
|
deprecated = "";
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (pr_token_type == tt_immediate && pr_immediate_type == type_string)
|
||||||
|
{
|
||||||
|
deprecated = strcpy(qccHunkAlloc(strlen(pr_immediate_string)+1), pr_immediate_string);
|
||||||
|
QCC_PR_Lex();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
deprecated = "";
|
||||||
|
QCC_PR_Expect(")");
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (flag_attributes && !pr_scope && QCC_PR_CheckToken("["))
|
else if (flag_attributes && !pr_scope && QCC_PR_CheckToken("["))
|
||||||
{
|
{
|
||||||
QCC_PR_Expect("[");
|
QCC_PR_Expect("[");
|
||||||
|
@ -15440,6 +15509,22 @@ void QCC_PR_ParseDefs (char *classname, pbool fatal)
|
||||||
}
|
}
|
||||||
else if (QCC_PR_CheckName("eraseable"))
|
else if (QCC_PR_CheckName("eraseable"))
|
||||||
noref = true;
|
noref = true;
|
||||||
|
else if (QCC_PR_CheckKeyword(false, "deprecated"))
|
||||||
|
{
|
||||||
|
if (!QCC_PR_CheckToken("("))
|
||||||
|
deprecated = "";
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (pr_token_type == tt_immediate && pr_immediate_type == type_string)
|
||||||
|
{
|
||||||
|
deprecated = strcpy(qccHunkAlloc(strlen(pr_immediate_string)+1), pr_immediate_string);
|
||||||
|
QCC_PR_Lex();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
QCC_PR_ParseError (ERR_EXPECTED, "expected string");
|
||||||
|
QCC_PR_Expect(")");
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
QCC_PR_ParseWarning(WARN_GMQCC_SPECIFIC, "Unknown attribute \"%s\"", pr_token);
|
QCC_PR_ParseWarning(WARN_GMQCC_SPECIFIC, "Unknown attribute \"%s\"", pr_token);
|
||||||
|
@ -15759,6 +15844,9 @@ void QCC_PR_ParseDefs (char *classname, pbool fatal)
|
||||||
def->isextern = true;
|
def->isextern = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (deprecated)
|
||||||
|
def->deprecated = deprecated;
|
||||||
|
|
||||||
if (isstatic)
|
if (isstatic)
|
||||||
{
|
{
|
||||||
if (!strcmp(def->filen, s_filen))
|
if (!strcmp(def->filen, s_filen))
|
||||||
|
|
|
@ -223,6 +223,7 @@ struct {
|
||||||
{" F323", WARN_UNREACHABLECODE},
|
{" F323", WARN_UNREACHABLECODE},
|
||||||
{" F324", WARN_FORMATSTRING},
|
{" F324", WARN_FORMATSTRING},
|
||||||
{" F325", WARN_NESTEDCOMMENT},
|
{" F325", WARN_NESTEDCOMMENT},
|
||||||
|
{" F326", WARN_DEPRECATEDVARIABLE},
|
||||||
|
|
||||||
{" F207", WARN_NOTREFERENCEDFIELD},
|
{" F207", WARN_NOTREFERENCEDFIELD},
|
||||||
{" F208", WARN_NOTREFERENCEDCONST},
|
{" F208", WARN_NOTREFERENCEDCONST},
|
||||||
|
@ -244,7 +245,7 @@ struct {
|
||||||
//Q618: Ran out of mem pointer space (malloc failure again)
|
//Q618: Ran out of mem pointer space (malloc failure again)
|
||||||
|
|
||||||
//we can put longer alternative names here...
|
//we can put longer alternative names here...
|
||||||
{" field-redeclared", WARN_DEPRECATEDWARNING},
|
{" field-redeclared", WARN_REMOVEDWARNING},
|
||||||
|
|
||||||
{NULL}
|
{NULL}
|
||||||
};
|
};
|
||||||
|
@ -383,7 +384,7 @@ compiler_flag_t compiler_flag[] = {
|
||||||
{&pr_subscopedlocals, FLAG_MIDCOMPILE,"subscope", "Subscoped Locals", "Restrict the scope of locals to the block they are actually defined within, as in C."},
|
{&pr_subscopedlocals, FLAG_MIDCOMPILE,"subscope", "Subscoped Locals", "Restrict the scope of locals to the block they are actually defined within, as in C."},
|
||||||
{&verbose, FLAG_MIDCOMPILE,"verbose", "Verbose", "Lots of extra compiler messages."},
|
{&verbose, FLAG_MIDCOMPILE,"verbose", "Verbose", "Lots of extra compiler messages."},
|
||||||
{&flag_typeexplicit, FLAG_MIDCOMPILE,"typeexplicit", "Explicit types", "All type conversions must be explicit or directly supported by instruction set."},
|
{&flag_typeexplicit, FLAG_MIDCOMPILE,"typeexplicit", "Explicit types", "All type conversions must be explicit or directly supported by instruction set."},
|
||||||
{&flag_boundchecks, defaultflag, "boundchecks","Disable Bound Checks", "Disable array index checks, speeding up array access but can result in your code misbehaving."},
|
{&flag_boundchecks, defaultflag, "boundchecks", "Disable Bound Checks", "Disable array index checks, speeding up array access but can result in your code misbehaving."},
|
||||||
{&flag_attributes, hideflag, "attributes", "[[attributes]]", "WARNING: This syntax conflicts with vector constructors."},
|
{&flag_attributes, hideflag, "attributes", "[[attributes]]", "WARNING: This syntax conflicts with vector constructors."},
|
||||||
{&flag_assumevar, hideflag, "assumevar", "explicit consts", "Initialised globals will be considered non-const by default."},
|
{&flag_assumevar, hideflag, "assumevar", "explicit consts", "Initialised globals will be considered non-const by default."},
|
||||||
{&flag_dblstarexp, hideflag, "ssp", "** exponent", "Treat ** as an operator for exponents, instead of multiplying by a dereferenced pointer."},
|
{&flag_dblstarexp, hideflag, "ssp", "** exponent", "Treat ** as an operator for exponents, instead of multiplying by a dereferenced pointer."},
|
||||||
|
|
Loading…
Reference in a new issue