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