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 = ¯o_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 = ¯o_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 = ¯o_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, ¶m);
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(¶m, &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 = ¶ms[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 = ¯o_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 = ¯o_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(¶m->name, context, strength, &labelexists, mfunc->file_list);
509 if (labelexists) {
510 if (label->constant) err_msg_double_defined(label, ¶m->name, ¶m->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, ¶m->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, ¶m->epoint);
614 ret = true;
615 break;
616 }
617 if (not_in_file(label.data, v->file_list->file)) str_cpy(¶m->name, &label);
618 else param->name = label;
619 str_cfcpy(¶m->cfname, &label);
620 if (param->cfname.data != label.data) str_cfcpy(¶m->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(¶ms[j].cfname, ¶m->cfname) == 0) break;
625 }
626 }
627 if (j != i) {
628 err_msg_double_definedo(v->file_list, ¶ms[j].epoint, &label, ¶m->epoint);
629 }
630 } else {
631 err_msg2(ERROR_GENERL_SYNTAX, NULL, ¶m->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(¶m->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(¶ms[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(¶m->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(¶m->name, context, 0, &labelexists, mfunc->file_list);
853 if (labelexists) {
854 if (label->constant) {
855 err_msg_double_defined(label, ¶m->name, ¶m->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, ¶m->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 = §ion_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