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:
Spoike 2020-05-20 02:00:37 +00:00
parent 80474cc3be
commit 53deb25340
3 changed files with 117 additions and 26 deletions

View file

@ -440,6 +440,7 @@ typedef struct QCC_def_s
pbool initialized:1; //true when a declaration included "= immediate".
pbool isextern:1; //fteqw-specific lump entry
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.
temp_t *temp;
@ -748,7 +749,7 @@ char *QCC_NameForWarning(int idx);
enum {
WARN_DEBUGGING,
WARN_ERROR,
WARN_DEPRECATEDWARNING, //to silence warnings about old warnings.
WARN_REMOVEDWARNING, //to silence warnings about old warnings.
WARN_WRITTENNOTREAD,
WARN_READNOTWRITTEN,
WARN_NOTREFERENCED,
@ -804,7 +805,8 @@ enum {
WARN_DUPLICATEPRECOMPILER,
WARN_IDENTICALPRECOMPILER,
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_FTE_SPECIFIC, //extension that only FTEQCC will have a clue about.
WARN_EXTENSION_USED, //extension that frikqcc also understands

View file

@ -5438,6 +5438,20 @@ static QCC_sref_t QCC_PR_Inline(QCC_sref_t fdef, QCC_ref_t **arglist, unsigned i
return ctx.result;
#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 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));
// if (!strcmp(funcname, "ftos"))
// 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)
@ -6068,36 +6085,63 @@ static QCC_sref_t QCC_PR_ParseFunctionCall (QCC_ref_t *funcref) //warning, the f
{
int sz;
int oldstcount = numstatements;
#if 1
QCC_ref_t refbuf, *r;
r = QCC_PR_RefExpression(&refbuf, TOP_PRIORITY, 0);
// r = QCC_PR_ParseRefValue(&refbuf, pr_classtype, false, false, false);
if (r->type == REF_ARRAYHEAD && !r->index.cast)
{
e = r->base;
sz = e.sym->arraysize;
}
if (r->type == REF_GLOBAL && r->base.sym->type == type_string && !strcmp(r->base.sym->name, "IMMEDIATE"))
sz = strlen(&strings[QCC_SRef_EvalConst(r->base)->string]) + 1; //sizeof("hello") includes the null, and is bytes not codepoints
else
sz = 1;
sz *= r->cast->size;
{
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;
}
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);
if (r->index.cast)
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.
numstatements = oldstcount;
QCC_PR_Expect(")");
sz *= 4; //4 bytes per word
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"))
d = QCC_MakeIntConst(0);
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, "entnum")) ||
(!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.cast = def->type;
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 nullsref;
@ -15171,6 +15223,7 @@ void QCC_PR_ParseDefs (char *classname, pbool fatal)
pbool doweak = false;
pbool forceused = false;
pbool accumulate = false;
const char *deprecated = NULL;
int arraysize;
unsigned int gd_flags;
const char *aliasof = NULL;
@ -15411,6 +15464,22 @@ void QCC_PR_ParseDefs (char *classname, pbool fatal)
doweak = true;
else if (QCC_PR_CheckKeyword(keyword_accumulate, "accumulate"))
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("["))
{
QCC_PR_Expect("[");
@ -15440,6 +15509,22 @@ void QCC_PR_ParseDefs (char *classname, pbool fatal)
}
else if (QCC_PR_CheckName("eraseable"))
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
{
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;
}
if (deprecated)
def->deprecated = deprecated;
if (isstatic)
{
if (!strcmp(def->filen, s_filen))

View file

@ -223,6 +223,7 @@ struct {
{" F323", WARN_UNREACHABLECODE},
{" F324", WARN_FORMATSTRING},
{" F325", WARN_NESTEDCOMMENT},
{" F326", WARN_DEPRECATEDVARIABLE},
{" F207", WARN_NOTREFERENCEDFIELD},
{" F208", WARN_NOTREFERENCEDCONST},
@ -244,7 +245,7 @@ struct {
//Q618: Ran out of mem pointer space (malloc failure again)
//we can put longer alternative names here...
{" field-redeclared", WARN_DEPRECATEDWARNING},
{" field-redeclared", WARN_REMOVEDWARNING},
{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."},
{&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_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_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."},