value now can be casted to virtual "bool" type
[d2dqcc.git] / src / libqcc / qcc_pr_comp_expr.c
blob14a5b232e20e1a80b392e07630dd381fa7cf711b
1 static QCC_def_t *QCC_PR_ExpressionEx (int priority, int exprflags, QCC_def_t *gotarg0);
4 /*
5 ============
6 QCC_ConversionOpcode
8 return conversion opcode.
9 zero return value means that no conversion needed.
10 negative return value means that there is no conversion available.
11 ============
13 static inline int QCC_ConversionOpcode (const QCC_def_t *var, qcc_etype wanted) {
14 //fprintf(stderr, "QCC_ConversionOpcode: from=%d; to=%d\n", var->type->type, wanted);
15 // no conversion needed
16 if (var->type->type == wanted) return 0;
17 if (var->type->type == ev_integer && wanted == ev_function) return 0;
18 if (var->type->type == ev_integer && wanted == ev_pointer) return 0;
19 // stuff needs converting
20 if (var->type->type == ev_pointer && var->type->aux_type) {
21 if (var->type->aux_type->type == ev_float && wanted == ev_integer) return OP_CP_FTOI;
22 if (var->type->aux_type->type == ev_integer && wanted == ev_float) return OP_CP_ITOF;
23 } else {
24 if (var->type->type == ev_float && wanted == ev_integer) return OP_CONV_FTOI;
25 if (var->type->type == ev_integer && wanted == ev_float) return OP_CONV_ITOF;
26 //if (var->type->type == ev_float && wanted == ev_string) return OP_CONV_FTOS;
27 //if (var->type->type == ev_integer && wanted == ev_string) return OP_CONV_ITOS;
29 // impossible
30 return -1;
35 ============
36 QCC_SupplyConversion
38 emit conversion operators if necessary.
39 fail if 'fatal' is true and there is no conversion available.
40 return converted def_t (this can be 'var' if no conversion necessary.
41 ============
43 static QCC_def_t *QCC_SupplyConversion (QCC_def_t *var, qcc_etype wanted, qccbool fatal) {
44 int o;
45 //fprintf(stderr, "QCC_SupplyConversion: from=%d; to=%d\n", var->type->type, wanted);
46 if ((o = QCC_ConversionOpcode(var, wanted)) == 0) return var; // type already matches
47 if (o < 0) {
48 if (fatal) {
49 QCC_PR_ParseErrorPrintDef(ERR_TYPEMISMATCH, var, "Implicit type mismatch. Needed %s, got %s.", basictypenames[wanted], var->type->name);
51 return var;
53 return QCC_PR_Statement(&pr_opcodes[o], var, NULL, NULL); // conversion return value
59 ============
60 QCC_canConv
62 check if we can convert 'from' to the given type.
63 return 'conversion cost' (wtf?!) or negative value if we can't.
64 conversion cost of zero means 'no conversion necessary'.
65 ============
67 static inline int QCC_canConv (const QCC_def_t *from, qcc_etype to) {
68 int op;
69 //fprintf(stderr, "[%s] f=%d t=%d\n", from->type->name, from->type->type, to);
70 if (from->type->type == to) return 0;
71 //if (from->type->type == ev_vector && to == ev_float) return 4; // don't want this, use vectors properly
73 op = QCC_ConversionOpcode(from, to);
74 if (op == 0) return 0;
75 if (op > 0) return 4;
77 if (from->type->type == ev_pointer && from->type->aux_type->type == to) return 1;
78 if (QCC_ConversionOpcode(from, to) >= 0) return 1;
80 //k8: if (from->type->type == ev_integer && to == ev_function) return 1;
81 //if (from->type->type == ev_integer && to == ev_string) return 1;
82 //if (from->type->type == ev_float && to == ev_string) return 1;
83 return -100;
88 ============
89 QCC_PR_ExprCast
91 process type casting.
92 ============
94 static QCC_def_t *QCC_PR_ExprCast (QCC_type_t *newtype) {
95 QCC_def_t *e, *e2;
96 //qcc_etype t;
97 // type casting
98 QCC_PR_Expect(")");
99 e = QCC_PR_Expression(UNARY_PRIORITY, EXPR_DISALLOW_COMMA);
101 if (newtype->type == e->type->type) return e; // ok
102 // you may cast from const 0 to any type of same size for free (from either int or float for simplicity)
103 if (newtype->size == e->type->size &&
104 (e->type->type == ev_integer || e->type->type == ev_float) &&
105 e->constant && !G_INT(e->ofs)) {
106 //TODO: wtf?!
107 QCC_PR_ParseError(0, "Bad type cast: TODO const 0");
109 // cast from int->float will convert
110 if (newtype->type == ev_float && e->type->type == ev_integer) {
111 return QCC_PR_Statement(&pr_opcodes[OP_CONV_ITOF], e, 0, NULL);
113 // cast from float->int will convert
114 if (newtype->type == ev_integer && e->type->type == ev_float) {
115 return QCC_PR_Statement(&pr_opcodes[OP_CONV_FTOI], e, 0, NULL);
117 // cast to string
118 if (newtype->type == ev_string) {
119 // cast from int->string will convert
120 if (e->type->type == ev_integer) return QCC_PR_Statement(&pr_opcodes[OP_CONV_ITOS], e, 0, NULL);
121 // cast from float->string will convert
122 if (e->type->type == ev_float) return QCC_PR_Statement(&pr_opcodes[OP_CONV_FTOS], e, 0, NULL);
123 QCC_PR_ParseError(0, "Bad type cast");
126 if (
127 //pointers
128 ((newtype->type == ev_pointer || newtype->type == ev_string || newtype->type == ev_integer) &&
129 (e->type->type == ev_pointer || e->type->type == ev_string || e->type->type == ev_integer)) ||
130 //ents/classs
131 (newtype->type == ev_entity && e->type->type == ev_entity)) {
132 // you may freely cast between pointers (and ints, as this is explicit)
133 // (strings count as pointers - WARNING: some strings may not be expressable as pointers)
134 //direct cast
135 e2 = (void *)qccHunkAlloc(sizeof(QCC_def_t));
136 memset(e2, 0, sizeof(QCC_def_t));
137 e2->type = newtype;
138 e2->ofs = e->ofs;
139 e2->constant = qcc_true;
140 e2->temp = e->temp;
141 return e2;
144 QCC_PR_ParseError(0, "Bad type cast");
148 static QCC_def_t *QCC_PR_ExprCast2Bool (void) {
149 QCC_def_t *e, *e2;
150 int opc, stnum;
151 QCC_PR_Expect(")");
152 e = QCC_PR_Expression(UNARY_PRIORITY, EXPR_DISALLOW_COMMA);
153 e2 = QCC_GetTemp(type_float);
154 if (!qcc_typecmp(e->type, type_string)) opc = OP_IF_S;
155 else if (!qcc_typecmp(e->type, type_float)) opc = OP_IF_F;
156 else opc = OP_IF_I;
157 // store 'true' value
158 QCC_PR_Statement3(&pr_opcodes[OP_STORE_F], QCC_MakeFloatConst(1.0f), e2, NULL, qcc_false);
159 // generate 'checkjump'
160 stnum = numstatements;
161 QCC_PR_Statement3(&pr_opcodes[opc], e, NULL, NULL, qcc_false);
162 // store 'false' value
163 QCC_PR_Statement3(&pr_opcodes[OP_STORE_F], QCC_MakeFloatConst(0.0f), e2, NULL, qcc_false);
164 // fix jump
165 statements[stnum].sb = numstatements-stnum;
166 // done
167 QCC_FreeTemp(e);
168 return e2;
173 ============
174 QCC_PR_Term
175 ============
177 static QCC_def_t *QCC_PR_Term (void) {
178 QCC_def_t *e, *e2;
179 qcc_etype t;
180 char ppmm = 0;
181 if (pr_token_type != TT_DELIM) {
182 e = QCC_PR_ParseValue(qcc_true);
183 // allow method calls only for correct conditions
184 if (e->type->type == ev_entity || (e->type->type == ev_field && e->type->aux_type->type == ev_entity)) {
185 if (pr_token[0] == ':') {
186 // this can be either ":" or "::", nothing else
187 e2 = e; // save self
188 if (pr_token[1] == ':') {
189 // call global function with new 'self'
190 QCC_PR_Lex(); // eat "::" token
191 e = QCC_PR_Term(); // get function
192 } else {
193 // call entity field with new 'self'
194 // stuff back "." to parse field load
195 strcpy(pr_token, "."); // overwrite ":"
196 e = QCC_PR_ExpressionEx(1/*dot priority*/, EXPR_DISALLOW_FCALL, e2); // load function
198 QCC_PR_Expect("("); // this SHOULD be function call
199 qcc_usefulstatement = qcc_true;
200 e = QCC_PR_ParseFunctionCall(e, e2);
203 return e;
205 // '++' or '--'
206 if (QCC_PR_EatDelim("++")) ppmm = '+'; else if (QCC_PR_EatDelim("--")) ppmm = '-';
207 if (ppmm) {
208 qcc_usefulstatement = qcc_true;
209 //e = QCC_PR_Term();
210 e = QCC_PR_ParseValue(qcc_true);
211 if (e->constant) QCC_PR_ParseError(0, "Assignment to constant %s", e->name);
212 if (e->temp) QCC_PR_ParseWarning(WARN_ASSIGNMENTTOCONSTANT, "Hey! That's a temp! %c%c operators cannot work on temps!", ppmm, ppmm);
213 switch (e->type->type) {
214 case ev_integer:
215 QCC_PR_Statement3(&pr_opcodes[ppmm == '+' ? OP_ADD_I : OP_SUB_I], e, QCC_MakeIntConst(1), e, qcc_false);
216 break;
217 case ev_float:
218 QCC_PR_Statement3(&pr_opcodes[ppmm == '+' ? OP_ADD_F : OP_SUB_F], e, QCC_MakeFloatConst(1), e, qcc_false);
219 break;
220 default:
221 QCC_PR_ParseError(ERR_BADPLUSPLUSOPERATOR, "%c%c operator on unsupported type", ppmm, ppmm);
222 break;
224 return e;
226 // unary logic not
227 if (QCC_PR_EatDelim("!")) {
228 int opcode;
229 e = QCC_PR_Expression(UNARY_PRIORITY, EXPR_DISALLOW_COMMA|EXPR_WARN_ABOVE_1);
230 switch ((t = e->type->type)) {
231 case ev_float: opcode = OP_NOT_F; break;
232 case ev_string: opcode = OP_NOT_S; break;
233 case ev_entity: opcode = OP_NOT_ENT; break;
234 case ev_vector: opcode = OP_NOT_V; break;
235 case ev_function: opcode = OP_NOT_FNC; break;
236 case ev_integer: opcode = OP_NOT_FNC; break; // functions are integer values too
237 case ev_pointer: opcode = OP_NOT_FNC; break; // ...and pointers
238 default: QCC_PR_ParseError(ERR_BADNOTTYPE, "type mismatch for !");
240 return QCC_PR_Statement(&pr_opcodes[opcode], e, 0, NULL);
242 // subexpression or typecast
243 if (QCC_PR_EatDelim("(")) {
244 qccbool oldcond;
245 QCC_type_t *newtype = QCC_PR_ParseType(qcc_false, qcc_true);
246 if (newtype) return QCC_PR_ExprCast(newtype);
247 if (QCC_PR_EatKeyword("bool")) return QCC_PR_ExprCast2Bool(); // wow, cast to boolean
248 // not a type casting, subexpression
249 oldcond = conditional;
250 conditional = (conditional ? 2 : 0);
251 e = QCC_PR_Expression(TOP_PRIORITY, 0);
252 QCC_PR_Expect(")");
253 conditional = oldcond;
254 return e;
256 // unary minus
257 if (QCC_PR_EatDelim("-")) {
258 e = QCC_PR_Expression(UNARY_PRIORITY, EXPR_DISALLOW_COMMA);
259 switch (e->type->type) {
260 case ev_float: e2 = QCC_PR_Statement(&pr_opcodes[OP_SUB_F], QCC_MakeFloatConst(0), e, NULL); break;
261 case ev_vector: e2 = QCC_PR_Statement(&pr_opcodes[OP_SUB_V], QCC_MakeVectorConst(0, 0, 0), e, NULL); break;
262 case ev_integer: e2 = QCC_PR_Statement(&pr_opcodes[OP_SUB_I], QCC_MakeIntConst(0), e, NULL); break;
263 default: QCC_PR_ParseError(ERR_BADNOTTYPE, "type mismatch for -"); break;
265 return e2;
267 // unary plus
268 if (QCC_PR_EatDelim("+")) {
269 e = QCC_PR_Expression(UNARY_PRIORITY, EXPR_DISALLOW_COMMA);
270 switch (e->type->type) {
271 case ev_float:
272 case ev_vector:
273 case ev_integer:
274 e2 = e;
275 break;
276 default: QCC_PR_ParseError(ERR_BADNOTTYPE, "type mismatch for +"); break;
278 return e2;
280 // unary address
281 if (QCC_PR_EatDelim("&")) {
282 int st = numstatements;
283 e = QCC_PR_Expression(UNARY_PRIORITY, EXPR_DISALLOW_COMMA);
284 t = e->type->type;
285 if (st != numstatements) {
286 // woo, something like ent.field?
287 if (is_edict_load(statements[numstatements-1].op)) {
288 statements[numstatements-1].op = OP_ADDRESS;
289 e->type = QCC_PR_PointerType(e->type);
290 return e;
292 if (is_array_load(statements[numstatements-1].op)) {
293 statements[numstatements-1].op = OP_GLOBALADDRESS;
294 e->type = QCC_PR_PointerType(e->type);
295 return e;
297 if (is_pointer_load(statements[numstatements-1].op)) {
298 statements[numstatements-1].op = OP_POINTER_ADD;
299 e->type = QCC_PR_PointerType(e->type);
300 return e;
302 // this is a restriction that could be lifted, I just want to make sure that I got all the bits first
303 QCC_PR_ParseError(ERR_BADNOTTYPE, "type mismatch for '&' Must be singular expression or field reference");
304 return e;
306 //QCC_PR_ParseWarning(0, "debug: &global");
307 e2 = QCC_PR_Statement(&pr_opcodes[OP_GLOBALADDRESS], e, 0, NULL);
308 e2->type = QCC_PR_PointerType(e->type);
309 return e2;
311 // unary ptrref
312 if (QCC_PR_EatDelim("*")) {
313 int opcode;
314 e = QCC_PR_Expression(UNARY_PRIORITY, EXPR_DISALLOW_COMMA);
315 t = e->type->type;
316 if (t != ev_pointer) QCC_PR_ParseError(ERR_BADNOTTYPE, "type mismatch for *");
317 switch (e->type->aux_type->type) {
318 case ev_float: opcode = OP_LOADP_F; break;
319 case ev_string: opcode = OP_LOADP_S; break;
320 case ev_vector: opcode = OP_LOADP_V; break;
321 case ev_entity: opcode = OP_LOADP_ENT; break;
322 case ev_field: opcode = OP_LOADP_FLD; break;
323 case ev_function: opcode = OP_LOADP_FLD; break;
324 case ev_integer: opcode = OP_LOADP_I; break;
325 case ev_pointer: opcode = OP_LOADP_I; break;
326 default: QCC_PR_ParseError(ERR_BADNOTTYPE, "type mismatch for * (unrecognised type)"); break;
328 e2 = QCC_PR_Statement(&pr_opcodes[opcode], e, 0, NULL);
329 e2->type = e->type->aux_type;
330 return e2;
332 // this will raise an error (i hope)
333 return QCC_PR_ParseValue(qcc_true);
338 ============
339 QCC_PR_ExprPMPost
341 process postfix '++' and '--'.
342 ============
344 static QCC_def_t *QCC_PR_ExprPMPost (QCC_def_t *e, int ppmm) {
345 QCC_def_t *e2;
346 int opcodef = (ppmm == '+' ? OP_ADD_F : OP_SUB_F);
347 int opcodei = (ppmm == '+' ? OP_ADD_I : OP_SUB_I);
348 // if the last statement was an ent.float (or something)
349 if (((unsigned int)(statements[numstatements-1].op-OP_LOAD_F) < 6 || statements[numstatements-1].op == OP_LOAD_I) &&
350 statements[numstatements-1].c == e->ofs) {
351 // we have our load
352 QCC_def_t *e3;
353 // the only inefficiency here is with an extra temp (we can't reuse the original)
354 // this is not a problem, as the optimise temps or locals marshalling can clean these up for us
355 qcc_usefulstatement = qcc_true;
356 // load
357 // add to temp / /subsctact from temp
358 // store temp to offset
359 // return original loaded (which is not at the same offset as the pointer we store to)
360 e2 = QCC_GetTemp(type_float);
361 e3 = QCC_GetTemp(type_pointer);
362 QCC_PR_SimpleStatement(OP_ADDRESS, statements[numstatements-1].a, statements[numstatements-1].b, e3->ofs, qcc_false);
363 if (e->type->type == ev_float) {
364 QCC_PR_Statement3(&pr_opcodes[opcodef], e, QCC_MakeFloatConst(1), e2, qcc_false);
365 QCC_PR_Statement3(&pr_opcodes[OP_STOREP_F], e2, e3, NULL, qcc_false);
366 } else if (e->type->type == ev_integer) {
367 QCC_PR_Statement3(&pr_opcodes[opcodei], e, QCC_MakeIntConst(1), e2, qcc_false);
368 QCC_PR_Statement3(&pr_opcodes[OP_STOREP_I], e2, e3, NULL, qcc_false);
369 } else {
370 QCC_PR_ParseError(ERR_PARSEERRORS, "%c%c suffix operator results in nonstandard behaviour. Use %c=1 or prefix form instead", ppmm, ppmm, ppmm);
372 QCC_FreeTemp(e2);
373 QCC_FreeTemp(e3);
374 } else if (e->type->type == ev_float) {
375 //copy to temp
376 //add to original
377 //return temp (which == original)
378 QCC_PR_ParseWarning(WARN_INEFFICIENTPLUSPLUS, "%c%c suffix operator results in inefficient behaviour. Use %c=1 or prefix form instead", ppmm, ppmm, ppmm);
379 qcc_usefulstatement = qcc_true;
380 e2 = QCC_GetTemp(type_float);
381 QCC_PR_Statement3(&pr_opcodes[OP_STORE_F], e, e2, NULL, qcc_false);
382 QCC_PR_Statement3(&pr_opcodes[opcodef], e, QCC_MakeFloatConst(1), e, qcc_false);
383 QCC_FreeTemp(e);
384 e = e2;
385 } else if (e->type->type == ev_integer) {
386 QCC_PR_ParseWarning(WARN_INEFFICIENTPLUSPLUS, "%c%c suffix operator results in inefficient behaviour. Use %c=1 or prefix form instead", ppmm, ppmm, ppmm);
387 qcc_usefulstatement = qcc_true;
388 e2 = QCC_GetTemp(type_integer);
389 QCC_PR_Statement3(&pr_opcodes[OP_STORE_I], e, e2, NULL, qcc_false);
390 QCC_PR_Statement3(&pr_opcodes[opcodei], e, QCC_MakeIntConst(1), e, qcc_false);
391 QCC_FreeTemp(e);
392 e = e2;
393 } else {
394 QCC_PR_ParseError(ERR_PARSEERRORS, "%c%c suffix operator results in nonstandard behaviour. Use %c=1 or prefix form instead", ppmm, ppmm, ppmm);
396 return e;
400 static const QCC_opcode_t *find_type_conversion (QCC_def_t *e, QCC_def_t *e2, const QCC_opcode_t *oldop,
401 qcc_etype type_a, qcc_etype type_c, int *numcvt)
403 const QCC_opcode_t *bestop = NULL;
404 int numconversions = 32767;
405 for (const QCC_opcode_t *op = pr_opcodes; op && op->name; ++op) {
406 int c;
408 if (op->priority != oldop->priority) continue; // not on this priority level, do not want
409 if (strcmp(op->name, oldop->name) != 0) continue; // ugly name, do not want
410 //if (!(type_c != ev_void && type_c != (*op->type_c)->type)) -- go on
411 if (type_c != ev_void && type_c != (*op->type_c)->type) continue; //??? but do not want anyway
413 if (op->associative != ASSOC_LEFT) {
414 // assignment
415 if (op->type_a == &type_pointer) {
416 // ent var
417 if (e->type->type != ev_pointer) {
418 c = -200; // don't cast to a pointer
419 } else if ((*op->type_c)->type == ev_void && op->type_b == &type_pointer && e2->type->type == ev_pointer) {
420 c = 0; // generic pointer... FIXME: is this safe? make sure both sides are equivalent
421 } else if (e->type->aux_type->type != (*op->type_b)->type) {
422 // if e isn't a pointer to a type_b
423 c = -200; // don't let the conversion work
424 } else {
425 c = QCC_canConv(e2, (*op->type_c)->type);
427 } else {
428 c = QCC_canConv(e2, (*op->type_b)->type);
429 // in this case, a is the final assigned value
430 if (type_a != (*op->type_a)->type) c = -300; // don't use this op, as we must not change var b's type
432 } else {
433 // not an assignment
434 if (op->type_a == &type_pointer) {
435 // ent var
436 // if e isn't a pointer to a type_b
437 if (e2->type->type != ev_pointer || e2->type->aux_type->type != (*op->type_b)->type) {
438 c = -200; // don't let the conversion work
439 } else {
440 c = 0;
442 } else {
443 c = QCC_canConv(e, (*op->type_a)->type);
444 c += QCC_canConv(e2, (*op->type_b)->type);
448 if (c >= 0 && c < numconversions) {
449 bestop = op;
450 numconversions = c;
451 if (c == 0) break; // can't get less conversions than 0...
455 if (numcvt != NULL) *numcvt = numconversions;
456 return bestop;
461 ==============
462 QCC_PR_Expression
464 parse expression, generate code.
466 exprflags:
467 EXPR_WARN_ABOVE_1
468 emit warning if priority greater than 1
469 EXPR_DISALLOW_COMMA
470 don't parse commas as expression part (we need this for function calls, for example)
472 seems that 'simplestore' is qcc_true for simple 'STORE_*', but qcc_false for complex operations like '+='
473 'conditional':
474 bit 0 set: this is conditional expression, warn on assigning
475 bit 1 set: this was conditional initially, but now we are in '(...)'
476 ==============
478 static QCC_def_t *QCC_PR_ExpressionEx (int priority, int exprflags, QCC_def_t *gotarg0) {
479 const QCC_opcode_t *op, *bestop;
480 int numconversions, bprevst = -1;
481 QCC_def_t *e, *e2, *ctemp = NULL;
482 qcc_etype type_a, type_c;
483 float negfinal = 0.0f;
484 int islogand = 0;
486 if (priority > TOP_PRIORITY+4) priority = TOP_PRIORITY+4; // just in case
487 // 0: term
488 if (priority == 0) return QCC_PR_Term();
489 // parse expression on the lower priority level
490 e = (gotarg0 == NULL ? QCC_PR_Expression(priority-1, exprflags) : gotarg0);
491 // ternary operator?
492 if (priority == TERN_PRIORITY && QCC_PR_EatDelim("?")) {
493 QCC_dstatement_t *fromj, *elsej;
494 QCC_FreeTemp(QCC_PR_Statement(&pr_opcodes[OP_IFNOT_I], e, NULL, &fromj));
495 e = QCC_PR_Expression(TOP_PRIORITY, 0);
496 e2 = QCC_GetTemp(e->type);
497 QCC_FreeTemp(QCC_PR_Statement(&pr_opcodes[e2->type->size >= 3 ? OP_STORE_V : OP_STORE_F], e, e2, NULL));
498 // e2 can be stomped upon until its reused anyway
499 QCC_UnFreeTemp(e2);
500 QCC_PR_Expect(":");
501 QCC_PR_Statement(&pr_opcodes[OP_GOTO], NULL, NULL, &elsej);
502 fromj->b = &statements[numstatements]-fromj;
503 e = QCC_PR_Expression(TOP_PRIORITY, 0);
504 if (qcc_typecmp(e->type, e2->type) != 0) QCC_PR_ParseError(0, "Ternary operator with mismatching types");
505 QCC_FreeTemp(QCC_PR_Statement(&pr_opcodes[e2->type->size >= 3 ? OP_STORE_V : OP_STORE_F], e, e2, NULL));
506 QCC_UnFreeTemp(e2);
507 elsej->a = &statements[numstatements]-elsej;
508 return e2;
510 // parse on the current priority level
511 for (;;) {
512 //if (gotarg0) fprintf(stderr, "gotarg0; token:[%s]; nofcall:%d\n", pr_token, exprflags&EXPR_DISALLOW_FCALL);
513 // function call?
514 if (priority == FUNC_PRIORITY && !(exprflags&EXPR_DISALLOW_FCALL)) {
515 if (QCC_PR_EatDelim("(")) {
516 qcc_usefulstatement = qcc_true;
517 e = QCC_PR_ParseFunctionCall(e, NULL);
518 continue;
519 //k8:??? continue or return?
522 //HACK: negative numbers eats '-', fix this
523 if (pr_token_type == TT_IMMED) {
524 if (pr_immediate_type->type == ev_float) {
525 if (pr_immediate._float < 0) {
526 // hehehe... was a minus all along...
527 QCC_PR_IncludeChunk(pr_token, qcc_true, NULL);
528 strcpy(pr_token, "+"); // two negatives would make a positive
529 pr_token_type = TT_DELIM;
534 if (pr_token_type != TT_DELIM) QCC_PR_ParseWarning(WARN_UNEXPECTEDPUNCT, "Expected punctuation");
535 // find opcode if any
536 op = NULL;
537 for (const QCC_opcode_t *xop = pr_opcodes; xop->name != NULL; ++xop) {
538 if (xop->priority != priority) continue; // not on this priority level
539 if (!QCC_PR_EatDelim(xop->name)) continue; // not the given operator
540 op = xop; // got it
541 if (op->associative != ASSOC_LEFT) {
542 // this is assign operator (only assigns have ASSOC_RIGHT)
543 // if last statement is an indirect, change it to an address of
544 e2 = NULL; // use as flag
545 if (!simplestore) {
546 // convert edict loads to 'taking pointer' instruction
547 if (is_edict_load(statements[numstatements-1].op) && statements[numstatements-1].c == e->ofs) {
548 qcc_usefulstatement = qcc_true; // hells why?
549 statements[numstatements-1].op = OP_ADDRESS;
550 type_pointer->aux_type->type = e->type->type;
551 e->type = type_pointer;
552 } else
553 // if last statement retrieved a value, switch it to retrieve a usable pointer
554 if (is_array_load(statements[numstatements-1].op)) {
555 statements[numstatements-1].op = OP_GLOBALADDRESS;
556 type_pointer->aux_type->type = e->type->type;
557 e->type = type_pointer;
558 } else
559 // convert 'load pointer'
560 if (is_pointer_load(statements[numstatements-1].op) && statements[numstatements-1].c == e->ofs) {
561 if (!statements[numstatements-1].b) {
562 // if the loadp has no offset, remove the instruction and convert the dest of this
563 // instruction directly to the pointer's load address
564 // this kills the add 0
565 e->ofs = statements[numstatements-1].a;
566 --numstatements;
567 if (e->type->type != ev_pointer) {
568 type_pointer->aux_type->type = e->type->type;
569 e->type = type_pointer;
571 } else {
572 // pointer arithmetics
573 statements[numstatements-1].op = OP_POINTER_ADD;
574 if (e->type->type != ev_pointer) {
575 type_pointer->aux_type->type = e->type->type;
576 e->type = type_pointer;
579 } else
580 // string indexing
581 if (statements[numstatements-1].op == OP_LOADP_C && e->ofs == statements[numstatements-1].c) {
582 //fprintf(stderr, "OPC: %s [%s]\n", op->name, op->opname);
583 // now we want to make sure that string = float can't work without it being a dereferenced pointer
584 // (we don't want to allow storep_c without dereferece)
585 if (op->name[0] != '=') {
586 // invalid string indexing operation (alas)
587 QCC_PR_ParseErrorPrintDef(0, e, "TODO: '%s' and string indexing", op->name);
590 e->type = type_string;
591 statements[numstatements-1].op = OP_ADD_SF;
592 e2 = QCC_PR_Expression(priority, exprflags);
594 if (e2->type->type == ev_float || e2->type->type == ev_integer) {
595 //HACK!
596 //FIXME: OP_STOREP_C can't index
597 op = &pr_opcodes[OP_STOREP_C];
598 } else {
599 QCC_PR_ParseErrorPrintDef(0, e, "invalid string assign operation");
603 if (e2 == NULL) e2 = QCC_PR_Expression(priority, exprflags);
604 } else {
605 // normal operator (not assign)
606 if (is_conditional_priority(op->priority)) {
607 // boolean short circuit
608 int opc, stn;
609 // select opcode
610 if (op->name[0] == '&') {
611 islogand = 1;
612 if (!qcc_typecmp(e->type, type_string)) opc = OP_IFNOT_S;
613 else if (!qcc_typecmp(e->type, type_float)) opc = OP_IFNOT_F;
614 else opc = OP_IFNOT_I;
615 } else {
616 islogand = 0;
617 if (!qcc_typecmp(e->type, type_string)) opc = OP_IF_S;
618 else if (!qcc_typecmp(e->type, type_float)) opc = OP_IF_F;
619 else opc = OP_IF_I;
621 if (ctemp == NULL) {
622 // boolean result is always float
623 ctemp = QCC_GetTemp(/*e->type*/type_float);
624 // this is the first logic op, so convert first operand to floatbool
625 // store 'final result'
626 //fprintf(stderr, "new ctemp at %u\n", numstatements);
627 negfinal = (islogand ? 1.0f : 0.0f);
628 QCC_PR_Statement3(&pr_opcodes[OP_STORE_F], QCC_MakeFloatConst(1.0f-negfinal), ctemp, NULL, qcc_false);
629 } else {
630 //fprintf(stderr, " jump at %u\n", numstatements);
632 // now jump out of here if we know the result
633 stn = numstatements;
634 // statement 3 because we don't want to optimise this into if from not ifnot
635 QCC_PR_Statement3(&pr_opcodes[opc], e, NULL, NULL, qcc_false);
636 // patch chain
637 statements[stn].sb = bprevst;
638 bprevst = stn;
640 e2 = QCC_PR_Expression(priority-1, exprflags);
642 // type check
643 type_a = e->type->type;
644 /*type_b = e2->type->type;*/
645 //if (type_a == ev_pointer && type_b == ev_pointer) QCC_PR_ParseWarning(0, "Debug: pointer op pointer");
646 if (op->name[0] == '.') {
647 // field access gets type from field
648 type_c = (e2->type->aux_type ? e2->type->aux_type->type : -1); // -1: not a field
649 } else {
650 type_c = ev_void;
652 // find 'best type conversion'
653 bestop = find_type_conversion(e, e2, op, type_a, type_c, &numconversions);
654 if (bestop == NULL) {
655 // no conversion found
656 if (!is_conditional_priority(op->priority)) {
657 if (op-pr_opcodes == OP_STOREP_C && e->type->type == ev_string) {
658 e2 = QCC_SupplyConversion(e2, ev_float, qcc_true);
659 if (e2->type->type != ev_float) {
660 //QCC_PR_ParseWarning(WARN_LAXCAST, "type mismatch for %s (%s and %s)", op->name, e->type->name, e2->type->name);
661 QCC_PR_ParseError(ERR_TYPEMISMATCH, "type mismatch for %s (%s and %s)", op->name, e->type->name, e2->type->name);
663 } else {
664 QCC_PR_ParseError(ERR_TYPEMISMATCH, "type mismatch for %s (%s and %s)", op->name, e->type->name, e2->type->name);
667 } else {
668 if (numconversions > 3) QCC_PR_ParseWarning(WARN_IMPLICITCONVERSION, "Implicit conversion");
669 op = bestop;
672 //if (type_a == ev_pointer && type_b != e->type->aux_type->type) QCC_PR_ParseError ("type mismatch for %s", op->name);
674 if (op->associative != ASSOC_LEFT) {
675 // assignment
676 qcc_usefulstatement = qcc_true;
677 if (priority == ASSIGN_PRIORITY && (e->constant || e->ofs < OFS_PARM0)) {
678 if (e->type->type == ev_function) {
679 QCC_PR_ParseWarning(WARN_ASSIGNMENTTOCONSTANTFUNC, "Assignment to function %s", e->name);
680 QCC_PR_ParsePrintDef(WARN_ASSIGNMENTTOCONSTANTFUNC, e);
681 } else {
682 QCC_PR_ParseErrorPrintDef(0, e, "Assignment to constant %s", e->name);
684 qcc_set_badfile_name(strings+s_file, pr_source_line);
686 if (conditional&1) QCC_PR_ParseWarning(WARN_ASSIGNMENTINCONDITIONAL, "Assignment in conditional");
687 e = QCC_PR_Statement(op, e2, e, NULL);
688 } else {
689 if (ctemp == NULL) {
690 // not boolop
691 e = QCC_PR_Statement(op, e, e2, NULL);
692 } else {
693 // boolop
694 QCC_FreeTemp(e);
695 e = e2; // go on
698 // field access gets type from field
699 if (type_c != ev_void/* && type_c != ev_string*/) e->type = e2->type->aux_type;
700 if (priority > 1 && (exprflags&EXPR_WARN_ABOVE_1)) QCC_PR_ParseWarning(0, "You may wish to add brackets after that '!' operator");
701 break;
703 // operator was (or wasn't) found, code was emited
704 if (!op) {
705 // th
706 if (e == NULL) QCC_PR_ParseError(ERR_INTERNAL, "e == NULL");
707 if (QCC_PR_EatDelim("++")) e = QCC_PR_ExprPMPost(e, '+');
708 else if (QCC_PR_EatDelim("--")) e = QCC_PR_ExprPMPost(e, '-');
709 break; // next token isn't at this priority level
711 // continue on this priority level
713 // fix patch chain, if any
714 if (ctemp != NULL) {
715 //fprintf(stderr, "negfinal at %u\n", numstatements);
716 int opc, stn;
717 // select opcode
718 if (islogand) {
719 if (!qcc_typecmp(e->type, type_string)) opc = OP_IFNOT_S;
720 else if (!qcc_typecmp(e->type, type_float)) opc = OP_IFNOT_F;
721 else opc = OP_IFNOT_I;
722 } else {
723 if (!qcc_typecmp(e->type, type_string)) opc = OP_IF_S;
724 else if (!qcc_typecmp(e->type, type_float)) opc = OP_IF_F;
725 else opc = OP_IF_I;
727 // now jump out of here if we know the result
728 stn = numstatements;
729 // statement 3 because we don't want to optimise this into if from not ifnot
730 QCC_PR_Statement3(&pr_opcodes[opc], e, NULL, NULL, qcc_false);
731 // patch chain
732 statements[stn].sb = bprevst;
733 bprevst = stn;
734 // store 'negative final result'
735 QCC_PR_Statement3(&pr_opcodes[OP_STORE_F], QCC_MakeFloatConst(negfinal), ctemp, NULL, qcc_false);
736 // drop out 'e' and change it to ctemp
737 QCC_FreeTemp(e);
738 e = ctemp;
739 //fprintf(stderr, "bprevst=%d\n", bprevst);
740 // now fix patch chain
741 while (bprevst != -1) {
742 int pnum = bprevst;
743 //fprintf(stderr, " fixing %d (jump to %u)\n", pnum, numstatements);
744 bprevst = statements[bprevst].sb;
745 statements[pnum].sb = numstatements-pnum;
749 if (e == NULL) QCC_PR_ParseError(ERR_INTERNAL, "e == NULL");
750 if (!(exprflags&EXPR_DISALLOW_COMMA) && priority == TOP_PRIORITY && QCC_PR_EatDelim(",")) {
751 // comma is allowed, and this is expression without side-effects? warn!
752 if (!qcc_usefulstatement) QCC_PR_ParseWarning(WARN_POINTLESSSTATEMENT, "Effectless statement");
753 QCC_FreeTemp(e);
754 qcc_usefulstatement = qcc_false;
755 e = QCC_PR_Expression(TOP_PRIORITY, exprflags);
757 return e;
761 static QCC_def_t *QCC_PR_Expression (int priority, int exprflags) { return QCC_PR_ExpressionEx(priority, exprflags, NULL); }