Added an accessor data type, eg: accessor strbuf : rawtype : dereferencetype {get[]=bufstr_get;set[]=bufstr_set;length=buf_getsize};

accvar.foo is equivelent to accvar["foo"]. get* or set* accessors can be used without indexes, but only with * prefix notation on use. the rawtype isn't changable with this, so you can't set infokey values.
accvar.length works. array.length will also work too now, if you dislike sizeof's weirdness.

updated preprocessor to comply slightly more with C.
fixed int emulation a little to be more robust. utility functions must be defined in advance. this avoids stealth dependancies resulting in unexpected bugs.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4745 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2014-09-05 19:17:57 +00:00
parent 110c19c6fd
commit 11279542a1
5 changed files with 579 additions and 130 deletions

View File

@ -875,7 +875,7 @@ reeval:
case OP_SUB_S: //(float)c = (char*)a - (char*)b
OPC->_int = OPA->_int - OPB->_int;
break;
case OP_LOADP_C: //load character from a string
case OP_LOADP_C: //load character from a string/pointer
i = (unsigned int)OPA->_int + (unsigned int)OPB->_float;
if ((unsigned int)i > prinst.addressableused-sizeof(char))
{
@ -914,7 +914,7 @@ reeval:
break;
case OP_LOADP_V:
i = OPA->_int + OPB->_int*4;
i = OPA->_int + OPB->_int*4; //NOTE: inconsistant!
if ((unsigned int)i > prinst.addressableused-sizeof(vec3_t))
{
if (i == -1)

View File

@ -49,7 +49,7 @@ typedef struct {
int spare[2];
} evalc_t;
#define sizeofevalc sizeof(evalc_t)
typedef enum {ev_void, ev_string, ev_float, ev_vector, ev_entity, ev_field, ev_function, ev_pointer, ev_integer, ev_variant, ev_struct, ev_union} etype_t;
typedef enum {ev_void, ev_string, ev_float, ev_vector, ev_entity, ev_field, ev_function, ev_pointer, ev_integer, ev_variant, ev_struct, ev_union, ev_accessor} etype_t;
typedef struct fdef_s
{

View File

@ -308,7 +308,6 @@ typedef struct QCC_type_s
etype_t type;
struct QCC_type_s *parentclass; //type_entity...
// struct QCC_type_s *next;
// function types are more complex
struct QCC_type_s *aux_type; // return type or field type
@ -321,6 +320,12 @@ typedef struct QCC_type_s
pbool vargcount:1;
char *name;
char *aname;
struct QCC_def_s *getptr;
struct QCC_def_s *getarr;
struct QCC_def_s *setptr;
struct QCC_def_s *setarr;
struct QCC_def_s *getlength;
} QCC_type_t;
int typecmp(QCC_type_t *a, QCC_type_t *b);
int typecmp_lax(QCC_type_t *a, QCC_type_t *b);
@ -378,7 +383,8 @@ typedef struct
REF_POINTER,//*(pointerdef+wordindex) - maths...
REF_FIELD, //(entity.field) - reading is a single load, writing requires address+storep
REF_STRING, //"hello"[1]=='e' - special opcodes, or str2chr builtin, or something
REF_NONVIRTUAL //(global.ofs) - identical to global except for function calls, where index can be used to provide the 'newself' for the call.
REF_NONVIRTUAL, //(global.ofs) - identical to global except for function calls, where index can be used to provide the 'newself' for the call.
REF_ACCESSOR //buf_create()[5]
} type;
QCC_def_t *base;
@ -681,6 +687,7 @@ enum {
WARN_EVILPREPROCESSOR, //exploited by nexuiz, and generally unsafe.
WARN_UNARYNOTSCOPE, //!foo & bar the ! applies to the result of &. This is unlike C.
WARN_STRICTTYPEMISMATCH, //self.think = T_Damage; both are functions, but the arguments/return types/etc differ.
WARN_MISUSEDAUTOCVAR, //various issues with autocvar definitions.
ERR_PARSEERRORS, //caused by qcc_pr_parseerror being called.

View File

@ -1317,28 +1317,38 @@ static int QCC_ShouldConvert(QCC_def_t *var, etype_t wanted)
/*impossible*/
return -1;
}
QCC_def_t *QCC_SupplyConversionForAssignment(QCC_def_t *to, QCC_def_t *from, etype_t wanted, pbool fatal)
QCC_def_t *QCC_SupplyConversionForAssignment(QCC_def_t *to, QCC_def_t *from, QCC_type_t *wanted, pbool fatal)
{
extern char *basictypenames[];
int o;
o = QCC_ShouldConvert(from, wanted);
if (wanted->type == ev_accessor && wanted->parentclass && from->type->type != ev_accessor)
wanted = wanted->parentclass;
o = QCC_ShouldConvert(from, wanted->type);
if (o == 0) //type already matches
return from;
if (flag_typeexplicit)
QCC_PR_ParseErrorPrintDef(ERR_TYPEMISMATCH, from, "Implicit type mismatch on assignment to %s. Needed %s, got %s.", to->name, basictypenames[wanted], basictypenames[from->type->type]);
{
char totypename[256], fromtypename[256];
TypeName(wanted, totypename, sizeof(totypename));
TypeName(from->type, fromtypename, sizeof(fromtypename));
QCC_PR_ParseErrorPrintDef(ERR_TYPEMISMATCH, from, "Implicit type mismatch on assignment to %s. Needed %s, got %s.", to->name, totypename, fromtypename);
}
if (o < 0)
{
if (fatal && wanted != ev_variant && from->type->type != ev_variant)
if (fatal && wanted->type != ev_variant && from->type->type != ev_variant)
{
char totypename[256], fromtypename[256];
TypeName(wanted, totypename, sizeof(totypename));
TypeName(from->type, fromtypename, sizeof(fromtypename));
if (flag_laxcasts)
{
QCC_PR_ParseWarning(WARN_LAXCAST, "Implicit type mismatch on assignment to %s. Needed %s, got %s.", to->name, basictypenames[wanted], basictypenames[from->type->type]);
QCC_PR_ParseWarning(WARN_LAXCAST, "Implicit type mismatch on assignment to %s. Needed %s, got %s.", to->name, totypename, fromtypename);
QCC_PR_ParsePrintDef(WARN_LAXCAST, from);
}
else
QCC_PR_ParseErrorPrintDef(ERR_TYPEMISMATCH, from, "Implicit type mismatch on assignment to %s. Needed %s, got %s.", to->name, basictypenames[wanted], basictypenames[from->type->type]);
QCC_PR_ParseErrorPrintDef(ERR_TYPEMISMATCH, from, "Implicit type mismatch on assignment to %s. Needed %s, got %s.", to->name, totypename, fromtypename);
}
return from;
}
@ -2506,12 +2516,41 @@ QCC_def_t *QCC_PR_StatementFlags (QCC_opcode_t *op, QCC_def_t *var_a, QCC_def_t
//divide the result
return QCC_PR_StatementFlags(&pr_opcodes[OP_DIV_I], var_c, var_b, NULL, 0);
case OP_BITAND_I:
{
QCC_def_t *arg[2] = {var_a, var_b};
QCC_type_t *argt[2] = {type_integer, type_integer};
QCC_def_t *fnc = QCC_PR_GetDef(NULL, "BitandInt", NULL, false, 0, 0);
if (!fnc)
QCC_PR_ParseError(0, "BitandInt function not defined: cannot emulate int+int");
numstatements--;
var_c = QCC_PR_GenerateFunctionCall(NULL, fnc, arg, argt, 2);
var_c->type = type_integer;
return var_c;
}
break;
case OP_BITOR_I:
{
QCC_def_t *arg[2] = {var_a, var_b};
QCC_type_t *argt[2] = {type_integer, type_integer};
QCC_def_t *fnc = QCC_PR_GetDef(NULL, "BitorInt", NULL, false, 0, 0);
if (!fnc)
QCC_PR_ParseError(0, "BitorInt function not defined: cannot emulate int+int");
numstatements--;
var_c = QCC_PR_GenerateFunctionCall(NULL, fnc, arg, argt, 2);
var_c->type = type_integer;
return var_c;
}
break;
case OP_ADD_I:
{
QCC_def_t *arg[2] = {var_a, var_b};
QCC_type_t *argt[2] = {type_integer, type_integer};
QCC_def_t *fnc = QCC_PR_GetDef(NULL, "AddInt", NULL, false, 0, 0);
if (!fnc)
QCC_PR_ParseError(0, "AddInt function not defined: cannot emulate int+int");
numstatements--;
var_c = QCC_PR_GenerateFunctionCall(NULL, QCC_PR_GetDef(type_function, "AddInt", NULL, true, 0, false), arg, argt, 2);
var_c = QCC_PR_GenerateFunctionCall(NULL, fnc, arg, argt, 2);
var_c->type = type_integer;
return var_c;
}
@ -2520,8 +2559,11 @@ QCC_def_t *QCC_PR_StatementFlags (QCC_opcode_t *op, QCC_def_t *var_a, QCC_def_t
{
QCC_def_t *arg[2] = {var_a, var_b};
QCC_type_t *argt[2] = {type_integer, type_integer};
QCC_def_t *fnc = QCC_PR_GetDef(NULL, "SubInt", NULL, false, 0, 0);
if (!fnc)
QCC_PR_ParseError(0, "SubInt function not defined: cannot emulate int-int");
numstatements--;
var_c = QCC_PR_GenerateFunctionCall(NULL, QCC_PR_GetDef(type_function, "SubInt", NULL, true, 0, false), arg, argt, 2);
var_c = QCC_PR_GenerateFunctionCall(NULL, fnc, arg, argt, 2);
var_c->type = type_integer;
return var_c;
}
@ -2530,8 +2572,11 @@ QCC_def_t *QCC_PR_StatementFlags (QCC_opcode_t *op, QCC_def_t *var_a, QCC_def_t
{
QCC_def_t *arg[2] = {var_a, var_b};
QCC_type_t *argt[2] = {type_integer, type_integer};
QCC_def_t *fnc = QCC_PR_GetDef(NULL, "MulInt", NULL, false, 0, 0);
if (!fnc)
QCC_PR_ParseError(0, "MulInt function not defined: cannot emulate int*int");
numstatements--;
var_c = QCC_PR_GenerateFunctionCall(NULL, QCC_PR_GetDef(type_function, "MulInt", NULL, true, 0, false), arg, argt, 2);
var_c = QCC_PR_GenerateFunctionCall(NULL, fnc, arg, argt, 2);
var_c->type = type_integer;
return var_c;
}
@ -2540,8 +2585,11 @@ QCC_def_t *QCC_PR_StatementFlags (QCC_opcode_t *op, QCC_def_t *var_a, QCC_def_t
{
QCC_def_t *arg[2] = {var_a, var_b};
QCC_type_t *argt[2] = {type_integer, type_integer};
QCC_def_t *fnc = QCC_PR_GetDef(NULL, "DivInt", NULL, false, 0, 0);
if (!fnc)
QCC_PR_ParseError(0, "DivInt function not defined: cannot emulate int/int");
numstatements--;
var_c = QCC_PR_GenerateFunctionCall(NULL, QCC_PR_GetDef(type_function, "DivInt", NULL, true, 0, false), arg, argt, 2);
var_c = QCC_PR_GenerateFunctionCall(NULL, fnc, arg, argt, 2);
var_c->type = type_integer;
return var_c;
}
@ -2562,32 +2610,42 @@ QCC_def_t *QCC_PR_StatementFlags (QCC_opcode_t *op, QCC_def_t *var_a, QCC_def_t
case OP_CONV_ITOF:
case OP_STORE_IF:
op = pr_opcodes+OP_STORE_F;
numstatements--;
if (var_a->constant)
var_a = QCC_MakeFloatConst(G_INT(var_a->ofs));
else
{
numstatements--;
var_a = QCC_PR_GenerateFunctionCall(NULL, QCC_PR_GetDef(type_function, "itof", NULL, true, 0, false), &var_a, &type_integer, 1);
var_c = QCC_PR_GetDef(NULL, "itof", NULL, false, 0, 0);
if (!var_c)
QCC_PR_ParseError(0, "itof function not defined: cannot emulate int -> float conversions");
var_a = QCC_PR_GenerateFunctionCall(NULL, var_c, &var_a, &type_integer, 1);
var_a->type = type_float;
statement = &statements[numstatements];
numstatements++;
}
break;
if (var_b)
{
QCC_FreeTemp(QCC_PR_StatementFlags(&pr_opcodes[OP_STORE_F], var_a, var_b, NULL, flags&STFL_PRESERVEB));
return var_b;
}
return var_a;
case OP_CONV_FTOI:
case OP_STORE_FI:
op = pr_opcodes+OP_STORE_I;
numstatements--;
if (var_a->constant)
var_a = QCC_MakeFloatConst(G_INT(var_a->ofs));
else
{
numstatements--;
var_a = QCC_PR_GenerateFunctionCall(NULL, QCC_PR_GetDef(type_function, "ftoi", NULL, true, 0, false), &var_a, &type_float, 1);
var_c = QCC_PR_GetDef(NULL, "ftoi", NULL, false, 0, 0);
if (!var_c)
QCC_PR_ParseError(0, "ftoi function not defined: cannot emulate float -> int conversions");
var_a = QCC_PR_GenerateFunctionCall(NULL, var_c, &var_a, &type_float, 1);
var_a->type = type_integer;
statement = &statements[numstatements];
numstatements++;
}
break;
if (var_b)
{
QCC_FreeTemp(QCC_PR_StatementFlags(&pr_opcodes[OP_STORE_I], var_a, var_b, NULL, flags&STFL_PRESERVEB));
return var_b;
}
return var_a;
case OP_STORE_I:
op = pr_opcodes+OP_STORE_F;
break;
@ -3044,16 +3102,32 @@ QCC_def_t *QCC_PR_StatementFlags (QCC_opcode_t *op, QCC_def_t *var_a, QCC_def_t
case OP_ADD_FI:
numstatements--;
var_b = QCC_PR_StatementFlags(&pr_opcodes[OP_CONV_ITOF], var_b, NULL, NULL, (flags&STFL_PRESERVEB)?STFL_PRESERVEA:0);
return QCC_PR_StatementFlags(&pr_opcodes[OP_ADD_F], var_a, var_b, NULL, flags&STFL_PRESERVEA);
return QCC_PR_StatementFlags(&pr_opcodes[OP_ADD_F], var_a, var_c, NULL, flags&STFL_PRESERVEA);
case OP_BITAND_FI:
numstatements--;
var_b = QCC_PR_StatementFlags(&pr_opcodes[OP_CONV_ITOF], var_b, NULL, NULL, (flags&STFL_PRESERVEB)?STFL_PRESERVEA:0);
return QCC_PR_StatementFlags(&pr_opcodes[OP_BITAND_F], var_a, var_c, NULL, flags&STFL_PRESERVEA);
case OP_BITOR_FI:
numstatements--;
var_b = QCC_PR_StatementFlags(&pr_opcodes[OP_CONV_ITOF], var_b, NULL, NULL, (flags&STFL_PRESERVEB)?STFL_PRESERVEA:0);
return QCC_PR_StatementFlags(&pr_opcodes[OP_BITOR_F], var_a, var_c, NULL, flags&STFL_PRESERVEA);
case OP_LT_FI:
numstatements--;
var_b = QCC_PR_StatementFlags(&pr_opcodes[OP_CONV_ITOF], var_b, NULL, NULL, (flags&STFL_PRESERVEB)?STFL_PRESERVEA:0);
return QCC_PR_StatementFlags(&pr_opcodes[OP_LT_F], var_a, var_b, NULL, flags&STFL_PRESERVEA);
return QCC_PR_StatementFlags(&pr_opcodes[OP_LT_F], var_a, var_c, NULL, flags&STFL_PRESERVEA);
//statements where the lhs is a const int and can be swapped with a float
case OP_ADD_IF:
numstatements--;
var_a = QCC_PR_StatementFlags(&pr_opcodes[OP_CONV_ITOF], var_a, NULL, NULL, flags&STFL_PRESERVEA);
return QCC_PR_StatementFlags(&pr_opcodes[OP_ADD_F], var_a, var_b, NULL, flags&STFL_PRESERVEB);
case OP_BITAND_IF:
numstatements--;
var_a = QCC_PR_StatementFlags(&pr_opcodes[OP_CONV_ITOF], var_a, NULL, NULL, flags&STFL_PRESERVEA);
return QCC_PR_StatementFlags(&pr_opcodes[OP_BITAND_F], var_a, var_b, NULL, flags&STFL_PRESERVEB);
case OP_BITOR_IF:
numstatements--;
var_a = QCC_PR_StatementFlags(&pr_opcodes[OP_CONV_ITOF], var_a, NULL, NULL, flags&STFL_PRESERVEA);
return QCC_PR_StatementFlags(&pr_opcodes[OP_BITOR_F], var_a, var_b, NULL, flags&STFL_PRESERVEB);
case OP_LT_IF:
numstatements--;
var_a = QCC_PR_StatementFlags(&pr_opcodes[OP_CONV_ITOF], var_a, NULL, NULL, flags&STFL_PRESERVEA);
@ -3208,15 +3282,26 @@ QCC_def_t *QCC_PR_ParseImmediate (void)
if (pr_immediate_type == type_string)
{
int t,l;
char tmp[8192];
strncpy(tmp, pr_immediate_string, sizeof(tmp)-1);
tmp[sizeof(tmp)-1] = 0;
t=l = strlen(pr_immediate_string);
if (l+1 > sizeof(tmp))
QCC_PR_ParseError (ERR_NAMETOOLONG, "string immediate is too long");
memcpy(tmp, pr_immediate_string, l);
tmp[l] = 0;
for(;;)
{
QCC_PR_Lex ();
if (pr_token_type == tt_immediate && pr_immediate_type == type_string)
strcat(tmp, pr_immediate_string);
{
l = strlen(pr_immediate_string);
if (t+l+1 > sizeof(tmp))
QCC_PR_ParseError (ERR_NAMETOOLONG, "string immediate is too long");
memcpy(tmp+t, pr_immediate_string, l);
tmp[t+l] = 0;
t+=l;
}
else
break;
}
@ -4773,7 +4858,8 @@ char *basictypenames[] = {
"integer",
"variant",
"struct",
"union"
"union",
"accessor"
};
QCC_type_t **basictypes[] =
@ -5178,6 +5264,27 @@ static QCC_ref_t *QCC_PR_ParseField(QCC_ref_t *refbuf, QCC_ref_t *lhs)
lhs = QCC_PR_ParseField(refbuf, lhs);
}
else if (t->type == ev_accessor && (QCC_PR_CheckToken(".") || QCC_PR_CheckToken("->")))
{
char *fieldname = QCC_PR_ParseName();
if (!t->aux_type)
QCC_PR_ParseError(ERR_INTERNAL, "Accessor %s was not defined yet", t->name);
else if (!strcmp(fieldname, "length"))
{
QCC_def_t *obj = QCC_RefToDef(lhs, true);
obj = QCC_PR_GenerateFunctionCall(NULL, t->getlength, &obj, &t->parentclass, 1);
lhs = QCC_PR_BuildRef(refbuf, REF_GLOBAL, obj, NULL, obj->type, true);
lhs = QCC_PR_ParseField(refbuf, lhs);
}
else
{
//these are not defs, but weird crap.
QCC_def_t *index = QCC_MakeStringConst(fieldname);
pbool noset = !t->setarr && !t->setptr;
lhs = QCC_PR_BuildRef(refbuf, REF_ACCESSOR, QCC_RefToDef(lhs, true), index, t->aux_type, lhs->readonly || noset);
lhs = QCC_PR_ParseField(refbuf, lhs);
}
}
return lhs;
}
@ -5203,6 +5310,7 @@ QCC_ref_t *QCC_PR_ParseRefArrayPointer (QCC_ref_t *retbuf, QCC_ref_t *r, pbool a
else
arraysize = 0;
idx = NULL;
while(1)
{
allowarray = false;
@ -5213,10 +5321,11 @@ QCC_ref_t *QCC_PR_ParseRefArrayPointer (QCC_ref_t *retbuf, QCC_ref_t *r, pbool a
else if (!idx)
{
allowarray = arraysize>0 ||
(t->type == ev_pointer) ||
(t->type == ev_string) ||
(t->type == ev_vector) ||
(t->type == ev_field && t->aux_type->type == ev_vector);
(t->type == ev_pointer) || //we can dereference pointers
(t->type == ev_string) || //strings are effectively pointers
(t->type == ev_vector) || //vectors are mini arrays
(t->type == ev_field && t->aux_type->type == ev_vector) || //as are field vectors
(t->type == ev_accessor); //custom accessors
}
if (allowarray && QCC_PR_CheckToken("["))
@ -5224,6 +5333,14 @@ QCC_ref_t *QCC_PR_ParseRefArrayPointer (QCC_ref_t *retbuf, QCC_ref_t *r, pbool a
tmp = QCC_PR_Expression (TOP_PRIORITY, 0);
QCC_PR_Expect("]");
if (!arraysize && t->type == ev_accessor)
{
if (!t->aux_type)
QCC_PR_ParseError(ERR_INTERNAL, "Accessor %s was not defined yet", t->name);
r = QCC_PR_BuildRef(retbuf, REF_ACCESSOR, QCC_RefToDef(r, true), tmp, t->aux_type, r->readonly || (!t->setarr && !t->setptr));
return QCC_PR_ParseRefArrayPointer(retbuf, r, allowarrayassign, makearraypointers);
}
/*if its a pointer that got dereferenced, follow the type*/
if (!idx && t->type == ev_pointer && !arraysize)
t = t->aux_type;
@ -5324,6 +5441,11 @@ QCC_ref_t *QCC_PR_ParseRefArrayPointer (QCC_ref_t *retbuf, QCC_ref_t *r, pbool a
else
idx = tmp;
}
else if (arraysize && (QCC_PR_CheckToken(".") || QCC_PR_CheckToken("->")))
{
QCC_PR_Expect("length");
return QCC_PR_BuildRef(retbuf, REF_GLOBAL, QCC_MakeIntConst(arraysize), NULL, type_integer, true);
}
else if ((t->type == ev_pointer || t->type == ev_struct || t->type == ev_union) && (QCC_PR_CheckToken(".") || QCC_PR_CheckToken("->")))
{
char *tname;
@ -5806,7 +5928,12 @@ QCC_ref_t *QCC_PR_RefTerm (QCC_ref_t *retbuf, unsigned int exprflags)
if (QCC_PR_CheckToken ("*"))
{
e = QCC_PR_Expression (UNARY_PRIORITY, EXPR_DISALLOW_COMMA);
return QCC_PR_BuildRef(retbuf, REF_POINTER, e, NULL, e->type->aux_type, false);
if (e->type->type == ev_pointer)
return QCC_PR_BuildRef(retbuf, REF_POINTER, e, NULL, e->type->aux_type, false);
else if (e->type->type == ev_accessor)
return QCC_PR_BuildRef(retbuf, REF_ACCESSOR, e, NULL, e->type->aux_type, !e->type->setptr);
else
QCC_PR_ParseErrorPrintDef (ERR_TYPEMISMATCH, e, "Unable to dereference non-pointer type.");
}
if (QCC_PR_CheckToken ("-"))
{
@ -5890,6 +6017,8 @@ QCC_ref_t *QCC_PR_RefTerm (QCC_ref_t *retbuf, unsigned int exprflags)
|| (newtype->type == ev_function && e->type->type == ev_function)
//variants are fine too
|| (newtype->type == ev_variant || e->type->type == ev_variant)
|| (newtype->type == ev_accessor && newtype->parentclass->type == e->type->type)
|| (e->type->type == ev_accessor && e->type->parentclass->type == newtype->type)
)
{
e->references++;
@ -5897,7 +6026,13 @@ QCC_ref_t *QCC_PR_RefTerm (QCC_ref_t *retbuf, unsigned int exprflags)
return QCC_PR_BuildRef(retbuf, REF_GLOBAL, e, NULL, newtype, true);
}
else
QCC_PR_ParseError(0, "Bad type cast\n");
{
char typea[256];
char typeb[256];
TypeName(e->type, typea, sizeof(typea));
TypeName(newtype, typeb, sizeof(typeb));
QCC_PR_ParseError(0, "Cannot cast from %s to %s\n", typea, typeb);
}
return QCC_DefToRef(retbuf, e);
}
@ -6030,10 +6165,6 @@ void QCC_StoreToDef(QCC_def_t *dest, QCC_def_t *source, QCC_type_t *type, pbool
QCC_PR_SimpleStatement(OP_STORE_V, source->ofs+i, dest->ofs+i, 0, false);
for (; i < type->size; i++)
QCC_PR_SimpleStatement(OP_STORE_F, source->ofs+i, dest->ofs+i, 0, false);
if (!preservesource)
QCC_FreeTemp(source);
if (!preservedest)
QCC_FreeTemp(dest);
break;
default:
case ev_float:
@ -6061,6 +6192,10 @@ void QCC_StoreToDef(QCC_def_t *dest, QCC_def_t *source, QCC_type_t *type, pbool
QCC_PR_StatementFlags(&pr_opcodes[OP_STORE_P], source, dest, NULL, flags);
break;
}
if (!preservesource)
QCC_FreeTemp(source);
if (!preservedest)
QCC_FreeTemp(dest);
}
//if readable, returns source (or dest if the store was folded), otherwise returns NULL
QCC_def_t *QCC_CollapseStore(QCC_def_t *dest, QCC_def_t *source, QCC_type_t *type, pbool readable, pbool preservedest)
@ -6488,6 +6623,20 @@ QCC_def_t *QCC_RefToDef(QCC_ref_t *ref, pbool freetemps)
return QCC_PR_ExpandField(ref->base, ref->index, ref->cast, freetemps?0:(STFL_PRESERVEA|STFL_PRESERVEB));
case REF_STRING:
return QCC_PR_StatementFlags(&pr_opcodes[OP_LOADP_C], ref->base, ref->index, NULL, freetemps?0:(STFL_PRESERVEA|STFL_PRESERVEB));
case REF_ACCESSOR:
if (!ref->index && ref->base->type->getptr)
{
QCC_def_t *arg[] = {ref->base};
return QCC_PR_GenerateFunctionCall(NULL, ref->base->type->getptr, arg, NULL, 1);
}
else if (ref->base->type->getarr)
{
QCC_def_t *arg[] = {ref->base, ref->index?QCC_SupplyConversion(ref->index, ref->base->type->aux_type->type, true):QCC_MakeIntConst(0)};
return QCC_PR_GenerateFunctionCall(NULL, ref->base->type->getarr, arg, NULL, 2);
}
else
QCC_PR_ParseErrorPrintDef(ERR_NOFUNC, ref->base, "Accessor has no appropriate get function");
break;
}
if (ref->cast != ret->type)
{
@ -6627,6 +6776,20 @@ QCC_def_t *QCC_StoreToRef(QCC_ref_t *dest, QCC_def_t *source, pbool readable, pb
QCC_PR_Statement(&pr_opcodes[OP_STOREP_C], addr, source, NULL);
}
break;
case REF_ACCESSOR:
if (!dest->index && dest->base->type->setptr)
{
QCC_def_t *arg[] = {dest->base, source};
QCC_FreeTemp(QCC_PR_GenerateFunctionCall(NULL, dest->base->type->setptr, arg, NULL/*argt*/, 2));
}
else if (dest->index && dest->base->type->setarr)
{
QCC_def_t *arg[] = {dest->base, dest->index?QCC_SupplyConversion(dest->index, dest->base->type->setarr->type->params[1].type->type, true):QCC_MakeIntConst(0), source};
QCC_FreeTemp(QCC_PR_GenerateFunctionCall(NULL, dest->base->type->setarr, arg, NULL/*argt*/, 2));
}
else
QCC_PR_ParseErrorPrintDef(ERR_NOFUNC, dest->base, "Accessor has no suitable set function");
break;
case REF_FIELD:
// {
//fixme: we should do this earlier, to preserve original instruction ordering.
@ -7015,7 +7178,7 @@ QCC_ref_t *QCC_PR_RefExpression (QCC_ref_t *retbuf, int priority, int exprflags)
//convert so we don't have issues with: i = (int)(float)(i+f)
//this will also catch things like vec *= vec; which would be trying to store a float into a vector.
rhsd = QCC_SupplyConversionForAssignment(lhsr->base, rhsd, lhsr->cast->type, true);
rhsd = QCC_SupplyConversionForAssignment(lhsr->base, rhsd, lhsr->cast, true);
}
else
{
@ -7035,7 +7198,7 @@ QCC_ref_t *QCC_PR_RefExpression (QCC_ref_t *retbuf, int priority, int exprflags)
rhsd = QCC_MakeIntConst(0);
}
else
rhsd = QCC_SupplyConversionForAssignment(lhsr->base, rhsd, lhsr->cast->type, true);
rhsd = QCC_SupplyConversionForAssignment(lhsr->base, rhsd, lhsr->cast, true);
}
rhsd = QCC_StoreToRef(lhsr, rhsd, true, false); //FIXME: this should not always be true, but we don't know if the caller actually needs it
qcc_usefulstatement = true;
@ -7492,7 +7655,7 @@ void QCC_PR_ParseStatement (void)
if (!QCC_PR_CheckToken(")"))
{
old_numstatements = numstatements;
QCC_FreeTemp(QCC_PR_Expression(TOP_PRIORITY, 0));
QCC_PR_DiscardExpression(TOP_PRIORITY, 0);
numtemp = numstatements - old_numstatements;
if (numtemp > sizeof(temp)/sizeof(temp[0]))
@ -7630,6 +7793,7 @@ void QCC_PR_ParseStatement (void)
(keyword_integer && !STRCMP ("integer", pr_token)) ||
(keyword_int && !STRCMP ("int", pr_token)) ||
(keyword_class && !STRCMP ("class", pr_token)) ||
(keyword_class && !STRCMP ("static", pr_token)) ||
(keyword_const && !STRCMP ("const", pr_token)))
{
QCC_PR_ParseDefs (NULL);
@ -9174,6 +9338,19 @@ void QCC_WriteAsmFunction(QCC_def_t *sc, unsigned int firststatement, gofs_t fir
fprintf(asmfile, ",\t%i", statements[i].c);
}
}
}
else
{
if (pr_opcodes[statements[i].op].type_c != &type_void)
{
if (pr_opcodes[statements[i].op].type_c)
{
fprintf(asmfile, "\t%s", QCC_VarAtOffset(statements[i].c, (*pr_opcodes[statements[i].op].type_c)->size));
fprintf(asmfile, "/*%i*/", statements[i].c);
}
else
fprintf(asmfile, "\t%i", statements[i].c);
}
}
fprintf(asmfile, "; /*%i*/\n", statements[i].linenum);
}
@ -10228,6 +10405,16 @@ QCC_def_t *QCC_PR_GetDef (QCC_type_t *type, char *name, QCC_def_t *scope, pbool
else
ofs = QCC_GetFreeGlobalOffsetSpace(type->size);
if (!strncmp(name, "autocvar_", 9))
{
if (scope)
QCC_PR_ParseWarning(WARN_MISUSEDAUTOCVAR, "Autocvar \"%s\" defined with local scope", name);
else if (flags & GDF_CONST)
QCC_PR_ParseWarning(WARN_MISUSEDAUTOCVAR, "Autocvar \"%s\" defined as constant", name);
else if (flags & GDF_STATIC)
QCC_PR_ParseWarning(WARN_MISUSEDAUTOCVAR, "Autocvar \"%s\" defined as static", name);
}
def = QCC_PR_DummyDef(type, name, scope, arraysize, ofs, true, flags);
if (scope && !(flags & (GDF_CONST|GDF_STATIC)))
@ -10529,6 +10716,10 @@ void QCC_PR_ParseInitializerType(int arraysize, QCC_def_t *def, QCC_type_t *type
/*cast from float->int will convert*/
else if (type->type == ev_integer && tmp->type->type == ev_float)
tmp = QCC_PR_Statement (&pr_opcodes[OP_CONV_FTOI], tmp, 0, NULL);
else if ( (type->type == ev_accessor && type->parentclass->type == tmp->type->type)
|| (tmp->type->type == ev_accessor && tmp->type->parentclass->type == type->type))
{
}
else
{
char gottype[256];
@ -10614,7 +10805,7 @@ void QCC_PR_ParseDefs (char *classname)
{
char *name;
QCC_type_t *type, *defclass;
QCC_def_t *def, *d;
QCC_def_t *def, *d, *dynlength;
QCC_function_t *f;
QCC_dfunction_t *df;
int i = 0; // warning: i may be used uninitialized in this function
@ -11184,11 +11375,13 @@ void QCC_PR_ParseDefs (char *classname)
return; //allow named structs
if (type->type == ev_entity && type != type_entity)
return; //allow forward class definititions with or without a variable.
if (type->type == ev_accessor) //accessors shouldn't trigger problems if they're just a type.
return;
// if (type->type == ev_union)
// {
// return;
// }
QCC_PR_ParseError (ERR_TYPEWITHNONAME, "type with no name");
QCC_PR_ParseError (ERR_TYPEWITHNONAME, "type (%s) with no name", type->name);
name = NULL;
}
else
@ -11204,6 +11397,7 @@ void QCC_PR_ParseDefs (char *classname)
//check for an array
dynlength = NULL;
if ( QCC_PR_CheckToken ("[") )
{
char *oldprfile = pr_file_p;
@ -11243,11 +11437,27 @@ void QCC_PR_ParseDefs (char *classname)
}
else
{
arraysize = QCC_PR_IntConstExpr();
arraysize = 0;
dynlength = QCC_PR_Expression(TOP_PRIORITY, 0);
if (dynlength->constant)
{
dynlength->references++;
if (dynlength->type->type == ev_integer)
arraysize = G_INT(dynlength->ofs);
else if (dynlength->type->type == ev_float)
{
int i = G_FLOAT(dynlength->ofs);
if ((float)i == G_FLOAT(dynlength->ofs))
arraysize = i;
}
dynlength = NULL;
}
else if (!pr_scope)
dynlength = NULL;
QCC_PR_Expect("]");
}
if (arraysize < 1)
if (arraysize < 1 && !dynlength)
{
QCC_PR_ParseError (ERR_BADARRAYSIZE, "Definition of array (%s) size is not of a numerical value", name);
arraysize=1; //grrr...
@ -11284,7 +11494,16 @@ void QCC_PR_ParseDefs (char *classname)
if (!nosave)
gd_flags |= GDF_SAVED;
def = QCC_PR_GetDef (type, name, pr_scope, allocatenew, arraysize, gd_flags);
if (dynlength)
{
def = QCC_PR_GetDef (QCC_PR_PointerType(type), name, pr_scope, allocatenew, 0, gd_flags);
dynlength = QCC_SupplyConversion(dynlength, ev_integer, true);
if (type->size != 1)
dynlength = QCC_PR_Statement(pr_opcodes+OP_MUL_I, dynlength, QCC_MakeIntConst(type->size), NULL);
QCC_PR_Statement3(&pr_opcodes[OP_PUSH], dynlength, NULL, def, false); //push *(int*)&a elements
}
else
def = QCC_PR_GetDef (type, name, pr_scope, allocatenew, arraysize, gd_flags);
if (!def)
QCC_PR_ParseError(ERR_NOTANAME, "%s is not part of class %s", name, classname);

View File

@ -2665,14 +2665,77 @@ static void QCC_PR_ExpandStrCat(char **buffer, size_t *bufferlen, size_t *buffer
/*no null terminator, remember to cat one if required*/
}
static char *QCC_PR_CheckBuiltinCompConst(char *constname, char *retbuf, size_t retbufsize)
{
if (!strcmp(constname, "__TIME__"))
{
time_t long_time;
time( &long_time );
strftime( retbuf, retbufsize, "\"%H:%M\"", localtime( &long_time ));
return retbuf;
}
if (!strcmp(constname, "__DATE__"))
{
time_t long_time;
time( &long_time );
strftime( retbuf, retbufsize, "\"%a %d %b %Y\"", localtime( &long_time ));
return retbuf;
}
if (!strcmp(constname, "__RAND__"))
{
QC_snprintfz(retbuf, retbufsize, "%i", rand());
return retbuf;
}
if (!strcmp(constname, "__QCCVER__"))
{
return "FTEQCC "__DATE__","__TIME__"";
}
if (!strcmp(constname, "__FILE__"))
{
QC_snprintfz(retbuf, retbufsize, "\"%s\"", strings + s_file);
return retbuf;
}
if (!strcmp(constname, "__LINE__"))
{
QC_snprintfz(retbuf, retbufsize, "%i", pr_source_line);
return retbuf;
}
if (!strcmp(constname, "__LINESTR__"))
{
QC_snprintfz(retbuf, retbufsize, "\"%i\"", pr_source_line);
return retbuf;
}
if (!strcmp(constname, "__FUNC__"))
{
QC_snprintfz(retbuf, retbufsize, "\"%s\"",pr_scope?pr_scope->name:"<NO FUNCTION>");
return retbuf;
}
if (!strcmp(constname, "__NULL__"))
{
return "0i";
}
return NULL; //didn't match
}
#define PASTE2(a,b) a##b
#define PASTE(a,b) PASTE2(a,b)
#define STRINGIFY2(a) #a
#define STRINGIFY(a) STRINGIFY2(a)
#define spam(x) /*static float PASTE(spam,__LINE__);*/ if (PASTE2(spam,__LINE__) != x) {dprint(#x " chaned in " __FILE__ " on line " STRINGIFY2(__LINE__) "\n"); PASTE2(spam,__LINE__) = x;}
#define dprint printf
int QCC_PR_CheckCompConst(void)
{
char *oldpr_file_p = pr_file_p;
int whitestart;
int whitestart = 5;
CompilerConstant_t *c;
char *end;
char *end, *tok;
char retbuf[256];
// spam(whitestart);
for (end = pr_file_p; ; end++)
{
if (!*end || qcc_iswhite(*end))
@ -2725,6 +2788,7 @@ int QCC_PR_CheckCompConst(void)
char *paramoffset[MAXCONSTANTPARAMS+1];
int param=0;
int plevel=0;
pbool noargexpand;
pr_file_p++;
QCC_PR_LexWhitespace(false);
@ -2785,6 +2849,7 @@ int QCC_PR_CheckCompConst(void)
pr_file_p = c->value;
for(;;)
{
noargexpand = false;
whitestart = bufferlen;
starttok = pr_file_p;
/*while(qcc_iswhite(*pr_file_p)) //copy across whitespace
@ -2818,6 +2883,7 @@ int QCC_PR_CheckCompConst(void)
{ //concatinate (strip out whitespace before the token)
bufferlen = whitestart;
pr_file_p+=2;
noargexpand = true;
}
else
{ //stringify
@ -2847,6 +2913,7 @@ int QCC_PR_CheckCompConst(void)
}
}
end = qcc_token;
pr_file_p = QCC_COM_Parse2(pr_file_p);
if (!pr_file_p)
break;
@ -2855,7 +2922,43 @@ int QCC_PR_CheckCompConst(void)
{
if (!STRCMP(qcc_token, c->params[p]))
{
QCC_PR_ExpandStrCat(&buffer, &bufferlen, &buffermax, paramoffset[p], strlen(paramoffset[p]));
char *argstart, *argend;
for (start = pr_file_p; qcc_iswhite(*start); start++)
;
if (noargexpand || (start[0] == '#' && start[1] == '#'))
QCC_PR_ExpandStrCat(&buffer, &bufferlen, &buffermax, paramoffset[p], strlen(paramoffset[p]));
else
{
for (argstart = paramoffset[p]; *argstart; argstart = argend)
{
argend = argstart;
while (qcc_iswhite(*argend))
argend++;
if (*argend == '\"')
{
do
{
argend++;
} while( (argend[-1] == '\\' || argend[0] != '\"') && *argend && *argend != '\n' );
if(*argend == '\"')
argend++;
end = NULL;
}
else
{
argend = QCC_COM_Parse2(argend);
if (!argend)
break;
end = QCC_PR_CheckBuiltinCompConst(qcc_token, retbuf, sizeof(retbuf));
}
//FIXME: we should be testing all defines instead of just built-in ones.
if (end)
QCC_PR_ExpandStrCat(&buffer, &bufferlen, &buffermax, end, strlen(end));
else
QCC_PR_ExpandStrCat(&buffer, &bufferlen, &buffermax, argstart, argend-argstart);
}
}
break;
}
}
@ -2899,78 +3002,11 @@ int QCC_PR_CheckCompConst(void)
return true;
}
if (!strncmp(pr_file_p, "__TIME__", 8))
tok = QCC_PR_CheckBuiltinCompConst(pr_token, retbuf, sizeof(retbuf));
if (tok)
{
char retbuf[128];
time_t long_time;
time( &long_time );
strftime( retbuf, sizeof(retbuf),
"\"%H:%M\"", localtime( &long_time ));
pr_file_p += 8;
QCC_PR_IncludeChunkEx(retbuf, true, NULL, NULL);
return true;
}
if (!strncmp(pr_file_p, "__DATE__", 8))
{
char retbuf[128];
time_t long_time;
time( &long_time );
strftime( retbuf, sizeof(retbuf),
"\"%a %d %b %Y\"", localtime( &long_time ));
pr_file_p += 8;
QCC_PR_IncludeChunkEx(retbuf, true, NULL, NULL);
return true;
}
if (!strncmp(pr_file_p, "__RAND__", 8))
{
char retbuf[128];
QC_snprintfz(retbuf, sizeof(retbuf), "%i", rand());
pr_file_p += 8;
QCC_PR_IncludeChunkEx(retbuf, true, NULL, NULL);
return true;
}
if (!strncmp(pr_file_p, "__QCCVER__", 8))
{
pr_file_p += 10;
QCC_PR_IncludeChunkEx("FTEQCC "__DATE__","__TIME__"", true, NULL, NULL);
return true;
}
if (!strncmp(pr_file_p, "__FILE__", 8))
{
char retbuf[256];
QC_snprintfz(retbuf, sizeof(retbuf), "\"%s\"", strings + s_file);
pr_file_p += 8;
QCC_PR_IncludeChunkEx(retbuf, true, NULL, NULL);
return true;
}
if (!strncmp(pr_file_p, "__LINE__", 8))
{
char retbuf[256];
QC_snprintfz(retbuf, sizeof(retbuf), "\"%i\"", pr_source_line);
pr_file_p += 8;
QCC_PR_IncludeChunkEx(retbuf, true, NULL, NULL);
return true;
}
if (!strncmp(pr_file_p, "__FUNC__", 8))
{
char retbuf[256];
QC_snprintfz(retbuf, sizeof(retbuf), "\"%s\"",pr_scope?pr_scope->name:"<NO FUNCTION>");
pr_file_p += 8;
QCC_PR_IncludeChunkEx(retbuf, true, NULL, NULL);
return true;
}
if (!strncmp(pr_file_p, "__NULL__", 8))
{
pr_file_p += 8;
QCC_PR_IncludeChunkEx("0i", false, NULL, NULL);
pr_file_p = end;
QCC_PR_IncludeChunkEx(tok, true, NULL, NULL);
return true;
}
return false;
@ -3612,7 +3648,53 @@ a new one and copies it out.
============
*/
//0 if same
//requires EVERYTHING to be the same
int typecmp_strict(QCC_type_t *a, QCC_type_t *b)
{
int i;
if (a == b)
return 0;
if (!a || !b)
return 1; //different (^ and not both null)
if (a->type != b->type)
return 1;
if (a->num_parms != b->num_parms)
return 1;
if (a->vargs != b->vargs)
return 1;
if (a->vargcount != b->vargcount)
return 1;
if (a->size != b->size)
return 1;
if (a->getarr != b->getarr ||
a->getptr != b->getptr ||
a->setarr != b->setarr ||
a->setptr != b->setptr ||
a->getlength != b->getlength)
return 1;
if (STRCMP(a->name, b->name))
return 1;
if (typecmp_strict(a->aux_type, b->aux_type))
return 1;
i = a->num_parms;
while(i-- > 0)
{
if (STRCMP(a->params[i].paramname, b->params[i].paramname))
return 1;
if (typecmp_strict(a->params[i].type, b->params[i].type))
return 1;
}
return 0;
}
//reports if they're functionally equivelent (allows assignments)
int typecmp(QCC_type_t *a, QCC_type_t *b)
{
int i;
@ -3659,6 +3741,7 @@ int typecmp_lax(QCC_type_t *a, QCC_type_t *b)
{
unsigned int minargs = 0;
unsigned int t;
if (a == b)
return 0;
if (!a || !b)
@ -3666,6 +3749,12 @@ int typecmp_lax(QCC_type_t *a, QCC_type_t *b)
if (a->type != b->type)
{
if (a->type == ev_accessor && a->parentclass)
if (!typecmp_lax(a->parentclass, b))
return 0;
if (b->type == ev_accessor && b->parentclass)
if (!typecmp_lax(a, b->parentclass))
return 0;
if (a->type != ev_variant && b->type != ev_variant)
return 1;
}
@ -3845,10 +3934,9 @@ QCC_type_t *QCC_PR_FindType (QCC_type_t *type)
for (t = 0; t < numtypeinfos; t++)
{
// check = &qcc_typeinfo[t];
if (typecmp(&qcc_typeinfo[t], type))
if (typecmp_strict(&qcc_typeinfo[t], type))
continue;
// c2 = check->next;
// n2 = type->next;
// for (i=0 ; n2&&c2 ; i++)
@ -4209,6 +4297,141 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
name = QCC_PR_CheckCompConstString(pr_token);
//accessors
if (QCC_PR_CheckKeyword (keyword_class, "accessor"))
{
char *accessorname;
char *funcname;
newt = NULL;
funcname = QCC_PR_ParseName();
accessorname = qccHunkAlloc(strlen(funcname)+1);
strcpy(accessorname, funcname);
/* Look to see if this type is already defined */
for(i=0;i<numtypeinfos;i++)
{
if (!qcc_typeinfo[i].typedefed)
continue;
if (STRCMP(qcc_typeinfo[i].name, accessorname) == 0 && qcc_typeinfo[i].type == ev_accessor)
{
newt = &qcc_typeinfo[i];
break;
}
}
if (QCC_PR_CheckToken(":"))
{
char *parentname = QCC_PR_ParseName();
type = QCC_TypeForName(parentname);
if (!type || type->type == ev_struct || type->type == ev_union)
QCC_PR_ParseError(ERR_NOTANAME, "Accessor %s cannot be based upon %s", accessorname, parentname);
}
if (!newt)
{
newt = QCC_PR_NewType(accessorname, ev_accessor, true);
newt->size=type->size;
}
if (!newt->parentclass)
newt->parentclass = type;
else if (type != newt->parentclass)
QCC_PR_ParseError(ERR_NOTANAME, "Accessor %s basic type mismatch", accessorname);
if (QCC_PR_CheckToken(":"))
{
char *parentname = QCC_PR_ParseName();
if (newt->aux_type)
QCC_PR_ParseError (ERR_UNKNOWNVALUE, "Accessor %s was already defined", accessorname);
newt->aux_type = QCC_TypeForName(parentname);
if (!newt->parentclass || newt->parentclass->type == ev_struct || newt->parentclass->type == ev_union || newt->size != newt->parentclass->size)
QCC_PR_ParseError(ERR_NOTANAME, "Accessor %s cannot be based upon %s", accessorname, parentname);
if (QCC_PR_CheckToken("["))
{
newt->vargcount = true;
QCC_PR_Expect("]");
}
QCC_PR_Expect("{");
do
{
if (QCC_PR_CheckName("length"))
{
QCC_PR_Expect("=");
funcname = QCC_PR_ParseName();
newt->getlength = QCC_PR_GetDef(NULL, funcname, NULL, false, 0, 0);
if (!newt->getlength)
QCC_PR_ParseError (ERR_UNKNOWNVALUE, "Unknown value \"%s\"", funcname);
else if (newt->getlength->type->type != ev_function || newt->getlength->type->num_parms != 1)
QCC_PR_ParseError (ERR_UNKNOWNVALUE, "length function unsuitable \"%s\"", funcname);
}
else if (QCC_PR_CheckName("get"))
{
pbool stareq = QCC_PR_CheckToken("*=");
if (stareq || QCC_PR_CheckToken("*"))
{
if (!stareq) QCC_PR_Expect("=");
funcname = QCC_PR_ParseName();
newt->getptr = QCC_PR_GetDef(NULL, funcname, NULL, false, 0, 0);
if (!newt->getptr)
QCC_PR_ParseError (ERR_UNKNOWNVALUE, "Unknown value \"%s\"", funcname);
else if (newt->getptr->type->type != ev_function || (newt->getptr->type->num_parms != 1 && !(newt->getptr->type->num_parms > 1 && newt->getptr->type->params[1].optional)))
QCC_PR_ParseError (ERR_UNKNOWNVALUE, "get* function unsuitable \"%s\"", funcname);
}
else
{
if (QCC_PR_CheckToken("["))
QCC_PR_Expect("]");
QCC_PR_Expect("=");
funcname = QCC_PR_ParseName();
newt->getarr = QCC_PR_GetDef(NULL, funcname, NULL, false, 0, 0);
if (!newt->getarr)
QCC_PR_ParseError (ERR_UNKNOWNVALUE, "Unknown value \"%s\"", funcname);
else if (newt->getarr->type->type != ev_function || (newt->getarr->type->num_parms != 2 && !(newt->getarr->type->num_parms > 2 && newt->getarr->type->params[2].optional)))
QCC_PR_ParseError (ERR_UNKNOWNVALUE, "get[] function unsuitable \"%s\"", funcname);
}
}
else if (QCC_PR_CheckName("set"))
{
pbool stareq = QCC_PR_CheckToken("*=");
if (stareq || QCC_PR_CheckToken("*"))
{
if (!stareq) QCC_PR_Expect("=");
funcname = QCC_PR_ParseName();
newt->setptr = QCC_PR_GetDef(NULL, funcname, NULL, false, 0, 0);
if (!newt->setptr)
QCC_PR_ParseError (ERR_UNKNOWNVALUE, "Unknown value \"%s\"", funcname);
else if (newt->setptr->type->type != ev_function || (newt->setptr->type->num_parms != 2 && !(newt->setptr->type->num_parms > 2 && newt->setptr->type->params[2].optional)))
QCC_PR_ParseError (ERR_UNKNOWNVALUE, "set* function unsuitable \"%s\"", funcname);
}
else
{
if (QCC_PR_CheckToken("["))
QCC_PR_Expect("]");
QCC_PR_Expect("=");
funcname = QCC_PR_ParseName();
newt->setarr = QCC_PR_GetDef(NULL, funcname, NULL, false, 0, 0);
if (!newt->setarr)
QCC_PR_ParseError (ERR_UNKNOWNVALUE, "Unknown value \"%s\"", funcname);
else if (newt->setarr->type->type != ev_function || (newt->setarr->type->num_parms != 3 && !(newt->setarr->type->num_parms > 3 && newt->setarr->type->params[3].optional)))
QCC_PR_ParseError (ERR_UNKNOWNVALUE, "set[] function unsuitable \"%s\"", funcname);
}
}
else
break;
} while (QCC_PR_CheckToken(",") || QCC_PR_CheckToken(";"));
QCC_PR_Expect("}");
}
if (newtype)
newt = QCC_PR_DuplicateType(newt, false);
return newt;
}
if (QCC_PR_CheckKeyword (keyword_class, "class"))
{
// int parms;