1 /*
2     $Id: macro.c 2597 2021-04-18 19:57:41Z soci $
3 
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8 
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13 
14     You should have received a copy of the GNU General Public License along
15     with this program; if not, write to the Free Software Foundation, Inc.,
16     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 
18 */
19 #include "macro.h"
20 #include <string.h>
21 #include "file.h"
22 #include "eval.h"
23 #include "values.h"
24 #include "section.h"
25 #include "variables.h"
26 #include "64tass.h"
27 #include "listing.h"
28 #include "error.h"
29 #include "arguments.h"
30 #include "optimizer.h"
31 
32 #include "listobj.h"
33 #include "typeobj.h"
34 #include "noneobj.h"
35 #include "namespaceobj.h"
36 #include "labelobj.h"
37 #include "macroobj.h"
38 #include "mfuncobj.h"
39 #include "memblocksobj.h"
40 
41 static int functionrecursion;
42 
43 struct macro_rpos_s {
44     linecpos_t opos, olen, pos, len;
45     argcount_t param;
46 };
47 
48 struct macro_pline_s {
49     uint8_t *data;
50     size_t len;
51     struct macro_rpos_s *rpositions;
52     argcount_t rp, rlen;
53 };
54 
55 struct macro_value_s {
56     const uint8_t *data;
57     size_t len;
58     linecpos_t pos;
59     bool init;
60 };
61 
62 struct macro_params_s {
63     argcount_t len, size;
64     struct macro_value_s *param, all;
65     struct macro_pline_s pline;
66     bool used;
67     Obj *macro;
68 };
69 
70 static struct {
71     size_t p, len;
72     struct macro_params_s *params, *current;
73 } macro_parameters = {0, 0, NULL, NULL};
74 
75 bool in_macro;
76 
77 #define ALL_MACRO_PARAMS (~(argcount_t)0)
78 
macro_error_translate(struct linepos_s * opoint,linecpos_t pos)79 const struct file_list_s *macro_error_translate(struct linepos_s *opoint, linecpos_t pos) {
80     const struct file_list_s *ret = NULL;
81     if (pline == macro_parameters.current->pline.data) {
82         const struct file_list_s *flist = current_file_list;
83         size_t p = macro_parameters.p;
84         while (p != 0) {
85             const struct macro_pline_s *mline;
86             argcount_t i;
87             p--;
88             mline = &macro_parameters.params[p].pline;
89             for (i = 0; i < mline->rp; i++) {
90                 linecpos_t c = pos - mline->rpositions[i].pos;
91                 if (c < mline->rpositions[i].len) {
92                     argcount_t param = mline->rpositions[i].param;
93                     if (param < macro_parameters.params[p].len) {
94                         if (macro_parameters.params[p].param[param].init) return ret;
95                         pos = macro_parameters.params[p].param[param].pos;
96                     } else {
97                         if (param != ALL_MACRO_PARAMS) return ret;
98                         pos = macro_parameters.params[p].all.pos;
99                     }
100                     opoint->pos = pos + c;
101                     opoint->line = flist->epoint.line;
102                     ret = parent_file_list(flist);
103                     flist = ret;
104                     break;
105                 }
106             }
107             if (i == mline->rp) break;
108             if (p > 0 && !macro_parameters.params[p - 1].used) break;
109         }
110     }
111     return ret;
112 }
113 
macro_error_translate2(linecpos_t pos)114 linecpos_t macro_error_translate2(linecpos_t pos) {
115     if (macro_parameters.p != 0) {
116         const struct macro_pline_s *mline = &macro_parameters.current->pline;
117         if (pline == mline->data) {
118             linecpos_t pos2 = pos;
119             argcount_t i;
120             for (i = 0; i < mline->rp; i++) {
121                 const struct macro_rpos_s *rpositions = &mline->rpositions[i];
122                 if (rpositions->pos > pos2) break;
123                 if (rpositions->pos + rpositions->len > pos2) {
124                     pos = rpositions->opos;
125                     break;
126                 }
127                 pos = pos + rpositions->olen - rpositions->len;
128             }
129         }
130     }
131     return pos;
132 }
133 
134 /* ------------------------------------------------------------------------------ */
mtranslate(void)135 bool mtranslate(void) {
136     unsigned int q;
137     argcount_t j, n;
138     linecpos_t p, p2, op;
139     linecpos_t last, last2;
140     struct macro_pline_s *mline;
141     bool changed, fault;
142     struct file_s *cfile = current_file_list->file;
143 
144     if (lpoint.line >= cfile->lines) return true;
145     llist = pline = &cfile->data[cfile->line[lpoint.line]];
146     changed = !in_macro || (cfile->nomacro != NULL && (cfile->nomacro[lpoint.line / 8] & (1 << (lpoint.line & 7))) != 0);
147     lpoint.pos = 0; lpoint.line++; vline++;
148     if (changed) return signal_received;
149     mline = &macro_parameters.current->pline;
150 
151     q = 0; p = 0; p2 = 0; n = 0; last = 0; last2 = 0; fault = false;
152     while (pline[p2] != 0) {
153         str_t param;
154         switch (pline[p2]) {
155         case '"':
156             if ((q & 2) == 0) q ^= 1;
157             p2++;
158             continue;
159         case '\'':
160             if ((q & 1) == 0) q ^= 2;
161             p2++;
162             continue;
163         case ';':
164             if (q == 0) q = 4;
165             p2++;
166             continue;
167         default:
168             p2++;
169             continue;
170         case '\\':
171             if (q != 0) {
172                 p2++;
173                 continue;
174             }
175             /* normal parameter reference */
176             j = (uint8_t)(pline[p2 + 1] - '1');
177             if (j < 9) {   /* \1..\9 */
178                 p += p2 - last2;
179                 op = p2;
180                 p2 += 2;
181                 break;
182             }
183             if (j == ('@' - '1')) { /* \@ gives complete parameter list */
184                 j = ALL_MACRO_PARAMS;
185                 p += p2 - last2;
186                 op = p2;
187                 p2 += 2;
188                 break;
189             }
190             if (j == ('{' - '1')) {
191                 lpoint.pos = p2 + 2;
192                 param.data = pline + lpoint.pos;
193                 param.len = get_label(param.data);
194                 lpoint.pos += (linecpos_t)param.len;
195                 if (pline[lpoint.pos] == '}') lpoint.pos++;
196                 else param.len = 0;
197             } else {
198                 lpoint.pos = p2 + 1;
199                 param.data = pline + lpoint.pos;
200                 param.len = get_label(param.data);
201                 lpoint.pos += (linecpos_t)param.len;
202             }
203             if (param.len != 0) {
204                 Macro *macro = Macro(macro_parameters.current->macro);
205                 str_t cf;
206                 p += p2 - last2;
207                 op = p2;
208                 p2 = lpoint.pos;
209                 str_cfcpy(&cf, &param);
210                 for (j = 0; j < macro->argc; j++) {
211                     const uint8_t *data;
212                     if (macro->param[j].cfname.len != cf.len) continue;
213                     data = macro->param[j].cfname.data;
214                     if (data[0] != cf.data[0]) continue;
215                     if (memcmp(data, cf.data, cf.len) == 0) break;
216                 }
217                 if (j < macro->argc) break;
218                 lpoint.pos -= (linecpos_t)param.len + 1;
219                 if (pline[lpoint.pos] != '\\') lpoint.pos -= 2;
220                 err_msg_unknown_argument(&param, &lpoint);
221                 p = last; last2 = p2; fault = true;
222                 continue;
223             }
224             p2++;
225             continue;
226         case '@':
227             if (arguments.tasmcomp) {
228                 /* text parameter reference */
229                 j = (uint8_t)(pline[p2 + 1] - '1');
230                 if (j < 9) { /* @1..@9 */
231                     p += p2 - last2;
232                     op = p2;
233                     p2 += 2;
234                     break;
235                 }
236             }
237             p2++;
238             continue;
239         }
240 
241         if (j < macro_parameters.current->len) {
242             param.data = macro_parameters.current->param[j].data;
243             param.len = macro_parameters.current->param[j].len;
244         } else if (j == ALL_MACRO_PARAMS) {
245             param.data = macro_parameters.current->all.data;
246             param.len = macro_parameters.current->all.len;
247         } else {
248             switch (macro_parameters.current->macro->obj->type) {
249             case T_STRUCT:
250             case T_UNION:
251                 param.data = (const uint8_t *)"?";
252                 param.len = 1;
253                 break;
254             default:
255                 param.data = NULL;
256                 param.len = 0;
257             }
258         }
259         if (p + param.len < p) err_msg_out_of_memory(); /* overflow */
260         if (p + param.len > mline->len) {
261             mline->len = p + param.len + 1024;
262             if (mline->len < 1024) err_msg_out_of_memory(); /* overflow */
263             mline->data = (uint8_t *)reallocx(mline->data, mline->len);
264         }
265         if (last != p) {
266             if (p < last) err_msg_out_of_memory(); /* overflow */
267             memcpy(mline->data + last, pline + last2, p - last);
268         }
269         if (n >= mline->rlen) {
270             mline->rlen += 8;
271             if (mline->rlen < 8 || mline->rlen > ARGCOUNT_MAX / sizeof *mline->rpositions) err_msg_out_of_memory(); /* overflow */
272             mline->rpositions = (struct macro_rpos_s *)reallocx(mline->rpositions, mline->rlen * sizeof *mline->rpositions);
273         }
274         mline->rpositions[n].opos = op;
275         mline->rpositions[n].olen = p2 - op;
276         mline->rpositions[n].pos = p;
277         mline->rpositions[n].param = j;
278         mline->rpositions[n++].len = (linecpos_t)param.len;
279         switch (param.len) {
280         case 0:
281             if (param.data == NULL) {
282                 lpoint.pos = last2 + p - last;
283                 err_msg_missing_argument(&lpoint, j);
284                 fault = true;
285             }
286             break;
287         case 1:
288             mline->data[p++] = *param.data;
289             break;
290         default:
291             memcpy(mline->data + p, param.data, param.len);
292             p += (linecpos_t)param.len;
293         }
294         last = p; last2 = p2;
295     }
296     mline->rp = n;
297     if (last2 != 0) {
298         while (p2 != 0 && (pline[p2 - 1] == 0x20 || pline[p2 - 1] == 0x09)) p2--;
299         p += p2 - last2;
300         if (p + 1 < p) err_msg_out_of_memory(); /* overflow */
301         if (p + 1 > mline->len) {
302             mline->len = p + 1024;
303             if (mline->len < 1024) err_msg_out_of_memory(); /* overflow */
304             mline->data = (uint8_t *)reallocx(mline->data, mline->len);
305         }
306         if (p != last) memcpy(mline->data + last, pline + last2, p - last);
307         mline->data[p] = 0;
308         llist = pline = fault ? (const uint8_t *)"" : mline->data;
309     } else {
310         linenum_t lnum;
311         if (cfile->nomacro == NULL) {
312             cfile->nomacro = (uint8_t *)calloc((cfile->lines + 7) / 8, sizeof *cfile->nomacro);
313             if (cfile->nomacro == NULL) err_msg_out_of_memory();
314         }
315         lnum = lpoint.line - 1;
316         cfile->nomacro[lnum / 8] |= (uint8_t)(1U << (lnum & 7));
317     }
318     lpoint.pos = 0;
319     return signal_received;
320 }
321 
macro_param_find(void)322 static size_t macro_param_find(void) {
323     uint8_t q = 0, ch;
324     size_t pp = 0, pl = 64;
325     uint8_t pbuf[64];
326     uint8_t *par = pbuf;
327     struct linepos_s opoint2, npoint2;
328 
329     opoint2.pos = lpoint.pos;
330     while ((ch = here()) != 0 && (q != 0 || (ch != ';' && (ch != ',' || pp != 0)))) {
331         if (ch == '"'  && (q & 2) == 0) { q ^= 1; }
332         else if (ch == '\'' && (q & 1) == 0) { q ^= 2; }
333         if (q == 0) {
334             if (ch == '(' || ch == '[' || ch == '{') {
335                 if (pp >= pl) {
336                     pl += 256;
337                     if (pl < 256) err_msg_out_of_memory();
338                     if (par == pbuf) {
339                         par = (uint8_t *)mallocx(pl);
340                         memcpy(par, pbuf, pp);
341                     } else par = (uint8_t *)reallocx(par, pl);
342                 }
343                 par[pp++] = ch;
344             } else if (pp != 0 && ((ch == ')' && par[pp-1]=='(') || (ch == ']' && par[pp-1]=='[') || (ch == '}' && par[pp-1]=='{'))) pp--;
345         }
346         lpoint.pos++;
347     }
348     npoint2.pos = lpoint.pos;
349     while (npoint2.pos > opoint2.pos && (pline[npoint2.pos-1] == 0x20 || pline[npoint2.pos-1] == 0x09)) npoint2.pos--;
350     if (par != pbuf) free(par);
351     return npoint2.pos - opoint2.pos;
352 }
353 
macro_recurse(Wait_types t,Obj * tmp2,Namespace * context,linepos_t epoint)354 Obj *macro_recurse(Wait_types t, Obj *tmp2, Namespace *context, linepos_t epoint) {
355     bool in_macro_old;
356     Obj *val;
357     Macro *macro = Macro(tmp2);
358     if (macro->recursion_pass == pass) return NULL;
359     if (macro_parameters.p > 100) {
360         macro->recursion_pass = pass;
361         err_msg2(ERROR__MACRECURSION, NULL, epoint);
362         return NULL;
363     }
364     if (macro_parameters.p >= macro_parameters.len) {
365         struct macro_params_s *params = macro_parameters.params;
366         macro_parameters.len += 1;
367         if (/*macro_parameters.len < 1 ||*/ macro_parameters.len > SIZE_MAX / sizeof *params) err_msg_out_of_memory();
368         params = (struct macro_params_s *)reallocx(params, macro_parameters.len * sizeof *params);
369         macro_parameters.params = params;
370         macro_parameters.current = &params[macro_parameters.p];
371         macro_parameters.current->param = NULL;
372         macro_parameters.current->size = 0;
373         macro_parameters.current->pline.len = 0;
374         macro_parameters.current->pline.data = NULL;
375         macro_parameters.current->pline.rpositions = NULL;
376         macro_parameters.current->pline.rp = 0;
377         macro_parameters.current->pline.rlen = 0;
378     }
379     if (macro_parameters.p > 0) {
380         macro_parameters.params[macro_parameters.p - 1].used = (pline == macro_parameters.params[macro_parameters.p - 1].pline.data);
381     }
382     macro_parameters.current = &macro_parameters.params[macro_parameters.p];
383     macro_parameters.current->macro = val_reference(Obj(macro));
384     macro_parameters.p++;
385     in_macro_old = in_macro;
386     in_macro = true;
387     {
388         struct linepos_s opoint, npoint;
389         argcount_t p = 0;
390 
391         ignore(); opoint = lpoint;
392         for (;;) {
393             struct macro_value_s *param, *params = macro_parameters.current->param;
394             if ((here() == 0 || here() == ';') && p >= macro->argc) break;
395             if (p >= macro_parameters.current->size) {
396                 if (macro_parameters.current->size < macro->argc) macro_parameters.current->size = macro->argc;
397                 else {
398                     macro_parameters.current->size += 4;
399                     if (macro_parameters.current->size < 4) err_msg_out_of_memory(); /* overflow */
400                 }
401                 if (macro_parameters.current->size > ARGCOUNT_MAX / sizeof *params) err_msg_out_of_memory();
402                 params = (struct macro_value_s *)reallocx(params, macro_parameters.current->size * sizeof *params);
403                 macro_parameters.current->param = params;
404             }
405             param = params + p;
406             param->pos = lpoint.pos;
407             param->data = pline + lpoint.pos;
408             param->len = macro_param_find();
409             param->init = (param->len == 0);
410             if (param->init) {
411                 if (p < macro->argc) {
412                     param->data = macro->param[p].init.data;
413                     param->len = macro->param[p].init.len;
414                 } else param->data = NULL;
415                 if (param->data == NULL) {
416                     if (macro->v.obj->type == T_STRUCT || macro->v.obj->type == T_UNION) {
417                         param->data = (const uint8_t *)"?";
418                         param->len = 1;
419                     }
420                 }
421             }
422             p++;
423             if (here() == 0 || here() == ';') {
424                 if (p < macro->argc) continue;
425             }
426             if (here() != ',') break;
427             lpoint.pos++;
428             ignore();
429         }
430         macro_parameters.current->len = p;
431         macro_parameters.current->all.pos = opoint.pos;
432         macro_parameters.current->all.data = pline + opoint.pos;
433         npoint = lpoint;
434         while (npoint.pos > opoint.pos && (pline[npoint.pos-1] == 0x20 || pline[npoint.pos-1] == 0x09)) npoint.pos--;
435         macro_parameters.current->all.len = npoint.pos - opoint.pos;
436     }
437     if (t == W_ENDS) {
438         enterfile(macro->file_list->file, epoint);
439         if (context != NULL) push_context(context);
440         val = compile();
441         if (context != NULL) pop_context();
442         exitfile();
443     } else {
444         linenum_t lin = lpoint.line;
445         bool starexists;
446         struct star_s *s = new_star(vline, &starexists);
447         struct star_s *stree_old = star_tree;
448 
449         if (diagnostics.optimize) cpu_opt_invalidate();
450         if (starexists && s->addr != star) {
451             if (fixeddig && pass > max_pass) err_msg_cant_calculate(NULL, &lpoint);
452             fixeddig = false;
453         }
454         s->addr = star;
455         star_tree->vline = vline; star_tree = s; vline = s->vline;
456         enterfile(macro->file_list->file, epoint);
457         lpoint.line = macro->line;
458         new_waitfor(t, epoint);
459         if (context != NULL) push_context(context);
460         val = compile();
461         if (context != NULL) pop_context();
462         close_waitfor(t);
463         star = s->addr;
464         exitfile();
465         s->vline = vline; star_tree = stree_old; vline = star_tree->vline;
466         lpoint.line = lin;
467     }
468     val_destroy(Obj(macro));
469     macro_parameters.p--;
470     in_macro = in_macro_old;
471     if (macro_parameters.p != 0) macro_parameters.current = &macro_parameters.params[macro_parameters.p - 1];
472     return val;
473 }
474 
mfunc_recurse(Mfunc * mfunc,Namespace * context,uint8_t strength,linepos_t epoint)475 Obj *mfunc_recurse(Mfunc *mfunc, Namespace *context, uint8_t strength, linepos_t epoint) {
476     argcount_t i;
477     Label *label;
478     Obj *val;
479     Tuple *tuple = NULL;
480     argcount_t max = 0, args = get_val_remaining();
481 
482     if (mfunc->recursion_pass == pass) return NULL;
483     if (functionrecursion>100) {
484         mfunc->recursion_pass = pass;
485         err_msg2(ERROR__FUNRECURSION, NULL, epoint);
486         return NULL;
487     }
488     for (i = 0; i < mfunc->argc; i++) {
489         const struct mfunc_param_s *param = &mfunc->param[i];
490         bool labelexists;
491         if (param->init == default_value) {
492             argcount_t j, len = get_val_remaining();
493             tuple = new_tuple(len);
494             for (j = 0; j < len; j++) {
495                 tuple->data[j] = pull_val(NULL);
496             }
497             val = Obj(tuple);
498         } else {
499             struct values_s *vs;
500             vs = get_val();
501             if (vs == NULL) {
502                 val = param->init;
503                 if (val == NULL) { max = i + 1; val = none_value; }
504             } else {
505                 val = vs->val;
506             }
507         }
508         label = new_label(&param->name, context, strength, &labelexists, mfunc->file_list);
509         if (labelexists) {
510             if (label->constant) err_msg_double_defined(label, &param->name, &param->epoint); /* not possible in theory */
511             else {
512                 if (label->defpass != pass) {
513                     label->ref = false;
514                     label->defpass = pass;
515                 } else {
516                     if (diagnostics.unused.variable && label->usepass != pass) err_msg_unused_variable(label);
517                 }
518                 label->owner = false;
519                 if (label->file_list != mfunc->file_list) {
520                     label_move(label, &param->name, mfunc->file_list);
521                 }
522                 label->epoint = param->epoint;
523                 val_replace(&label->value, val);
524                 label->usepass = 0;
525             }
526         } else {
527             label->constant = false;
528             label->owner = false;
529             label->value = val_reference(val);
530             label->epoint = param->epoint;
531         }
532     }
533     if (tuple != NULL) val_destroy(Obj(tuple));
534     else if (i < args) err_msg_argnum(args, i, i, epoint);
535     if (max != 0) err_msg_argnum(args, max, mfunc->argc, epoint);
536     {
537         linenum_t lin = lpoint.line;
538         bool starexists;
539         struct star_s *s = new_star(vline, &starexists);
540         struct star_s *stree_old = star_tree;
541         size_t oldbottom;
542         bool in_macro_old = in_macro;
543         in_macro = false;
544 
545         if (diagnostics.optimize) cpu_opt_invalidate();
546         if (starexists && s->addr != star) {
547             if (fixeddig && pass > max_pass) err_msg_cant_calculate(NULL, &lpoint);
548             fixeddig = false;
549         }
550         s->addr = star;
551         star_tree->vline = vline; star_tree = s; vline = s->vline;
552         enterfile(mfunc->file_list->file, epoint);
553         lpoint.line = mfunc->epoint.line;
554         new_waitfor(W_ENDF3, epoint);
555         oldbottom = context_get_bottom();
556         for (i = 0; i < mfunc->nslen; i++) {
557             push_context(mfunc->namespaces[i]);
558         }
559         push_context(context);
560         functionrecursion++;
561         val = compile();
562         functionrecursion--;
563         context_set_bottom(oldbottom);
564         pop_context();
565         for (i = 0; i < mfunc->nslen; i++) {
566             pop_context();
567         }
568         close_waitfor(W_ENDF3);
569         star = s->addr;
570         exitfile();
571         s->vline = vline; star_tree = stree_old; vline = star_tree->vline;
572         lpoint.line = lin;
573         in_macro = in_macro_old;
574     }
575     return val;
576 }
577 
get_func_params(Mfunc * v,bool single)578 bool get_func_params(Mfunc *v, bool single) {
579     struct mfunc_param_s *params;
580     argcount_t len = v->argc, i = 0, j;
581     str_t label;
582     bool stard = false, ret = false;
583 
584     params = (len != 0) ? (struct mfunc_param_s *)mallocx(len * sizeof *params) : NULL;
585     if (here() != 0 && here() != ';') {
586         for (;;) {
587             struct mfunc_param_s *param;
588             ignore();
589             if (here() == '*') {
590                 stard = true;
591                 lpoint.pos++;ignore();
592             }
593             if (i >= len) {
594                 len += 16;
595                 if (len < 16 || len > ARGCOUNT_MAX / sizeof *params) err_msg_out_of_memory(); /* overflow */
596                 params = (struct mfunc_param_s *)reallocx(params, len * sizeof *params);
597             }
598             param = params + i;
599             param->epoint = lpoint;
600             label.data = pline + lpoint.pos;
601             label.len = get_label(label.data);
602             if (single) {
603                 const uint8_t *s = pline + lpoint.pos + label.len;
604                 if (!stard && s[0] != ',' && (s[0] != '=' || s[1] == '=')) {
605                     v->epoint.line = lpoint.line - 1;
606                     v->epoint.pos = lpoint.pos;
607                     break;
608                 }
609             }
610             if (label.len != 0) {
611                 lpoint.pos += (linecpos_t)label.len;
612                 if (label.len > 1 && label.data[0] == '_' && label.data[1] == '_') {
613                     err_msg2(ERROR_RESERVED_LABL, &label, &param->epoint);
614                     ret = true;
615                     break;
616                 }
617                 if (not_in_file(label.data, v->file_list->file)) str_cpy(&param->name, &label);
618                 else param->name = label;
619                 str_cfcpy(&param->cfname, &label);
620                 if (param->cfname.data != label.data) str_cfcpy(&param->cfname, NULL);
621                 else param->cfname = param->name;
622                 for (j = 0; j < i; j++) {
623                     if (params[j].name.data != NULL) {
624                         if (str_cmp(&params[j].cfname, &param->cfname) == 0) break;
625                     }
626                 }
627                 if (j != i) {
628                     err_msg_double_definedo(v->file_list, &params[j].epoint, &label, &param->epoint);
629                 }
630             } else {
631                 err_msg2(ERROR_GENERL_SYNTAX, NULL, &param->epoint);
632                 ret = true;
633                 break;
634             }
635             i++;
636             ignore();
637             if (stard) {
638                 param->init = ref_default();
639                 if (single) {
640                     if (here() != ',') {
641                         err_msg2(ERROR______EXPECTED, "','", &lpoint);
642                         ret = true;
643                         break;
644                     }
645                     lpoint.pos++;
646                     ignore();
647                     v->epoint.line = lpoint.line - 1;
648                     v->epoint.pos = lpoint.pos;
649                 }
650                 break;
651             }
652             param->init = NULL;
653             if (here() == '=') {
654                 lpoint.pos++;
655                 if (!get_exp(1, 1, 1, &lpoint)) {
656                     ret = true;
657                     break;
658                 }
659                 param->init = pull_val(NULL);
660             }
661             if (here() == 0 || here() == ';') {
662                 break;
663             }
664             if (here() != ',') {
665                 err_msg2(ERROR______EXPECTED, "','", &lpoint);
666                 ret = true;
667                 break;
668             }
669             lpoint.pos++;
670         }
671     }
672     if (i < len) {
673         if (i != 0) {
674             struct mfunc_param_s *p = (struct mfunc_param_s *)realloc(params, i * sizeof *params);
675             if (p != NULL) params = p;
676         } else {
677             free(params);
678             params = NULL;
679         }
680     }
681     v->argc = i;
682     v->param = params;
683     return ret;
684 }
685 
get_macro_params(Obj * v)686 void get_macro_params(Obj *v) {
687     Macro *macro = Macro(v);
688     struct macro_param_s *params;
689     argcount_t len = macro->argc, i = 0, j;
690     str_t label;
691     struct linepos_s *epoints;
692     struct linepos_s vepoints[4];
693     const struct file_s *cfile = macro->file_list->file;
694 
695     params = (len != 0) ? (struct macro_param_s *)mallocx(len * sizeof *params) : NULL;
696     epoints = (len <= lenof(vepoints)) ? vepoints : (struct linepos_s *)mallocx(len * sizeof *epoints);
697     for (;;) {
698         struct macro_param_s *param;
699         ignore();if (here() == 0 || here() == ';') break;
700         if (i >= len) {
701             len += 16;
702             if (len < 16 || len > ARGCOUNT_MAX / (sizeof *params > sizeof *epoints ? sizeof *params : sizeof *epoints)) err_msg_out_of_memory(); /* overflow */
703             params = (struct macro_param_s *)reallocx(params, len * sizeof *params);
704             if (epoints == vepoints) {
705                 epoints = (struct linepos_s *)mallocx(len * sizeof *epoints);
706                 memcpy(epoints, vepoints, sizeof vepoints);
707             } else {
708                 epoints = (struct linepos_s *)reallocx(epoints, len * sizeof *epoints);
709             }
710         }
711         param = params + i;
712         epoints[i] = lpoint;
713         label.data = pline + lpoint.pos;
714         label.len = get_label(label.data);
715         if (label.len != 0) {
716             str_t cf;
717             lpoint.pos += (linecpos_t)label.len;
718             if (label.len > 1 && label.data[0] == '_' && label.data[1] == '_') {err_msg2(ERROR_RESERVED_LABL, &label, &epoints[i]);param->cfname.len = 0; param->cfname.data = NULL;}
719             str_cfcpy(&cf, &label);
720             if (cf.data == label.data) {
721                 if (not_in_file(label.data, cfile)) str_cpy(&param->cfname, &label);
722                 else param->cfname = label;
723             } else {str_cfcpy(&cf, NULL); param->cfname = cf;}
724             for (j = 0; j < i; j++) if (params[j].cfname.data != NULL) {
725                 if (str_cmp(&params[j].cfname, &cf) == 0) break;
726             }
727             if (j != i) {
728                 err_msg_double_definedo(macro->file_list, &epoints[j], &label, &epoints[i]);
729             }
730         } else {param->cfname.len = 0; param->cfname.data = NULL;}
731         i++;
732         ignore();
733         if (here() == '=') {
734             lpoint.pos++;
735             label.data = pline + lpoint.pos;
736             label.len = macro_param_find();
737             if (not_in_file(label.data, cfile)) str_cpy(&param->init, &label);
738             else param->init = label;
739         } else {param->init.len = 0; param->init.data = NULL;}
740         ignore();
741         if (here() == 0 || here() == ';') {
742             break;
743         }
744         if (here() != ',') {
745             err_msg2(ERROR______EXPECTED, "','", &lpoint);
746             break;
747         }
748         lpoint.pos++;
749     }
750     if (i < len) {
751         if (i != 0) {
752             struct macro_param_s *p = (struct macro_param_s *)realloc(params, i * sizeof *params);
753             if (p != NULL) params = p;
754         } else {
755             free(params);
756             params = NULL;
757         }
758     }
759     macro->argc = i;
760     macro->param = params;
761     if (epoints != vepoints) free(epoints);
762 }
763 
clean_namespace(Namespace * v1)764 static bool clean_namespace(Namespace *v1) {
765     size_t n, n2;
766     if (v1->len == 0) return true;
767     for (n = n2 = 0; n <= v1->mask && n2 < v1->len; n++) {
768         const Label *p = v1->data[n];
769         if (p == NULL) continue;
770         if (p->constant) {
771             return false;
772         }
773         n2++;
774     }
775     for (n2 = 0; n2 < n; n2++) {
776         Label *p = v1->data[n2];
777         if (p == NULL) continue;
778         val_destroy(Obj(p));
779         v1->data[n2] = NULL;
780     }
781     v1->len = 0;
782     return true;
783 }
784 
mfunc2_recurse(Mfunc * mfunc,Funcargs * v2,linepos_t epoint)785 Obj *mfunc2_recurse(Mfunc *mfunc, Funcargs *v2, linepos_t epoint) {
786     struct values_s *vals = v2->val;
787     argcount_t args = v2->len;
788     argcount_t i;
789     Label *label;
790     Obj *val;
791     Tuple *tuple;
792     Obj *retval = NULL;
793     Namespace *context;
794 
795     if (mfunc->recursion_pass == pass) return NULL;
796     if (functionrecursion>100) {
797         mfunc->recursion_pass = pass;
798         err_msg2(ERROR__FUNRECURSION, NULL, epoint);
799         return NULL;
800     }
801 
802     if (mfunc->inamespaces == Tuple(null_tuple)) {
803         val_destroy(Obj(mfunc->inamespaces));
804         mfunc->inamespaces = new_tuple(1);
805         context = NULL;
806     } else {
807         List *lst = mfunc->inamespaces;
808         if (mfunc->ipoint >= lst->len) {
809             if ((lst->data == lst->u.val ? mfunc->ipoint >= lenof(lst->u.val) : mfunc->ipoint >= lst->u.s.max)) {
810                 if (list_extend(lst)) {
811                     err_msg2(ERROR_OUT_OF_MEMORY, NULL, epoint);
812                     return ref_none();
813                 }
814             }
815             lst->len++;
816             context = NULL;
817         } else context = Namespace(lst->data[mfunc->ipoint]);
818     }
819     if (context == NULL) {
820         struct linepos_s xpoint;
821         xpoint.line = mfunc->epoint.line;
822         xpoint.pos = 0;
823         context = new_namespace(mfunc->file_list, &xpoint);
824         mfunc->inamespaces->data[mfunc->ipoint] = Obj(context);
825     } else {
826         context->backr = context->forwr = 0;
827     }
828     mfunc->ipoint++;
829 
830     enterfile(mfunc->file_list->file, epoint);
831     tuple = NULL;
832     for (i = 0; i < mfunc->argc; i++) {
833         const struct mfunc_param_s *param = &mfunc->param[i];
834         bool labelexists;
835         if (param->init == default_value) {
836             if (i < args) {
837                 argcount_t j = i;
838                 tuple = new_tuple(args - i);
839                 none_value->refcount += args - i;
840                 while (j < args) {
841                     tuple->data[j - i] = vals[j].val;
842                     vals[j].val = none_value;
843                     j++;
844                 }
845             } else {
846                 tuple = Tuple(val_reference(null_tuple));
847             }
848             val = Obj(tuple);
849         } else {
850             val = (i < args) ? vals[i].val : (param->init != NULL) ? param->init : none_value;
851         }
852         label = new_label(&param->name, context, 0, &labelexists, mfunc->file_list);
853         if (labelexists) {
854             if (label->constant) {
855                 err_msg_double_defined(label, &param->name, &param->epoint);
856             } else {
857                 if (label->defpass != pass) {
858                     label->ref = false;
859                     label->defpass = pass;
860                 } else {
861                     if (diagnostics.unused.variable && label->usepass != pass) err_msg_unused_variable(label);
862                 }
863                 label->owner = false;
864                 if (label->file_list != mfunc->file_list) {
865                     label_move(label, &param->name, mfunc->file_list);
866                 }
867                 label->epoint = param->epoint;
868                 val_destroy(label->value);
869                 label->value = val_reference(val);
870                 label->usepass = 0;
871             }
872         } else {
873             label->constant = false;
874             label->owner = false;
875             label->value = val_reference(val);
876             label->epoint = param->epoint;
877         }
878     }
879     if (tuple != NULL) val_destroy(Obj(tuple));
880     else if (i < args) err_msg_argnum(args, i, i, &vals[i].epoint);
881     {
882         struct linepos_s opoint = lpoint;
883         const uint8_t *opline = pline;
884         const uint8_t *ollist = llist;
885         size_t oldbottom;
886         bool in_macro_old = in_macro;
887         struct section_address_s section_address, *oldsection_address = current_address;
888         bool starexists;
889         struct star_s *s = new_star(vline, &starexists);
890         struct star_s *stree_old = star_tree;
891         size_t j;
892 
893         if (starexists && s->addr != star) {
894             if (fixeddig && pass > max_pass) err_msg_cant_calculate(NULL, &lpoint);
895             fixeddig = false;
896         }
897         s->addr = star;
898         star_tree->vline = vline; star_tree = s; vline = s->vline;
899 
900         in_macro = false;
901 
902         lpoint.line = mfunc->epoint.line;
903         oldbottom = context_get_bottom();
904         for (j = 0; j < mfunc->nslen; j++) {
905             push_context(mfunc->namespaces[j]);
906         }
907         push_context(context);
908         temporary_label_branch++;
909         functionrecursion++;
910         if (mfunc->v.obj == SFUNC_OBJ) {
911             if (mtranslate()) {
912                 lpoint.pos = mfunc->epoint.pos;
913                 if (mfunc->line != NULL) pline = mfunc->line;
914                 if (signal_received) err_msg_signal();
915                 retval = NULL;
916             } else {
917                 lpoint.pos = mfunc->epoint.pos;
918                 if (mfunc->line != NULL) pline = mfunc->line;
919                 if (!get_exp(0, 0, 0, &mfunc->epoint)) {
920                     retval = NULL;
921                 } else {
922                     retval = get_vals_tuple();
923                 }
924             }
925         } else {
926             if (diagnostics.optimize) cpu_opt_invalidate();
927 
928             new_waitfor(W_ENDF3, epoint);
929 
930             section_address.moved = section_address.wrapwarn = section_address.bankwarn = section_address.unionmode = false;
931             section_address.address = 0;
932             section_address.start = 0;
933             section_address.l_start = 0;
934             section_address.l_union = 0;
935             section_address.end = 0;
936             section_address.mem = new_memblocks(0, 0);
937             section_address.mem->lastaddr = 0;
938             section_address.l_address = current_address->l_address;
939             section_address.l_address_val = val_reference(current_address->l_address_val);
940             current_address = &section_address;
941 
942             retval = compile();
943 
944             val_destroy(current_address->l_address_val);
945             val_destroy(Obj(current_address->mem));
946             current_address = oldsection_address;
947             if (current_address->l_address > all_mem) {
948                 err_msg_big_address(epoint);
949                 current_address->l_address &= all_mem;
950             }
951 
952             close_waitfor(W_ENDF3);
953         }
954         star = s->addr;
955         s->vline = vline; star_tree = stree_old; vline = star_tree->vline;
956         functionrecursion--;
957         context_set_bottom(oldbottom);
958         pop_context();
959         for (j = 0; j < mfunc->nslen; j++) {
960             pop_context();
961         }
962         temporary_label_branch--;
963         lpoint = opoint;
964         pline = opline;
965         llist = ollist;
966         in_macro = in_macro_old;
967     }
968     exitfile();
969     if (context->v.refcount == 1 && clean_namespace(context)) {
970         mfunc->ipoint--;
971     }
972     return retval;
973 }
974 
init_macro(void)975 void init_macro(void) {
976     macro_parameters.p = 0;
977     in_macro = false;
978     functionrecursion = 0;
979 }
980 
free_macro(void)981 void free_macro(void) {
982     size_t i;
983     for (i = 0; i < macro_parameters.len; i++) {
984         free(macro_parameters.params[i].pline.rpositions);
985         free(macro_parameters.params[i].pline.data);
986         free(macro_parameters.params[i].param);
987     }
988     free(macro_parameters.params);
989 }
990