]> de.git.xonotic.org Git - xonotic/gmqcc.git/blob - parser.cpp
b2957d4ee5294b2cd6e4d93ac986ae76f8db4cd3
[xonotic/gmqcc.git] / parser.cpp
1 #include <string.h>
2 #include <math.h>
3
4 #include "intrin.h"
5 #include "fold.h"
6 #include "ast.h"
7 #include "parser.h"
8
9 #define PARSER_HT_LOCALS  2
10 #define PARSER_HT_SIZE    512
11 #define TYPEDEF_HT_SIZE   512
12
13 static void parser_enterblock(parser_t &parser);
14 static bool parser_leaveblock(parser_t &parser);
15 static void parser_addlocal(parser_t &parser, const char *name, ast_expression *e);
16 static void parser_addlocal(parser_t &parser, const std::string &name, ast_expression *e);
17 static void parser_addglobal(parser_t &parser, const char *name, ast_expression *e);
18 static void parser_addglobal(parser_t &parser, const std::string &name, ast_expression *e);
19 static bool parse_typedef(parser_t &parser);
20 static bool parse_variable(parser_t &parser, ast_block *localblock, bool nofields, int qualifier, ast_value *cached_typedef, bool noref, bool is_static, uint32_t qflags, char *vstring);
21 static ast_block* parse_block(parser_t &parser);
22 static bool parse_block_into(parser_t &parser, ast_block *block);
23 static bool parse_statement_or_block(parser_t &parser, ast_expression **out);
24 static bool parse_statement(parser_t &parser, ast_block *block, ast_expression **out, bool allow_cases);
25 static ast_expression* parse_expression_leave(parser_t &parser, bool stopatcomma, bool truthvalue, bool with_labels);
26 static ast_expression* parse_expression(parser_t &parser, bool stopatcomma, bool with_labels);
27 static ast_value* parser_create_array_setter_proto(parser_t &parser, ast_value *array, const char *funcname);
28 static ast_value* parser_create_array_getter_proto(parser_t &parser, ast_value *array, const ast_expression *elemtype, const char *funcname);
29 static ast_value *parse_typename(parser_t &parser, ast_value **storebase, ast_value *cached_typedef, bool *is_vararg);
30
31 static void parseerror_(parser_t &parser, const char *fmt, ...)
32 {
33     va_list ap;
34     va_start(ap, fmt);
35     vcompile_error(parser.lex->tok.ctx, fmt, ap);
36     va_end(ap);
37 }
38
39 template<typename... Ts>
40 static inline void parseerror(parser_t &parser, const char *fmt, const Ts&... ts) {
41     return parseerror_(parser, fmt, formatNormalize(ts)...);
42 }
43
44 // returns true if it counts as an error
45 static bool GMQCC_WARN parsewarning_(parser_t &parser, int warntype, const char *fmt, ...)
46 {
47     bool    r;
48     va_list ap;
49     va_start(ap, fmt);
50     r = vcompile_warning(parser.lex->tok.ctx, warntype, fmt, ap);
51     va_end(ap);
52     return r;
53 }
54
55 template<typename... Ts>
56 static inline bool GMQCC_WARN parsewarning(parser_t &parser, int warntype, const char *fmt, const Ts&... ts) {
57     return parsewarning_(parser, warntype, fmt, formatNormalize(ts)...);
58 }
59
60 /**********************************************************************
61  * parsing
62  */
63
64 static bool parser_next(parser_t &parser)
65 {
66     /* lex_do kills the previous token */
67     parser.tok = lex_do(parser.lex);
68     if (parser.tok == Token::END)
69         return true;
70     if (parser.tok >= Token::ERROR) {
71         parseerror(parser, "lex error");
72         return false;
73     }
74     return true;
75 }
76
77 #define parser_tokval(p) ((p).lex->tok.value)
78 #define parser_token(p)  (&((p).lex->tok))
79
80 static ast_expression* parser_find_field(parser_t &parser, const char *name) {
81     return (ast_expression*)util_htget(parser.htfields, name);
82 }
83 static ast_expression* parser_find_field(parser_t &parser, const std::string &name) {
84     return parser_find_field(parser, name.c_str());
85 }
86
87 static ast_expression* parser_find_label(parser_t &parser, const char *name)
88 {
89     for (auto &it : parser.labels)
90         if (it->m_name == name)
91             return it;
92     return nullptr;
93 }
94 static inline ast_expression* parser_find_label(parser_t &parser, const std::string &name) {
95     return parser_find_label(parser, name.c_str());
96 }
97
98 ast_expression* parser_find_global(parser_t &parser, const char *name)
99 {
100     ast_expression *var = (ast_expression*)util_htget(parser.aliases, parser_tokval(parser));
101     if (var)
102         return var;
103     return (ast_expression*)util_htget(parser.htglobals, name);
104 }
105
106 ast_expression* parser_find_global(parser_t &parser, const std::string &name) {
107     return parser_find_global(parser, name.c_str());
108 }
109
110 static ast_expression* parser_find_param(parser_t &parser, const char *name)
111 {
112     ast_value *fun;
113     if (!parser.function)
114         return nullptr;
115     fun = parser.function->m_function_type;
116     for (auto &it : fun->m_type_params) {
117         if (it->m_name == name)
118             return it.get();
119     }
120     return nullptr;
121 }
122
123 static ast_expression* parser_find_local(parser_t &parser, const char *name, size_t upto, bool *isparam)
124 {
125     size_t          i, hash;
126     ast_expression *e;
127
128     hash = util_hthash(parser.htglobals, name);
129
130     *isparam = false;
131     for (i = parser.variables.size(); i > upto;) {
132         --i;
133         if ( (e = (ast_expression*)util_htgeth(parser.variables[i], name, hash)) )
134             return e;
135     }
136     *isparam = true;
137     return parser_find_param(parser, name);
138 }
139
140 static ast_expression* parser_find_local(parser_t &parser, const std::string &name, size_t upto, bool *isparam) {
141     return parser_find_local(parser, name.c_str(), upto, isparam);
142 }
143
144 static ast_expression* parser_find_var(parser_t &parser, const char *name)
145 {
146     bool dummy;
147     ast_expression *v;
148     v         = parser_find_local(parser, name, 0, &dummy);
149     if (!v) v = parser_find_global(parser, name);
150     return v;
151 }
152
153 static inline ast_expression* parser_find_var(parser_t &parser, const std::string &name) {
154     return parser_find_var(parser, name.c_str());
155 }
156
157 static ast_value* parser_find_typedef(parser_t &parser, const char *name, size_t upto)
158 {
159     size_t     i, hash;
160     ast_value *e;
161     hash = util_hthash(parser.typedefs[0], name);
162
163     for (i = parser.typedefs.size(); i > upto;) {
164         --i;
165         if ( (e = (ast_value*)util_htgeth(parser.typedefs[i], name, hash)) )
166             return e;
167     }
168     return nullptr;
169 }
170
171 static ast_value* parser_find_typedef(parser_t &parser, const std::string &name, size_t upto) {
172     return parser_find_typedef(parser, name.c_str(), upto);
173 }
174
175 struct sy_elem {
176     size_t etype; /* 0 = expression, others are operators */
177     bool isparen;
178     size_t off;
179     ast_expression *out;
180     ast_block *block; /* for commas and function calls */
181     lex_ctx_t ctx;
182 };
183
184 enum {
185     PAREN_EXPR,
186     PAREN_FUNC,
187     PAREN_INDEX,
188     PAREN_TERNARY1,
189     PAREN_TERNARY2
190 };
191
192 struct shunt {
193     std::vector<sy_elem> out;
194     std::vector<sy_elem> ops;
195     std::vector<size_t> argc;
196     std::vector<unsigned int> paren;
197 };
198
199 static sy_elem syexp(lex_ctx_t ctx, ast_expression *v) {
200     sy_elem e;
201     e.etype = 0;
202     e.off   = 0;
203     e.out   = v;
204     e.block = nullptr;
205     e.ctx   = ctx;
206     e.isparen = false;
207     return e;
208 }
209
210 static sy_elem syblock(lex_ctx_t ctx, ast_block *v) {
211     sy_elem e;
212     e.etype = 0;
213     e.off   = 0;
214     e.out   = v;
215     e.block = v;
216     e.ctx   = ctx;
217     e.isparen = false;
218     return e;
219 }
220
221 static sy_elem syop(lex_ctx_t ctx, const oper_info *op) {
222     sy_elem e;
223     e.etype = 1 + (op - operators);
224     e.off   = 0;
225     e.out   = nullptr;
226     e.block = nullptr;
227     e.ctx   = ctx;
228     e.isparen = false;
229     return e;
230 }
231
232 static sy_elem syparen(lex_ctx_t ctx, size_t off) {
233     sy_elem e;
234     e.etype = 0;
235     e.off   = off;
236     e.out   = nullptr;
237     e.block = nullptr;
238     e.ctx   = ctx;
239     e.isparen = true;
240     return e;
241 }
242
243 /* With regular precedence rules, ent.foo[n] is the same as (ent.foo)[n],
244  * so we need to rotate it to become ent.(foo[n]).
245  */
246 static bool rotate_entfield_array_index_nodes(ast_expression **out)
247 {
248     ast_array_index *index, *oldindex;
249     ast_entfield    *entfield;
250
251     ast_value       *field;
252     ast_expression  *sub;
253     ast_expression  *entity;
254
255     lex_ctx_t ctx = (*out)->m_context;
256
257     if (!ast_istype(*out, ast_array_index))
258         return false;
259     index = (ast_array_index*)*out;
260
261     if (!ast_istype(index->m_array, ast_entfield))
262         return false;
263     entfield = (ast_entfield*)index->m_array;
264
265     if (!ast_istype(entfield->m_field, ast_value))
266         return false;
267     field = (ast_value*)entfield->m_field;
268
269     sub    = index->m_index;
270     entity = entfield->m_entity;
271
272     oldindex = index;
273
274     index = ast_array_index::make(ctx, field, sub);
275     entfield = new ast_entfield(ctx, entity, index);
276     *out = entfield;
277
278     oldindex->m_array = nullptr;
279     oldindex->m_index = nullptr;
280     delete oldindex;
281
282     return true;
283 }
284
285 static bool check_write_to(lex_ctx_t ctx, ast_expression *expr)
286 {
287     if (ast_istype(expr, ast_value)) {
288         ast_value *val = (ast_value*)expr;
289         if (val->m_cvq == CV_CONST) {
290             if (val->m_name[0] == '#') {
291                 compile_error(ctx, "invalid assignment to a literal constant");
292                 return false;
293             }
294             /*
295              * To work around quakeworld we must elide the error and make it
296              * a warning instead.
297              */
298             if (OPTS_OPTION_U32(OPTION_STANDARD) != COMPILER_QCC)
299                 compile_error(ctx, "assignment to constant `%s`", val->m_name);
300             else
301                 (void)!compile_warning(ctx, WARN_CONST_OVERWRITE, "assignment to constant `%s`", val->m_name);
302             return false;
303         }
304     }
305     return true;
306 }
307
308 static bool parser_sy_apply_operator(parser_t &parser, shunt *sy)
309 {
310     const oper_info *op;
311     lex_ctx_t ctx;
312     ast_expression *out = nullptr;
313     ast_expression *exprs[3];
314     ast_block      *blocks[3];
315     ast_binstore   *asbinstore;
316     size_t i, assignop, addop, subop;
317     qcint_t  generated_op = 0;
318
319     char ty1[1024];
320     char ty2[1024];
321
322     if (sy->ops.empty()) {
323         parseerror(parser, "internal error: missing operator");
324         return false;
325     }
326
327     if (sy->ops.back().isparen) {
328         parseerror(parser, "unmatched parenthesis");
329         return false;
330     }
331
332     op = &operators[sy->ops.back().etype - 1];
333     ctx = sy->ops.back().ctx;
334
335     if (sy->out.size() < op->operands) {
336         if (op->flags & OP_PREFIX)
337             compile_error(ctx, "expected expression after unary operator `%s`", op->op, (int)op->id);
338         else /* this should have errored previously already */
339             compile_error(ctx, "expected expression after operator `%s`", op->op, (int)op->id);
340         return false;
341     }
342
343     sy->ops.pop_back();
344
345     /* op(:?) has no input and no output */
346     if (!op->operands)
347         return true;
348
349     sy->out.erase(sy->out.end() - op->operands, sy->out.end());
350     for (i = 0; i < op->operands; ++i) {
351         exprs[i]  = sy->out[sy->out.size()+i].out;
352         blocks[i] = sy->out[sy->out.size()+i].block;
353
354         if (exprs[i]->m_vtype == TYPE_NOEXPR &&
355             !(i != 0 && op->id == opid2('?',':')) &&
356             !(i == 1 && op->id == opid1('.')))
357         {
358             if (ast_istype(exprs[i], ast_label))
359                 compile_error(exprs[i]->m_context, "expected expression, got an unknown identifier");
360             else
361                 compile_error(exprs[i]->m_context, "not an expression");
362             (void)!compile_warning(exprs[i]->m_context, WARN_DEBUG, "expression %u\n", (unsigned int)i);
363         }
364     }
365
366     if (blocks[0] && blocks[0]->m_exprs.empty() && op->id != opid1(',')) {
367         compile_error(ctx, "internal error: operator cannot be applied on empty blocks");
368         return false;
369     }
370
371 #define NotSameType(T) \
372              (exprs[0]->m_vtype != exprs[1]->m_vtype || \
373               exprs[0]->m_vtype != T)
374
375     switch (op->id)
376     {
377         default:
378             compile_error(ctx, "internal error: unhandled operator: %s (%i)", op->op, (int)op->id);
379             return false;
380
381         case opid1('.'):
382             if (exprs[0]->m_vtype == TYPE_VECTOR &&
383                 exprs[1]->m_vtype == TYPE_NOEXPR)
384             {
385                 if      (exprs[1] == parser.const_vec[0])
386                     out = ast_member::make(ctx, exprs[0], 0, "");
387                 else if (exprs[1] == parser.const_vec[1])
388                     out = ast_member::make(ctx, exprs[0], 1, "");
389                 else if (exprs[1] == parser.const_vec[2])
390                     out = ast_member::make(ctx, exprs[0], 2, "");
391                 else {
392                     compile_error(ctx, "access to invalid vector component");
393                     return false;
394                 }
395             }
396             else if (exprs[0]->m_vtype == TYPE_ENTITY) {
397                 if (exprs[1]->m_vtype != TYPE_FIELD) {
398                     compile_error(exprs[1]->m_context, "type error: right hand of member-operand should be an entity-field");
399                     return false;
400                 }
401                 out = new ast_entfield(ctx, exprs[0], exprs[1]);
402             }
403             else if (exprs[0]->m_vtype == TYPE_VECTOR) {
404                 compile_error(exprs[1]->m_context, "vectors cannot be accessed this way");
405                 return false;
406             }
407             else {
408                 compile_error(exprs[1]->m_context, "type error: member-of operator on something that is not an entity or vector");
409                 return false;
410             }
411             break;
412
413         case opid1('['):
414             if (exprs[0]->m_vtype != TYPE_ARRAY &&
415                 !(exprs[0]->m_vtype == TYPE_FIELD &&
416                   exprs[0]->m_next->m_vtype == TYPE_ARRAY))
417             {
418                 ast_type_to_string(exprs[0], ty1, sizeof(ty1));
419                 compile_error(exprs[0]->m_context, "cannot index value of type %s", ty1);
420                 return false;
421             }
422             if (exprs[1]->m_vtype != TYPE_FLOAT) {
423                 ast_type_to_string(exprs[0], ty1, sizeof(ty1));
424                 compile_error(exprs[1]->m_context, "index must be of type float, not %s", ty1);
425                 return false;
426             }
427             out = ast_array_index::make(ctx, exprs[0], exprs[1]);
428             rotate_entfield_array_index_nodes(&out);
429             break;
430
431         case opid1(','):
432             if (sy->paren.size() && sy->paren.back() == PAREN_FUNC) {
433                 sy->out.push_back(syexp(ctx, exprs[0]));
434                 sy->out.push_back(syexp(ctx, exprs[1]));
435                 sy->argc.back()++;
436                 return true;
437             }
438             if (blocks[0]) {
439                 if (!blocks[0]->addExpr(exprs[1]))
440                     return false;
441             } else {
442                 blocks[0] = new ast_block(ctx);
443                 if (!blocks[0]->addExpr(exprs[0]) ||
444                     !blocks[0]->addExpr(exprs[1]))
445                 {
446                     return false;
447                 }
448             }
449             blocks[0]->setType(*exprs[1]);
450
451             sy->out.push_back(syblock(ctx, blocks[0]));
452             return true;
453
454         case opid2('+','P'):
455             out = exprs[0];
456             break;
457         case opid2('-','P'):
458             if ((out = parser.m_fold.op(op, exprs)))
459                 break;
460
461             if (exprs[0]->m_vtype != TYPE_FLOAT &&
462                 exprs[0]->m_vtype != TYPE_VECTOR) {
463                     compile_error(ctx, "invalid types used in unary expression: cannot negate type %s",
464                                   type_name[exprs[0]->m_vtype]);
465                 return false;
466             }
467             if (exprs[0]->m_vtype == TYPE_FLOAT)
468                 out = ast_unary::make(ctx, VINSTR_NEG_F, exprs[0]);
469             else
470                 out = ast_unary::make(ctx, VINSTR_NEG_V, exprs[0]);
471             break;
472
473         case opid2('!','P'):
474             if (!(out = parser.m_fold.op(op, exprs))) {
475                 switch (exprs[0]->m_vtype) {
476                     case TYPE_FLOAT:
477                         out = ast_unary::make(ctx, INSTR_NOT_F, exprs[0]);
478                         break;
479                     case TYPE_VECTOR:
480                         out = ast_unary::make(ctx, INSTR_NOT_V, exprs[0]);
481                         break;
482                     case TYPE_STRING:
483                         if (OPTS_FLAG(TRUE_EMPTY_STRINGS))
484                             out = ast_unary::make(ctx, INSTR_NOT_F, exprs[0]);
485                         else
486                             out = ast_unary::make(ctx, INSTR_NOT_S, exprs[0]);
487                         break;
488                     /* we don't constant-fold NOT for these types */
489                     case TYPE_ENTITY:
490                         out = ast_unary::make(ctx, INSTR_NOT_ENT, exprs[0]);
491                         break;
492                     case TYPE_FUNCTION:
493                         out = ast_unary::make(ctx, INSTR_NOT_FNC, exprs[0]);
494                         break;
495                     default:
496                     compile_error(ctx, "invalid types used in expression: cannot logically negate type %s",
497                                   type_name[exprs[0]->m_vtype]);
498                     return false;
499                 }
500             }
501             break;
502
503         case opid1('+'):
504             if (exprs[0]->m_vtype != exprs[1]->m_vtype ||
505                (exprs[0]->m_vtype != TYPE_VECTOR && exprs[0]->m_vtype != TYPE_FLOAT) )
506             {
507                 compile_error(ctx, "invalid types used in expression: cannot add type %s and %s",
508                               type_name[exprs[0]->m_vtype],
509                               type_name[exprs[1]->m_vtype]);
510                 return false;
511             }
512             if (!(out = parser.m_fold.op(op, exprs))) {
513                 switch (exprs[0]->m_vtype) {
514                     case TYPE_FLOAT:
515                         out = fold::binary(ctx, INSTR_ADD_F, exprs[0], exprs[1]);
516                         break;
517                     case TYPE_VECTOR:
518                         out = fold::binary(ctx, INSTR_ADD_V, exprs[0], exprs[1]);
519                         break;
520                     default:
521                         compile_error(ctx, "invalid types used in expression: cannot add type %s and %s",
522                                       type_name[exprs[0]->m_vtype],
523                                       type_name[exprs[1]->m_vtype]);
524                         return false;
525                 }
526             }
527             break;
528         case opid1('-'):
529             if  (exprs[0]->m_vtype != exprs[1]->m_vtype ||
530                 (exprs[0]->m_vtype != TYPE_VECTOR && exprs[0]->m_vtype != TYPE_FLOAT))
531             {
532                 compile_error(ctx, "invalid types used in expression: cannot subtract type %s from %s",
533                               type_name[exprs[1]->m_vtype],
534                               type_name[exprs[0]->m_vtype]);
535                 return false;
536             }
537             if (!(out = parser.m_fold.op(op, exprs))) {
538                 switch (exprs[0]->m_vtype) {
539                     case TYPE_FLOAT:
540                         out = fold::binary(ctx, INSTR_SUB_F, exprs[0], exprs[1]);
541                         break;
542                     case TYPE_VECTOR:
543                         out = fold::binary(ctx, INSTR_SUB_V, exprs[0], exprs[1]);
544                         break;
545                     default:
546                         compile_error(ctx, "invalid types used in expression: cannot subtract type %s from %s",
547                                       type_name[exprs[1]->m_vtype],
548                                       type_name[exprs[0]->m_vtype]);
549                         return false;
550                 }
551             }
552             break;
553         case opid1('*'):
554             if (exprs[0]->m_vtype != exprs[1]->m_vtype &&
555                 !(exprs[0]->m_vtype == TYPE_VECTOR &&
556                   exprs[1]->m_vtype == TYPE_FLOAT) &&
557                 !(exprs[1]->m_vtype == TYPE_VECTOR &&
558                   exprs[0]->m_vtype == TYPE_FLOAT)
559                 )
560             {
561                 compile_error(ctx, "invalid types used in expression: cannot multiply types %s and %s",
562                               type_name[exprs[1]->m_vtype],
563                               type_name[exprs[0]->m_vtype]);
564                 return false;
565             }
566             if (!(out = parser.m_fold.op(op, exprs))) {
567                 switch (exprs[0]->m_vtype) {
568                     case TYPE_FLOAT:
569                         if (exprs[1]->m_vtype == TYPE_VECTOR)
570                             out = fold::binary(ctx, INSTR_MUL_FV, exprs[0], exprs[1]);
571                         else
572                             out = fold::binary(ctx, INSTR_MUL_F, exprs[0], exprs[1]);
573                         break;
574                     case TYPE_VECTOR:
575                         if (exprs[1]->m_vtype == TYPE_FLOAT)
576                             out = fold::binary(ctx, INSTR_MUL_VF, exprs[0], exprs[1]);
577                         else
578                             out = fold::binary(ctx, INSTR_MUL_V, exprs[0], exprs[1]);
579                         break;
580                     default:
581                         compile_error(ctx, "invalid types used in expression: cannot multiply types %s and %s",
582                                       type_name[exprs[1]->m_vtype],
583                                       type_name[exprs[0]->m_vtype]);
584                         return false;
585                 }
586             }
587             break;
588
589         case opid1('/'):
590             if (exprs[1]->m_vtype != TYPE_FLOAT) {
591                 ast_type_to_string(exprs[0], ty1, sizeof(ty1));
592                 ast_type_to_string(exprs[1], ty2, sizeof(ty2));
593                 compile_error(ctx, "invalid types used in expression: cannot divide types %s and %s", ty1, ty2);
594                 return false;
595             }
596             if (!(out = parser.m_fold.op(op, exprs))) {
597                 if (exprs[0]->m_vtype == TYPE_FLOAT)
598                     out = fold::binary(ctx, INSTR_DIV_F, exprs[0], exprs[1]);
599                 else {
600                     ast_type_to_string(exprs[0], ty1, sizeof(ty1));
601                     ast_type_to_string(exprs[1], ty2, sizeof(ty2));
602                     compile_error(ctx, "invalid types used in expression: cannot divide types %s and %s", ty1, ty2);
603                     return false;
604                 }
605             }
606             break;
607
608         case opid1('%'):
609             if (NotSameType(TYPE_FLOAT)) {
610                 compile_error(ctx, "invalid types used in expression: cannot perform modulo operation between types %s and %s",
611                     type_name[exprs[0]->m_vtype],
612                     type_name[exprs[1]->m_vtype]);
613                 return false;
614             } else if (!(out = parser.m_fold.op(op, exprs))) {
615                 /* generate a call to __builtin_mod */
616                 ast_expression *mod  = parser.m_intrin.func("mod");
617                 ast_call       *call = nullptr;
618                 if (!mod) return false; /* can return null for missing floor */
619
620                 call = ast_call::make(parser_ctx(parser), mod);
621                 call->m_params.push_back(exprs[0]);
622                 call->m_params.push_back(exprs[1]);
623
624                 out = call;
625             }
626             break;
627
628         case opid2('%','='):
629             compile_error(ctx, "%= is unimplemented");
630             return false;
631
632         case opid1('|'):
633         case opid1('&'):
634         case opid1('^'):
635             if ( !(exprs[0]->m_vtype == TYPE_FLOAT  && exprs[1]->m_vtype == TYPE_FLOAT) &&
636                  !(exprs[0]->m_vtype == TYPE_VECTOR && exprs[1]->m_vtype == TYPE_FLOAT) &&
637                  !(exprs[0]->m_vtype == TYPE_VECTOR && exprs[1]->m_vtype == TYPE_VECTOR))
638             {
639                 compile_error(ctx, "invalid types used in expression: cannot perform bit operations between types %s and %s",
640                               type_name[exprs[0]->m_vtype],
641                               type_name[exprs[1]->m_vtype]);
642                 return false;
643             }
644
645             if (!(out = parser.m_fold.op(op, exprs))) {
646                 /*
647                  * IF the first expression is float, the following will be too
648                  * since scalar ^ vector is not allowed.
649                  */
650                 if (exprs[0]->m_vtype == TYPE_FLOAT) {
651                     out = fold::binary(ctx,
652                         (op->id == opid1('^') ? VINSTR_BITXOR : op->id == opid1('|') ? INSTR_BITOR : INSTR_BITAND),
653                         exprs[0], exprs[1]);
654                 } else {
655                     /*
656                      * The first is a vector: vector is allowed to bitop with vector and
657                      * with scalar, branch here for the second operand.
658                      */
659                     if (exprs[1]->m_vtype == TYPE_VECTOR) {
660                         /*
661                          * Bitop all the values of the vector components against the
662                          * vectors components in question.
663                          */
664                         out = fold::binary(ctx,
665                             (op->id == opid1('^') ? VINSTR_BITXOR_V : op->id == opid1('|') ? VINSTR_BITOR_V : VINSTR_BITAND_V),
666                             exprs[0], exprs[1]);
667                     } else {
668                         out = fold::binary(ctx,
669                             (op->id == opid1('^') ? VINSTR_BITXOR_VF : op->id == opid1('|') ? VINSTR_BITOR_VF : VINSTR_BITAND_VF),
670                             exprs[0], exprs[1]);
671                     }
672                 }
673             }
674             break;
675
676         case opid2('<','<'):
677         case opid2('>','>'):
678             if (NotSameType(TYPE_FLOAT)) {
679                 compile_error(ctx, "invalid types used in expression: cannot perform shift between types %s and %s",
680                     type_name[exprs[0]->m_vtype],
681                     type_name[exprs[1]->m_vtype]);
682                 return false;
683             }
684
685             if (!(out = parser.m_fold.op(op, exprs))) {
686                 ast_expression *shift = parser.m_intrin.func((op->id == opid2('<','<')) ? "__builtin_lshift" : "__builtin_rshift");
687                 ast_call *call  = ast_call::make(parser_ctx(parser), shift);
688                 call->m_params.push_back(exprs[0]);
689                 call->m_params.push_back(exprs[1]);
690                 out = call;
691             }
692             break;
693
694         case opid3('<','<','='):
695         case opid3('>','>','='):
696             if (NotSameType(TYPE_FLOAT)) {
697                 compile_error(ctx, "invalid types used in expression: cannot perform shift operation between types %s and %s",
698                     type_name[exprs[0]->m_vtype],
699                     type_name[exprs[1]->m_vtype]);
700                 return false;
701             }
702
703             if(!(out = parser.m_fold.op(op, exprs))) {
704                 ast_expression *shift = parser.m_intrin.func((op->id == opid3('<','<','=')) ? "__builtin_lshift" : "__builtin_rshift");
705                 ast_call *call  = ast_call::make(parser_ctx(parser), shift);
706                 call->m_params.push_back(exprs[0]);
707                 call->m_params.push_back(exprs[1]);
708                 out = new ast_store(
709                     parser_ctx(parser),
710                     INSTR_STORE_F,
711                     exprs[0],
712                     call
713                 );
714             }
715
716             break;
717
718         case opid2('|','|'):
719             generated_op += 1; /* INSTR_OR */
720             [[fallthrough]];
721         case opid2('&','&'):
722             generated_op += INSTR_AND;
723             if (!(out = parser.m_fold.op(op, exprs))) {
724                 if (OPTS_FLAG(PERL_LOGIC) && !exprs[0]->compareType(*exprs[1])) {
725                     ast_type_to_string(exprs[0], ty1, sizeof(ty1));
726                     ast_type_to_string(exprs[1], ty2, sizeof(ty2));
727                     compile_error(ctx, "invalid types for logical operation with -fperl-logic: %s and %s", ty1, ty2);
728                     return false;
729                 }
730                 for (i = 0; i < 2; ++i) {
731                     if (OPTS_FLAG(CORRECT_LOGIC) && exprs[i]->m_vtype == TYPE_VECTOR) {
732                         out = ast_unary::make(ctx, INSTR_NOT_V, exprs[i]);
733                         if (!out) break;
734                         out = ast_unary::make(ctx, INSTR_NOT_F, out);
735                         if (!out) break;
736                         exprs[i] = out; out = nullptr;
737                         if (OPTS_FLAG(PERL_LOGIC)) {
738                             /* here we want to keep the right expressions' type */
739                             break;
740                         }
741                     }
742                     else if (OPTS_FLAG(FALSE_EMPTY_STRINGS) && exprs[i]->m_vtype == TYPE_STRING) {
743                         out = ast_unary::make(ctx, INSTR_NOT_S, exprs[i]);
744                         if (!out) break;
745                         out = ast_unary::make(ctx, INSTR_NOT_F, out);
746                         if (!out) break;
747                         exprs[i] = out; out = nullptr;
748                         if (OPTS_FLAG(PERL_LOGIC)) {
749                             /* here we want to keep the right expressions' type */
750                             break;
751                         }
752                     }
753                 }
754                 out = fold::binary(ctx, generated_op, exprs[0], exprs[1]);
755             }
756             break;
757
758         case opid2('?',':'):
759             if (sy->paren.back() != PAREN_TERNARY2) {
760                 compile_error(ctx, "mismatched parenthesis/ternary");
761                 return false;
762             }
763             sy->paren.pop_back();
764             if (!exprs[1]->compareType(*exprs[2])) {
765                 ast_type_to_string(exprs[1], ty1, sizeof(ty1));
766                 ast_type_to_string(exprs[2], ty2, sizeof(ty2));
767                 compile_error(ctx, "operands of ternary expression must have the same type, got %s and %s", ty1, ty2);
768                 return false;
769             }
770             if (!(out = parser.m_fold.op(op, exprs)))
771                 out = new ast_ternary(ctx, exprs[0], exprs[1], exprs[2]);
772             break;
773
774         case opid2('*', '*'):
775             if (NotSameType(TYPE_FLOAT)) {
776                 ast_type_to_string(exprs[0], ty1, sizeof(ty1));
777                 ast_type_to_string(exprs[1], ty2, sizeof(ty2));
778                 compile_error(ctx, "invalid types used in exponentiation: %s and %s",
779                     ty1, ty2);
780                 return false;
781             }
782
783             if (!(out = parser.m_fold.op(op, exprs))) {
784                 ast_call *gencall = ast_call::make(parser_ctx(parser), parser.m_intrin.func("pow"));
785                 gencall->m_params.push_back(exprs[0]);
786                 gencall->m_params.push_back(exprs[1]);
787                 out = gencall;
788             }
789             break;
790
791         case opid2('>', '<'):
792             if (NotSameType(TYPE_VECTOR)) {
793                 ast_type_to_string(exprs[0], ty1, sizeof(ty1));
794                 ast_type_to_string(exprs[1], ty2, sizeof(ty2));
795                 compile_error(ctx, "invalid types used in cross product: %s and %s",
796                     ty1, ty2);
797                 return false;
798             }
799
800             if (!(out = parser.m_fold.op(op, exprs))) {
801                 out = fold::binary(
802                     parser_ctx(parser),
803                     VINSTR_CROSS,
804                     exprs[0],
805                     exprs[1]
806                 );
807             }
808
809             break;
810
811         case opid3('<','=','>'): /* -1, 0, or 1 */
812             if (NotSameType(TYPE_FLOAT)) {
813                 ast_type_to_string(exprs[0], ty1, sizeof(ty1));
814                 ast_type_to_string(exprs[1], ty2, sizeof(ty2));
815                 compile_error(ctx, "invalid types used in comparision: %s and %s",
816                     ty1, ty2);
817
818                 return false;
819             }
820
821             if (!(out = parser.m_fold.op(op, exprs))) {
822                 /* This whole block is NOT fold_binary safe */
823                 ast_binary *eq = new ast_binary(ctx, INSTR_EQ_F, exprs[0], exprs[1]);
824
825                 eq->m_refs = AST_REF_NONE;
826
827                     /* if (lt) { */
828                 out = new ast_ternary(ctx,
829                         new ast_binary(ctx, INSTR_LT, exprs[0], exprs[1]),
830                         /* out = -1 */
831                         parser.m_fold.imm_float(2),
832                     /* } else { */
833                         /* if (eq) { */
834                         new ast_ternary(ctx, eq,
835                             /* out = 0 */
836                             parser.m_fold.imm_float(0),
837                         /* } else { */
838                             /* out = 1 */
839                             parser.m_fold.imm_float(1)
840                         /* } */
841                         )
842                     /* } */
843                     );
844
845             }
846             break;
847
848         case opid1('>'):
849             generated_op += 1; /* INSTR_GT */
850             [[fallthrough]];
851         case opid1('<'):
852             generated_op += 1; /* INSTR_LT */
853             [[fallthrough]];
854         case opid2('>', '='):
855             generated_op += 1; /* INSTR_GE */
856             [[fallthrough]];
857         case opid2('<', '='):
858             generated_op += INSTR_LE;
859             if (NotSameType(TYPE_FLOAT)) {
860                 compile_error(ctx, "invalid types used in expression: cannot perform comparison between types %s and %s",
861                               type_name[exprs[0]->m_vtype],
862                               type_name[exprs[1]->m_vtype]);
863                 return false;
864             }
865             if (!(out = parser.m_fold.op(op, exprs)))
866                 out = fold::binary(ctx, generated_op, exprs[0], exprs[1]);
867             break;
868         case opid2('!', '='):
869             if (exprs[0]->m_vtype != exprs[1]->m_vtype) {
870                 compile_error(ctx, "invalid types used in expression: cannot perform comparison between types %s and %s",
871                               type_name[exprs[0]->m_vtype],
872                               type_name[exprs[1]->m_vtype]);
873                 return false;
874             }
875             if (!(out = parser.m_fold.op(op, exprs)))
876                 out = fold::binary(ctx, type_ne_instr[exprs[0]->m_vtype], exprs[0], exprs[1]);
877             break;
878         case opid2('=', '='):
879             if (exprs[0]->m_vtype != exprs[1]->m_vtype) {
880                 compile_error(ctx, "invalid types used in expression: cannot perform comparison between types %s and %s",
881                               type_name[exprs[0]->m_vtype],
882                               type_name[exprs[1]->m_vtype]);
883                 return false;
884             }
885             if (!(out = parser.m_fold.op(op, exprs)))
886                 out = fold::binary(ctx, type_eq_instr[exprs[0]->m_vtype], exprs[0], exprs[1]);
887             break;
888
889         case opid1('='):
890             if (ast_istype(exprs[0], ast_entfield)) {
891                 ast_expression *field = ((ast_entfield*)exprs[0])->m_field;
892                 if (OPTS_FLAG(ADJUST_VECTOR_FIELDS) &&
893                     exprs[0]->m_vtype == TYPE_FIELD &&
894                     exprs[0]->m_next->m_vtype == TYPE_VECTOR)
895                 {
896                     assignop = type_storep_instr[TYPE_VECTOR];
897                 }
898                 else
899                     assignop = type_storep_instr[exprs[0]->m_vtype];
900                 if (assignop == VINSTR_END || !field->m_next->compareType(*exprs[1]))
901                 {
902                     ast_type_to_string(field->m_next, ty1, sizeof(ty1));
903                     ast_type_to_string(exprs[1], ty2, sizeof(ty2));
904                     if (OPTS_FLAG(ASSIGN_FUNCTION_TYPES) &&
905                         field->m_next->m_vtype == TYPE_FUNCTION &&
906                         exprs[1]->m_vtype == TYPE_FUNCTION)
907                     {
908                         (void)!compile_warning(ctx, WARN_ASSIGN_FUNCTION_TYPES,
909                                                "invalid types in assignment: cannot assign %s to %s", ty2, ty1);
910                     }
911                     else
912                         compile_error(ctx, "invalid types in assignment: cannot assign %s to %s", ty2, ty1);
913                 }
914             }
915             else
916             {
917                 if (OPTS_FLAG(ADJUST_VECTOR_FIELDS) &&
918                     exprs[0]->m_vtype == TYPE_FIELD &&
919                     exprs[0]->m_next->m_vtype == TYPE_VECTOR)
920                 {
921                     assignop = type_store_instr[TYPE_VECTOR];
922                 }
923                 else {
924                     assignop = type_store_instr[exprs[0]->m_vtype];
925                 }
926
927                 if (assignop == VINSTR_END) {
928                     ast_type_to_string(exprs[0], ty1, sizeof(ty1));
929                     ast_type_to_string(exprs[1], ty2, sizeof(ty2));
930                     compile_error(ctx, "invalid types in assignment: cannot assign %s to %s", ty2, ty1);
931                 }
932                 else if (!exprs[0]->compareType(*exprs[1]))
933                 {
934                     ast_type_to_string(exprs[0], ty1, sizeof(ty1));
935                     ast_type_to_string(exprs[1], ty2, sizeof(ty2));
936                     if (OPTS_FLAG(ASSIGN_FUNCTION_TYPES) &&
937                         exprs[0]->m_vtype == TYPE_FUNCTION &&
938                         exprs[1]->m_vtype == TYPE_FUNCTION)
939                     {
940                         (void)!compile_warning(ctx, WARN_ASSIGN_FUNCTION_TYPES,
941                                                "invalid types in assignment: cannot assign %s to %s", ty2, ty1);
942                     }
943                     else
944                         compile_error(ctx, "invalid types in assignment: cannot assign %s to %s", ty2, ty1);
945                 }
946             }
947             (void)check_write_to(ctx, exprs[0]);
948             /* When we're a vector of part of an entity field we use STOREP */
949             if (ast_istype(exprs[0], ast_member) && ast_istype(((ast_member*)exprs[0])->m_owner, ast_entfield))
950                 assignop = INSTR_STOREP_F;
951             out = new ast_store(ctx, assignop, exprs[0], exprs[1]);
952             break;
953         case opid3('+','+','P'):
954         case opid3('-','-','P'):
955             /* prefix ++ */
956             if (exprs[0]->m_vtype != TYPE_FLOAT) {
957                 ast_type_to_string(exprs[0], ty1, sizeof(ty1));
958                 compile_error(exprs[0]->m_context, "invalid type for prefix increment: %s", ty1);
959                 return false;
960             }
961             if (op->id == opid3('+','+','P'))
962                 addop = INSTR_ADD_F;
963             else
964                 addop = INSTR_SUB_F;
965             (void)check_write_to(exprs[0]->m_context, exprs[0]);
966             if (ast_istype(exprs[0], ast_entfield)) {
967                 out = new ast_binstore(ctx, INSTR_STOREP_F, addop,
968                                        exprs[0],
969                                        parser.m_fold.imm_float(1));
970             } else {
971                 out = new ast_binstore(ctx, INSTR_STORE_F, addop,
972                                        exprs[0],
973                                        parser.m_fold.imm_float(1));
974             }
975             break;
976         case opid3('S','+','+'):
977         case opid3('S','-','-'):
978             /* prefix ++ */
979             if (exprs[0]->m_vtype != TYPE_FLOAT) {
980                 ast_type_to_string(exprs[0], ty1, sizeof(ty1));
981                 compile_error(exprs[0]->m_context, "invalid type for suffix increment: %s", ty1);
982                 return false;
983             }
984             if (op->id == opid3('S','+','+')) {
985                 addop = INSTR_ADD_F;
986                 subop = INSTR_SUB_F;
987             } else {
988                 addop = INSTR_SUB_F;
989                 subop = INSTR_ADD_F;
990             }
991             (void)check_write_to(exprs[0]->m_context, exprs[0]);
992             if (ast_istype(exprs[0], ast_entfield)) {
993                 out = new ast_binstore(ctx, INSTR_STOREP_F, addop,
994                                        exprs[0],
995                                        parser.m_fold.imm_float(1));
996             } else {
997                 out = new ast_binstore(ctx, INSTR_STORE_F, addop,
998                                        exprs[0],
999                                        parser.m_fold.imm_float(1));
1000             }
1001             if (!out)
1002                 return false;
1003             out = fold::binary(ctx, subop,
1004                               out,
1005                               parser.m_fold.imm_float(1));
1006
1007             break;
1008         case opid2('+','='):
1009         case opid2('-','='):
1010             if (exprs[0]->m_vtype != exprs[1]->m_vtype ||
1011                 (exprs[0]->m_vtype != TYPE_VECTOR && exprs[0]->m_vtype != TYPE_FLOAT) )
1012             {
1013                 ast_type_to_string(exprs[0], ty1, sizeof(ty1));
1014                 ast_type_to_string(exprs[1], ty2, sizeof(ty2));
1015                 compile_error(ctx, "invalid types used in expression: cannot add or subtract type %s and %s",
1016                               ty1, ty2);
1017                 return false;
1018             }
1019             (void)check_write_to(ctx, exprs[0]);
1020             if (ast_istype(exprs[0], ast_entfield))
1021                 assignop = type_storep_instr[exprs[0]->m_vtype];
1022             else
1023                 assignop = type_store_instr[exprs[0]->m_vtype];
1024             switch (exprs[0]->m_vtype) {
1025                 case TYPE_FLOAT:
1026                     out = new ast_binstore(ctx, assignop,
1027                                            (op->id == opid2('+','=') ? INSTR_ADD_F : INSTR_SUB_F),
1028                                            exprs[0], exprs[1]);
1029                     break;
1030                 case TYPE_VECTOR:
1031                     out = new ast_binstore(ctx, assignop,
1032                                            (op->id == opid2('+','=') ? INSTR_ADD_V : INSTR_SUB_V),
1033                                            exprs[0], exprs[1]);
1034                     break;
1035                 default:
1036                     compile_error(ctx, "invalid types used in expression: cannot add or subtract type %s and %s",
1037                                   type_name[exprs[0]->m_vtype],
1038                                   type_name[exprs[1]->m_vtype]);
1039                     return false;
1040             };
1041             break;
1042         case opid2('*','='):
1043         case opid2('/','='):
1044             if (exprs[1]->m_vtype != TYPE_FLOAT ||
1045                 !(exprs[0]->m_vtype == TYPE_FLOAT ||
1046                   exprs[0]->m_vtype == TYPE_VECTOR))
1047             {
1048                 ast_type_to_string(exprs[0], ty1, sizeof(ty1));
1049                 ast_type_to_string(exprs[1], ty2, sizeof(ty2));
1050                 compile_error(ctx, "invalid types used in expression: %s and %s",
1051                               ty1, ty2);
1052                 return false;
1053             }
1054             (void)check_write_to(ctx, exprs[0]);
1055             if (ast_istype(exprs[0], ast_entfield))
1056                 assignop = type_storep_instr[exprs[0]->m_vtype];
1057             else
1058                 assignop = type_store_instr[exprs[0]->m_vtype];
1059             switch (exprs[0]->m_vtype) {
1060                 case TYPE_FLOAT:
1061                     out = new ast_binstore(ctx, assignop,
1062                                            (op->id == opid2('*','=') ? INSTR_MUL_F : INSTR_DIV_F),
1063                                            exprs[0], exprs[1]);
1064                     break;
1065                 case TYPE_VECTOR:
1066                     if (op->id == opid2('*','=')) {
1067                         out = new ast_binstore(ctx, assignop, INSTR_MUL_VF,
1068                                                exprs[0], exprs[1]);
1069                     } else {
1070                         out = fold::binary(ctx, INSTR_DIV_F,
1071                                          parser.m_fold.imm_float(1),
1072                                          exprs[1]);
1073                         if (!out) {
1074                             compile_error(ctx, "internal error: failed to generate division");
1075                             return false;
1076                         }
1077                         out = new ast_binstore(ctx, assignop, INSTR_MUL_VF,
1078                                                exprs[0], out);
1079                     }
1080                     break;
1081                 default:
1082                     compile_error(ctx, "invalid types used in expression: cannot add or subtract type %s and %s",
1083                                   type_name[exprs[0]->m_vtype],
1084                                   type_name[exprs[1]->m_vtype]);
1085                     return false;
1086             };
1087             break;
1088         case opid2('&','='):
1089         case opid2('|','='):
1090         case opid2('^','='):
1091             if (NotSameType(TYPE_FLOAT) && NotSameType(TYPE_VECTOR)) {
1092                 ast_type_to_string(exprs[0], ty1, sizeof(ty1));
1093                 ast_type_to_string(exprs[1], ty2, sizeof(ty2));
1094                 compile_error(ctx, "invalid types used in expression: %s and %s",
1095                               ty1, ty2);
1096                 return false;
1097             }
1098             (void)check_write_to(ctx, exprs[0]);
1099             if (ast_istype(exprs[0], ast_entfield))
1100                 assignop = type_storep_instr[exprs[0]->m_vtype];
1101             else
1102                 assignop = type_store_instr[exprs[0]->m_vtype];
1103             if (exprs[0]->m_vtype == TYPE_FLOAT)
1104                 out = new ast_binstore(ctx, assignop,
1105                                        (op->id == opid2('^','=') ? VINSTR_BITXOR : op->id == opid2('&','=') ? INSTR_BITAND : INSTR_BITOR),
1106                                        exprs[0], exprs[1]);
1107             else
1108                 out = new ast_binstore(ctx, assignop,
1109                                        (op->id == opid2('^','=') ? VINSTR_BITXOR_V : op->id == opid2('&','=') ? VINSTR_BITAND_V : VINSTR_BITOR_V),
1110                                        exprs[0], exprs[1]);
1111             break;
1112         case opid3('&','~','='):
1113             /* This is like: a &= ~(b);
1114              * But QC has no bitwise-not, so we implement it as
1115              * a -= a & (b);
1116              */
1117             if (NotSameType(TYPE_FLOAT) && NotSameType(TYPE_VECTOR)) {
1118                 ast_type_to_string(exprs[0], ty1, sizeof(ty1));
1119                 ast_type_to_string(exprs[1], ty2, sizeof(ty2));
1120                 compile_error(ctx, "invalid types used in expression: %s and %s",
1121                               ty1, ty2);
1122                 return false;
1123             }
1124             if (ast_istype(exprs[0], ast_entfield))
1125                 assignop = type_storep_instr[exprs[0]->m_vtype];
1126             else
1127                 assignop = type_store_instr[exprs[0]->m_vtype];
1128             if (exprs[0]->m_vtype == TYPE_FLOAT)
1129                 out = fold::binary(ctx, INSTR_BITAND, exprs[0], exprs[1]);
1130             else
1131                 out = fold::binary(ctx, VINSTR_BITAND_V, exprs[0], exprs[1]);
1132             if (!out)
1133                 return false;
1134             (void)check_write_to(ctx, exprs[0]);
1135             if (exprs[0]->m_vtype == TYPE_FLOAT)
1136                 asbinstore = new ast_binstore(ctx, assignop, INSTR_SUB_F, exprs[0], out);
1137             else
1138                 asbinstore = new ast_binstore(ctx, assignop, INSTR_SUB_V, exprs[0], out);
1139             asbinstore->m_keep_dest = true;
1140             out = asbinstore;
1141             break;
1142
1143         case opid3('l', 'e', 'n'):
1144             if (exprs[0]->m_vtype != TYPE_STRING && exprs[0]->m_vtype != TYPE_ARRAY) {
1145                 ast_type_to_string(exprs[0], ty1, sizeof(ty1));
1146                 compile_error(exprs[0]->m_context, "invalid type for length operator: %s", ty1);
1147                 return false;
1148             }
1149             /* strings must be const, arrays are statically sized */
1150             if (exprs[0]->m_vtype == TYPE_STRING &&
1151                 !(((ast_value*)exprs[0])->m_hasvalue && ((ast_value*)exprs[0])->m_cvq == CV_CONST))
1152             {
1153                 compile_error(exprs[0]->m_context, "operand of length operator not a valid constant expression");
1154                 return false;
1155             }
1156             out = parser.m_fold.op(op, exprs);
1157             break;
1158
1159         case opid2('~', 'P'):
1160             if (exprs[0]->m_vtype != TYPE_FLOAT && exprs[0]->m_vtype != TYPE_VECTOR) {
1161                 ast_type_to_string(exprs[0], ty1, sizeof(ty1));
1162                 compile_error(exprs[0]->m_context, "invalid type for bit not: %s", ty1);
1163                 return false;
1164             }
1165             if (!(out = parser.m_fold.op(op, exprs))) {
1166                 if (exprs[0]->m_vtype == TYPE_FLOAT) {
1167                     out = fold::binary(ctx, INSTR_SUB_F, parser.m_fold.imm_float(2), exprs[0]);
1168                 } else {
1169                     out = fold::binary(ctx, INSTR_SUB_V, parser.m_fold.imm_vector(1), exprs[0]);
1170                 }
1171             }
1172             break;
1173     }
1174 #undef NotSameType
1175     if (!out) {
1176         compile_error(ctx, "failed to apply operator %s", op->op);
1177         return false;
1178     }
1179
1180     sy->out.push_back(syexp(ctx, out));
1181     return true;
1182 }
1183
1184 static bool parser_close_call(parser_t &parser, shunt *sy)
1185 {
1186     /* was a function call */
1187     ast_expression *fun;
1188     ast_value      *funval = nullptr;
1189     ast_call       *call;
1190
1191     size_t          fid;
1192     size_t          paramcount, i;
1193     bool            fold = true;
1194
1195     fid = sy->ops.back().off;
1196     sy->ops.pop_back();
1197
1198     /* out[fid] is the function
1199      * everything above is parameters...
1200      */
1201     if (sy->argc.empty()) {
1202         parseerror(parser, "internal error: no argument counter available");
1203         return false;
1204     }
1205
1206     paramcount = sy->argc.back();
1207     sy->argc.pop_back();
1208
1209     if (sy->out.size() < fid) {
1210         parseerror(parser, "internal error: broken function call %zu < %zu+%zu\n",
1211                    sy->out.size(),
1212                    fid,
1213                    paramcount);
1214         return false;
1215     }
1216
1217     /*
1218      * TODO handle this at the intrinsic level with an ast_intrinsic
1219      * node and codegen.
1220      */
1221     if ((fun = sy->out[fid].out) == parser.m_intrin.debug_typestring()) {
1222         char ty[1024];
1223         if (fid+2 != sy->out.size() || sy->out.back().block) {
1224             parseerror(parser, "intrinsic __builtin_debug_typestring requires exactly 1 parameter");
1225             return false;
1226         }
1227         ast_type_to_string(sy->out.back().out, ty, sizeof(ty));
1228         ast_unref(sy->out.back().out);
1229         sy->out[fid] = syexp(sy->out.back().out->m_context,
1230                              parser.m_fold.constgen_string(ty, false));
1231         sy->out.pop_back();
1232         return true;
1233     }
1234
1235     /*
1236      * Now we need to determine if the function that is being called is
1237      * an intrinsic so we can evaluate if the arguments to it are constant
1238      * and than fruitfully fold them.
1239      */
1240 #define fold_can_1(X)  \
1241     (ast_istype(((X)), ast_value) && (X)->m_hasvalue && ((X)->m_cvq == CV_CONST) && \
1242                 ((X))->m_vtype != TYPE_FUNCTION)
1243
1244     if (fid + 1 < sy->out.size())
1245         ++paramcount;
1246
1247     for (i = 0; i < paramcount; ++i) {
1248         if (!fold_can_1((ast_value*)sy->out[fid + 1 + i].out)) {
1249             fold = false;
1250             break;
1251         }
1252     }
1253
1254     /*
1255      * All is well which ends well, if we make it into here we can ignore the
1256      * intrinsic call and just evaluate it i.e constant fold it.
1257      */
1258     if (fold && ast_istype(fun, ast_value) && ((ast_value*)fun)->m_intrinsic) {
1259         std::vector<ast_expression*> exprs;
1260         ast_expression *foldval = nullptr;
1261
1262         exprs.reserve(paramcount);
1263         for (i = 0; i < paramcount; i++)
1264             exprs.push_back(sy->out[fid+1 + i].out);
1265
1266         if (!(foldval = parser.m_intrin.do_fold((ast_value*)fun, exprs.data()))) {
1267             goto fold_leave;
1268         }
1269
1270         /*
1271          * Blub: what sorts of unreffing and resizing of
1272          * sy->out should I be doing here?
1273          */
1274         sy->out[fid] = syexp(foldval->m_context, foldval);
1275         sy->out.erase(sy->out.end() - paramcount, sy->out.end());
1276
1277         return true;
1278     }
1279
1280     fold_leave:
1281     call = ast_call::make(sy->ops[sy->ops.size()].ctx, fun);
1282
1283     if (!call)
1284         return false;
1285
1286     if (fid+1 + paramcount != sy->out.size()) {
1287         parseerror(parser, "internal error: parameter count mismatch: (%zu+1+%zu), %zu",
1288                    fid,
1289                    paramcount,
1290                    sy->out.size());
1291         return false;
1292     }
1293
1294     for (i = 0; i < paramcount; ++i)
1295         call->m_params.push_back(sy->out[fid+1 + i].out);
1296     sy->out.erase(sy->out.end() - paramcount, sy->out.end());
1297     (void)!call->checkTypes(parser.function->m_function_type->m_varparam);
1298     if (parser.max_param_count < paramcount)
1299         parser.max_param_count = paramcount;
1300
1301     if (ast_istype(fun, ast_value)) {
1302         funval = (ast_value*)fun;
1303         if ((fun->m_flags & AST_FLAG_VARIADIC) &&
1304             !(/*funval->m_cvq == CV_CONST && */ funval->m_hasvalue && funval->m_constval.vfunc->m_builtin))
1305         {
1306             call->m_va_count = parser.m_fold.constgen_float((qcfloat_t)paramcount, false);
1307         }
1308     }
1309
1310     /* overwrite fid, the function, with a call */
1311     sy->out[fid] = syexp(call->m_context, call);
1312
1313     if (fun->m_vtype != TYPE_FUNCTION) {
1314         parseerror(parser, "not a function (%s)", type_name[fun->m_vtype]);
1315         return false;
1316     }
1317
1318     if (!fun->m_next) {
1319         parseerror(parser, "could not determine function return type");
1320         return false;
1321     } else {
1322         ast_value *fval = (ast_istype(fun, ast_value) ? ((ast_value*)fun) : nullptr);
1323
1324         if (fun->m_flags & AST_FLAG_DEPRECATED) {
1325             if (!fval) {
1326                 return !parsewarning(parser, WARN_DEPRECATED,
1327                         "call to function (which is marked deprecated)\n",
1328                         "-> it has been declared here: %s:%i",
1329                         fun->m_context.file, fun->m_context.line);
1330             }
1331             if (!fval->m_desc.length()) {
1332                 return !parsewarning(parser, WARN_DEPRECATED,
1333                         "call to `%s` (which is marked deprecated)\n"
1334                         "-> `%s` declared here: %s:%i",
1335                         fval->m_name, fval->m_name, fun->m_context.file, fun->m_context.line);
1336             }
1337             return !parsewarning(parser, WARN_DEPRECATED,
1338                     "call to `%s` (deprecated: %s)\n"
1339                     "-> `%s` declared here: %s:%i",
1340                     fval->m_name, fval->m_desc, fval->m_name, fun->m_context.file,
1341                     fun->m_context.line);
1342         }
1343
1344         if (fun->m_type_params.size() != paramcount &&
1345             !((fun->m_flags & AST_FLAG_VARIADIC) &&
1346               fun->m_type_params.size() < paramcount))
1347         {
1348             const char *fewmany = (fun->m_type_params.size() > paramcount) ? "few" : "many";
1349             if (fval)
1350                 return !parsewarning(parser, WARN_INVALID_PARAMETER_COUNT,
1351                                      "too %s parameters for call to %s: expected %i, got %i\n"
1352                                      " -> `%s` has been declared here: %s:%i",
1353                                      fewmany, fval->m_name, (int)fun->m_type_params.size(), (int)paramcount,
1354                                      fval->m_name, fun->m_context.file, (int)fun->m_context.line);
1355             else
1356                 return !parsewarning(parser, WARN_INVALID_PARAMETER_COUNT,
1357                                      "too %s parameters for function call: expected %i, got %i\n"
1358                                      " -> it has been declared here: %s:%i",
1359                                      fewmany, (int)fun->m_type_params.size(), (int)paramcount,
1360                                      fun->m_context.file, (int)fun->m_context.line);
1361         }
1362     }
1363
1364     return true;
1365 }
1366
1367 static bool parser_close_paren(parser_t &parser, shunt *sy)
1368 {
1369     if (sy->ops.empty()) {
1370         parseerror(parser, "unmatched closing paren");
1371         return false;
1372     }
1373
1374     while (sy->ops.size()) {
1375         if (sy->ops.back().isparen) {
1376             if (sy->paren.back() == PAREN_FUNC) {
1377                 sy->paren.pop_back();
1378                 if (!parser_close_call(parser, sy))
1379                     return false;
1380                 break;
1381             }
1382             if (sy->paren.back() == PAREN_EXPR) {
1383                 sy->paren.pop_back();
1384                 if (sy->out.empty()) {
1385                     compile_error(sy->ops.back().ctx, "empty paren expression");
1386                     sy->ops.pop_back();
1387                     return false;
1388                 }
1389                 sy->ops.pop_back();
1390                 break;
1391             }
1392             if (sy->paren.back() == PAREN_INDEX) {
1393                 sy->paren.pop_back();
1394                 // pop off the parenthesis
1395                 sy->ops.pop_back();
1396                 /* then apply the index operator */
1397                 if (!parser_sy_apply_operator(parser, sy))
1398                     return false;
1399                 break;
1400             }
1401             if (sy->paren.back() == PAREN_TERNARY1) {
1402                 sy->paren.back() = PAREN_TERNARY2;
1403                 // pop off the parenthesis
1404                 sy->ops.pop_back();
1405                 break;
1406             }
1407             compile_error(sy->ops.back().ctx, "invalid parenthesis");
1408             return false;
1409         }
1410         if (!parser_sy_apply_operator(parser, sy))
1411             return false;
1412     }
1413     return true;
1414 }
1415
1416 static void parser_reclassify_token(parser_t &parser)
1417 {
1418     size_t i;
1419     if (parser.tok >= Token::START)
1420         return;
1421     for (i = 0; i < operator_count; ++i) {
1422         if (!strcmp(parser_tokval(parser), operators[i].op)) {
1423             parser.tok = Token::OPERATOR;
1424             return;
1425         }
1426     }
1427 }
1428
1429 static ast_expression* parse_vararg_do(parser_t &parser)
1430 {
1431     ast_expression *idx, *out;
1432     ast_value      *typevar;
1433     ast_value      *funtype = parser.function->m_function_type;
1434     lex_ctx_t         ctx     = parser_ctx(parser);
1435
1436     if (!parser.function->m_varargs) {
1437         parseerror(parser, "function has no variable argument list");
1438         return nullptr;
1439     }
1440
1441     if (!parser_next(parser) || parser.tok != '(') {
1442         parseerror(parser, "expected parameter index and type in parenthesis");
1443         return nullptr;
1444     }
1445     if (!parser_next(parser)) {
1446         parseerror(parser, "error parsing parameter index");
1447         return nullptr;
1448     }
1449
1450     idx = parse_expression_leave(parser, true, false, false);
1451     if (!idx)
1452         return nullptr;
1453
1454     if (parser.tok != ',') {
1455         if (parser.tok != ')') {
1456             ast_unref(idx);
1457             parseerror(parser, "expected comma after parameter index");
1458             return nullptr;
1459         }
1460         // vararg piping: ...(start)
1461         out = new ast_argpipe(ctx, idx);
1462         return out;
1463     }
1464
1465     if (!parser_next(parser) || (parser.tok != Token::IDENT && parser.tok != Token::TYPENAME)) {
1466         ast_unref(idx);
1467         parseerror(parser, "expected typename for vararg");
1468         return nullptr;
1469     }
1470
1471     typevar = parse_typename(parser, nullptr, nullptr, nullptr);
1472     if (!typevar) {
1473         ast_unref(idx);
1474         return nullptr;
1475     }
1476
1477     if (parser.tok != ')') {
1478         ast_unref(idx);
1479         delete typevar;
1480         parseerror(parser, "expected closing paren");
1481         return nullptr;
1482     }
1483
1484     if (funtype->m_varparam &&
1485         !typevar->compareType(*funtype->m_varparam))
1486     {
1487         char ty1[1024];
1488         char ty2[1024];
1489         ast_type_to_string(typevar, ty1, sizeof(ty1));
1490         ast_type_to_string(funtype->m_varparam, ty2, sizeof(ty2));
1491         compile_error(typevar->m_context,
1492                       "function was declared to take varargs of type `%s`, requested type is: %s",
1493                       ty2, ty1);
1494     }
1495
1496     out = ast_array_index::make(ctx, parser.function->m_varargs.get(), idx);
1497     out->adoptType(*typevar);
1498     delete typevar;
1499     return out;
1500 }
1501
1502 static ast_expression* parse_vararg(parser_t &parser)
1503 {
1504     bool           old_noops = parser.lex->flags.noops;
1505
1506     ast_expression *out;
1507
1508     parser.lex->flags.noops = true;
1509     out = parse_vararg_do(parser);
1510
1511     parser.lex->flags.noops = old_noops;
1512     return out;
1513 }
1514
1515 /* not to be exposed */
1516 bool ftepp_predef_exists(const char *name);
1517 static bool parse_sya_operand(parser_t &parser, shunt *sy, bool with_labels)
1518 {
1519     if (OPTS_FLAG(TRANSLATABLE_STRINGS) &&
1520         parser.tok == Token::IDENT &&
1521         !strcmp(parser_tokval(parser), "_"))
1522     {
1523         /* a translatable string */
1524         ast_value *val;
1525
1526         parser.lex->flags.noops = true;
1527         if (!parser_next(parser) || parser.tok != '(') {
1528             parseerror(parser, "use _(\"string\") to create a translatable string constant");
1529             return false;
1530         }
1531         parser.lex->flags.noops = false;
1532         if (!parser_next(parser) || parser.tok != Token::STRINGCONST) {
1533             parseerror(parser, "expected a constant string in translatable-string extension");
1534             return false;
1535         }
1536         val = (ast_value*)parser.m_fold.constgen_string(parser_tokval(parser), true);
1537         if (!val)
1538             return false;
1539         sy->out.push_back(syexp(parser_ctx(parser), val));
1540
1541         if (!parser_next(parser) || parser.tok != ')') {
1542             parseerror(parser, "expected closing paren after translatable string");
1543             return false;
1544         }
1545         return true;
1546     }
1547     else if (parser.tok == Token::DOTS)
1548     {
1549         ast_expression *va;
1550         if (!OPTS_FLAG(VARIADIC_ARGS)) {
1551             parseerror(parser, "cannot access varargs (try -fvariadic-args)");
1552             return false;
1553         }
1554         va = parse_vararg(parser);
1555         if (!va)
1556             return false;
1557         sy->out.push_back(syexp(parser_ctx(parser), va));
1558         return true;
1559     }
1560     else if (parser.tok == Token::FLOATCONST) {
1561         ast_expression *val = parser.m_fold.constgen_float((parser_token(parser)->constval.f), false);
1562         if (!val)
1563             return false;
1564         sy->out.push_back(syexp(parser_ctx(parser), val));
1565         return true;
1566     }
1567     else if (parser.tok == Token::INTCONST || parser.tok == Token::CHARCONST) {
1568         ast_expression *val = parser.m_fold.constgen_float((qcfloat_t)(parser_token(parser)->constval.i), false);
1569         if (!val)
1570             return false;
1571         sy->out.push_back(syexp(parser_ctx(parser), val));
1572         return true;
1573     }
1574     else if (parser.tok == Token::STRINGCONST) {
1575         ast_expression *val = parser.m_fold.constgen_string(parser_tokval(parser), false);
1576         if (!val)
1577             return false;
1578         sy->out.push_back(syexp(parser_ctx(parser), val));
1579         return true;
1580     }
1581     else if (parser.tok == Token::VECTORCONST) {
1582         ast_expression *val = parser.m_fold.constgen_vector(parser_token(parser)->constval.v);
1583         if (!val)
1584             return false;
1585         sy->out.push_back(syexp(parser_ctx(parser), val));
1586         return true;
1587     }
1588     else if (parser.tok == Token::IDENT)
1589     {
1590         const char     *ctoken = parser_tokval(parser);
1591         ast_expression *prev = sy->out.size() ? sy->out.back().out : nullptr;
1592         ast_expression *var;
1593         /* a_vector.{x,y,z} */
1594         if (sy->ops.empty() ||
1595             !sy->ops.back().etype ||
1596             operators[sy->ops.back().etype-1].id != opid1('.'))
1597         {
1598             /* When adding more intrinsics, fix the above condition */
1599             prev = nullptr;
1600         }
1601         if (prev && prev->m_vtype == TYPE_VECTOR && ctoken[0] >= 'x' && ctoken[0] <= 'z' && !ctoken[1])
1602         {
1603             var = parser.const_vec[ctoken[0]-'x'];
1604         } else {
1605             var = parser_find_var(parser, parser_tokval(parser));
1606             if (!var)
1607                 var = parser_find_field(parser, parser_tokval(parser));
1608         }
1609         if (!var && with_labels) {
1610             var = parser_find_label(parser, parser_tokval(parser));
1611             if (!with_labels) {
1612                 ast_label *lbl = new ast_label(parser_ctx(parser), parser_tokval(parser), true);
1613                 var = lbl;
1614                 parser.labels.push_back(lbl);
1615             }
1616         }
1617         if (!var && !strcmp(parser_tokval(parser), "__FUNC__"))
1618             var = parser.m_fold.constgen_string(parser.function->m_name, false);
1619         if (!var) {
1620             /*
1621              * now we try for the real intrinsic hashtable. If the string
1622              * begins with __builtin, we simply skip past it, otherwise we
1623              * use the identifier as is.
1624              */
1625             if (!strncmp(parser_tokval(parser), "__builtin_", 10)) {
1626                 var = parser.m_intrin.func(parser_tokval(parser));
1627             }
1628
1629             /*
1630              * Try it again, intrin_func deals with the alias method as well
1631              * the first one masks for __builtin though, we emit warning here.
1632              */
1633             if (!var) {
1634                 if ((var = parser.m_intrin.func(parser_tokval(parser)))) {
1635                     (void)!compile_warning(
1636                         parser_ctx(parser),
1637                         WARN_BUILTINS,
1638                         "using implicitly defined builtin `__builtin_%s' for `%s'",
1639                         parser_tokval(parser),
1640                         parser_tokval(parser)
1641                     );
1642                 }
1643             }
1644
1645
1646             if (!var) {
1647                 /*
1648                  * sometimes people use preprocessing predefs without enabling them
1649                  * i've done this thousands of times already myself.  Lets check for
1650                  * it in the predef table.  And diagnose it better :)
1651                  */
1652                 if (!OPTS_FLAG(FTEPP_PREDEFS) && ftepp_predef_exists(parser_tokval(parser))) {
1653                     parseerror(parser, "unexpected identifier: %s (use -fftepp-predef to enable pre-defined macros)", parser_tokval(parser));
1654                     return false;
1655                 }
1656
1657                 parseerror(parser, "unexpected identifier: %s", parser_tokval(parser));
1658                 return false;
1659             }
1660         }
1661         else
1662         {
1663             // promote these to norefs
1664             if (ast_istype(var, ast_value))
1665             {
1666                 ((ast_value *)var)->m_flags |= AST_FLAG_NOREF;
1667             }
1668             else if (ast_istype(var, ast_member))
1669             {
1670                 ast_member *mem = (ast_member *)var;
1671                 if (ast_istype(mem->m_owner, ast_value))
1672                     ((ast_value *)mem->m_owner)->m_flags |= AST_FLAG_NOREF;
1673             }
1674         }
1675         sy->out.push_back(syexp(parser_ctx(parser), var));
1676         return true;
1677     }
1678     parseerror(parser, "unexpected token `%s`", parser_tokval(parser));
1679     return false;
1680 }
1681
1682 static ast_expression* parse_expression_leave(parser_t &parser, bool stopatcomma, bool truthvalue, bool with_labels)
1683 {
1684     ast_expression *expr = nullptr;
1685     shunt sy;
1686     bool wantop = false;
1687     /* only warn once about an assignment in a truth value because the current code
1688      * would trigger twice on: if(a = b && ...), once for the if-truth-value, once for the && part
1689      */
1690     bool warn_parenthesis = true;
1691
1692     /* count the parens because an if starts with one, so the
1693      * end of a condition is an unmatched closing paren
1694      */
1695     int ternaries = 0;
1696
1697     memset(&sy, 0, sizeof(sy));
1698
1699     parser.lex->flags.noops = false;
1700
1701     parser_reclassify_token(parser);
1702
1703     while (true)
1704     {
1705         if (parser.tok == Token::TYPENAME) {
1706             parseerror(parser, "unexpected typename `%s`", parser_tokval(parser));
1707             goto onerr;
1708         }
1709
1710         if (parser.tok == Token::OPERATOR)
1711         {
1712             /* classify the operator */
1713             const oper_info *op;
1714             const oper_info *olast = nullptr;
1715             size_t o;
1716             for (o = 0; o < operator_count; ++o) {
1717                 if (((!(operators[o].flags & OP_PREFIX) == !!wantop)) &&
1718                     /* !(operators[o].flags & OP_SUFFIX) && / * remove this */
1719                     !strcmp(parser_tokval(parser), operators[o].op))
1720                 {
1721                     break;
1722                 }
1723             }
1724             if (o == operator_count) {
1725                 compile_error(parser_ctx(parser), "unexpected operator: %s", parser_tokval(parser));
1726                 goto onerr;
1727             }
1728             /* found an operator */
1729             op = &operators[o];
1730
1731             /* when declaring variables, a comma starts a new variable */
1732             if (op->id == opid1(',') && sy.paren.empty() && stopatcomma) {
1733                 /* fixup the token */
1734                 parser.tok = Token::COMMA;
1735                 break;
1736             }
1737
1738             /* a colon without a pervious question mark cannot be a ternary */
1739             if (!ternaries && op->id == opid2(':','?')) {
1740                 parser.tok = Token::COLON;
1741                 break;
1742             }
1743
1744             if (op->id == opid1(',')) {
1745                 if (sy.paren.size() && sy.paren.back() == PAREN_TERNARY2) {
1746                     (void)!parsewarning(parser, WARN_TERNARY_PRECEDENCE, "suggesting parenthesis around ternary expression");
1747                 }
1748             }
1749
1750             if (sy.ops.size() && !sy.ops.back().isparen)
1751                 olast = &operators[sy.ops.back().etype-1];
1752
1753             /* first only apply higher precedences, assoc_left+equal comes after we warn about precedence rules */
1754             while (olast && op->prec < olast->prec)
1755             {
1756                 if (!parser_sy_apply_operator(parser, &sy))
1757                     goto onerr;
1758                 if (sy.ops.size() && !sy.ops.back().isparen)
1759                     olast = &operators[sy.ops.back().etype-1];
1760                 else
1761                     olast = nullptr;
1762             }
1763
1764 #define IsAssignOp(x) (\
1765                 (x) == opid1('=') || \
1766                 (x) == opid2('+','=') || \
1767                 (x) == opid2('-','=') || \
1768                 (x) == opid2('*','=') || \
1769                 (x) == opid2('/','=') || \
1770                 (x) == opid2('%','=') || \
1771                 (x) == opid2('&','=') || \
1772                 (x) == opid2('|','=') || \
1773                 (x) == opid3('&','~','=') \
1774                 )
1775             if (warn_parenthesis) {
1776                 if ( (olast && IsAssignOp(olast->id) && (op->id == opid2('&','&') || op->id == opid2('|','|'))) ||
1777                      (olast && IsAssignOp(op->id) && (olast->id == opid2('&','&') || olast->id == opid2('|','|'))) ||
1778                      (truthvalue && sy.paren.empty() && IsAssignOp(op->id))
1779                    )
1780                 {
1781                     (void)!parsewarning(parser, WARN_PARENTHESIS, "suggesting parenthesis around assignment used as truth value");
1782                     warn_parenthesis = false;
1783                 }
1784
1785                 if (olast && olast->id != op->id) {
1786                     if ((op->id    == opid1('&') || op->id    == opid1('|') || op->id    == opid1('^')) &&
1787                         (olast->id == opid1('&') || olast->id == opid1('|') || olast->id == opid1('^')))
1788                     {
1789                         (void)!parsewarning(parser, WARN_PARENTHESIS, "suggesting parenthesis around bitwise operations");
1790                         warn_parenthesis = false;
1791                     }
1792                     else if ((op->id    == opid2('&','&') || op->id    == opid2('|','|')) &&
1793                              (olast->id == opid2('&','&') || olast->id == opid2('|','|')))
1794                     {
1795                         (void)!parsewarning(parser, WARN_PARENTHESIS, "suggesting parenthesis around logical operations");
1796                         warn_parenthesis = false;
1797                     }
1798                 }
1799             }
1800
1801             while (olast && (
1802                     (op->prec < olast->prec) ||
1803                     (op->assoc == ASSOC_LEFT && op->prec <= olast->prec) ) )
1804             {
1805                 if (!parser_sy_apply_operator(parser, &sy))
1806                     goto onerr;
1807                 if (sy.ops.size() && !sy.ops.back().isparen)
1808                     olast = &operators[sy.ops.back().etype-1];
1809                 else
1810                     olast = nullptr;
1811             }
1812
1813             if (op->id == opid1('(')) {
1814                 if (wantop) {
1815                     size_t sycount = sy.out.size();
1816                     /* we expected an operator, this is the function-call operator */
1817                     sy.paren.push_back(PAREN_FUNC);
1818                     sy.ops.push_back(syparen(parser_ctx(parser), sycount-1));
1819                     sy.argc.push_back(0);
1820                 } else {
1821                     sy.paren.push_back(PAREN_EXPR);
1822                     sy.ops.push_back(syparen(parser_ctx(parser), 0));
1823                 }
1824                 wantop = false;
1825             } else if (op->id == opid1('[')) {
1826                 if (!wantop) {
1827                     parseerror(parser, "unexpected array subscript");
1828                     goto onerr;
1829                 }
1830                 sy.paren.push_back(PAREN_INDEX);
1831                 /* push both the operator and the paren, this makes life easier */
1832                 sy.ops.push_back(syop(parser_ctx(parser), op));
1833                 sy.ops.push_back(syparen(parser_ctx(parser), 0));
1834                 wantop = false;
1835             } else if (op->id == opid2('?',':')) {
1836                 sy.ops.push_back(syop(parser_ctx(parser), op));
1837                 sy.ops.push_back(syparen(parser_ctx(parser), 0));
1838                 wantop = false;
1839                 ++ternaries;
1840                 sy.paren.push_back(PAREN_TERNARY1);
1841             } else if (op->id == opid2(':','?')) {
1842                 if (sy.paren.empty()) {
1843                     parseerror(parser, "unexpected colon outside ternary expression (missing parenthesis?)");
1844                     goto onerr;
1845                 }
1846                 if (sy.paren.back() != PAREN_TERNARY1) {
1847                     parseerror(parser, "unexpected colon outside ternary expression (missing parenthesis?)");
1848                     goto onerr;
1849                 }
1850                 if (!parser_close_paren(parser, &sy))
1851                     goto onerr;
1852                 sy.ops.push_back(syop(parser_ctx(parser), op));
1853                 wantop = false;
1854                 --ternaries;
1855             } else {
1856                 sy.ops.push_back(syop(parser_ctx(parser), op));
1857                 wantop = !!(op->flags & OP_SUFFIX);
1858             }
1859         }
1860         else if (parser.tok == ')') {
1861             while (sy.paren.size() && sy.paren.back() == PAREN_TERNARY2) {
1862                 if (!parser_sy_apply_operator(parser, &sy))
1863                     goto onerr;
1864             }
1865             if (sy.paren.empty())
1866                 break;
1867             if (wantop) {
1868                 if (sy.paren.back() == PAREN_TERNARY1) {
1869                     parseerror(parser, "mismatched parentheses (closing paren in ternary expression?)");
1870                     goto onerr;
1871                 }
1872                 if (!parser_close_paren(parser, &sy))
1873                     goto onerr;
1874             } else {
1875                 /* must be a function call without parameters */
1876                 if (sy.paren.back() != PAREN_FUNC) {
1877                     parseerror(parser, "closing paren in invalid position");
1878                     goto onerr;
1879                 }
1880                 if (!parser_close_paren(parser, &sy))
1881                     goto onerr;
1882             }
1883             wantop = true;
1884         }
1885         else if (parser.tok == '(') {
1886             parseerror(parser, "internal error: '(' should be classified as operator");
1887             goto onerr;
1888         }
1889         else if (parser.tok == '[') {
1890             parseerror(parser, "internal error: '[' should be classified as operator");
1891             goto onerr;
1892         }
1893         else if (parser.tok == ']') {
1894             while (sy.paren.size() && sy.paren.back() == PAREN_TERNARY2) {
1895                 if (!parser_sy_apply_operator(parser, &sy))
1896                     goto onerr;
1897             }
1898             if (sy.paren.empty())
1899                 break;
1900             if (sy.paren.back() != PAREN_INDEX) {
1901                 parseerror(parser, "mismatched parentheses, unexpected ']'");
1902                 goto onerr;
1903             }
1904             if (!parser_close_paren(parser, &sy))
1905                 goto onerr;
1906             wantop = true;
1907         }
1908         else if (!wantop) {
1909             if (!parse_sya_operand(parser, &sy, with_labels))
1910                 goto onerr;
1911             wantop = true;
1912         }
1913         else {
1914             /* in this case we might want to allow constant string concatenation */
1915             bool concatenated = false;
1916             if (parser.tok == Token::STRINGCONST && sy.out.size()) {
1917                 ast_expression *lexpr = sy.out.back().out;
1918                 if (ast_istype(lexpr, ast_value)) {
1919                     ast_value *last = (ast_value*)lexpr;
1920                     if (last->m_isimm == true && last->m_cvq == CV_CONST &&
1921                         last->m_hasvalue && last->m_vtype == TYPE_STRING)
1922                     {
1923                         char *newstr = nullptr;
1924                         util_asprintf(&newstr, "%s%s", last->m_constval.vstring, parser_tokval(parser));
1925                         sy.out.back().out = parser.m_fold.constgen_string(newstr, false);
1926                         mem_d(newstr);
1927                         concatenated = true;
1928                     }
1929                 }
1930             }
1931             if (!concatenated) {
1932                 parseerror(parser, "expected operator or end of statement");
1933                 goto onerr;
1934             }
1935         }
1936
1937         if (!parser_next(parser)) {
1938             goto onerr;
1939         }
1940         if (parser.tok == ';' ||
1941             ((sy.paren.empty() || (sy.paren.size() == 1 && sy.paren.back() == PAREN_TERNARY2)) &&
1942             (parser.tok == ']' || parser.tok == ')' || parser.tok == '}')))
1943         {
1944             break;
1945         }
1946     }
1947
1948     while (sy.ops.size()) {
1949         if (!parser_sy_apply_operator(parser, &sy))
1950             goto onerr;
1951     }
1952
1953     parser.lex->flags.noops = true;
1954     if (sy.out.size() != 1) {
1955         parseerror(parser, "expression expected");
1956         expr = nullptr;
1957     } else
1958         expr = sy.out[0].out;
1959     if (sy.paren.size()) {
1960         parseerror(parser, "internal error: sy.paren.size() = %zu", sy.paren.size());
1961         return nullptr;
1962     }
1963     return expr;
1964
1965 onerr:
1966     parser.lex->flags.noops = true;
1967     for (auto &it : sy.out)
1968         if (it.out) ast_unref(it.out);
1969     return nullptr;
1970 }
1971
1972 static ast_expression* parse_expression(parser_t &parser, bool stopatcomma, bool with_labels)
1973 {
1974     ast_expression *e = parse_expression_leave(parser, stopatcomma, false, with_labels);
1975     if (!e)
1976         return nullptr;
1977     if (parser.tok != ';') {
1978         parseerror(parser, "semicolon expected after expression");
1979         ast_unref(e);
1980         return nullptr;
1981     }
1982     if (!parser_next(parser)) {
1983         ast_unref(e);
1984         return nullptr;
1985     }
1986     return e;
1987 }
1988
1989 static void parser_enterblock(parser_t &parser)
1990 {
1991     parser.variables.push_back(util_htnew(PARSER_HT_SIZE));
1992     parser._blocklocals.push_back(parser._locals.size());
1993     parser.typedefs.push_back(util_htnew(TYPEDEF_HT_SIZE));
1994     parser._blocktypedefs.push_back(parser._typedefs.size());
1995     parser._block_ctx.push_back(parser_ctx(parser));
1996 }
1997
1998 static bool parser_leaveblock(parser_t &parser)
1999 {
2000     bool   rv = true;
2001     size_t locals, typedefs;
2002
2003     if (parser.variables.size() <= PARSER_HT_LOCALS) {
2004         parseerror(parser, "internal error: parser_leaveblock with no block");
2005         return false;
2006     }
2007
2008     util_htdel(parser.variables.back());
2009
2010     parser.variables.pop_back();
2011     if (!parser._blocklocals.size()) {
2012         parseerror(parser, "internal error: parser_leaveblock with no block (2)");
2013         return false;
2014     }
2015
2016     locals = parser._blocklocals.back();
2017     parser._blocklocals.pop_back();
2018     parser._locals.resize(locals);
2019
2020     typedefs = parser._blocktypedefs.back();
2021     parser._typedefs.resize(typedefs);
2022     util_htdel(parser.typedefs.back());
2023     parser.typedefs.pop_back();
2024
2025     parser._block_ctx.pop_back();
2026
2027     return rv;
2028 }
2029
2030 static void parser_addlocal(parser_t &parser, const char *name, ast_expression *e)
2031 {
2032     parser._locals.push_back(e);
2033     util_htset(parser.variables.back(), name, (void*)e);
2034 }
2035 static void parser_addlocal(parser_t &parser, const std::string &name, ast_expression *e) {
2036     return parser_addlocal(parser, name.c_str(), e);
2037 }
2038
2039 static void parser_addglobal(parser_t &parser, const char *name, ast_expression *e)
2040 {
2041     parser.globals.push_back(e);
2042     util_htset(parser.htglobals, name, e);
2043 }
2044 static void parser_addglobal(parser_t &parser, const std::string &name, ast_expression *e) {
2045     return parser_addglobal(parser, name.c_str(), e);
2046 }
2047
2048 static ast_expression* process_condition(parser_t &parser, ast_expression *cond, bool *_ifnot)
2049 {
2050     bool       ifnot = false;
2051     ast_unary *unary;
2052     ast_expression *prev;
2053
2054     if (cond->m_vtype == TYPE_VOID || cond->m_vtype >= TYPE_VARIANT) {
2055         char ty[1024];
2056         ast_type_to_string(cond, ty, sizeof(ty));
2057         compile_error(cond->m_context, "invalid type for if() condition: %s", ty);
2058     }
2059
2060     if (OPTS_FLAG(FALSE_EMPTY_STRINGS) && cond->m_vtype == TYPE_STRING)
2061     {
2062         prev = cond;
2063         cond = ast_unary::make(cond->m_context, INSTR_NOT_S, cond);
2064         if (!cond) {
2065             ast_unref(prev);
2066             parseerror(parser, "internal error: failed to process condition");
2067             return nullptr;
2068         }
2069         ifnot = !ifnot;
2070     }
2071     else if (OPTS_FLAG(CORRECT_LOGIC) && cond->m_vtype == TYPE_VECTOR)
2072     {
2073         /* vector types need to be cast to true booleans */
2074         ast_binary *bin = (ast_binary*)cond;
2075         if (!OPTS_FLAG(PERL_LOGIC) || !ast_istype(cond, ast_binary) || !(bin->m_op == INSTR_AND || bin->m_op == INSTR_OR))
2076         {
2077             /* in perl-logic, AND and OR take care of the -fcorrect-logic */
2078             prev = cond;
2079             cond = ast_unary::make(cond->m_context, INSTR_NOT_V, cond);
2080             if (!cond) {
2081                 ast_unref(prev);
2082                 parseerror(parser, "internal error: failed to process condition");
2083                 return nullptr;
2084             }
2085             ifnot = !ifnot;
2086         }
2087     }
2088
2089     unary = (ast_unary*)cond;
2090     /* ast_istype dereferences cond, should test here for safety */
2091     while (cond && ast_istype(cond, ast_unary) && unary->m_op == INSTR_NOT_F)
2092     {
2093         cond = unary->m_operand;
2094         unary->m_operand = nullptr;
2095         delete unary;
2096         ifnot = !ifnot;
2097         unary = (ast_unary*)cond;
2098     }
2099
2100     if (!cond)
2101         parseerror(parser, "internal error: failed to process condition");
2102
2103     if (ifnot) *_ifnot = !*_ifnot;
2104     return cond;
2105 }
2106
2107 static bool parse_if(parser_t &parser, ast_block *block, ast_expression **out)
2108 {
2109     ast_ifthen *ifthen;
2110     ast_expression *cond, *ontrue = nullptr, *onfalse = nullptr;
2111     bool ifnot = false;
2112
2113     lex_ctx_t ctx = parser_ctx(parser);
2114
2115     (void)block; /* not touching */
2116
2117     /* skip the 'if', parse an optional 'not' and check for an opening paren */
2118     if (!parser_next(parser)) {
2119         parseerror(parser, "expected condition or 'not'");
2120         return false;
2121     }
2122     if (parser.tok == Token::IDENT && !strcmp(parser_tokval(parser), "not")) {
2123         ifnot = true;
2124         if (!parser_next(parser)) {
2125             parseerror(parser, "expected condition in parenthesis");
2126             return false;
2127         }
2128     }
2129     if (parser.tok != '(') {
2130         parseerror(parser, "expected 'if' condition in parenthesis");
2131         return false;
2132     }
2133     /* parse into the expression */
2134     if (!parser_next(parser)) {
2135         parseerror(parser, "expected 'if' condition after opening paren");
2136         return false;
2137     }
2138     /* parse the condition */
2139     cond = parse_expression_leave(parser, false, true, false);
2140     if (!cond)
2141         return false;
2142     /* closing paren */
2143     if (parser.tok != ')') {
2144         parseerror(parser, "expected closing paren after 'if' condition");
2145         ast_unref(cond);
2146         return false;
2147     }
2148     /* parse into the 'then' branch */
2149     if (!parser_next(parser)) {
2150         parseerror(parser, "expected statement for on-true branch of 'if'");
2151         ast_unref(cond);
2152         return false;
2153     }
2154     if (!parse_statement_or_block(parser, &ontrue)) {
2155         ast_unref(cond);
2156         return false;
2157     }
2158     if (!ontrue)
2159         ontrue = new ast_block(parser_ctx(parser));
2160     /* check for an else */
2161     if (!strcmp(parser_tokval(parser), "else")) {
2162         /* parse into the 'else' branch */
2163         if (!parser_next(parser)) {
2164             parseerror(parser, "expected on-false branch after 'else'");
2165             delete ontrue;
2166             ast_unref(cond);
2167             return false;
2168         }
2169         if (!parse_statement_or_block(parser, &onfalse)) {
2170             delete ontrue;
2171             ast_unref(cond);
2172             return false;
2173         }
2174     }
2175
2176     cond = process_condition(parser, cond, &ifnot);
2177     if (!cond) {
2178         if (ontrue)  delete ontrue;
2179         if (onfalse) delete onfalse;
2180         return false;
2181     }
2182
2183     if (ifnot)
2184         ifthen = new ast_ifthen(ctx, cond, onfalse, ontrue);
2185     else
2186         ifthen = new ast_ifthen(ctx, cond, ontrue, onfalse);
2187     *out = ifthen;
2188     return true;
2189 }
2190
2191 static bool parse_while_go(parser_t &parser, ast_block *block, ast_expression **out);
2192 static bool parse_while(parser_t &parser, ast_block *block, ast_expression **out)
2193 {
2194     bool rv;
2195     char *label = nullptr;
2196
2197     /* skip the 'while' and get the body */
2198     if (!parser_next(parser)) {
2199         if (OPTS_FLAG(LOOP_LABELS))
2200             parseerror(parser, "expected loop label or 'while' condition in parenthesis");
2201         else
2202             parseerror(parser, "expected 'while' condition in parenthesis");
2203         return false;
2204     }
2205
2206     if (parser.tok == ':') {
2207         if (!OPTS_FLAG(LOOP_LABELS))
2208             parseerror(parser, "labeled loops not activated, try using -floop-labels");
2209         if (!parser_next(parser) || parser.tok != Token::IDENT) {
2210             parseerror(parser, "expected loop label");
2211             return false;
2212         }
2213         label = util_strdup(parser_tokval(parser));
2214         if (!parser_next(parser)) {
2215             mem_d(label);
2216             parseerror(parser, "expected 'while' condition in parenthesis");
2217             return false;
2218         }
2219     }
2220
2221     if (parser.tok != '(') {
2222         parseerror(parser, "expected 'while' condition in parenthesis");
2223         return false;
2224     }
2225
2226     parser.breaks.push_back(label);
2227     parser.continues.push_back(label);
2228
2229     rv = parse_while_go(parser, block, out);
2230     if (label)
2231         mem_d(label);
2232     if (parser.breaks.back() != label || parser.continues.back() != label) {
2233         parseerror(parser, "internal error: label stack corrupted");
2234         rv = false;
2235         delete *out;
2236         *out = nullptr;
2237     }
2238     else {
2239         parser.breaks.pop_back();
2240         parser.continues.pop_back();
2241     }
2242     return rv;
2243 }
2244
2245 static bool parse_while_go(parser_t &parser, ast_block *block, ast_expression **out)
2246 {
2247     ast_loop *aloop;
2248     ast_expression *cond, *ontrue;
2249
2250     bool ifnot = false;
2251
2252     lex_ctx_t ctx = parser_ctx(parser);
2253
2254     (void)block; /* not touching */
2255
2256     /* parse into the expression */
2257     if (!parser_next(parser)) {
2258         parseerror(parser, "expected 'while' condition after opening paren");
2259         return false;
2260     }
2261     /* parse the condition */
2262     cond = parse_expression_leave(parser, false, true, false);
2263     if (!cond)
2264         return false;
2265     /* closing paren */
2266     if (parser.tok != ')') {
2267         parseerror(parser, "expected closing paren after 'while' condition");
2268         ast_unref(cond);
2269         return false;
2270     }
2271     /* parse into the 'then' branch */
2272     if (!parser_next(parser)) {
2273         parseerror(parser, "expected while-loop body");
2274         ast_unref(cond);
2275         return false;
2276     }
2277     if (!parse_statement_or_block(parser, &ontrue)) {
2278         ast_unref(cond);
2279         return false;
2280     }
2281
2282     cond = process_condition(parser, cond, &ifnot);
2283     if (!cond) {
2284         ast_unref(ontrue);
2285         return false;
2286     }
2287     aloop = new ast_loop(ctx, nullptr, cond, ifnot, nullptr, false, nullptr, ontrue);
2288     *out = aloop;
2289     return true;
2290 }
2291
2292 static bool parse_dowhile_go(parser_t &parser, ast_block *block, ast_expression **out);
2293 static bool parse_dowhile(parser_t &parser, ast_block *block, ast_expression **out)
2294 {
2295     bool rv;
2296     char *label = nullptr;
2297
2298     /* skip the 'do' and get the body */
2299     if (!parser_next(parser)) {
2300         if (OPTS_FLAG(LOOP_LABELS))
2301             parseerror(parser, "expected loop label or body");
2302         else
2303             parseerror(parser, "expected loop body");
2304         return false;
2305     }
2306
2307     if (parser.tok == ':') {
2308         if (!OPTS_FLAG(LOOP_LABELS))
2309             parseerror(parser, "labeled loops not activated, try using -floop-labels");
2310         if (!parser_next(parser) || parser.tok != Token::IDENT) {
2311             parseerror(parser, "expected loop label");
2312             return false;
2313         }
2314         label = util_strdup(parser_tokval(parser));
2315         if (!parser_next(parser)) {
2316             mem_d(label);
2317             parseerror(parser, "expected loop body");
2318             return false;
2319         }
2320     }
2321
2322     parser.breaks.push_back(label);
2323     parser.continues.push_back(label);
2324
2325     rv = parse_dowhile_go(parser, block, out);
2326     if (label)
2327         mem_d(label);
2328     if (parser.breaks.back() != label || parser.continues.back() != label) {
2329         parseerror(parser, "internal error: label stack corrupted");
2330         rv = false;
2331         delete *out;
2332         *out = nullptr;
2333     }
2334     else {
2335         parser.breaks.pop_back();
2336         parser.continues.pop_back();
2337     }
2338     return rv;
2339 }
2340
2341 static bool parse_dowhile_go(parser_t &parser, ast_block *block, ast_expression **out)
2342 {
2343     ast_loop *aloop;
2344     ast_expression *cond, *ontrue;
2345
2346     bool ifnot = false;
2347
2348     lex_ctx_t ctx = parser_ctx(parser);
2349
2350     (void)block; /* not touching */
2351
2352     if (!parse_statement_or_block(parser, &ontrue))
2353         return false;
2354
2355     /* expect the "while" */
2356     if (parser.tok != Token::KEYWORD ||
2357         strcmp(parser_tokval(parser), "while"))
2358     {
2359         parseerror(parser, "expected 'while' and condition");
2360         delete ontrue;
2361         return false;
2362     }
2363
2364     /* skip the 'while' and check for opening paren */
2365     if (!parser_next(parser) || parser.tok != '(') {
2366         parseerror(parser, "expected 'while' condition in parenthesis");
2367         delete ontrue;
2368         return false;
2369     }
2370     /* parse into the expression */
2371     if (!parser_next(parser)) {
2372         parseerror(parser, "expected 'while' condition after opening paren");
2373         delete ontrue;
2374         return false;
2375     }
2376     /* parse the condition */
2377     cond = parse_expression_leave(parser, false, true, false);
2378     if (!cond)
2379         return false;
2380     /* closing paren */
2381     if (parser.tok != ')') {
2382         parseerror(parser, "expected closing paren after 'while' condition");
2383         delete ontrue;
2384         ast_unref(cond);
2385         return false;
2386     }
2387     /* parse on */
2388     if (!parser_next(parser) || parser.tok != ';') {
2389         parseerror(parser, "expected semicolon after condition");
2390         delete ontrue;
2391         ast_unref(cond);
2392         return false;
2393     }
2394
2395     if (!parser_next(parser)) {
2396         parseerror(parser, "parse error");
2397         delete ontrue;
2398         ast_unref(cond);
2399         return false;
2400     }
2401
2402     cond = process_condition(parser, cond, &ifnot);
2403     if (!cond) {
2404         delete ontrue;
2405         return false;
2406     }
2407     aloop = new ast_loop(ctx, nullptr, nullptr, false, cond, ifnot, nullptr, ontrue);
2408     *out = aloop;
2409     return true;
2410 }
2411
2412 static bool parse_for_go(parser_t &parser, ast_block *block, ast_expression **out);
2413 static bool parse_for(parser_t &parser, ast_block *block, ast_expression **out)
2414 {
2415     bool rv;
2416     char *label = nullptr;
2417
2418     /* skip the 'for' and check for opening paren */
2419     if (!parser_next(parser)) {
2420         if (OPTS_FLAG(LOOP_LABELS))
2421             parseerror(parser, "expected loop label or 'for' expressions in parenthesis");
2422         else
2423             parseerror(parser, "expected 'for' expressions in parenthesis");
2424         return false;
2425     }
2426
2427     if (parser.tok == ':') {
2428         if (!OPTS_FLAG(LOOP_LABELS))
2429             parseerror(parser, "labeled loops not activated, try using -floop-labels");
2430         if (!parser_next(parser) || parser.tok != Token::IDENT) {
2431             parseerror(parser, "expected loop label");
2432             return false;
2433         }
2434         label = util_strdup(parser_tokval(parser));
2435         if (!parser_next(parser)) {
2436             mem_d(label);
2437             parseerror(parser, "expected 'for' expressions in parenthesis");
2438             return false;
2439         }
2440     }
2441
2442     if (parser.tok != '(') {
2443         parseerror(parser, "expected 'for' expressions in parenthesis");
2444         return false;
2445     }
2446
2447     parser.breaks.push_back(label);
2448     parser.continues.push_back(label);
2449
2450     rv = parse_for_go(parser, block, out);
2451     if (label)
2452         mem_d(label);
2453     if (parser.breaks.back() != label || parser.continues.back() != label) {
2454         parseerror(parser, "internal error: label stack corrupted");
2455         rv = false;
2456         delete *out;
2457         *out = nullptr;
2458     }
2459     else {
2460         parser.breaks.pop_back();
2461         parser.continues.pop_back();
2462     }
2463     return rv;
2464 }
2465 static bool parse_for_go(parser_t &parser, ast_block *block, ast_expression **out)
2466 {
2467     ast_loop       *aloop;
2468     ast_expression *initexpr, *cond, *increment, *ontrue;
2469     ast_value      *typevar;
2470
2471     bool ifnot  = false;
2472
2473     lex_ctx_t ctx = parser_ctx(parser);
2474
2475     parser_enterblock(parser);
2476
2477     initexpr  = nullptr;
2478     cond      = nullptr;
2479     increment = nullptr;
2480     ontrue    = nullptr;
2481
2482     /* parse into the expression */
2483     if (!parser_next(parser)) {
2484         parseerror(parser, "expected 'for' initializer after opening paren");
2485         goto onerr;
2486     }
2487
2488     typevar = nullptr;
2489     if (parser.tok == Token::IDENT)
2490         typevar = parser_find_typedef(parser, parser_tokval(parser), 0);
2491
2492     if (typevar || parser.tok == Token::TYPENAME) {
2493         if (!parse_variable(parser, block, true, CV_VAR, typevar, false, false, 0, nullptr))
2494             goto onerr;
2495     }
2496     else if (parser.tok != ';')
2497     {
2498         initexpr = parse_expression_leave(parser, false, false, false);
2499         if (!initexpr)
2500             goto onerr;
2501         /* move on to condition */
2502         if (parser.tok != ';') {
2503             parseerror(parser, "expected semicolon after for-loop initializer");
2504             goto onerr;
2505         }
2506         if (!parser_next(parser)) {
2507             parseerror(parser, "expected for-loop condition");
2508             goto onerr;
2509         }
2510     } else if (!parser_next(parser)) {
2511         parseerror(parser, "expected for-loop condition");
2512         goto onerr;
2513     }
2514
2515     /* parse the condition */
2516     if (parser.tok != ';') {
2517         cond = parse_expression_leave(parser, false, true, false);
2518         if (!cond)
2519             goto onerr;
2520     }
2521     /* move on to incrementor */
2522     if (parser.tok != ';') {
2523         parseerror(parser, "expected semicolon after for-loop initializer");
2524         goto onerr;
2525     }
2526     if (!parser_next(parser)) {
2527         parseerror(parser, "expected for-loop condition");
2528         goto onerr;
2529     }
2530
2531     /* parse the incrementor */
2532     if (parser.tok != ')') {
2533         lex_ctx_t condctx = parser_ctx(parser);
2534         increment = parse_expression_leave(parser, false, false, false);
2535         if (!increment)
2536             goto onerr;
2537         if (!increment->m_side_effects) {
2538             if (compile_warning(condctx, WARN_EFFECTLESS_STATEMENT, "statement has no effect"))
2539                 goto onerr;
2540         }
2541     }
2542
2543     /* closing paren */
2544     if (parser.tok != ')') {
2545         parseerror(parser, "expected closing paren after 'for-loop' incrementor");
2546         goto onerr;
2547     }
2548     /* parse into the 'then' branch */
2549     if (!parser_next(parser)) {
2550         parseerror(parser, "expected for-loop body");
2551         goto onerr;
2552     }
2553     if (!parse_statement_or_block(parser, &ontrue))
2554         goto onerr;
2555
2556     if (cond) {
2557         cond = process_condition(parser, cond, &ifnot);
2558         if (!cond)
2559             goto onerr;
2560     }
2561     aloop = new ast_loop(ctx, initexpr, cond, ifnot, nullptr, false, increment, ontrue);
2562     *out = aloop;
2563
2564     if (!parser_leaveblock(parser)) {
2565         delete aloop;
2566         return false;
2567     }
2568     return true;
2569 onerr:
2570     if (initexpr)  ast_unref(initexpr);
2571     if (cond)      ast_unref(cond);
2572     if (increment) ast_unref(increment);
2573     (void)!parser_leaveblock(parser);
2574     return false;
2575 }
2576
2577 static bool parse_return(parser_t &parser, ast_block *block, ast_expression **out)
2578 {
2579     ast_expression *exp      = nullptr;
2580     ast_expression *var      = nullptr;
2581     ast_return     *ret      = nullptr;
2582     ast_value      *retval   = parser.function->m_return_value;
2583     ast_value      *expected = parser.function->m_function_type;
2584
2585     lex_ctx_t ctx = parser_ctx(parser);
2586
2587     (void)block; /* not touching */
2588
2589     if (!parser_next(parser)) {
2590         parseerror(parser, "expected return expression");
2591         return false;
2592     }
2593
2594     /* return assignments */
2595     if (parser.tok == '=') {
2596         if (!OPTS_FLAG(RETURN_ASSIGNMENTS)) {
2597             parseerror(parser, "return assignments not activated, try using -freturn-assigments");
2598             return false;
2599         }
2600
2601         if (type_store_instr[expected->m_next->m_vtype] == VINSTR_END) {
2602             char ty1[1024];
2603             ast_type_to_string(expected->m_next, ty1, sizeof(ty1));
2604             parseerror(parser, "invalid return type: `%s'", ty1);
2605             return false;
2606         }
2607
2608         if (!parser_next(parser)) {
2609             parseerror(parser, "expected return assignment expression");
2610             return false;
2611         }
2612
2613         if (!(exp = parse_expression_leave(parser, false, false, false)))
2614             return false;
2615
2616         /* prepare the return value */
2617         if (!retval) {
2618             retval = new ast_value(ctx, "#LOCAL_RETURN", TYPE_VOID);
2619             retval->adoptType(*expected->m_next);
2620             parser.function->m_return_value = retval;
2621             parser.function->m_return_value->m_flags |= AST_FLAG_NOREF;
2622         }
2623
2624         if (!exp->compareType(*retval)) {
2625             char ty1[1024], ty2[1024];
2626             ast_type_to_string(exp, ty1, sizeof(ty1));
2627             ast_type_to_string(retval, ty2, sizeof(ty2));
2628             parseerror(parser, "invalid type for return value: `%s', expected `%s'", ty1, ty2);
2629         }
2630
2631         /* store to 'return' local variable */
2632         var = new ast_store(
2633             ctx,
2634             type_store_instr[expected->m_next->m_vtype],
2635             retval, exp);
2636
2637         if (!var) {
2638             ast_unref(exp);
2639             return false;
2640         }
2641
2642         if (parser.tok != ';')
2643             parseerror(parser, "missing semicolon after return assignment");
2644         else if (!parser_next(parser))
2645             parseerror(parser, "parse error after return assignment");
2646
2647         *out = var;
2648         return true;
2649     }
2650
2651     if (parser.tok != ';') {
2652         exp = parse_expression(parser, false, false);
2653         if (!exp)
2654             return false;
2655
2656         if (exp->m_vtype != TYPE_NIL &&
2657             exp->m_vtype != (expected)->m_next->m_vtype)
2658         {
2659             parseerror(parser, "return with invalid expression");
2660         }
2661
2662         ret = new ast_return(ctx, exp);
2663         if (!ret) {
2664             ast_unref(exp);
2665             return false;
2666         }
2667     } else {
2668         if (!parser_next(parser))
2669             parseerror(parser, "parse error");
2670
2671         if (!retval && expected->m_next->m_vtype != TYPE_VOID)
2672         {
2673             (void)!parsewarning(parser, WARN_MISSING_RETURN_VALUES, "return without value");
2674         }
2675         ret = new ast_return(ctx, retval);
2676     }
2677     *out = ret;
2678     return true;
2679 }
2680
2681 static bool parse_break_continue(parser_t &parser, ast_block *block, ast_expression **out, bool is_continue)
2682 {
2683     size_t i;
2684     unsigned int levels = 0;
2685     lex_ctx_t ctx = parser_ctx(parser);
2686     auto &loops = (is_continue ? parser.continues : parser.breaks);
2687
2688     (void)block; /* not touching */
2689     if (!parser_next(parser)) {
2690         parseerror(parser, "expected semicolon or loop label");
2691         return false;
2692     }
2693
2694     if (loops.empty()) {
2695         if (is_continue)
2696             parseerror(parser, "`continue` can only be used inside loops");
2697         else
2698             parseerror(parser, "`break` can only be used inside loops or switches");
2699     }
2700
2701     if (parser.tok == Token::IDENT) {
2702         if (!OPTS_FLAG(LOOP_LABELS))
2703             parseerror(parser, "labeled loops not activated, try using -floop-labels");
2704         i = loops.size();
2705         while (i--) {
2706             if (loops[i] && !strcmp(loops[i], parser_tokval(parser)))
2707                 break;
2708             if (!i) {
2709                 parseerror(parser, "no such loop to %s: `%s`",
2710                            (is_continue ? "continue" : "break out of"),
2711                            parser_tokval(parser));
2712                 return false;
2713             }
2714             ++levels;
2715         }
2716         if (!parser_next(parser)) {
2717             parseerror(parser, "expected semicolon");
2718             return false;
2719         }
2720     }
2721
2722     if (parser.tok != ';') {
2723         parseerror(parser, "expected semicolon");
2724         return false;
2725     }
2726
2727     if (!parser_next(parser))
2728         parseerror(parser, "parse error");
2729
2730     *out = new ast_breakcont(ctx, is_continue, levels);
2731     return true;
2732 }
2733
2734 /* returns true when it was a variable qualifier, false otherwise!
2735  * on error, cvq is set to CV_WRONG
2736  */
2737 struct attribute_t {
2738     const char *name;
2739     size_t      flag;
2740 };
2741
2742 static bool parse_qualifiers(parser_t &parser, bool with_local, int *cvq, bool *noref, bool *is_static, uint32_t *_flags, char **message)
2743 {
2744     bool had_const    = false;
2745     bool had_var      = false;
2746     bool had_noref    = false;
2747     bool had_attrib   = false;
2748     bool had_static   = false;
2749     uint32_t flags    = 0;
2750
2751     static attribute_t attributes[] = {
2752         { "noreturn",   AST_FLAG_NORETURN   },
2753         { "inline",     AST_FLAG_INLINE     },
2754         { "eraseable",  AST_FLAG_ERASEABLE  },
2755         { "accumulate", AST_FLAG_ACCUMULATE },
2756         { "last",       AST_FLAG_FINAL_DECL }
2757     };
2758
2759    *cvq = CV_NONE;
2760
2761     for (;;) {
2762         size_t i;
2763         if (parser.tok == Token::ATTRIBUTE_OPEN) {
2764             had_attrib = true;
2765             /* parse an attribute */
2766             if (!parser_next(parser)) {
2767                 parseerror(parser, "expected attribute after `[[`");
2768                 *cvq = CV_WRONG;
2769                 return false;
2770             }
2771
2772             for (i = 0; i < GMQCC_ARRAY_COUNT(attributes); i++) {
2773                 if (!strcmp(parser_tokval(parser), attributes[i].name)) {
2774                     flags |= attributes[i].flag;
2775                     if (!parser_next(parser) || parser.tok != Token::ATTRIBUTE_CLOSE) {
2776                         parseerror(parser, "`%s` attribute has no parameters, expected `]]`",
2777                             attributes[i].name);
2778                         *cvq = CV_WRONG;
2779                         return false;
2780                     }
2781                     break;
2782                 }
2783             }
2784
2785             if (i != GMQCC_ARRAY_COUNT(attributes))
2786                 goto leave;
2787
2788
2789             if (!strcmp(parser_tokval(parser), "noref")) {
2790                 had_noref = true;
2791                 if (!parser_next(parser) || parser.tok != Token::ATTRIBUTE_CLOSE) {
2792                     parseerror(parser, "`noref` attribute has no parameters, expected `]]`");
2793                     *cvq = CV_WRONG;
2794                     return false;
2795                 }
2796             }
2797             else if (!strcmp(parser_tokval(parser), "alias") && !(flags & AST_FLAG_ALIAS)) {
2798                 flags   |= AST_FLAG_ALIAS;
2799                 *message = nullptr;
2800
2801                 if (!parser_next(parser)) {
2802                     parseerror(parser, "parse error in attribute");
2803                     goto argerr;
2804                 }
2805
2806                 if (parser.tok == '(') {
2807                     if (!parser_next(parser) || parser.tok != Token::STRINGCONST) {
2808                         parseerror(parser, "`alias` attribute missing parameter");
2809                         goto argerr;
2810                     }
2811
2812                     *message = util_strdup(parser_tokval(parser));
2813
2814                     if (!parser_next(parser)) {
2815                         parseerror(parser, "parse error in attribute");
2816                         goto argerr;
2817                     }
2818
2819                     if (parser.tok != ')') {
2820                         parseerror(parser, "`alias` attribute expected `)` after parameter");
2821                         goto argerr;
2822                     }
2823
2824                     if (!parser_next(parser)) {
2825                         parseerror(parser, "parse error in attribute");
2826                         goto argerr;
2827                     }
2828                 }
2829
2830                 if (parser.tok != Token::ATTRIBUTE_CLOSE) {
2831                     parseerror(parser, "`alias` attribute expected `]]`");
2832                     goto argerr;
2833                 }
2834             }
2835             else if (!strcmp(parser_tokval(parser), "deprecated") && !(flags & AST_FLAG_DEPRECATED)) {
2836                 flags   |= AST_FLAG_DEPRECATED;
2837                 *message = nullptr;
2838
2839                 if (!parser_next(parser)) {
2840                     parseerror(parser, "parse error in attribute");
2841                     goto argerr;
2842                 }
2843
2844                 if (parser.tok == '(') {
2845                     if (!parser_next(parser) || parser.tok != Token::STRINGCONST) {
2846                         parseerror(parser, "`deprecated` attribute missing parameter");
2847                         goto argerr;
2848                     }
2849
2850                     *message = util_strdup(parser_tokval(parser));
2851
2852                     if (!parser_next(parser)) {
2853                         parseerror(parser, "parse error in attribute");
2854                         goto argerr;
2855                     }
2856
2857                     if(parser.tok != ')') {
2858                         parseerror(parser, "`deprecated` attribute expected `)` after parameter");
2859                         goto argerr;
2860                     }
2861
2862                     if (!parser_next(parser)) {
2863                         parseerror(parser, "parse error in attribute");
2864                         goto argerr;
2865                     }
2866                 }
2867                 /* no message */
2868                 if (parser.tok != Token::ATTRIBUTE_CLOSE) {
2869                     parseerror(parser, "`deprecated` attribute expected `]]`");
2870
2871                     argerr: /* ugly */
2872                     if (*message) mem_d(*message);
2873                     *message = nullptr;
2874                     *cvq     = CV_WRONG;
2875                     return false;
2876                 }
2877             }
2878             else if (!strcmp(parser_tokval(parser), "coverage") && !(flags & AST_FLAG_COVERAGE)) {
2879                 flags |= AST_FLAG_COVERAGE;
2880                 if (!parser_next(parser)) {
2881                     error_in_coverage:
2882                     parseerror(parser, "parse error in coverage attribute");
2883                     *cvq = CV_WRONG;
2884                     return false;
2885                 }
2886                 if (parser.tok == '(') {
2887                     if (!parser_next(parser)) {
2888                         bad_coverage_arg:
2889                         parseerror(parser, "invalid parameter for coverage() attribute\n"
2890                                            "valid are: block");
2891                         *cvq = CV_WRONG;
2892                         return false;
2893                     }
2894                     if (parser.tok != ')') {
2895                         do {
2896                             if (parser.tok != Token::IDENT)
2897                                 goto bad_coverage_arg;
2898                             if (!strcmp(parser_tokval(parser), "block"))
2899                                 flags |= AST_FLAG_BLOCK_COVERAGE;
2900                             else if (!strcmp(parser_tokval(parser), "none"))
2901                                 flags &= ~(AST_FLAG_COVERAGE_MASK);
2902                             else
2903                                 goto bad_coverage_arg;
2904                             if (!parser_next(parser))
2905                                 goto error_in_coverage;
2906                             if (parser.tok == ',') {
2907                                 if (!parser_next(parser))
2908                                     goto error_in_coverage;
2909                             }
2910                         } while (parser.tok != ')');
2911                     }
2912                     if (parser.tok != ')' || !parser_next(parser))
2913                         goto error_in_coverage;
2914                 } else {
2915                     /* without parameter [[coverage]] equals [[coverage(block)]] */
2916                     flags |= AST_FLAG_BLOCK_COVERAGE;
2917                 }
2918             }
2919             else
2920             {
2921                 /* Skip tokens until we hit a ]] */
2922                 (void)!parsewarning(parser, WARN_UNKNOWN_ATTRIBUTE, "unknown attribute starting with `%s`", parser_tokval(parser));
2923                 while (parser.tok != Token::ATTRIBUTE_CLOSE) {
2924                     if (!parser_next(parser)) {
2925                         parseerror(parser, "error inside attribute");
2926                         *cvq = CV_WRONG;
2927                         return false;
2928                     }
2929                 }
2930             }
2931         }
2932         else if (with_local && !strcmp(parser_tokval(parser), "static"))
2933             had_static = true;
2934         else if (!strcmp(parser_tokval(parser), "const"))
2935             had_const = true;
2936         else if (!strcmp(parser_tokval(parser), "var"))
2937             had_var = true;
2938         else if (with_local && !strcmp(parser_tokval(parser), "local"))
2939             had_var = true;
2940         else if (!strcmp(parser_tokval(parser), "noref"))
2941             had_noref = true;
2942         else if (!had_const && !had_var && !had_noref && !had_attrib && !had_static && !flags) {
2943             return false;
2944         }
2945         else
2946             break;
2947
2948         leave:
2949         if (!parser_next(parser))
2950             goto onerr;
2951     }
2952     if (had_const)
2953         *cvq = CV_CONST;
2954     else if (had_var)
2955         *cvq = CV_VAR;
2956     else
2957         *cvq = CV_NONE;
2958     *noref     = had_noref;
2959     *is_static = had_static;
2960     *_flags    = flags;
2961     return true;
2962 onerr:
2963     parseerror(parser, "parse error after variable qualifier");
2964     *cvq = CV_WRONG;
2965     return true;
2966 }
2967
2968 static bool parse_switch_go(parser_t &parser, ast_block *block, ast_expression **out);
2969 static bool parse_switch(parser_t &parser, ast_block *block, ast_expression **out)
2970 {
2971     bool rv;
2972     char *label = nullptr;
2973
2974     /* skip the 'while' and get the body */
2975     if (!parser_next(parser)) {
2976         if (OPTS_FLAG(LOOP_LABELS))
2977             parseerror(parser, "expected loop label or 'switch' operand in parenthesis");
2978         else
2979             parseerror(parser, "expected 'switch' operand in parenthesis");
2980         return false;
2981     }
2982
2983     if (parser.tok == ':') {
2984         if (!OPTS_FLAG(LOOP_LABELS))
2985             parseerror(parser, "labeled loops not activated, try using -floop-labels");
2986         if (!parser_next(parser) || parser.tok != Token::IDENT) {
2987             parseerror(parser, "expected loop label");
2988             return false;
2989         }
2990         label = util_strdup(parser_tokval(parser));
2991         if (!parser_next(parser)) {
2992             mem_d(label);
2993             parseerror(parser, "expected 'switch' operand in parenthesis");
2994             return false;
2995         }
2996     }
2997
2998     if (parser.tok != '(') {
2999         parseerror(parser, "expected 'switch' operand in parenthesis");
3000         return false;
3001     }
3002
3003     parser.breaks.push_back(label);
3004
3005     rv = parse_switch_go(parser, block, out);
3006     if (label)
3007         mem_d(label);
3008     if (parser.breaks.back() != label) {
3009         parseerror(parser, "internal error: label stack corrupted");
3010         rv = false;
3011         delete *out;
3012         *out = nullptr;
3013     }
3014     else {
3015         parser.breaks.pop_back();
3016     }
3017     return rv;
3018 }
3019
3020 static bool parse_switch_go(parser_t &parser, ast_block *block, ast_expression **out)
3021 {
3022     ast_expression *operand;
3023     ast_value      *opval;
3024     ast_value      *typevar;
3025     ast_switch     *switchnode;
3026     ast_switch_case swcase;
3027
3028     int  cvq;
3029     bool noref, is_static;
3030     uint32_t qflags = 0;
3031
3032     lex_ctx_t ctx = parser_ctx(parser);
3033
3034     (void)block; /* not touching */
3035     (void)opval;
3036
3037     /* parse into the expression */
3038     if (!parser_next(parser)) {
3039         parseerror(parser, "expected switch operand");
3040         return false;
3041     }
3042     /* parse the operand */
3043     operand = parse_expression_leave(parser, false, false, false);
3044     if (!operand)
3045         return false;
3046
3047     switchnode = new ast_switch(ctx, operand);
3048
3049     /* closing paren */
3050     if (parser.tok != ')') {
3051         delete switchnode;
3052         parseerror(parser, "expected closing paren after 'switch' operand");
3053         return false;
3054     }
3055
3056     /* parse over the opening paren */
3057     if (!parser_next(parser) || parser.tok != '{') {
3058         delete switchnode;
3059         parseerror(parser, "expected list of cases");
3060         return false;
3061     }
3062
3063     if (!parser_next(parser)) {
3064         delete switchnode;
3065         parseerror(parser, "expected 'case' or 'default'");
3066         return false;
3067     }
3068
3069     /* new block; allow some variables to be declared here */
3070     parser_enterblock(parser);
3071     while (true) {
3072         typevar = nullptr;
3073         if (parser.tok == Token::IDENT)
3074             typevar = parser_find_typedef(parser, parser_tokval(parser), 0);
3075         if (typevar || parser.tok == Token::TYPENAME) {
3076             if (!parse_variable(parser, block, true, CV_NONE, typevar, false, false, 0, nullptr)) {
3077                 delete switchnode;
3078                 return false;
3079             }
3080             continue;
3081         }
3082         if (parse_qualifiers(parser, true, &cvq, &noref, &is_static, &qflags, nullptr))
3083         {
3084             if (cvq == CV_WRONG) {
3085                 delete switchnode;
3086                 return false;
3087             }
3088             if (!parse_variable(parser, block, true, cvq, nullptr, noref, is_static, qflags, nullptr)) {
3089                 delete switchnode;
3090                 return false;
3091             }
3092             continue;
3093         }
3094         break;
3095     }
3096
3097     /* case list! */
3098     while (parser.tok != '}') {
3099         ast_block *caseblock;
3100
3101         if (!strcmp(parser_tokval(parser), "case")) {
3102             if (!parser_next(parser)) {
3103                 delete switchnode;
3104                 parseerror(parser, "expected expression for case");
3105                 return false;
3106             }
3107             swcase.m_value = parse_expression_leave(parser, false, false, false);
3108
3109             if (!operand->compareType(*swcase.m_value)) {
3110                 char ty1[1024];
3111                 char ty2[1024];
3112
3113                 ast_type_to_string(swcase.m_value, ty1, sizeof ty1);
3114                 ast_type_to_string(operand, ty2, sizeof ty2);
3115
3116                 auto fnLiteral = [](ast_expression *expression) -> char* {
3117                     if (!ast_istype(expression, ast_value))
3118                         return nullptr;
3119                     ast_value *value = (ast_value *)expression;
3120                     if (!value->m_hasvalue)
3121                         return nullptr;
3122                     char *string = nullptr;
3123                     basic_value_t *constval = &value->m_constval;
3124                     switch (value->m_vtype)
3125                     {
3126                     case TYPE_FLOAT:
3127                         util_asprintf(&string, "%.2f", constval->vfloat);
3128                         return string;
3129                     case TYPE_VECTOR:
3130                         util_asprintf(&string, "'%.2f %.2f %.2f'",
3131                             constval->vvec.x,
3132                             constval->vvec.y,
3133                             constval->vvec.z);
3134                         return string;
3135                     case TYPE_STRING:
3136                         util_asprintf(&string, "\"%s\"", constval->vstring);
3137                         return string;
3138                     default:
3139                         break;
3140                     }
3141                     return nullptr;
3142                 };
3143
3144                 char *literal = fnLiteral(swcase.m_value);
3145                 if (literal)
3146                     compile_error(parser_ctx(parser), "incompatible type `%s` for switch case `%s` expected `%s`", ty1, literal, ty2);
3147                 else
3148                     compile_error(parser_ctx(parser), "incompatible type `%s` for switch case expected `%s`", ty1, ty2);
3149                 mem_d(literal);
3150                 delete switchnode;
3151                 return false;
3152             }
3153
3154             if (!swcase.m_value) {
3155                 delete switchnode;
3156                 parseerror(parser, "expected expression for case");
3157                 return false;
3158             }
3159             if (!OPTS_FLAG(RELAXED_SWITCH)) {
3160                 if (!ast_istype(swcase.m_value, ast_value)) { /* || ((ast_value*)swcase.m_value)->m_cvq != CV_CONST) { */
3161                     parseerror(parser, "case on non-constant values need to be explicitly enabled via -frelaxed-switch");
3162                     ast_unref(operand);
3163                     return false;
3164                 }
3165             }
3166         }
3167         else if (!strcmp(parser_tokval(parser), "default")) {
3168             swcase.m_value = nullptr;
3169             if (!parser_next(parser)) {
3170                 delete switchnode;
3171                 parseerror(parser, "expected colon");
3172                 return false;
3173             }
3174         }
3175         else {
3176             delete switchnode;
3177             parseerror(parser, "expected 'case' or 'default'");
3178             return false;
3179         }
3180
3181         /* Now the colon and body */
3182         if (parser.tok != ':') {
3183             if (swcase.m_value) ast_unref(swcase.m_value);
3184             delete switchnode;
3185             parseerror(parser, "expected colon");
3186             return false;
3187         }
3188
3189         if (!parser_next(parser)) {
3190             if (swcase.m_value) ast_unref(swcase.m_value);
3191             delete switchnode;
3192             parseerror(parser, "expected statements or case");
3193             return false;
3194         }
3195         caseblock = new ast_block(parser_ctx(parser));
3196         if (!caseblock) {
3197             if (swcase.m_value) ast_unref(swcase.m_value);
3198             delete switchnode;
3199             return false;
3200         }
3201         swcase.m_code = caseblock;
3202         switchnode->m_cases.push_back(swcase);
3203         while (true) {
3204             ast_expression *expr;
3205             if (parser.tok == '}')
3206                 break;
3207             if (parser.tok == Token::KEYWORD) {
3208                 if (!strcmp(parser_tokval(parser), "case") ||
3209                     !strcmp(parser_tokval(parser), "default"))
3210                 {
3211                     break;
3212                 }
3213             }
3214             if (!parse_statement(parser, caseblock, &expr, true)) {
3215                 delete switchnode;
3216                 return false;
3217             }
3218             if (!expr)
3219                 continue;
3220             if (!caseblock->addExpr(expr)) {
3221                 delete switchnode;
3222                 return false;
3223             }
3224         }
3225     }
3226
3227     parser_leaveblock(parser);
3228
3229     /* closing paren */
3230     if (parser.tok != '}') {
3231         delete switchnode;
3232         parseerror(parser, "expected closing paren of case list");
3233         return false;
3234     }
3235     if (!parser_next(parser)) {
3236         delete switchnode;
3237         parseerror(parser, "parse error after switch");
3238         return false;
3239     }
3240     *out = switchnode;
3241     return true;
3242 }
3243
3244 /* parse computed goto sides */
3245 static ast_expression *parse_goto_computed(parser_t &parser, ast_expression **side) {
3246     ast_expression *on_true;
3247     ast_expression *on_false;
3248     ast_expression *cond;
3249
3250     if (!*side)
3251         return nullptr;
3252
3253     if (ast_istype(*side, ast_ternary)) {
3254         ast_ternary *tern = (ast_ternary*)*side;
3255         on_true  = parse_goto_computed(parser, &tern->m_on_true);
3256         on_false = parse_goto_computed(parser, &tern->m_on_false);
3257
3258         if (!on_true || !on_false) {
3259             parseerror(parser, "expected label or expression in ternary");
3260             if (on_true) ast_unref(on_true);
3261             if (on_false) ast_unref(on_false);
3262             return nullptr;
3263         }
3264
3265         cond = tern->m_cond;
3266         tern->m_cond = nullptr;
3267         delete tern;
3268         *side = nullptr;
3269         return new ast_ifthen(parser_ctx(parser), cond, on_true, on_false);
3270     } else if (ast_istype(*side, ast_label)) {
3271         ast_goto *gt = new ast_goto(parser_ctx(parser), ((ast_label*)*side)->m_name);
3272         gt->setLabel(reinterpret_cast<ast_label*>(*side));
3273         *side = nullptr;
3274         return gt;
3275     }
3276     return nullptr;
3277 }
3278
3279 static bool parse_goto(parser_t &parser, ast_expression **out)
3280 {
3281     ast_goto       *gt = nullptr;
3282     ast_expression *lbl;
3283
3284     if (!parser_next(parser))
3285         return false;
3286
3287     if (parser.tok != Token::IDENT) {
3288         ast_expression *expression;
3289
3290         /* could be an expression i.e computed goto :-) */
3291         if (parser.tok != '(') {
3292             parseerror(parser, "expected label name after `goto`");
3293             return false;
3294         }
3295
3296         /* failed to parse expression for goto */
3297         if (!(expression = parse_expression(parser, false, true)) ||
3298             !(*out = parse_goto_computed(parser, &expression))) {
3299             parseerror(parser, "invalid goto expression");
3300             if(expression)
3301                 ast_unref(expression);
3302             return false;
3303         }
3304
3305         return true;
3306     }
3307
3308     /* not computed goto */
3309     gt = new ast_goto(parser_ctx(parser), parser_tokval(parser));
3310     lbl = parser_find_label(parser, gt->m_name);
3311     if (lbl) {
3312         if (!ast_istype(lbl, ast_label)) {
3313             parseerror(parser, "internal error: label is not an ast_label");
3314             delete gt;
3315             return false;
3316         }
3317         gt->setLabel(reinterpret_cast<ast_label*>(lbl));
3318     }
3319     else
3320         parser.gotos.push_back(gt);
3321
3322     if (!parser_next(parser) || parser.tok != ';') {
3323         parseerror(parser, "semicolon expected after goto label");
3324         return false;
3325     }
3326     if (!parser_next(parser)) {
3327         parseerror(parser, "parse error after goto");
3328         return false;
3329     }
3330
3331     *out = gt;
3332     return true;
3333 }
3334
3335 static bool parse_skipwhite(parser_t &parser)
3336 {
3337     do {
3338         if (!parser_next(parser))
3339             return false;
3340     } while (parser.tok == Token::WHITE && parser.tok < Token::ERROR);
3341     return parser.tok < Token::ERROR;
3342 }
3343
3344 static bool parse_eol(parser_t &parser)
3345 {
3346     if (!parse_skipwhite(parser))
3347         return false;
3348     return parser.tok == Token::EOL;
3349 }
3350
3351 static bool parse_pragma_do(parser_t &parser)
3352 {
3353     if (!parser_next(parser) ||
3354         parser.tok != Token::IDENT ||
3355         strcmp(parser_tokval(parser), "pragma"))
3356     {
3357         parseerror(parser, "expected `pragma` keyword after `#`, got `%s`", parser_tokval(parser));
3358         return false;
3359     }
3360     if (!parse_skipwhite(parser) || parser.tok != Token::IDENT) {
3361         parseerror(parser, "expected pragma, got `%s`", parser_tokval(parser));
3362         return false;
3363     }
3364
3365     if (!strcmp(parser_tokval(parser), "noref")) {
3366         if (!parse_skipwhite(parser) || parser.tok != Token::INTCONST) {
3367             parseerror(parser, "`noref` pragma requires an argument: 0 or 1");
3368             return false;
3369         }
3370         parser.noref = !!parser_token(parser)->constval.i;
3371         if (!parse_eol(parser)) {
3372             parseerror(parser, "parse error after `noref` pragma");
3373             return false;
3374         }
3375     }
3376     else
3377     {
3378         (void)!parsewarning(parser, WARN_UNKNOWN_PRAGMAS, "ignoring #pragma %s", parser_tokval(parser));
3379
3380         /* skip to eol */
3381         while (!parse_eol(parser)) {
3382             parser_next(parser);
3383         }
3384
3385         return true;
3386     }
3387
3388     return true;
3389 }
3390
3391 static bool parse_pragma(parser_t &parser)
3392 {
3393     parser.lex->flags.preprocessing = true;
3394     parser.lex->flags.mergelines = true;
3395     auto ret = parse_pragma_do(parser);
3396     if (parser.tok != Token::EOL) {
3397         parseerror(parser, "junk after pragma");
3398         ret = false;
3399     }
3400     parser.lex->flags.preprocessing = false;
3401     parser.lex->flags.mergelines = false;
3402     if (!parser_next(parser)) {
3403         parseerror(parser, "parse error after pragma");
3404         ret = false;
3405     }
3406     return ret;
3407 }
3408
3409 static bool parse_statement(parser_t &parser, ast_block *block, ast_expression **out, bool allow_cases)
3410 {
3411     bool       noref, is_static;
3412     int        cvq     = CV_NONE;
3413     uint32_t   qflags  = 0;
3414     ast_value *typevar = nullptr;
3415     char      *vstring = nullptr;
3416
3417     *out = nullptr;
3418
3419     if (parser.tok == Token::IDENT)
3420         typevar = parser_find_typedef(parser, parser_tokval(parser), 0);
3421
3422     if (typevar || parser.tok == Token::TYPENAME || parser.tok == '.' || parser.tok == Token::DOTS)
3423     {
3424         /* local variable */
3425         if (!block) {
3426             parseerror(parser, "cannot declare a variable from here");
3427             return false;
3428         }
3429         if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_QCC) {
3430             if (parsewarning(parser, WARN_EXTENSIONS, "missing 'local' keyword when declaring a local variable"))
3431                 return false;
3432         }
3433         if (!parse_variable(parser, block, false, CV_NONE, typevar, false, false, 0, nullptr))
3434             return false;
3435         return true;
3436     }
3437     else if (parse_qualifiers(parser, !!block, &cvq, &noref, &is_static, &qflags, &vstring))
3438     {
3439         if (cvq == CV_WRONG)
3440             return false;
3441         return parse_variable(parser, block, false, cvq, nullptr, noref, is_static, qflags, vstring);
3442     }
3443     else if (parser.tok == Token::KEYWORD)
3444     {
3445         if (!strcmp(parser_tokval(parser), "__builtin_debug_printtype"))
3446         {
3447             char ty[1024];
3448             ast_value *tdef;
3449
3450             if (!parser_next(parser)) {
3451                 parseerror(parser, "parse error after __builtin_debug_printtype");
3452                 return false;
3453             }
3454
3455             if (parser.tok == Token::IDENT && (tdef = parser_find_typedef(parser, parser_tokval(parser), 0)))
3456             {
3457                 ast_type_to_string(tdef, ty, sizeof(ty));
3458                 con_out("__builtin_debug_printtype: `%s`=`%s`\n", tdef->m_name.c_str(), ty);
3459                 if (!parser_next(parser)) {
3460                     parseerror(parser, "parse error after __builtin_debug_printtype typename argument");
3461                     return false;
3462                 }
3463             }
3464             else
3465             {
3466                 if (!parse_statement(parser, block, out, allow_cases))
3467                     return false;
3468                 if (!*out)
3469                     con_out("__builtin_debug_printtype: got no output node\n");
3470                 else
3471                 {
3472                     ast_type_to_string(*out, ty, sizeof(ty));
3473                     con_out("__builtin_debug_printtype: `%s`\n", ty);
3474                 }
3475             }
3476             return true;
3477         }
3478         else if (!strcmp(parser_tokval(parser), "return"))
3479         {
3480             return parse_return(parser, block, out);
3481         }
3482         else if (!strcmp(parser_tokval(parser), "if"))
3483         {
3484             return parse_if(parser, block, out);
3485         }
3486         else if (!strcmp(parser_tokval(parser), "while"))
3487         {
3488             return parse_while(parser, block, out);
3489         }
3490         else if (!strcmp(parser_tokval(parser), "do"))
3491         {
3492             return parse_dowhile(parser, block, out);
3493         }
3494         else if (!strcmp(parser_tokval(parser), "for"))
3495         {
3496             if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_QCC) {
3497                 if (parsewarning(parser, WARN_EXTENSIONS, "for loops are not recognized in the original Quake C standard, to enable try an alternate standard --std=?"))
3498                     return false;
3499             }
3500             return parse_for(parser, block, out);
3501         }
3502         else if (!strcmp(parser_tokval(parser), "break"))
3503         {
3504             return parse_break_continue(parser, block, out, false);
3505         }
3506         else if (!strcmp(parser_tokval(parser), "continue"))
3507         {
3508             return parse_break_continue(parser, block, out, true);
3509         }
3510         else if (!strcmp(parser_tokval(parser), "switch"))
3511         {
3512             return parse_switch(parser, block, out);
3513         }
3514         else if (!strcmp(parser_tokval(parser), "case") ||
3515                  !strcmp(parser_tokval(parser), "default"))
3516         {
3517             if (!allow_cases) {
3518                 parseerror(parser, "unexpected 'case' label");
3519                 return false;
3520             }
3521             return true;
3522         }
3523         else if (!strcmp(parser_tokval(parser), "goto"))
3524         {
3525             return parse_goto(parser, out);
3526         }
3527         else if (!strcmp(parser_tokval(parser), "typedef"))
3528         {
3529             if (!parser_next(parser)) {
3530                 parseerror(parser, "expected type definition after 'typedef'");
3531                 return false;
3532             }
3533             return parse_typedef(parser);
3534         }
3535         parseerror(parser, "Unexpected keyword: `%s'", parser_tokval(parser));
3536         return false;
3537     }
3538     else if (parser.tok == '{')
3539     {
3540         ast_block *inner;
3541         inner = parse_block(parser);
3542         if (!inner)
3543             return false;
3544         *out = inner;
3545         return true;
3546     }
3547     else if (parser.tok == ':')
3548     {
3549         size_t i;
3550         ast_label *label;
3551         if (!parser_next(parser)) {
3552             parseerror(parser, "expected label name");
3553             return false;
3554         }
3555         if (parser.tok != Token::IDENT) {
3556             parseerror(parser, "label must be an identifier");
3557             return false;
3558         }
3559         label = (ast_label*)parser_find_label(parser, parser_tokval(parser));
3560         if (label) {
3561             if (!label->m_undefined) {
3562                 parseerror(parser, "label `%s` already defined", label->m_name);
3563                 return false;
3564             }
3565             label->m_undefined = false;
3566         }
3567         else {
3568             label = new ast_label(parser_ctx(parser), parser_tokval(parser), false);
3569             parser.labels.push_back(label);
3570         }
3571         *out = label;
3572         if (!parser_next(parser)) {
3573             parseerror(parser, "parse error after label");
3574             return false;
3575         }
3576         for (i = 0; i < parser.gotos.size(); ++i) {
3577             if (parser.gotos[i]->m_name == label->m_name) {
3578                 parser.gotos[i]->setLabel(label);
3579                 parser.gotos.erase(parser.gotos.begin() + i);
3580                 --i;
3581             }
3582         }
3583         return true;
3584     }
3585     else if (parser.tok == ';')
3586     {
3587         if (!parser_next(parser)) {
3588             parseerror(parser, "parse error after empty statement");
3589             return false;
3590         }
3591         return true;
3592     }
3593     else
3594     {
3595         lex_ctx_t ctx = parser_ctx(parser);
3596         ast_expression *exp = parse_expression(parser, false, false);
3597         if (!exp)
3598             return false;
3599         *out = exp;
3600         if (!exp->m_side_effects) {
3601             if (compile_warning(ctx, WARN_EFFECTLESS_STATEMENT, "statement has no effect"))
3602                 return false;
3603         }
3604         return true;
3605     }
3606 }
3607
3608 static bool parse_enum(parser_t &parser)
3609 {
3610     bool        flag = false;
3611     bool        reverse = false;
3612     qcfloat_t     num = 0;
3613     ast_value  *var = nullptr;
3614     ast_value  *asvalue;
3615     std::vector<ast_value*> values;
3616
3617     ast_expression *old;
3618
3619     if (!parser_next(parser) || (parser.tok != '{' && parser.tok != ':')) {
3620         parseerror(parser, "expected `{` or `:` after `enum` keyword");
3621         return false;
3622     }
3623
3624     /* enumeration attributes (can add more later) */
3625     if (parser.tok == ':') {
3626         if (!parser_next(parser) || parser.tok != Token::IDENT){
3627             parseerror(parser, "expected `flag` or `reverse` for enumeration attribute");
3628             return false;
3629         }
3630
3631         /* attributes? */
3632         if (!strcmp(parser_tokval(parser), "flag")) {
3633             num  = 1;
3634             flag = true;
3635         }
3636         else if (!strcmp(parser_tokval(parser), "reverse")) {
3637             reverse = true;
3638         }
3639         else {
3640             parseerror(parser, "invalid attribute `%s` for enumeration", parser_tokval(parser));
3641             return false;
3642         }
3643
3644         if (!parser_next(parser) || parser.tok != '{') {
3645             parseerror(parser, "expected `{` after enum attribute ");
3646             return false;
3647         }
3648     }
3649
3650     while (true) {
3651         if (!parser_next(parser) || parser.tok != Token::IDENT) {
3652             if (parser.tok == '}') {
3653                 /* allow an empty enum */
3654                 break;
3655             }
3656             parseerror(parser, "expected identifier or `}`");
3657             return false;
3658         }
3659
3660         old = parser_find_field(parser, parser_tokval(parser));
3661         if (!old)
3662             old = parser_find_global(parser, parser_tokval(parser));
3663         if (old) {
3664             parseerror(parser, "value `%s` has already been declared here: %s:%i",
3665                        parser_tokval(parser), old->m_context.file, old->m_context.line);
3666             return false;
3667         }
3668
3669         var = new ast_value(parser_ctx(parser), parser_tokval(parser), TYPE_FLOAT);
3670         values.push_back(var);
3671         var->m_cvq             = CV_CONST;
3672         var->m_hasvalue        = true;
3673
3674         /* for flagged enumerations increment in POTs of TWO */
3675         var->m_constval.vfloat = (flag) ? (num *= 2) : (num ++);
3676         parser_addglobal(parser, var->m_name, var);
3677
3678         if (!parser_next(parser)) {
3679             parseerror(parser, "expected `=`, `}` or comma after identifier");
3680             return false;
3681         }
3682
3683         if (parser.tok == ',')
3684             continue;
3685         if (parser.tok == '}')
3686             break;
3687         if (parser.tok != '=') {
3688             parseerror(parser, "expected `=`, `}` or comma after identifier");
3689             return false;
3690         }
3691
3692         if (!parser_next(parser)) {
3693             parseerror(parser, "expected expression after `=`");
3694             return false;
3695         }
3696
3697         /* We got a value! */
3698         old = parse_expression_leave(parser, true, false, false);
3699         asvalue = (ast_value*)old;
3700         if (!ast_istype(old, ast_value) || asvalue->m_cvq != CV_CONST || !asvalue->m_hasvalue) {
3701             compile_error(var->m_context, "constant value or expression expected");
3702             return false;
3703         }
3704         num = (var->m_constval.vfloat = asvalue->m_constval.vfloat) + 1;
3705
3706         if (parser.tok == '}')
3707             break;
3708         if (parser.tok != ',') {
3709             parseerror(parser, "expected `}` or comma after expression");
3710             return false;
3711         }
3712     }
3713
3714     /* patch them all (for reversed attribute) */
3715     if (reverse) {
3716         size_t i;
3717         for (i = 0; i < values.size(); i++)
3718             values[i]->m_constval.vfloat = values.size() - i - 1;
3719     }
3720
3721     if (parser.tok != '}') {
3722         parseerror(parser, "internal error: breaking without `}`");
3723         return false;
3724     }
3725
3726     if (!parser_next(parser) || parser.tok != ';') {
3727         parseerror(parser, "expected semicolon after enumeration");
3728         return false;
3729     }
3730
3731     if (!parser_next(parser)) {
3732         parseerror(parser, "parse error after enumeration");
3733         return false;
3734     }
3735
3736     return true;
3737 }
3738
3739 static bool parse_block_into(parser_t &parser, ast_block *block)
3740 {
3741     bool   retval = true;
3742
3743     parser_enterblock(parser);
3744
3745     if (!parser_next(parser)) { /* skip the '{' */
3746         parseerror(parser, "expected function body");
3747         goto cleanup;
3748     }
3749
3750     while (parser.tok != Token::END && parser.tok < Token::ERROR)
3751     {
3752         ast_expression *expr = nullptr;
3753         if (parser.tok == '}')
3754             break;
3755
3756         if (!parse_statement(parser, block, &expr, false)) {
3757             /* parseerror(parser, "parse error"); */
3758             block = nullptr;
3759             goto cleanup;
3760         }
3761         if (!expr)
3762             continue;
3763         if (!block->addExpr(expr)) {
3764             delete block;
3765             block = nullptr;
3766             goto cleanup;
3767         }
3768     }
3769
3770     if (parser.tok != '}') {
3771         block = nullptr;
3772     } else {
3773         (void)parser_next(parser);
3774     }
3775
3776 cleanup:
3777     if (!parser_leaveblock(parser))
3778         retval = false;
3779     return retval && !!block;
3780 }
3781
3782 static ast_block* parse_block(parser_t &parser)
3783 {
3784     ast_block *block;
3785     block = new ast_block(parser_ctx(parser));
3786     if (!block)
3787         return nullptr;
3788     if (!parse_block_into(parser, block)) {
3789         delete block;
3790         return nullptr;
3791     }
3792     return block;
3793 }
3794
3795 static bool parse_statement_or_block(parser_t &parser, ast_expression **out)
3796 {
3797     if (parser.tok == '{') {
3798         *out = parse_block(parser);
3799         return !!*out;
3800     }
3801     return parse_statement(parser, nullptr, out, false);
3802 }
3803
3804 static bool create_vector_members(ast_value *var, ast_member **me)
3805 {
3806     size_t i;
3807     size_t len = var->m_name.length();
3808
3809     for (i = 0; i < 3; ++i) {
3810         char *name = (char*)mem_a(len+3);
3811         memcpy(name, var->m_name.c_str(), len);
3812         name[len+0] = '_';
3813         name[len+1] = 'x'+i;
3814         name[len+2] = 0;
3815         me[i] = ast_member::make(var->m_context, var, i, name);
3816         mem_d(name);
3817         if (!me[i])
3818             break;
3819     }
3820     if (i == 3)
3821         return true;
3822
3823     /* unroll */
3824     do { delete me[--i]; } while(i);
3825     return false;
3826 }
3827
3828 static bool parse_function_body(parser_t &parser, ast_value *var)
3829 {
3830     ast_block *block = nullptr;
3831     ast_function *func;
3832     ast_function *old;
3833
3834     ast_expression *framenum  = nullptr;
3835     ast_expression *nextthink = nullptr;
3836     /* None of the following have to be deleted */
3837     ast_expression *fld_think = nullptr, *fld_nextthink = nullptr, *fld_frame = nullptr;
3838     ast_expression *gbl_time = nullptr, *gbl_self = nullptr;
3839     bool has_frame_think;
3840
3841     bool retval = true;
3842
3843     has_frame_think = false;
3844     old = parser.function;
3845
3846     if (var->m_flags & AST_FLAG_ALIAS) {
3847         parseerror(parser, "function aliases cannot have bodies");
3848         return false;
3849     }
3850
3851     if (parser.gotos.size() || parser.labels.size()) {
3852         parseerror(parser, "gotos/labels leaking");
3853         return false;
3854     }
3855
3856     if (!OPTS_FLAG(VARIADIC_ARGS) && var->m_flags & AST_FLAG_VARIADIC) {
3857         if (parsewarning(parser, WARN_VARIADIC_FUNCTION,
3858                          "variadic function with implementation will not be able to access additional parameters (try -fvariadic-args)"))
3859         {
3860             return false;
3861         }
3862     }
3863
3864     if (parser.tok == '[') {
3865         /* got a frame definition: [ framenum, nextthink ]
3866          * this translates to:
3867          * self.frame = framenum;
3868          * self.nextthink = time + 0.1;
3869          * self.think = nextthink;
3870          */
3871         nextthink = nullptr;
3872
3873         fld_think     = parser_find_field(parser, "think");
3874         fld_nextthink = parser_find_field(parser, "nextthink");
3875         fld_frame     = parser_find_field(parser, "frame");
3876         if (!fld_think || !fld_nextthink || !fld_frame) {
3877             parseerror(parser, "cannot use [frame,think] notation without the required fields");
3878             parseerror(parser, "please declare the following entityfields: `frame`, `think`, `nextthink`");
3879             return false;
3880         }
3881         gbl_time      = parser_find_global(parser, "time");
3882         gbl_self      = parser_find_global(parser, "self");
3883         if (!gbl_time || !gbl_self) {
3884             parseerror(parser, "cannot use [frame,think] notation without the required globals");
3885             parseerror(parser, "please declare the following globals: `time`, `self`");
3886             return false;
3887         }
3888
3889         if (!parser_next(parser))
3890             return false;
3891
3892         framenum = parse_expression_leave(parser, true, false, false);
3893         if (!framenum) {
3894             parseerror(parser, "expected a framenumber constant in[frame,think] notation");
3895             return false;
3896         }
3897         if (!ast_istype(framenum, ast_value) || !( (ast_value*)framenum )->m_hasvalue) {
3898             ast_unref(framenum);
3899             parseerror(parser, "framenumber in [frame,think] notation must be a constant");
3900             return false;
3901         }
3902
3903         if (parser.tok != ',') {
3904             ast_unref(framenum);
3905             parseerror(parser, "expected comma after frame number in [frame,think] notation");
3906             parseerror(parser, "Got a %i\n", parser.tok);
3907             return false;
3908         }
3909
3910         if (!parser_next(parser)) {
3911             ast_unref(framenum);
3912             return false;
3913         }
3914
3915         if (parser.tok == Token::IDENT && !parser_find_var(parser, parser_tokval(parser)))
3916         {
3917             /* qc allows the use of not-yet-declared functions here
3918              * - this automatically creates a prototype */
3919             ast_value      *thinkfunc;
3920             ast_expression *functype = fld_think->m_next;
3921
3922             thinkfunc = new ast_value(parser_ctx(parser), parser_tokval(parser), functype->m_vtype);
3923             if (!thinkfunc) { /* || !thinkfunc->adoptType(*functype)*/
3924                 ast_unref(framenum);
3925                 parseerror(parser, "failed to create implicit prototype for `%s`", parser_tokval(parser));
3926                 return false;
3927             }
3928             thinkfunc->adoptType(*functype);
3929
3930             if (!parser_next(parser)) {
3931                 ast_unref(framenum);
3932                 delete thinkfunc;
3933                 return false;
3934             }
3935
3936             parser_addglobal(parser, thinkfunc->m_name, thinkfunc);
3937
3938             nextthink = thinkfunc;
3939
3940         } else {
3941             nextthink = parse_expression_leave(parser, true, false, false);
3942             if (!nextthink) {
3943                 ast_unref(framenum);
3944                 parseerror(parser, "expected a think-function in [frame,think] notation");
3945                 return false;
3946             }
3947         }
3948
3949         if (!ast_istype(nextthink, ast_value)) {
3950             parseerror(parser, "think-function in [frame,think] notation must be a constant");
3951             retval = false;
3952         }
3953
3954         if (retval && parser.tok != ']') {
3955             parseerror(parser, "expected closing `]` for [frame,think] notation");
3956             retval = false;
3957         }
3958
3959         if (retval && !parser_next(parser)) {
3960             retval = false;
3961         }
3962
3963         if (retval && parser.tok != '{') {
3964             parseerror(parser, "a function body has to be declared after a [frame,think] declaration");
3965             retval = false;
3966         }
3967
3968         if (!retval) {
3969             ast_unref(nextthink);
3970             ast_unref(framenum);
3971             return false;
3972         }
3973
3974         has_frame_think = true;
3975     }
3976
3977     block = new ast_block(parser_ctx(parser));
3978     if (!block) {
3979         parseerror(parser, "failed to allocate block");
3980         if (has_frame_think) {
3981             ast_unref(nextthink);
3982             ast_unref(framenum);
3983         }
3984         return false;
3985     }
3986
3987     if (has_frame_think) {
3988         if (!OPTS_FLAG(EMULATE_STATE)) {
3989             ast_state *state_op = new ast_state(parser_ctx(parser), framenum, nextthink);
3990             if (!block->addExpr(state_op)) {
3991                 parseerror(parser, "failed to generate state op for [frame,think]");
3992                 ast_unref(nextthink);
3993                 ast_unref(framenum);
3994                 delete block;
3995                 return false;
3996             }
3997         } else {
3998             /* emulate OP_STATE in code: */
3999             lex_ctx_t ctx;
4000             ast_expression *self_frame;
4001             ast_expression *self_nextthink;
4002             ast_expression *self_think;
4003             ast_expression *time_plus_1;
4004             ast_store *store_frame;
4005             ast_store *store_nextthink;
4006             ast_store *store_think;
4007
4008             float frame_delta = 1.0f / (float)OPTS_OPTION_U32(OPTION_STATE_FPS);
4009
4010             ctx = parser_ctx(parser);
4011             self_frame     = new ast_entfield(ctx, gbl_self, fld_frame);
4012             self_nextthink = new ast_entfield(ctx, gbl_self, fld_nextthink);
4013             self_think     = new ast_entfield(ctx, gbl_self, fld_think);
4014
4015             time_plus_1    = new ast_binary(ctx, INSTR_ADD_F,
4016                              gbl_time, parser.m_fold.constgen_float(frame_delta, false));
4017
4018             if (!self_frame || !self_nextthink || !self_think || !time_plus_1) {
4019                 if (self_frame)     delete self_frame;
4020                 if (self_nextthink) delete self_nextthink;
4021                 if (self_think)     delete self_think;
4022                 if (time_plus_1)    delete time_plus_1;
4023                 retval = false;
4024             }
4025
4026             if (retval)
4027             {
4028                 store_frame     = new ast_store(ctx, INSTR_STOREP_F,   self_frame,     framenum);
4029                 store_nextthink = new ast_store(ctx, INSTR_STOREP_F,   self_nextthink, time_plus_1);
4030                 store_think     = new ast_store(ctx, INSTR_STOREP_FNC, self_think,     nextthink);
4031
4032                 if (!store_frame) {
4033                     delete self_frame;
4034                     retval = false;
4035                 }
4036                 if (!store_nextthink) {
4037                     delete self_nextthink;
4038                     retval = false;
4039                 }
4040                 if (!store_think) {
4041                     delete self_think;
4042                     retval = false;
4043                 }
4044                 if (!retval) {
4045                     if (store_frame)     delete store_frame;
4046                     if (store_nextthink) delete store_nextthink;
4047                     if (store_think)     delete store_think;
4048                     retval = false;
4049                 }
4050                 if (!block->addExpr(store_frame) ||
4051                     !block->addExpr(store_nextthink) ||
4052                     !block->addExpr(store_think))
4053                 {
4054                     retval = false;
4055                 }
4056             }
4057
4058             if (!retval) {
4059                 parseerror(parser, "failed to generate code for [frame,think]");
4060                 ast_unref(nextthink);
4061                 ast_unref(framenum);
4062                 delete block;
4063                 return false;
4064             }
4065         }
4066     }
4067
4068     if (var->m_hasvalue) {
4069         if (!(var->m_flags & AST_FLAG_ACCUMULATE)) {
4070             parseerror(parser, "function `%s` declared with multiple bodies", var->m_name);
4071             delete block;
4072             goto enderr;
4073         }
4074         func = var->m_constval.vfunc;
4075
4076         if (!func) {
4077             parseerror(parser, "internal error: nullptr function: `%s`", var->m_name);
4078             delete block;
4079             goto enderr;
4080         }
4081     } else {
4082         func = ast_function::make(var->m_context, var->m_name, var);
4083
4084         if (!func) {
4085             parseerror(parser, "failed to allocate function for `%s`", var->m_name);
4086             delete block;
4087             goto enderr;
4088         }
4089         parser.functions.push_back(func);
4090     }
4091
4092     parser_enterblock(parser);
4093
4094     for (auto &it : var->m_type_params) {
4095         size_t e;
4096         ast_member *me[3];
4097
4098         if (it->m_vtype != TYPE_VECTOR &&
4099             (it->m_vtype != TYPE_FIELD ||
4100              it->m_next->m_vtype != TYPE_VECTOR))
4101         {
4102             continue;
4103         }
4104
4105         if (!create_vector_members(it.get(), me)) {
4106             delete block;
4107             goto enderrfn;
4108         }
4109
4110         for (e = 0; e < 3; ++e) {
4111             parser_addlocal(parser, me[e]->m_name, me[e]);
4112             block->collect(me[e]);
4113         }
4114     }
4115
4116     if (var->m_argcounter && !func->m_argc) {
4117         ast_value *argc = new ast_value(var->m_context, var->m_argcounter, TYPE_FLOAT);
4118         parser_addlocal(parser, argc->m_name, argc);
4119         func->m_argc.reset(argc);
4120     }
4121
4122     if (OPTS_FLAG(VARIADIC_ARGS) && var->m_flags & AST_FLAG_VARIADIC && !func->m_varargs) {
4123         char name[1024];
4124         ast_value *varargs = new ast_value(var->m_context, "reserved:va_args", TYPE_ARRAY);
4125         varargs->m_flags |= AST_FLAG_IS_VARARG;
4126         varargs->m_next = new ast_value(var->m_context, "", TYPE_VECTOR);
4127         varargs->m_count = 0;
4128         util_snprintf(name, sizeof(name), "%s##va##SET", var->m_name.c_str());
4129         if (!parser_create_array_setter_proto(parser, varargs, name)) {
4130             delete varargs;
4131             delete block;
4132             goto enderrfn;
4133         }
4134         util_snprintf(name, sizeof(name), "%s##va##GET", var->m_name.c_str());
4135         if (!parser_create_array_getter_proto(parser, varargs, varargs->m_next, name)) {
4136             delete varargs;
4137             delete block;
4138             goto enderrfn;
4139         }
4140         func->m_varargs.reset(varargs);
4141         func->m_fixedparams = (ast_value*)parser.m_fold.constgen_float(var->m_type_params.size(), false);
4142     }
4143
4144     parser.function = func;
4145     if (!parse_block_into(parser, block)) {
4146         delete block;
4147         goto enderrfn;
4148     }
4149
4150     func->m_blocks.emplace_back(block);
4151
4152     parser.function = old;
4153     if (!parser_leaveblock(parser))
4154         retval = false;
4155     if (parser.variables.size() != PARSER_HT_LOCALS) {
4156         parseerror(parser, "internal error: local scopes left");
4157         retval = false;
4158     }
4159
4160     if (parser.tok == ';')
4161         return parser_next(parser);
4162     else if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_QCC)
4163         parseerror(parser, "missing semicolon after function body (mandatory with -std=qcc)");
4164     return retval;
4165
4166 enderrfn:
4167     (void)!parser_leaveblock(parser);
4168     parser.functions.pop_back();
4169     delete func;
4170     var->m_constval.vfunc = nullptr;
4171
4172 enderr:
4173     parser.function = old;
4174     return false;
4175 }
4176
4177 static ast_expression *array_accessor_split(
4178     parser_t  &parser,
4179     ast_value *array,
4180     ast_value *index,
4181     size_t     middle,
4182     ast_expression *left,
4183     ast_expression *right
4184     )
4185 {
4186     ast_ifthen *ifthen;
4187     ast_binary *cmp;
4188
4189     lex_ctx_t ctx = array->m_context;
4190
4191     if (!left || !right) {
4192         if (left)  delete left;
4193         if (right) delete right;
4194         return nullptr;
4195     }
4196
4197     cmp = new ast_binary(ctx, INSTR_LT,
4198                          index,
4199                          parser.m_fold.constgen_float(middle, false));
4200     if (!cmp) {
4201         delete left;
4202         delete right;
4203         parseerror(parser, "internal error: failed to create comparison for array setter");
4204         return nullptr;
4205     }
4206
4207     ifthen = new ast_ifthen(ctx, cmp, left, right);
4208     if (!ifthen) {
4209         delete cmp; /* will delete left and right */
4210         parseerror(parser, "internal error: failed to create conditional jump for array setter");
4211         return nullptr;
4212     }
4213
4214     return ifthen;
4215 }
4216
4217 static ast_expression *array_setter_node(parser_t &parser, ast_value *array, ast_value *index, ast_value *value, size_t from, size_t afterend)
4218 {
4219     lex_ctx_t ctx = array->m_context;
4220
4221     if (from+1 == afterend) {
4222         /* set this value */
4223         ast_block       *block;
4224         ast_return      *ret;
4225         ast_array_index *subscript;
4226         ast_store       *st;
4227         int assignop = type_store_instr[value->m_vtype];
4228
4229         if (value->m_vtype == TYPE_FIELD && value->m_next->m_vtype == TYPE_VECTOR)
4230             assignop = INSTR_STORE_V;
4231
4232         subscript = ast_array_index::make(ctx, array, parser.m_fold.constgen_float(from, false));
4233         if (!subscript)
4234             return nullptr;
4235
4236         st = new ast_store(ctx, assignop, subscript, value);
4237         if (!st) {
4238             delete subscript;
4239             return nullptr;
4240         }
4241
4242         block = new ast_block(ctx);
4243         if (!block) {
4244             delete st;
4245             return nullptr;
4246         }
4247
4248         if (!block->addExpr(st)) {
4249             delete block;
4250             return nullptr;
4251         }
4252
4253         ret = new ast_return(ctx, nullptr);
4254         if (!ret) {
4255             delete block;
4256             return nullptr;
4257         }
4258
4259         if (!block->addExpr(ret)) {
4260             delete block;
4261             return nullptr;
4262         }
4263
4264         return block;
4265     } else {
4266         ast_expression *left, *right;
4267         size_t diff = afterend - from;
4268         size_t middle = from + diff/2;
4269         left  = array_setter_node(parser, array, index, value, from, middle);
4270         right = array_setter_node(parser, array, index, value, middle, afterend);
4271         return array_accessor_split(parser, array, index, middle, left, right);
4272     }
4273 }
4274
4275 static ast_expression *array_field_setter_node(
4276     parser_t  &parser,
4277     ast_value *array,
4278     ast_value *entity,
4279     ast_value *index,
4280     ast_value *value,
4281     size_t     from,
4282     size_t     afterend)
4283 {
4284     lex_ctx_t ctx = array->m_context;
4285
4286     if (from+1 == afterend) {
4287         /* set this value */
4288         ast_block       *block;
4289         ast_return      *ret;
4290         ast_entfield    *entfield;
4291         ast_array_index *subscript;
4292         ast_store       *st;
4293         int assignop = type_storep_instr[value->m_vtype];
4294
4295         if (value->m_vtype == TYPE_FIELD && value->m_next->m_vtype == TYPE_VECTOR)
4296             assignop = INSTR_STOREP_V;
4297
4298         subscript = ast_array_index::make(ctx, array, parser.m_fold.constgen_float(from, false));
4299         if (!subscript)
4300             return nullptr;
4301
4302         subscript->m_next = new ast_expression(ast_copy_type, subscript->m_context, *subscript);
4303         subscript->m_vtype = TYPE_FIELD;
4304
4305         entfield = new ast_entfield(ctx, entity, subscript, subscript);
4306         if (!entfield) {
4307             delete subscript;
4308             return nullptr;
4309         }
4310
4311         st = new ast_store(ctx, assignop, entfield, value);
4312         if (!st) {
4313             delete entfield;
4314             return nullptr;
4315         }
4316
4317         block = new ast_block(ctx);
4318         if (!block) {
4319             delete st;
4320             return nullptr;
4321         }
4322
4323         if (!block->addExpr(st)) {
4324             delete block;
4325             return nullptr;
4326         }
4327
4328         ret = new ast_return(ctx, nullptr);
4329         if (!ret) {
4330             delete block;
4331             return nullptr;
4332         }
4333
4334         if (!block->addExpr(ret)) {
4335             delete block;
4336             return nullptr;
4337         }
4338
4339         return block;
4340     } else {
4341         ast_expression *left, *right;
4342         size_t diff = afterend - from;
4343         size_t middle = from + diff/2;
4344         left  = array_field_setter_node(parser, array, entity, index, value, from, middle);
4345         right = array_field_setter_node(parser, array, entity, index, value, middle, afterend);
4346         return array_accessor_split(parser, array, index, middle, left, right);
4347     }
4348 }
4349
4350 static ast_expression *array_getter_node(parser_t &parser, ast_value *array, ast_value *index, size_t from, size_t afterend)
4351 {
4352     lex_ctx_t ctx = array->m_context;
4353
4354     if (from+1 == afterend) {
4355         ast_return      *ret;
4356         ast_array_index *subscript;
4357
4358         subscript = ast_array_index::make(ctx, array, parser.m_fold.constgen_float(from, false));
4359         if (!subscript)
4360             return nullptr;
4361
4362         ret = new ast_return(ctx, subscript);
4363         if (!ret) {
4364             delete subscript;
4365             return nullptr;
4366         }
4367
4368         return ret;
4369     } else {
4370         ast_expression *left, *right;
4371         size_t diff = afterend - from;
4372         size_t middle = from + diff/2;
4373         left  = array_getter_node(parser, array, index, from, middle);
4374         right = array_getter_node(parser, array, index, middle, afterend);
4375         return array_accessor_split(parser, array, index, middle, left, right);
4376     }
4377 }
4378
4379 static bool parser_create_array_accessor(parser_t &parser, ast_value *array, const char *funcname, ast_value **out)
4380 {
4381     ast_function   *func = nullptr;
4382     ast_value      *fval = nullptr;
4383     ast_block      *body = nullptr;
4384
4385     fval = new ast_value(array->m_context, funcname, TYPE_FUNCTION);
4386     if (!fval) {
4387         parseerror(parser, "failed to create accessor function value");
4388         return false;
4389     }
4390     fval->m_flags &= ~(AST_FLAG_COVERAGE_MASK);
4391
4392     func = ast_function::make(array->m_context, funcname, fval);
4393     if (!func) {
4394         delete fval;
4395         parseerror(parser, "failed to create accessor function node");
4396         return false;
4397     }
4398
4399     body = new ast_block(array->m_context);
4400     if (!body) {
4401         parseerror(parser, "failed to create block for array accessor");
4402         delete fval;
4403         delete func;
4404         return false;
4405     }
4406
4407     func->m_blocks.emplace_back(body);
4408     *out = fval;
4409
4410     parser.accessors.push_back(fval);
4411
4412     return true;
4413 }
4414
4415 static ast_value* parser_create_array_setter_proto(parser_t &parser, ast_value *array, const char *funcname)
4416 {
4417     ast_value      *index = nullptr;
4418     ast_value      *value = nullptr;
4419     ast_function   *func;
4420     ast_value      *fval;
4421
4422     if (!ast_istype(array->m_next, ast_value)) {
4423         parseerror(parser, "internal error: array accessor needs to build an ast_value with a copy of the element type");
4424         return nullptr;
4425     }
4426
4427     if (!parser_create_array_accessor(parser, array, funcname, &fval))
4428         return nullptr;
4429     func = fval->m_constval.vfunc;
4430     fval->m_next = new ast_value(array->m_context, "<void>", TYPE_VOID);
4431
4432     index = new ast_value(array->m_context, "index", TYPE_FLOAT);
4433     value = new ast_value(ast_copy_type, *(ast_value*)array->m_next);
4434
4435     if (!index || !value) {
4436         parseerror(parser, "failed to create locals for array accessor");
4437         goto cleanup;
4438     }
4439     value->m_name = "value"; // not important
4440     fval->m_type_params.emplace_back(index);
4441     fval->m_type_params.emplace_back(value);
4442
4443     array->m_setter = fval;
4444     return fval;
4445 cleanup:
4446     if (index) delete index;
4447     if (value) delete value;
4448     delete func;
4449     delete fval;
4450     return nullptr;
4451 }
4452
4453 static bool parser_create_array_setter_impl(parser_t &parser, ast_value *array)
4454 {
4455     ast_expression *root = nullptr;
4456     root = array_setter_node(parser, array,
4457                              array->m_setter->m_type_params[0].get(),
4458                              array->m_setter->m_type_params[1].get(),
4459                              0, array->m_count);
4460     if (!root) {
4461         parseerror(parser, "failed to build accessor search tree");
4462         return false;
4463     }
4464     if (!array->m_setter->m_constval.vfunc->m_blocks[0].get()->addExpr(root)) {
4465         delete root;
4466         return false;
4467     }
4468     return true;
4469 }
4470
4471 static bool parser_create_array_setter(parser_t &parser, ast_value *array, const char *funcname)
4472 {
4473     if (!parser_create_array_setter_proto(parser, array, funcname))
4474         return false;
4475     return parser_create_array_setter_impl(parser, array);
4476 }
4477
4478 static bool parser_create_array_field_setter(parser_t &parser, ast_value *array, const char *funcname)
4479 {
4480     ast_expression *root = nullptr;
4481     ast_value      *entity = nullptr;
4482     ast_value      *index = nullptr;
4483     ast_value      *value = nullptr;
4484     ast_function   *func;
4485     ast_value      *fval;
4486
4487     if (!ast_istype(array->m_next, ast_value)) {
4488         parseerror(parser, "internal error: array accessor needs to build an ast_value with a copy of the element type");
4489         return false;
4490     }
4491
4492     if (!parser_create_array_accessor(parser, array, funcname, &fval))
4493         return false;
4494     func = fval->m_constval.vfunc;
4495     fval->m_next = new ast_value(array->m_context, "<void>", TYPE_VOID);
4496
4497     entity = new ast_value(array->m_context, "entity", TYPE_ENTITY);
4498     index  = new ast_value(array->m_context, "index",  TYPE_FLOAT);
4499     value  = new ast_value(ast_copy_type, *(ast_value*)array->m_next);
4500     if (!entity || !index || !value) {
4501         parseerror(parser, "failed to create locals for array accessor");
4502         goto cleanup;
4503     }
4504     value->m_name = "value"; // not important
4505     fval->m_type_params.emplace_back(entity);
4506     fval->m_type_params.emplace_back(index);
4507     fval->m_type_params.emplace_back(value);
4508
4509     root = array_field_setter_node(parser, array, entity, index, value, 0, array->m_count);
4510     if (!root) {
4511         parseerror(parser, "failed to build accessor search tree");
4512         goto cleanup;
4513     }
4514
4515     array->m_setter = fval;
4516     return func->m_blocks[0].get()->addExpr(root);
4517 cleanup:
4518     if (entity) delete entity;
4519     if (index)  delete index;
4520     if (value)  delete value;
4521     if (root)   delete root;
4522     delete func;
4523     delete fval;
4524     return false;
4525 }
4526
4527 static ast_value* parser_create_array_getter_proto(parser_t &parser, ast_value *array, const ast_expression *elemtype, const char *funcname)
4528 {
4529     ast_value      *index = nullptr;
4530     ast_value      *fval;
4531     ast_function   *func;
4532
4533     /* NOTE: checking array->m_next rather than elemtype since
4534      * for fields elemtype is a temporary fieldtype.
4535      */
4536     if (!ast_istype(array->m_next, ast_value)) {
4537         parseerror(parser, "internal error: array accessor needs to build an ast_value with a copy of the element type");
4538         return nullptr;
4539     }
4540
4541     if (!parser_create_array_accessor(parser, array, funcname, &fval))
4542         return nullptr;
4543     func = fval->m_constval.vfunc;
4544     fval->m_next = new ast_expression(ast_copy_type, array->m_context, *elemtype);
4545
4546     index = new ast_value(array->m_context, "index", TYPE_FLOAT);
4547
4548     if (!index) {
4549         parseerror(parser, "failed to create locals for array accessor");
4550         goto cleanup;
4551     }
4552     fval->m_type_params.emplace_back(index);
4553
4554     array->m_getter = fval;
4555     return fval;
4556 cleanup:
4557     if (index) delete index;
4558     delete func;
4559     delete fval;
4560     return nullptr;
4561 }
4562
4563 static bool parser_create_array_getter_impl(parser_t &parser, ast_value *array)
4564 {
4565     ast_expression *root = nullptr;
4566
4567     root = array_getter_node(parser, array, array->m_getter->m_type_params[0].get(), 0, array->m_count);
4568     if (!root) {
4569         parseerror(parser, "failed to build accessor search tree");
4570         return false;
4571     }
4572     if (!array->m_getter->m_constval.vfunc->m_blocks[0].get()->addExpr(root)) {
4573         delete root;
4574         return false;
4575     }
4576     return true;
4577 }
4578
4579 static bool parser_create_array_getter(parser_t &parser, ast_value *array, const ast_expression *elemtype, const char *funcname)
4580 {
4581     if (!parser_create_array_getter_proto(parser, array, elemtype, funcname))
4582         return false;
4583     return parser_create_array_getter_impl(parser, array);
4584 }
4585
4586 static ast_value *parse_parameter_list(parser_t &parser, ast_value *var)
4587 {
4588     lex_ctx_t ctx = parser_ctx(parser);
4589     std::vector<std::unique_ptr<ast_value>> params;
4590     ast_value *fval;
4591     bool first = true;
4592     bool variadic = false;
4593     ast_value *varparam = nullptr;
4594     char *argcounter = nullptr;
4595
4596     /* for the sake of less code we parse-in in this function */
4597     if (!parser_next(parser)) {
4598         delete var;
4599         parseerror(parser, "expected parameter list");
4600         return nullptr;
4601     }
4602
4603     /* parse variables until we hit a closing paren */
4604     while (parser.tok != ')') {
4605         bool is_varargs = false;
4606
4607         if (!first) {
4608             /* there must be commas between them */
4609             if (parser.tok != ',') {
4610                 parseerror(parser, "expected comma or end of parameter list");
4611                 goto on_error;
4612             }
4613             if (!parser_next(parser)) {
4614                 parseerror(parser, "expected parameter");
4615                 goto on_error;
4616             }
4617         }
4618         first = false;
4619
4620         ast_value *param = parse_typename(parser, nullptr, nullptr, &is_varargs);
4621         if (!param && !is_varargs)
4622             goto on_error;
4623         if (is_varargs) {
4624             /* '...' indicates a varargs function */
4625             variadic = true;
4626             if (parser.tok != ')' && parser.tok != Token::IDENT) {
4627                 parseerror(parser, "`...` must be the last parameter of a variadic function declaration");
4628                 goto on_error;
4629             }
4630             if (parser.tok == Token::IDENT) {
4631                 argcounter = util_strdup(parser_tokval(parser));
4632                 if (!parser_next(parser) || parser.tok != ')') {
4633                     parseerror(parser, "`...` must be the last parameter of a variadic function declaration");
4634                     goto on_error;
4635                 }
4636             }
4637         } else {
4638             params.emplace_back(param);
4639             if (param->m_vtype >= TYPE_VARIANT) {
4640                 char tname[1024]; /* typename is reserved in C++ */
4641                 ast_type_to_string(param, tname, sizeof(tname));
4642                 parseerror(parser, "type not supported as part of a parameter list: %s", tname);
4643                 goto on_error;
4644             }
4645             /* type-restricted varargs */
4646             if (parser.tok == Token::DOTS) {
4647                 variadic = true;
4648                 varparam = params.back().release();
4649                 params.pop_back();
4650                 if (!parser_next(parser) || (parser.tok != ')' && parser.tok != Token::IDENT)) {
4651                     parseerror(parser, "`...` must be the last parameter of a variadic function declaration");
4652                     goto on_error;
4653                 }
4654                 if (parser.tok == Token::IDENT) {
4655                     argcounter = util_strdup(parser_tokval(parser));
4656                     param->m_name = argcounter;
4657                     if (!parser_next(parser) || parser.tok != ')') {
4658                         parseerror(parser, "`...` must be the last parameter of a variadic function declaration");
4659                         goto on_error;
4660                     }
4661                 }
4662             }
4663             if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_FTEQCC && param->m_name[0] == '<') {
4664                 parseerror(parser, "parameter name omitted");
4665                 goto on_error;
4666             }
4667         }
4668     }
4669
4670     if (params.size() == 1 && params[0]->m_vtype == TYPE_VOID)
4671         params.clear();
4672
4673     /* sanity check */
4674     if (params.size() > 8 && OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_QCC)
4675         (void)!parsewarning(parser, WARN_EXTENSIONS, "more than 8 parameters are not supported by this standard");
4676
4677     /* parse-out */
4678     if (!parser_next(parser)) {
4679         parseerror(parser, "parse error after typename");
4680         goto on_error;
4681     }
4682
4683     /* now turn 'var' into a function type */
4684     fval = new ast_value(ctx, "<type()>", TYPE_FUNCTION);
4685     fval->m_next = var;
4686     if (variadic)
4687         fval->m_flags |= AST_FLAG_VARIADIC;
4688     var = fval;
4689
4690     var->m_type_params = move(params);
4691     var->m_varparam = varparam;
4692     var->m_argcounter = argcounter;
4693
4694     return var;
4695
4696 on_error:
4697     if (argcounter)
4698         mem_d(argcounter);
4699     if (varparam)
4700         delete varparam;
4701     delete var;
4702     return nullptr;
4703 }
4704
4705 static ast_value *parse_arraysize(parser_t &parser, ast_value *var)
4706 {
4707     ast_expression *cexp;
4708     ast_value      *cval, *tmp;
4709     lex_ctx_t ctx;
4710
4711     ctx = parser_ctx(parser);
4712
4713     if (!parser_next(parser)) {
4714         delete var;
4715         parseerror(parser, "expected array-size");
4716         return nullptr;
4717     }
4718
4719     if (parser.tok != ']') {
4720         cexp = parse_expression_leave(parser, true, false, false);
4721
4722         if (!cexp || !ast_istype(cexp, ast_value)) {
4723             if (cexp)
4724                 ast_unref(cexp);
4725             delete var;
4726             parseerror(parser, "expected array-size as constant positive integer");
4727             return nullptr;
4728         }
4729         cval = (ast_value*)cexp;
4730     }
4731     else {
4732         cexp = nullptr;
4733         cval = nullptr;
4734     }
4735
4736     tmp = new ast_value(ctx, "<type[]>", TYPE_ARRAY);
4737     tmp->m_next = var;
4738     var = tmp;
4739
4740     if (cval) {
4741         if (cval->m_vtype == TYPE_INTEGER)
4742             tmp->m_count = cval->m_constval.vint;
4743         else if (cval->m_vtype == TYPE_FLOAT)
4744             tmp->m_count = cval->m_constval.vfloat;
4745         else {
4746             ast_unref(cexp);
4747             delete var;
4748             parseerror(parser, "array-size must be a positive integer constant");
4749             return nullptr;
4750         }
4751
4752         ast_unref(cexp);
4753     } else {
4754         var->m_count = -1;
4755         var->m_flags |= AST_FLAG_ARRAY_INIT;
4756     }
4757
4758     if (parser.tok != ']') {
4759         delete var;
4760         parseerror(parser, "expected ']' after array-size");
4761         return nullptr;
4762     }
4763     if (!parser_next(parser)) {
4764         delete var;
4765         parseerror(parser, "error after parsing array size");
4766         return nullptr;
4767     }
4768     return var;
4769 }
4770
4771 /* Parse a complete typename.
4772  * for single-variables (ie. function parameters or typedefs) storebase should be nullptr
4773  * but when parsing variables separated by comma
4774  * 'storebase' should point to where the base-type should be kept.
4775  * The base type makes up every bit of type information which comes *before* the
4776  * variable name.
4777  *
4778  * NOTE: The value must either be named, have a nullptr name, or a name starting
4779  *       with '<'. In the first case, this will be the actual variable or type
4780  *       name, in the other cases it is assumed that the name will appear
4781  *       later, and an error is generated otherwise.
4782  *
4783  * The following will be parsed in its entirety:
4784  *     void() foo()
4785  * The 'basetype' in this case is 'void()'
4786  * and if there's a comma after it, say:
4787  *     void() foo(), bar
4788  * then the type-information 'void()' can be stored in 'storebase'
4789  */
4790 static ast_value *parse_typename(parser_t &parser, ast_value **storebase, ast_value *cached_typedef, bool *is_vararg)
4791 {
4792     ast_value *var, *tmp;
4793     lex_ctx_t    ctx;
4794
4795     const char *name = nullptr;
4796     bool        isfield  = false;
4797     bool        wasarray = false;
4798     size_t      morefields = 0;
4799
4800     bool        vararg = (parser.tok == Token::DOTS);
4801
4802     ctx = parser_ctx(parser);
4803
4804     /* types may start with a dot */
4805     if (parser.tok == '.' || parser.tok == Token::DOTS) {
4806         isfield = true;
4807         if (parser.tok == Token::DOTS)
4808             morefields += 2;
4809         /* if we parsed a dot we need a typename now */
4810         if (!parser_next(parser)) {
4811             parseerror(parser, "expected typename for field definition");
4812             return nullptr;
4813         }
4814
4815         /* Further dots are handled seperately because they won't be part of the
4816          * basetype
4817          */
4818         while (true) {
4819             if (parser.tok == '.')
4820                 ++morefields;
4821             else if (parser.tok == Token::DOTS)
4822                 morefields += 3;
4823             else
4824                 break;
4825             vararg = false;
4826             if (!parser_next(parser)) {
4827                 parseerror(parser, "expected typename for field definition");
4828                 return nullptr;
4829             }
4830         }
4831     }
4832     if (parser.tok == Token::IDENT)
4833         cached_typedef = parser_find_typedef(parser, parser_tokval(parser), 0);
4834     if (!cached_typedef && parser.tok != Token::TYPENAME) {
4835         if (vararg && is_vararg) {
4836             *is_vararg = true;
4837             return nullptr;
4838         }
4839         parseerror(parser, "expected typename");
4840         return nullptr;
4841     }
4842
4843     /* generate the basic type value */
4844     if (cached_typedef) {
4845         var = new ast_value(ast_copy_type, *cached_typedef);
4846         var->m_name = "<type(from_def)>";
4847     } else
4848         var = new ast_value(ctx, "<type>", parser_token(parser)->constval.t);
4849
4850     for (; morefields; --morefields) {
4851         tmp = new ast_value(ctx, "<.type>", TYPE_FIELD);
4852         tmp->m_next = var;
4853         var = tmp;
4854     }
4855
4856     /* do not yet turn into a field - remember:
4857      * .void() foo; is a field too
4858      * .void()() foo; is a function
4859      */
4860
4861     /* parse on */
4862     if (!parser_next(parser)) {
4863         delete var;
4864         parseerror(parser, "parse error after typename");
4865         return nullptr;
4866     }
4867
4868     /* an opening paren now starts the parameter-list of a function
4869      * this is where original-QC has parameter lists.
4870      * We allow a single parameter list here.
4871      * Much like fteqcc we don't allow `float()() x`
4872      */
4873     if (parser.tok == '(') {
4874         var = parse_parameter_list(parser, var);
4875         if (!var)
4876             return nullptr;
4877     }
4878
4879     /* store the base if requested */
4880     if (storebase) {
4881         *storebase = new ast_value(ast_copy_type, *var);
4882         if (isfield) {
4883             tmp = new ast_value(ctx, "<type:f>", TYPE_FIELD);
4884             tmp->m_next = *storebase;
4885             *storebase = tmp;
4886         }
4887     }
4888
4889     /* there may be a name now */
4890     if (parser.tok == Token::IDENT || parser.tok == Token::KEYWORD) {
4891         if (!strcmp(parser_tokval(parser), "break"))
4892             (void)!parsewarning(parser, WARN_BREAKDEF, "break definition ignored (suggest removing it)");
4893         else if (parser.tok == Token::KEYWORD)
4894             goto leave;
4895
4896         name = util_strdup(parser_tokval(parser));
4897
4898         /* parse on */
4899         if (!parser_next(parser)) {
4900             delete var;
4901             mem_d(name);
4902             parseerror(parser, "error after variable or field declaration");
4903             return nullptr;
4904         }
4905     }
4906
4907     leave:
4908     /* now this may be an array */
4909     if (parser.tok == '[') {
4910         wasarray = true;
4911         var = parse_arraysize(parser, var);
4912         if (!var) {
4913             if (name) mem_d(name);
4914             return nullptr;
4915         }
4916     }
4917
4918     /* This is the point where we can turn it into a field */
4919     if (isfield) {
4920         /* turn it into a field if desired */
4921         tmp = new ast_value(ctx, "<type:f>", TYPE_FIELD);
4922         tmp->m_next = var;
4923         var = tmp;
4924     }
4925
4926     /* now there may be function parens again */
4927     if (parser.tok == '(' && OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_QCC)
4928         parseerror(parser, "C-style function syntax is not allowed in -std=qcc");
4929     if (parser.tok == '(' && wasarray)
4930         parseerror(parser, "arrays as part of a return type is not supported");
4931     while (parser.tok == '(') {
4932         var = parse_parameter_list(parser, var);
4933         if (!var) {
4934             if (name) mem_d(name);
4935             return nullptr;
4936         }
4937     }
4938
4939     /* finally name it */
4940     if (name) {
4941         var->m_name = name;
4942         // free the name, ast_value_set_name duplicates
4943         mem_d(name);
4944     }
4945
4946     return var;
4947 }
4948
4949 static bool parse_typedef(parser_t &parser)
4950 {
4951     ast_value      *typevar, *oldtype;
4952     ast_expression *old;
4953
4954     typevar = parse_typename(parser, nullptr, nullptr, nullptr);
4955
4956     if (!typevar)
4957         return false;
4958
4959     // while parsing types, the ast_value's get named '<something>'
4960     if (!typevar->m_name.length() || typevar->m_name[0] == '<') {
4961         parseerror(parser, "missing name in typedef");
4962         delete typevar;
4963         return false;
4964     }
4965
4966     if ( (old = parser_find_var(parser, typevar->m_name)) ) {
4967         parseerror(parser, "cannot define a type with the same name as a variable: %s\n"
4968                    " -> `%s` has been declared here: %s:%i",
4969                    typevar->m_name, old->m_context.file, old->m_context.line);
4970         delete typevar;
4971         return false;
4972     }
4973
4974     if ( (oldtype = parser_find_typedef(parser, typevar->m_name, parser._blocktypedefs.back())) ) {
4975         parseerror(parser, "type `%s` has already been declared here: %s:%i",
4976                    typevar->m_name, oldtype->m_context.file, oldtype->m_context.line);
4977         delete typevar;
4978         return false;
4979     }
4980
4981     parser._typedefs.emplace_back(typevar);
4982     util_htset(parser.typedefs.back(), typevar->m_name.c_str(), typevar);
4983
4984     if (parser.tok != ';') {
4985         parseerror(parser, "expected semicolon after typedef");
4986         return false;
4987     }
4988     if (!parser_next(parser)) {
4989         parseerror(parser, "parse error after typedef");
4990         return false;
4991     }
4992
4993     return true;
4994 }
4995
4996 static const char *cvq_to_str(int cvq) {
4997     switch (cvq) {
4998         case CV_NONE:  return "none";
4999         case CV_VAR:   return "`var`";
5000         case CV_CONST: return "`const`";
5001         default:       return "<INVALID>";
5002     }
5003 }
5004
5005 static bool parser_check_qualifiers(parser_t &parser, const ast_value *var, const ast_value *proto)
5006 {
5007     bool av, ao;
5008     if (proto->m_cvq != var->m_cvq) {
5009         if (!(proto->m_cvq == CV_CONST && var->m_cvq == CV_NONE &&
5010               !OPTS_FLAG(INITIALIZED_NONCONSTANTS) &&
5011               parser.tok == '='))
5012         {
5013             return !parsewarning(parser, WARN_DIFFERENT_QUALIFIERS,
5014                                  "`%s` declared with different qualifiers: %s\n"
5015                                  " -> previous declaration here: %s:%i uses %s",
5016                                  var->m_name, cvq_to_str(var->m_cvq),
5017                                  proto->m_context.file, proto->m_context.line,
5018                                  cvq_to_str(proto->m_cvq));
5019         }
5020     }
5021     av = (var  ->m_flags & AST_FLAG_NORETURN);
5022     ao = (proto->m_flags & AST_FLAG_NORETURN);
5023     if (!av != !ao) {
5024         return !parsewarning(parser, WARN_DIFFERENT_ATTRIBUTES,
5025                              "`%s` declared with different attributes%s\n"
5026                              " -> previous declaration here: %s:%i",
5027                              var->m_name, (av ? ": noreturn" : ""),
5028                              proto->m_context.file, proto->m_context.line,
5029                              (ao ? ": noreturn" : ""));
5030     }
5031     return true;
5032 }
5033
5034 static bool create_array_accessors(parser_t &parser, ast_value *var)
5035 {
5036     char name[1024];
5037     util_snprintf(name, sizeof(name), "%s##SET", var->m_name.c_str());
5038     if (!parser_create_array_setter(parser, var, name))
5039         return false;
5040     util_snprintf(name, sizeof(name), "%s##GET", var->m_name.c_str());
5041     if (!parser_create_array_getter(parser, var, var->m_next, name))
5042         return false;
5043     return true;
5044 }
5045
5046 static bool parse_array(parser_t &parser, ast_value *array)
5047 {
5048     size_t i;
5049     if (array->m_initlist.size()) {
5050         parseerror(parser, "array already initialized elsewhere");
5051         return false;
5052     }
5053     if (!parser_next(parser)) {
5054         parseerror(parser, "parse error in array initializer");
5055         return false;
5056     }
5057     i = 0;
5058     while (parser.tok != '}') {
5059         ast_value *v = (ast_value*)parse_expression_leave(parser, true, false, false);
5060         if (!v)
5061             return false;
5062         if (!ast_istype(v, ast_value) || !v->m_hasvalue || v->m_cvq != CV_CONST) {
5063             ast_unref(v);
5064             parseerror(parser, "initializing element must be a compile time constant");
5065             return false;
5066         }
5067         array->m_initlist.push_back(v->m_constval);
5068         if (v->m_vtype == TYPE_STRING) {
5069             array->m_initlist[i].vstring = util_strdupe(array->m_initlist[i].vstring);
5070             ++i;
5071         }
5072         ast_unref(v);
5073         if (parser.tok == '}')
5074             break;
5075         if (parser.tok != ',' || !parser_next(parser)) {
5076             parseerror(parser, "expected comma or '}' in element list");
5077             return false;
5078         }
5079     }
5080     if (!parser_next(parser) || parser.tok != ';') {
5081         parseerror(parser, "expected semicolon after initializer, got %s");
5082         return false;
5083     }
5084     /*
5085     if (!parser_next(parser)) {
5086         parseerror(parser, "parse error after initializer");
5087         return false;
5088     }
5089     */
5090
5091     if (array->m_flags & AST_FLAG_ARRAY_INIT) {
5092         if (array->m_count != (size_t)-1) {
5093             parseerror(parser, "array `%s' has already been initialized with %u elements",
5094                        array->m_name, (unsigned)array->m_count);
5095         }
5096         array->m_count = array->m_initlist.size();
5097         if (!create_array_accessors(parser, array))
5098             return false;
5099     }
5100     return true;
5101 }
5102
5103 static bool parse_variable(parser_t &parser, ast_block *localblock, bool nofields, int qualifier, ast_value *cached_typedef, bool noref, bool is_static, uint32_t qflags, char *vstring)
5104 {
5105     if (!localblock && is_static) {
5106         parseerror(parser, "`static` qualifier is not supported in global scope");
5107     }
5108
5109     // get the first complete variable
5110     ast_value *basetype = nullptr;
5111     auto var = parse_typename(parser, &basetype, cached_typedef, nullptr);
5112     if (!var) {
5113         if (basetype) {
5114             delete basetype;
5115         }
5116         return false;
5117     }
5118
5119     // while parsing types, the ast_value's get named '<something>'
5120     if (!var->m_name.length() || var->m_name[0] == '<') {
5121         parseerror(parser, "declaration does not declare anything");
5122         if (basetype) {
5123             delete basetype;
5124         }
5125         return false;
5126     }
5127
5128
5129     size_t     i;
5130
5131     bool      isparam   = false;
5132     bool      isvector  = false;
5133     bool      cleanvar  = true;
5134
5135     ast_member *me[3] = { nullptr, nullptr, nullptr };
5136     ast_member *last_me[3] = { nullptr, nullptr, nullptr };
5137
5138     bool retval = true;
5139     while (true) {
5140         ast_value *proto = nullptr;
5141         bool wasarray = false;
5142
5143         // Part 0: finish the type
5144         if (parser.tok == '(') {
5145             if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_QCC) {
5146                 parseerror(parser, "C-style function syntax is not allowed in -std=qcc");
5147             }
5148             var = parse_parameter_list(parser, var);
5149             if (!var) {
5150                 retval = false;
5151                 goto cleanup;
5152             }
5153         }
5154         // we only allow 1-dimensional arrays
5155         if (parser.tok == '[') {
5156             wasarray = true;
5157             var = parse_arraysize(parser, var);
5158             if (!var) {
5159                 retval = false;
5160                 goto cleanup;
5161             }
5162         }
5163         if (parser.tok == '(' && wasarray) {
5164             parseerror(parser, "arrays as part of a return type is not supported");
5165             // we'll still parse the type completely for now
5166         }
5167         // for functions returning functions
5168         while (parser.tok == '(') {
5169             if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_QCC) {
5170                 parseerror(parser, "C-style function syntax is not allowed in -std=qcc");
5171             }
5172             var = parse_parameter_list(parser, var);
5173             if (!var) {
5174                 retval = false;
5175                 goto cleanup;
5176             }
5177         }
5178
5179         var->m_cvq = qualifier;
5180         if (qflags & AST_FLAG_COVERAGE) {
5181             // specified in QC, drop our default
5182             var->m_flags &= ~(AST_FLAG_COVERAGE_MASK);
5183         }
5184         var->m_flags |= qflags;
5185
5186         /*
5187          * store the vstring back to var for alias and
5188          * deprecation messages.
5189          */
5190         if (var->m_flags & AST_FLAG_DEPRECATED
5191             || var->m_flags & AST_FLAG_ALIAS) {
5192             var->m_desc = vstring;
5193         }
5194
5195         if (parser_find_global(parser, var->m_name) && var->m_flags & AST_FLAG_ALIAS) {
5196             parseerror(parser, "function aliases cannot be forward declared");
5197             retval = false;
5198             goto cleanup;
5199         }
5200
5201
5202         /* Part 1:
5203          * check for validity: (end_sys_..., multiple-definitions, prototypes, ...)
5204          * Also: if there was a prototype, `var` will be deleted and set to `proto` which
5205          * is then filled with the previous definition and the parameter-names replaced.
5206          */
5207         if (var->m_name == "nil") {
5208             if (OPTS_FLAG(UNTYPED_NIL)) {
5209                 if (!localblock || !OPTS_FLAG(PERMISSIVE)) {
5210                     parseerror(parser, "name `nil` not allowed (try -fpermissive)");
5211                 }
5212             } else {
5213                 (void) parsewarning(parser, WARN_RESERVED_NAMES, "variable name `nil` is reserved");
5214             }
5215         }
5216         if (!localblock) {
5217             /* Deal with end_sys_ vars */
5218             bool was_end = false;
5219             if (var->m_name == "end_sys_globals") {
5220                 var->m_flags |= AST_FLAG_NOREF;
5221                 parser.crc_globals = parser.globals.size();
5222                 was_end = true;
5223             }
5224             else if (var->m_name == "end_sys_fields") {
5225                 var->m_flags |= AST_FLAG_NOREF;
5226                 parser.crc_fields = parser.fields.size();
5227                 was_end = true;
5228             }
5229             if (was_end && var->m_vtype == TYPE_FIELD) {
5230                 if (parsewarning(parser, WARN_END_SYS_FIELDS,
5231                                  "global '%s' hint should not be a field",
5232                                  parser_tokval(parser))) {
5233                     retval = false;
5234                     goto cleanup;
5235                 }
5236             }
5237
5238             if (!nofields && var->m_vtype == TYPE_FIELD) {
5239                 /* deal with field declarations */
5240                 auto old = parser_find_field(parser, var->m_name);
5241                 if (old) {
5242                     if (parsewarning(parser, WARN_FIELD_REDECLARED, "field `%s` already declared here: %s:%i",
5243                                      var->m_name, old->m_context.file, (int)old->m_context.line)) {
5244                         retval = false;
5245                         goto cleanup;
5246                     }
5247                     delete var;
5248                     var = nullptr;
5249                     goto skipvar;
5250                     /*
5251                     parseerror(parser, "field `%s` already declared here: %s:%i",
5252                                var->m_name, old->m_context.file, old->m_context.line);
5253                     retval = false;
5254                     goto cleanup;
5255                     */
5256                 }
5257                 if ((OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_QCC || OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_FTEQCC)
5258                     && (old = parser_find_global(parser, var->m_name)))
5259                 {
5260                     parseerror(parser, "cannot declare a field and a global of the same name with -std=qcc");
5261                     parseerror(parser, "field `%s` already declared here: %s:%i",
5262                                var->m_name, old->m_context.file, old->m_context.line);
5263                     retval = false;
5264                     goto cleanup;
5265                 }
5266             }
5267             else
5268             {
5269                 /* deal with other globals */
5270                 auto old = parser_find_global(parser, var->m_name);
5271                 if (old && var->m_vtype == TYPE_FUNCTION && old->m_vtype == TYPE_FUNCTION)
5272                 {
5273                     /* This is a function which had a prototype */
5274                     if (!ast_istype(old, ast_value)) {
5275                         parseerror(parser, "internal error: prototype is not an ast_value");
5276                         retval = false;
5277                         goto cleanup;
5278                     }
5279                     proto = (ast_value*)old;
5280                     proto->m_desc = var->m_desc;
5281                     if (!proto->compareType(*var)) {
5282                         parseerror(parser, "conflicting types for `%s`, previous declaration was here: %s:%i",
5283                                    proto->m_name,
5284                                    proto->m_context.file, proto->m_context.line);
5285                         retval = false;
5286                         goto cleanup;
5287                     }
5288                     /* we need the new parameter-names */
5289                     for (i = 0; i < proto->m_type_params.size(); ++i)
5290                         proto->m_type_params[i]->m_name = var->m_type_params[i]->m_name;
5291                     if (!parser_check_qualifiers(parser, var, proto)) {
5292                         retval = false;
5293                         proto = nullptr;
5294                         goto cleanup;
5295                     }
5296                     proto->m_flags |= var->m_flags;
5297                     delete var;
5298                     var = proto;
5299                 }
5300                 else
5301                 {
5302                     /* other globals */
5303                     if (old) {
5304                         if (parsewarning(parser, WARN_DOUBLE_DECLARATION,
5305                                          "global `%s` already declared here: %s:%i",
5306                                          var->m_name, old->m_context.file, old->m_context.line))
5307                         {
5308                             retval = false;
5309                             goto cleanup;
5310                         }
5311                         if (old->m_flags & AST_FLAG_FINAL_DECL) {
5312                             parseerror(parser, "cannot redeclare variable `%s`, declared final here: %s:%i",
5313                                        var->m_name, old->m_context.file, old->m_context.line);
5314                             retval = false;
5315                             goto cleanup;
5316                         }
5317                         proto = (ast_value*)old;
5318                         if (!ast_istype(old, ast_value)) {
5319                             parseerror(parser, "internal error: not an ast_value");
5320                             retval = false;
5321                             proto = nullptr;
5322                             goto cleanup;
5323                         }
5324                         if (!parser_check_qualifiers(parser, var, proto)) {
5325                             retval = false;
5326                             proto = nullptr;
5327                             goto cleanup;
5328                         }
5329                         proto->m_flags |= var->m_flags;
5330                         /* copy the context for finals,
5331                          * so the error can show where it was actually made 'final'
5332                          */
5333                         if (proto->m_flags & AST_FLAG_FINAL_DECL)
5334                             old->m_context = var->m_context;
5335                         delete var;
5336                         var = proto;
5337                     }
5338                     if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_QCC &&
5339                         (old = parser_find_field(parser, var->m_name)))
5340                     {
5341                         parseerror(parser, "cannot declare a field and a global of the same name with -std=qcc");
5342                         parseerror(parser, "global `%s` already declared here: %s:%i",
5343                                    var->m_name, old->m_context.file, old->m_context.line);
5344                         retval = false;
5345                         goto cleanup;
5346                     }
5347                 }
5348             }
5349         }
5350         else { // it's not a global
5351             if (auto old = parser_find_local(parser, var->m_name, parser.variables.size() - 1, &isparam)) {
5352                 if (!isparam) {
5353                     parseerror(parser, "local `%s` already declared here: %s:%i",
5354                                var->m_name, old->m_context.file, (int) old->m_context.line);
5355                     retval = false;
5356                     goto cleanup;
5357                 }
5358             }
5359             // doing this here as the above is just for a single scope
5360             if (auto old = parser_find_local(parser, var->m_name, 0, &isparam)) {
5361                 if (isparam) {
5362                     if (parsewarning(parser, WARN_LOCAL_SHADOWS,
5363                                      "local `%s` is shadowing a parameter", var->m_name)) {
5364                         parseerror(parser, "local `%s` already declared here: %s:%i",
5365                                    var->m_name, old->m_context.file, (int) old->m_context.line);
5366                         retval = false;
5367                         goto cleanup;
5368                     }
5369                     if (OPTS_OPTION_U32(OPTION_STANDARD) != COMPILER_GMQCC) {
5370                         delete var;
5371                         if (ast_istype(old, ast_value))
5372                             var = proto = (ast_value *) old;
5373                         else {
5374                             var = nullptr;
5375                             goto skipvar;
5376                         }
5377                     }
5378                 }
5379             }
5380         }
5381
5382         if (noref || parser.noref) {
5383             var->m_flags |= AST_FLAG_NOREF;
5384         }
5385
5386         /* Part 2:
5387          * Create the global/local, and deal with vector types.
5388          */
5389         if (!proto) {
5390             if (var->m_vtype == TYPE_VECTOR) {
5391                 isvector = true;
5392             } else if (var->m_vtype == TYPE_FIELD
5393                        && var->m_next->m_vtype == TYPE_VECTOR) {
5394                 isvector = true;
5395             }
5396
5397             if (isvector && !create_vector_members(var, me)) {
5398                 retval = false;
5399                 goto cleanup;
5400             }
5401
5402             if (!localblock) {
5403                 // deal with global variables, fields, functions
5404                 if (!nofields && var->m_vtype == TYPE_FIELD && parser.tok != '=') {
5405                     var->m_isfield = true;
5406                     parser.fields.push_back(var);
5407                     util_htset(parser.htfields, var->m_name.c_str(), var);
5408                     if (isvector) {
5409                         for (i = 0; i < 3; ++i) {
5410                             parser.fields.push_back(me[i]);
5411                             util_htset(parser.htfields, me[i]->m_name.c_str(), me[i]);
5412                         }
5413                     }
5414                 } else if (!(var->m_flags & AST_FLAG_ALIAS)) {
5415                     parser_addglobal(parser, var->m_name, var);
5416                     if (isvector) {
5417                         for (i = 0; i < 3; ++i) {
5418                             parser_addglobal(parser, me[i]->m_name.c_str(), me[i]);
5419                         }
5420                     }
5421                 } else {
5422                     ast_expression *find  = parser_find_global(parser, var->m_desc);
5423
5424                     if (!find) {
5425                         compile_error(parser_ctx(parser), "undeclared variable `%s` for alias `%s`", var->m_desc, var->m_name);
5426                         return false;
5427                     }
5428
5429                     if (!var->compareType(*find)) {
5430                         char ty1[1024];
5431                         char ty2[1024];
5432
5433                         ast_type_to_string(find, ty1, sizeof(ty1));
5434                         ast_type_to_string(var,  ty2, sizeof(ty2));
5435
5436                         compile_error(parser_ctx(parser), "incompatible types `%s` and `%s` for alias `%s`",
5437                             ty1, ty2, var->m_name
5438                         );
5439                         return false;
5440                     }
5441
5442                     util_htset(parser.aliases, var->m_name.c_str(), find);
5443
5444                     /* generate aliases for vector components */
5445                     if (isvector) {
5446                         char *buffer[3];
5447
5448                         util_asprintf(&buffer[0], "%s_x", var->m_desc.c_str());
5449                         util_asprintf(&buffer[1], "%s_y", var->m_desc.c_str());
5450                         util_asprintf(&buffer[2], "%s_z", var->m_desc.c_str());
5451
5452                         util_htset(parser.aliases, me[0]->m_name.c_str(), parser_find_global(parser, buffer[0]));
5453                         util_htset(parser.aliases, me[1]->m_name.c_str(), parser_find_global(parser, buffer[1]));
5454                         util_htset(parser.aliases, me[2]->m_name.c_str(), parser_find_global(parser, buffer[2]));
5455
5456                         mem_d(buffer[0]);
5457                         mem_d(buffer[1]);
5458                         mem_d(buffer[2]);
5459                     }
5460                 }
5461             } else {
5462                 if (is_static) {
5463                     // a static adds itself to be generated like any other global
5464                     // but is added to the local namespace instead
5465                     std::string defname;
5466                     size_t  prefix_len;
5467                     size_t  sn, sn_size;
5468
5469                     defname = parser.function->m_name;
5470                     defname.append(2, ':');
5471
5472                     // remember the length up to here
5473                     prefix_len = defname.length();
5474
5475                     // Add it to the local scope
5476                     util_htset(parser.variables.back(), var->m_name.c_str(), (void*)var);
5477
5478                     // now rename the global
5479                     defname.append(var->m_name);
5480                     // if a variable of that name already existed, add the
5481                     // counter value.
5482                     // The counter is incremented either way.
5483                     sn_size = parser.function->m_static_names.size();
5484                     for (sn = 0; sn != sn_size; ++sn) {
5485                         if (parser.function->m_static_names[sn] == var->m_name.c_str())
5486                             break;
5487                     }
5488                     if (sn != sn_size) {
5489                         char *num = nullptr;
5490                         int   len = util_asprintf(&num, "#%u", parser.function->m_static_count);
5491                         defname.append(num, 0, len);
5492                         mem_d(num);
5493                     }
5494                     else
5495                         parser.function->m_static_names.emplace_back(var->m_name);
5496                     parser.function->m_static_count++;
5497                     var->m_name = defname;
5498
5499                     // push it to the to-be-generated globals
5500                     parser.globals.push_back(var);
5501
5502                     // same game for the vector members
5503                     if (isvector) {
5504                         defname.erase(prefix_len);
5505                         for (i = 0; i < 3; ++i) {
5506                             util_htset(parser.variables.back(), me[i]->m_name.c_str(), (void*)(me[i]));
5507                             me[i]->m_name = defname + me[i]->m_name;
5508                             parser.globals.push_back(me[i]);
5509                         }
5510                     }
5511                 } else {
5512                     localblock->m_locals.push_back(var);
5513                     parser_addlocal(parser, var->m_name, var);
5514                     if (isvector) {
5515                         for (i = 0; i < 3; ++i) {
5516                             parser_addlocal(parser, me[i]->m_name, me[i]);
5517                             localblock->collect(me[i]);
5518                         }
5519                     }
5520                 }
5521             }
5522         }
5523         memcpy(last_me, me, sizeof(me));
5524         me[0] = me[1] = me[2] = nullptr;
5525         cleanvar = false;
5526         /* Part 2.2
5527          * deal with arrays
5528          */
5529         if (var->m_vtype == TYPE_ARRAY) {
5530             if (var->m_count != (size_t)-1) {
5531                 if (!create_array_accessors(parser, var))
5532                     goto cleanup;
5533             }
5534         } else if (!localblock && !nofields &&
5535                  var->m_vtype == TYPE_FIELD &&
5536                  var->m_next->m_vtype == TYPE_ARRAY) {
5537             char name[1024];
5538             ast_expression *telem;
5539             ast_value      *tfield;
5540             ast_value      *array = (ast_value*)var->m_next;
5541
5542             if (!ast_istype(var->m_next, ast_value)) {
5543                 parseerror(parser, "internal error: field element type must be an ast_value");
5544                 goto cleanup;
5545             }
5546
5547             util_snprintf(name, sizeof(name), "%s##SETF", var->m_name.c_str());
5548             if (!parser_create_array_field_setter(parser, array, name))
5549                 goto cleanup;
5550
5551             telem = new ast_expression(ast_copy_type, var->m_context, *array->m_next);
5552             tfield = new ast_value(var->m_context, "<.type>", TYPE_FIELD);
5553             tfield->m_next = telem;
5554             util_snprintf(name, sizeof(name), "%s##GETFP", var->m_name.c_str());
5555             if (!parser_create_array_getter(parser, array, tfield, name)) {
5556                 delete tfield;
5557                 goto cleanup;
5558             }
5559             delete tfield;
5560         }
5561
5562 skipvar:
5563         if (parser.tok == ';') {
5564             delete basetype;
5565             if (!parser_next(parser)) {
5566                 parseerror(parser, "error after variable declaration");
5567                 return false;
5568             }
5569             return true;
5570         }
5571
5572         if (parser.tok == ',')
5573             goto another;
5574
5575         /*
5576         if (!var || (!localblock && !nofields && basetype->m_vtype == TYPE_FIELD)) {
5577         */
5578         if (!var) {
5579             parseerror(parser, "missing comma or semicolon while parsing variables");
5580             break;
5581         }
5582
5583         if (localblock && OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_QCC) {
5584             if (parsewarning(parser, WARN_LOCAL_CONSTANTS,
5585                              "initializing expression turns variable `%s` into a constant in this standard",
5586                              var->m_name) ) {
5587                 break;
5588             }
5589         }
5590
5591         if (parser.tok != '{' || var->m_vtype != TYPE_FUNCTION) {
5592             if (parser.tok != '=') {
5593                 parseerror(parser, "missing semicolon or initializer, got: `%s`", parser_tokval(parser));
5594                 break;
5595             }
5596
5597             if (!parser_next(parser)) {
5598                 parseerror(parser, "error parsing initializer");
5599                 break;
5600             }
5601         }
5602         else if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_QCC) {
5603             parseerror(parser, "expected '=' before function body in this standard");
5604         }
5605
5606         if (parser.tok == '#') {
5607             ast_function *func   = nullptr;
5608             ast_value    *number = nullptr;
5609
5610             if (localblock) {
5611                 parseerror(parser, "cannot declare builtins within functions");
5612                 break;
5613             }
5614             if (var->m_vtype != TYPE_FUNCTION) {
5615                 parseerror(parser, "unexpected builtin number, '%s' is not a function", var->m_name);
5616                 break;
5617             }
5618             if (!parser_next(parser)) {
5619                 parseerror(parser, "expected builtin number");
5620                 break;
5621             }
5622
5623             int builtin_num;
5624             if (OPTS_FLAG(EXPRESSIONS_FOR_BUILTINS)) {
5625                 number = (ast_value*)parse_expression_leave(parser, true, false, false);
5626                 if (!number) {
5627                     parseerror(parser, "builtin number expected");
5628                     break;
5629                 }
5630                 if (!ast_istype(number, ast_value) || !number->m_hasvalue || number->m_cvq != CV_CONST)
5631                 {
5632                     ast_unref(number);
5633                     parseerror(parser, "builtin number must be a compile time constant");
5634                     break;
5635                 }
5636                 if (number->m_vtype == TYPE_INTEGER)
5637                     builtin_num = number->m_constval.vint;
5638                 else if (number->m_vtype == TYPE_FLOAT)
5639                     builtin_num = number->m_constval.vfloat;
5640                 else {
5641                     ast_unref(number);
5642                     parseerror(parser, "builtin number must be an integer constant");
5643                     break;
5644                 }
5645                 ast_unref(number);
5646
5647                 float integral;
5648                 float fractional = modff(builtin_num, &integral);
5649                 if (builtin_num < 0 || fractional != 0) {
5650                     parseerror(parser, "builtin number must be an integer greater than zero");
5651                     break;
5652                 }
5653
5654                 /* we only want the integral part anyways */
5655                 builtin_num = integral;
5656             } else if (parser.tok == Token::INTCONST) {
5657                 builtin_num = parser_token(parser)->constval.i;
5658             } else {
5659                 parseerror(parser, "builtin number must be a compile time constant");
5660                 break;
5661             }
5662
5663             if (var->m_hasvalue) {
5664                 (void) parsewarning(parser, WARN_DOUBLE_DECLARATION,
5665                                     "builtin `%s` has already been defined\n"
5666                                     " -> previous declaration here: %s:%i",
5667                                     var->m_name, var->m_context.file, (int)var->m_context.line);
5668             }
5669             else
5670             {
5671                 func = ast_function::make(var->m_context, var->m_name, var);
5672                 if (!func) {
5673                     parseerror(parser, "failed to allocate function for `%s`", var->m_name);
5674                     break;
5675                 }
5676                 parser.functions.push_back(func);
5677
5678                 func->m_builtin = -builtin_num-1;
5679             }
5680
5681             if (OPTS_FLAG(EXPRESSIONS_FOR_BUILTINS)
5682                     ? (parser.tok != ',' && parser.tok != ';')
5683                     : (!parser_next(parser)))
5684             {
5685                 parseerror(parser, "expected comma or semicolon");
5686                 delete func;
5687                 var->m_constval.vfunc = nullptr;
5688                 break;
5689             }
5690         }
5691         else if (var->m_vtype == TYPE_ARRAY && parser.tok == '{')
5692         {
5693             if (localblock) {
5694                 /* Note that fteqcc and most others don't even *have*
5695                  * local arrays, so this is not a high priority.
5696                  */
5697                 parseerror(parser, "TODO: initializers for local arrays");
5698                 break;
5699             }
5700
5701             var->m_hasvalue = true;
5702             if (!parse_array(parser, var))
5703                 break;
5704         }
5705         else if (var->m_vtype == TYPE_FUNCTION && (parser.tok == '{' || parser.tok == '['))
5706         {
5707             if (localblock) {
5708                 parseerror(parser, "cannot declare functions within functions");
5709                 break;
5710             }
5711
5712             if (proto)
5713                 proto->m_context = parser_ctx(parser);
5714
5715             if (!parse_function_body(parser, var))
5716                 break;
5717             delete basetype;
5718             for (auto &it : parser.gotos)
5719                 parseerror(parser, "undefined label: `%s`", it->m_name);
5720             parser.gotos.clear();
5721             parser.labels.clear();
5722             return true;
5723         } else {
5724             bool folded_const = false;
5725
5726             auto cexp = parse_expression_leave(parser, true, false, false);
5727             if (!cexp)
5728                 break;
5729             auto cval = ast_istype(cexp, ast_value) ? reinterpret_cast<ast_value*>(cexp) : nullptr;
5730
5731             /* deal with foldable constants: */
5732             if (localblock &&
5733                 var->m_cvq == CV_CONST && cval && cval->m_hasvalue && cval->m_cvq == CV_CONST && !cval->m_isfield)
5734             {
5735                 /* remove it from the current locals */
5736                 if (isvector) {
5737                     for (i = 0; i < 3; ++i) {
5738                         parser._locals.pop_back();
5739                         localblock->m_collect.pop_back();
5740                     }
5741                 }
5742                 /* do sanity checking, this function really needs refactoring */
5743                 if (parser._locals.back() != var)
5744                     parseerror(parser, "internal error: unexpected change in local variable handling");
5745                 else
5746                     parser._locals.pop_back();
5747                 if (localblock->m_locals.back() != var)
5748                     parseerror(parser, "internal error: unexpected change in local variable handling (2)");
5749                 else
5750                     localblock->m_locals.pop_back();
5751                 /* push it to the to-be-generated globals */
5752                 parser.globals.push_back(var);
5753                 if (isvector)
5754                     for (i = 0; i < 3; ++i)
5755                         parser.globals.push_back(last_me[i]);
5756                 folded_const = true;
5757             }
5758
5759             if (folded_const || !localblock || is_static) {
5760                 if (cval != parser.nil &&
5761                     (!cval || ((!cval->m_hasvalue || cval->m_cvq != CV_CONST) && !cval->m_isfield))
5762                    )
5763                 {
5764                     parseerror(parser, "initializer is non constant");
5765                 }
5766                 else
5767                 {
5768                     if (!is_static &&
5769                         !OPTS_FLAG(INITIALIZED_NONCONSTANTS) &&
5770                         qualifier != CV_VAR)
5771                     {
5772                         var->m_cvq = CV_CONST;
5773                     }
5774                     if (cval == parser.nil)
5775                     {
5776                         var->m_flags |= AST_FLAG_INITIALIZED;
5777                         var->m_flags |= AST_FLAG_NOREF;
5778                     }
5779                     else
5780                     {
5781                         var->m_hasvalue = true;
5782                         if (cval->m_vtype == TYPE_STRING)
5783                             var->m_constval.vstring = parser_strdup(cval->m_constval.vstring);
5784                         else if (cval->m_vtype == TYPE_FIELD)
5785                             var->m_constval.vfield = cval;
5786                         else
5787                             memcpy(&var->m_constval, &cval->m_constval, sizeof(var->m_constval));
5788                         ast_unref(cval);
5789                     }
5790                 }
5791             } else {
5792                 shunt sy;
5793                 int cvq = var->m_cvq;
5794                 var->m_cvq = CV_NONE;
5795                 sy.out.push_back(syexp(var->m_context, var));
5796                 sy.out.push_back(syexp(cexp->m_context, cexp));
5797                 sy.ops.push_back(syop(var->m_context, parser.assign_op));
5798                 if (!parser_sy_apply_operator(parser, &sy))
5799                     ast_unref(cexp);
5800                 else {
5801                     if (sy.out.size() != 1 && sy.ops.size() != 0)
5802                         parseerror(parser, "internal error: leaked operands");
5803                     if (!localblock->addExpr(sy.out[0].out))
5804                         break;
5805                 }
5806                 var->m_cvq = cvq;
5807             }
5808             /* a constant initialized to an inexact value should be marked inexact:
5809              * const float x = <inexact>; should propagate the inexact flag
5810              */
5811             if (var->m_cvq == CV_CONST && var->m_vtype == TYPE_FLOAT) {
5812                 if (cval && cval->m_hasvalue && cval->m_cvq == CV_CONST)
5813                     var->m_inexact = cval->m_inexact;
5814             }
5815         }
5816
5817 another:
5818         if (parser.tok == ',') {
5819             if (!parser_next(parser)) {
5820                 parseerror(parser, "expected another variable");
5821                 break;
5822             }
5823
5824             if (parser.tok != Token::IDENT) {
5825                 parseerror(parser, "expected another variable");
5826                 break;
5827             }
5828             var = new ast_value(ast_copy_type, *basetype);
5829             cleanvar = true;
5830             var->m_name = parser_tokval(parser);
5831             if (!parser_next(parser)) {
5832                 parseerror(parser, "error parsing variable declaration");
5833                 break;
5834             }
5835             continue;
5836         }
5837
5838         if (parser.tok != ';') {
5839             parseerror(parser, "missing semicolon after variables");
5840             break;
5841         }
5842
5843         if (!parser_next(parser)) {
5844             parseerror(parser, "parse error after variable declaration");
5845             break;
5846         }
5847
5848         delete basetype;
5849         return true;
5850     }
5851
5852     if (cleanvar && var)
5853         delete var;
5854     delete basetype;
5855     return false;
5856
5857 cleanup:
5858     delete basetype;
5859     if (cleanvar && var)
5860         delete var;
5861     delete me[0];
5862     delete me[1];
5863     delete me[2];
5864     return retval;
5865 }
5866
5867 static bool parser_global_statement(parser_t &parser)
5868 {
5869     ast_value *istype    = nullptr;
5870     if ((parser.tok == Token::IDENT && (istype = parser_find_typedef(parser, parser_tokval(parser), 0)) != nullptr)
5871         || parser.tok == Token::TYPENAME
5872         || parser.tok == '.' || parser.tok == Token::DOTS) {
5873         return parse_variable(parser, nullptr, false, CV_NONE, istype, false, false, 0, nullptr);
5874     }
5875
5876     int cvq = CV_WRONG;
5877     bool noref = false;
5878     bool is_static = false;
5879     uint32_t qflags = 0;
5880     char *vstring = nullptr;
5881     if (parse_qualifiers(parser, false, &cvq, &noref, &is_static, &qflags, &vstring)) {
5882         if (cvq == CV_WRONG)
5883             return false;
5884         return parse_variable(parser, nullptr, false, cvq, nullptr, noref, is_static, qflags, vstring);
5885     }
5886
5887     if (parser.tok == Token::IDENT && strcmp(parser_tokval(parser), "enum") == 0) {
5888         return parse_enum(parser);
5889     }
5890
5891     if (parser.tok == Token::KEYWORD) {
5892         if (strcmp(parser_tokval(parser), "typedef") == 0) {
5893             if (!parser_next(parser)) {
5894                 parseerror(parser, "expected type definition after 'typedef'");
5895                 return false;
5896             }
5897             return parse_typedef(parser);
5898         }
5899         parseerror(parser, "unrecognized keyword `%s`", parser_tokval(parser));
5900         return false;
5901     }
5902
5903     if (parser.tok == '#') {
5904         return parse_pragma(parser);
5905     }
5906
5907     if (parser.tok == '$') {
5908         if (!parser_next(parser)) {
5909             parseerror(parser, "parse error");
5910             return false;
5911         }
5912         return true;
5913     }
5914
5915     parseerror(parser, "unexpected token: `%s`", parser.lex->tok.value);
5916     return false;
5917 }
5918
5919 static uint16_t progdefs_crc_sum(uint16_t old, const char *str)
5920 {
5921     return util_crc16(old, str, strlen(str));
5922 }
5923
5924 static void progdefs_crc_file(const char *str)
5925 {
5926     /* write to progdefs.h here */
5927     (void)str;
5928 }
5929
5930 static uint16_t progdefs_crc_both(uint16_t old, const char *str)
5931 {
5932     old = progdefs_crc_sum(old, str);
5933     progdefs_crc_file(str);
5934     return old;
5935 }
5936
5937 static void generate_checksum(parser_t &parser, ir_builder &ir)
5938 {
5939     uint16_t   crc = 0xFFFF;
5940     size_t     i;
5941     ast_value *value;
5942
5943     crc = progdefs_crc_both(crc, "\n/* file generated by qcc, do not modify */\n\ntypedef struct\n{");
5944     crc = progdefs_crc_sum(crc, "\tint\tpad[28];\n");
5945     /*
5946     progdefs_crc_file("\tint\tpad;\n");
5947     progdefs_crc_file("\tint\tofs_return[3];\n");
5948     progdefs_crc_file("\tint\tofs_parm0[3];\n");
5949     progdefs_crc_file("\tint\tofs_parm1[3];\n");
5950     progdefs_crc_file("\tint\tofs_parm2[3];\n");
5951     progdefs_crc_file("\tint\tofs_parm3[3];\n");
5952     progdefs_crc_file("\tint\tofs_parm4[3];\n");
5953     progdefs_crc_file("\tint\tofs_parm5[3];\n");
5954     progdefs_crc_file("\tint\tofs_parm6[3];\n");
5955     progdefs_crc_file("\tint\tofs_parm7[3];\n");
5956     */
5957     for (i = 0; i < parser.crc_globals; ++i) {
5958         if (!ast_istype(parser.globals[i], ast_value))
5959             continue;
5960         value = (ast_value*)(parser.globals[i]);
5961         switch (value->m_vtype) {
5962             case TYPE_FLOAT:    crc = progdefs_crc_both(crc, "\tfloat\t"); break;
5963             case TYPE_VECTOR:   crc = progdefs_crc_both(crc, "\tvec3_t\t"); break;
5964             case TYPE_STRING:   crc = progdefs_crc_both(crc, "\tstring_t\t"); break;
5965             case TYPE_FUNCTION: crc = progdefs_crc_both(crc, "\tfunc_t\t"); break;
5966             default:
5967                 crc = progdefs_crc_both(crc, "\tint\t");
5968                 break;
5969         }
5970         crc = progdefs_crc_both(crc, value->m_name.c_str());
5971         crc = progdefs_crc_both(crc, ";\n");
5972     }
5973     crc = progdefs_crc_both(crc, "} globalvars_t;\n\ntypedef struct\n{\n");
5974     for (i = 0; i < parser.crc_fields; ++i) {
5975         if (!ast_istype(parser.fields[i], ast_value))
5976             continue;
5977         value = (ast_value*)(parser.fields[i]);
5978         switch (value->m_next->m_vtype) {
5979             case TYPE_FLOAT:    crc = progdefs_crc_both(crc, "\tfloat\t"); break;
5980             case TYPE_VECTOR:   crc = progdefs_crc_both(crc, "\tvec3_t\t"); break;
5981             case TYPE_STRING:   crc = progdefs_crc_both(crc, "\tstring_t\t"); break;
5982             case TYPE_FUNCTION: crc = progdefs_crc_both(crc, "\tfunc_t\t"); break;
5983             default:
5984                 crc = progdefs_crc_both(crc, "\tint\t");
5985                 break;
5986         }
5987         crc = progdefs_crc_both(crc, value->m_name.c_str());
5988         crc = progdefs_crc_both(crc, ";\n");
5989     }
5990     crc = progdefs_crc_both(crc, "} entvars_t;\n\n");
5991     ir.m_code->crc = crc;
5992 }
5993
5994 parser_t::parser_t()
5995     : lex(nullptr)
5996     , tok(Token::NONE)
5997     , ast_cleaned(false)
5998     , translated(0)
5999     , crc_globals(0)
6000     , crc_fields(0)
6001     , function(nullptr)
6002     , aliases(util_htnew(PARSER_HT_SIZE))
6003     , htfields(util_htnew(PARSER_HT_SIZE))
6004     , htglobals(util_htnew(PARSER_HT_SIZE))
6005     , assign_op(nullptr)
6006     , noref(false)
6007     , max_param_count(1)
6008     , m_fold(*this)
6009     , m_intrin(*this)
6010 {
6011     variables.push_back(htfields);
6012     variables.push_back(htglobals);
6013     typedefs.push_back(util_htnew(TYPEDEF_HT_SIZE));
6014     _blocktypedefs.push_back(0);
6015
6016     lex_ctx_t empty_ctx;
6017     empty_ctx.file   = "<internal>";
6018     empty_ctx.line   = 0;
6019     empty_ctx.column = 0;
6020     nil = new ast_value(empty_ctx, "nil", TYPE_NIL);
6021     nil->m_cvq = CV_CONST;
6022     if (OPTS_FLAG(UNTYPED_NIL))
6023         util_htset(htglobals, "nil", (void*)nil);
6024
6025     const_vec[0] = new ast_value(empty_ctx, "<vector.x>", TYPE_NOEXPR);
6026     const_vec[1] = new ast_value(empty_ctx, "<vector.y>", TYPE_NOEXPR);
6027     const_vec[2] = new ast_value(empty_ctx, "<vector.z>", TYPE_NOEXPR);
6028
6029     if (OPTS_OPTION_BOOL(OPTION_ADD_INFO)) {
6030         reserved_version = new ast_value(empty_ctx, "reserved:version", TYPE_STRING);
6031         reserved_version->m_cvq = CV_CONST;
6032         reserved_version->m_hasvalue = true;
6033         reserved_version->m_flags |= AST_FLAG_INCLUDE_DEF;
6034         reserved_version->m_flags |= AST_FLAG_NOREF;
6035         reserved_version->m_constval.vstring = util_strdup(GMQCC_FULL_VERSION_STRING);
6036     } else {
6037         reserved_version = nullptr;
6038     }
6039 }
6040
6041 parser_t::~parser_t()
6042 {
6043     remove_ast();
6044 }
6045
6046 parser_t *parser_create()
6047 {
6048     auto parser = new parser_t;
6049     for (size_t i = 0; i < operator_count; ++i) {
6050         if (operators[i].id == opid1('=')) {
6051             parser->assign_op = &operators[i];
6052             break;
6053         }
6054     }
6055     if (!parser->assign_op) {
6056         con_err("internal error: initializing parser: failed to find assign operator\n");
6057         delete parser;
6058         return nullptr;
6059     }
6060
6061     return parser;
6062 }
6063
6064 /** parser entrypoint */
6065 static bool parser_compile(parser_t &parser)
6066 {
6067     /* initial lexer/parser state */
6068     parser.lex->flags.noops = true;
6069
6070     if (!parser_next(parser)) {
6071         parseerror(parser, "parse error");
6072         compile_errors = true;
6073         goto cleanup;
6074     }
6075     while (parser.tok != Token::END && parser.tok < Token::ERROR) {
6076         if (parser_global_statement(parser)) continue;
6077         if (parser.tok == Token::END) {
6078             parseerror(parser, "unexpected end of file");
6079         } else if (compile_errors) {
6080             parseerror(parser, "there have been errors, bailing out");
6081         }
6082         compile_errors = true;
6083         goto cleanup;
6084     }
6085
6086 cleanup:
6087     lex_close(parser.lex);
6088     parser.lex = nullptr;
6089     return !compile_errors;
6090 }
6091
6092 bool parser_compile_file(parser_t &parser, const char *filename)
6093 {
6094     parser.lex = lex_open(filename);
6095     if (!parser.lex) {
6096         con_err("failed to open file \"%s\"\n", filename);
6097         return false;
6098     }
6099     return parser_compile(parser);
6100 }
6101
6102 bool parser_compile_string(parser_t &parser, const char *name, const char *str, size_t len)
6103 {
6104     parser.lex = lex_open_string(str, len, name);
6105     if (!parser.lex) {
6106         con_err("failed to create lexer for string \"%s\"\n", name);
6107         return false;
6108     }
6109     return parser_compile(parser);
6110 }
6111
6112 void parser_t::remove_ast()
6113 {
6114     if (ast_cleaned)
6115         return;
6116     ast_cleaned = true;
6117     for (auto &it : accessors) {
6118         delete it->m_constval.vfunc;
6119         it->m_constval.vfunc = nullptr;
6120         delete it;
6121     }
6122     for (auto &it : functions) delete it;
6123     for (auto &it : globals) delete it;
6124     for (auto &it : fields) delete it;
6125
6126     for (auto &it : variables) util_htdel(it);
6127     variables.clear();
6128     _blocklocals.clear();
6129     _locals.clear();
6130
6131     _typedefs.clear();
6132     for (auto &it : typedefs) util_htdel(it);
6133     typedefs.clear();
6134     _blocktypedefs.clear();
6135
6136     _block_ctx.clear();
6137
6138     delete nil;
6139
6140     delete const_vec[0];
6141     delete const_vec[1];
6142     delete const_vec[2];
6143
6144     if (reserved_version)
6145         delete reserved_version;
6146
6147     util_htdel(aliases);
6148 }
6149
6150 static bool parser_set_coverage_func(parser_t &parser, ir_builder &ir) {
6151     ast_expression *expr;
6152     ast_value      *cov;
6153     ast_function   *func;
6154
6155     if (!OPTS_OPTION_BOOL(OPTION_COVERAGE))
6156         return true;
6157
6158     func = nullptr;
6159     for (auto &it : parser.functions) {
6160         if (it->m_name == "coverage") {
6161             func = it;
6162             break;
6163         }
6164     }
6165     if (!func) {
6166         if (OPTS_OPTION_BOOL(OPTION_COVERAGE)) {
6167             con_out("coverage support requested but no coverage() builtin declared\n");
6168             return false;
6169         }
6170         return true;
6171     }
6172
6173     cov  = func->m_function_type;
6174     expr = cov;
6175
6176     if (expr->m_vtype != TYPE_FUNCTION || expr->m_type_params.size()) {
6177         char ty[1024];
6178         ast_type_to_string(expr, ty, sizeof(ty));
6179         con_out("invalid type for coverage(): %s\n", ty);
6180         return false;
6181     }
6182
6183     ir.m_coverage_func = func->m_ir_func->m_value;
6184     return true;
6185 }
6186
6187 bool parser_finish(parser_t &parser, const char *output)
6188 {
6189     bool retval = true;
6190
6191     if (compile_errors) {
6192         con_out("*** there were compile errors\n");
6193         return false;
6194     }
6195
6196     ir_builder ir("gmqcc_out");
6197
6198     for (auto &it : parser.fields) {
6199         if (!ast_istype(it, ast_value))
6200             continue;
6201         auto field = reinterpret_cast<ast_value*>(it);
6202         auto hasvalue = field->m_hasvalue;
6203         field->m_hasvalue = false;
6204         if (!field->generateGlobal(ir, true)) {
6205             con_out("failed to generate field %s\n", field->m_name.c_str());
6206             return false;
6207         }
6208         field->m_hasvalue = hasvalue;
6209         if (hasvalue) {
6210             auto subtype = field->m_next;
6211             auto ifld = ir.createField(field->m_name, subtype->m_vtype);
6212             if (subtype->m_vtype == TYPE_FIELD)
6213                 ifld->m_fieldtype = subtype->m_next->m_vtype;
6214             else if (subtype->m_vtype == TYPE_FUNCTION)
6215                 ifld->m_outtype = subtype->m_next->m_vtype;
6216             (void)!field->m_ir_v->setField(ifld);
6217         }
6218     }
6219     for (auto &it : parser.globals) {
6220         if (!ast_istype(it, ast_value))
6221             continue;
6222         auto asvalue = reinterpret_cast<ast_value*>(it);
6223         if (!(asvalue->m_flags & AST_FLAG_NOREF) && asvalue->m_cvq != CV_CONST && asvalue->m_vtype != TYPE_FUNCTION) {
6224             retval = retval && !compile_warning(asvalue->m_context, WARN_UNUSED_VARIABLE,
6225                                                 "unused global: `%s`", asvalue->m_name);
6226         }
6227         if (!asvalue->generateGlobal(ir, false)) {
6228             con_out("failed to generate global %s\n", asvalue->m_name.c_str());
6229             return false;
6230         }
6231     }
6232     /* Build function vararg accessor ast tree now before generating
6233      * immediates, because the accessors may add new immediates
6234      */
6235     for (auto &f : parser.functions) {
6236         if (f->m_varargs) {
6237             if (parser.max_param_count > f->m_function_type->m_type_params.size()) {
6238                 f->m_varargs->m_count = parser.max_param_count - f->m_function_type->m_type_params.size();
6239                 if (!parser_create_array_setter_impl(parser, f->m_varargs.get())) {
6240                     con_out("failed to generate vararg setter for %s\n", f->m_name.c_str());
6241                     return false;
6242                 }
6243                 if (!parser_create_array_getter_impl(parser, f->m_varargs.get())) {
6244                     con_out("failed to generate vararg getter for %s\n", f->m_name.c_str());
6245                     return false;
6246                 }
6247             } else {
6248                 f->m_varargs = nullptr;
6249             }
6250         }
6251     }
6252     /* Now we can generate immediates */
6253     if (!parser.m_fold.generate(ir))
6254         return false;
6255
6256     /* before generating any functions we need to set the coverage_func */
6257     if (!parser_set_coverage_func(parser, ir))
6258         return false;
6259     for (auto &it : parser.globals) {
6260         if (!ast_istype(it, ast_value))
6261             continue;
6262         auto asvalue = reinterpret_cast<ast_value*>(it);
6263         if (!(asvalue->m_flags & AST_FLAG_INITIALIZED))
6264         {
6265             if (asvalue->m_cvq == CV_CONST && !asvalue->m_hasvalue)
6266                 (void)!compile_warning(asvalue->m_context, WARN_UNINITIALIZED_CONSTANT,
6267                                        "uninitialized constant: `%s`",
6268                                        asvalue->m_name);
6269             else if ((asvalue->m_cvq == CV_NONE || asvalue->m_cvq == CV_CONST) && !asvalue->m_hasvalue)
6270                 (void)!compile_warning(asvalue->m_context, WARN_UNINITIALIZED_GLOBAL,
6271                                        "uninitialized global: `%s`",
6272                                        asvalue->m_name);
6273         }
6274         if (!asvalue->generateAccessors(ir)) {
6275             return false;
6276         }
6277     }
6278     for (auto &it : parser.fields) {
6279         auto asvalue = reinterpret_cast<ast_value*>(it->m_next);
6280         if (!ast_istype(asvalue, ast_value))
6281             continue;
6282         if (asvalue->m_vtype != TYPE_ARRAY)
6283             continue;
6284         if (!asvalue->generateAccessors(ir)) {
6285             return false;
6286         }
6287     }
6288     if (parser.reserved_version &&
6289         !parser.reserved_version->generateGlobal(ir, false))
6290     {
6291         con_out("failed to generate reserved::version");
6292         return false;
6293     }
6294     for (auto &f : parser.functions) {
6295         if (!f->generateFunction(ir)) {
6296             con_out("failed to generate function %s\n", f->m_name.c_str());
6297             return false;
6298         }
6299     }
6300
6301     generate_checksum(parser, ir);
6302
6303     if (OPTS_OPTION_BOOL(OPTION_DUMP))
6304         ir.dump(con_out);
6305     for (auto &it : parser.functions) {
6306         if (!ir_function_finalize(it->m_ir_func)) {
6307             con_out("failed to finalize function %s\n", it->m_name.c_str());
6308             return false;
6309         }
6310     }
6311     parser.remove_ast();
6312
6313     auto fnCheckWErrors = [&retval]() {
6314         if (compile_Werrors) {
6315             con_out("*** there were warnings treated as errors\n");
6316             compile_show_werrors();
6317             retval = false;
6318         }
6319     };
6320
6321     fnCheckWErrors();
6322
6323     if (retval) {
6324         if (OPTS_OPTION_BOOL(OPTION_DUMPFIN))
6325             ir.dump(con_out);
6326
6327         if (!ir.generate(output)) {
6328             con_out("*** failed to generate output file\n");
6329             return false;
6330         }
6331
6332         // ir->generate can generate compiler warnings
6333         fnCheckWErrors();
6334     }
6335     return retval;
6336 }