1 /*
2 $Id: variables.c 2618 2021-04-25 11:11:11Z 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 "variables.h"
20 #include <string.h>
21 #include <errno.h>
22 #include "unicode.h"
23 #include "64tass.h"
24 #include "file.h"
25 #include "obj.h"
26 #include "error.h"
27 #include "values.h"
28 #include "arguments.h"
29 #include "eval.h"
30
31 #include "boolobj.h"
32 #include "floatobj.h"
33 #include "namespaceobj.h"
34 #include "strobj.h"
35 #include "codeobj.h"
36 #include "registerobj.h"
37 #include "functionobj.h"
38 #include "listobj.h"
39 #include "intobj.h"
40 #include "bytesobj.h"
41 #include "bitsobj.h"
42 #include "dictobj.h"
43 #include "addressobj.h"
44 #include "gapobj.h"
45 #include "typeobj.h"
46 #include "noneobj.h"
47 #include "labelobj.h"
48 #include "errorobj.h"
49 #include "mfuncobj.h"
50
51 static Label *lastlb = NULL;
52
53 #define EQUAL_COLUMN 16
54
55 Namespace *root_namespace;
56 static Namespace *builtin_namespace;
57 Namespace *current_context;
58 Namespace *cheap_context;
59 size_t fwcount;
60
61 struct cstack_s {
62 Namespace *normal;
63 Namespace *cheap;
64 };
65
66 struct context_stack_s {
67 struct cstack_s *stack;
68 size_t len, p, bottom;
69 };
70
71 static struct context_stack_s context_stack;
72
push_context(Namespace * name)73 void push_context(Namespace *name) {
74 if (context_stack.p >= context_stack.len) {
75 context_stack.len += 8;
76 if (/*context_stack.len < 8 ||*/ context_stack.len > SIZE_MAX / sizeof *context_stack.stack) err_msg_out_of_memory(); /* overflow */
77 context_stack.stack = (struct cstack_s *)reallocx(context_stack.stack, context_stack.len * sizeof *context_stack.stack);
78 }
79 context_stack.stack[context_stack.p].normal = ref_namespace(name);
80 current_context = name;
81 context_stack.stack[context_stack.p].cheap = cheap_context;
82 cheap_context = ref_namespace(name);
83 context_stack.p++;
84 }
85
push_dummy_context(void)86 void push_dummy_context(void) {
87 push_context(builtin_namespace);
88 }
89
pop_context(void)90 bool pop_context(void) {
91 if (context_stack.p > 1 + context_stack.bottom) {
92 struct cstack_s *c = &context_stack.stack[--context_stack.p];
93 val_destroy(Obj(c->normal));
94 val_destroy(Obj(cheap_context));
95 cheap_context = c->cheap;
96 c = &context_stack.stack[context_stack.p - 1];
97 current_context = c->normal;
98 return false;
99 }
100 return true;
101 }
102
push_context2(Namespace * name)103 void push_context2(Namespace *name) {
104 if (context_stack.p >= context_stack.len) {
105 context_stack.len += 8;
106 if (/*context_stack.len < 8 ||*/ context_stack.len > SIZE_MAX / sizeof *context_stack.stack) err_msg_out_of_memory(); /* overflow */
107 context_stack.stack = (struct cstack_s *)reallocx(context_stack.stack, context_stack.len * sizeof *context_stack.stack);
108 }
109 context_stack.stack[context_stack.p].normal = context_stack.stack[context_stack.p - 1].normal;
110 context_stack.stack[context_stack.p - 1].normal = ref_namespace(name);
111 context_stack.stack[context_stack.p].cheap = ref_namespace(name);
112 context_stack.p++;
113 }
114
pop_context2(void)115 bool pop_context2(void) {
116 if (context_stack.p > 1 + context_stack.bottom) {
117 struct cstack_s *c = &context_stack.stack[--context_stack.p];
118 val_destroy(Obj(context_stack.stack[context_stack.p - 1].normal));
119 context_stack.stack[context_stack.p - 1].normal = c->normal;
120 val_destroy(Obj(c->cheap));
121 return false;
122 }
123 return true;
124 }
125
reset_context(void)126 void reset_context(void) {
127 context_stack.bottom = 0;
128 while (context_stack.p != 0) {
129 struct cstack_s *c = &context_stack.stack[--context_stack.p];
130 val_destroy(Obj(c->normal));
131 val_destroy(Obj(c->cheap));
132 }
133 val_destroy(Obj(cheap_context));
134 cheap_context = ref_namespace(root_namespace);
135 push_context(root_namespace);
136 root_namespace->backr = root_namespace->forwr = 0;
137 }
138
139 struct label_stack_s {
140 Label **stack;
141 size_t len, p;
142 };
143
144 static struct label_stack_s label_stack;
145
push_label(Label * name)146 static void push_label(Label *name) {
147 if (label_stack.p >= label_stack.len) {
148 label_stack.len += 8;
149 if (/*label_stack.len < 8 ||*/ label_stack.len > SIZE_MAX / sizeof(*label_stack.stack)) err_msg_out_of_memory(); /* overflow */
150 label_stack.stack = (Label **)reallocx(label_stack.stack, label_stack.len * sizeof(*label_stack.stack));
151 }
152 label_stack.stack[label_stack.p] = name;
153 label_stack.p++;
154 }
155
pop_label(void)156 static void pop_label(void) {
157 label_stack.p--;
158 }
159
get_namespaces(Mfunc * mfunc)160 void get_namespaces(Mfunc *mfunc) {
161 size_t i, len = context_stack.p - context_stack.bottom;
162 if (len > SIZE_MAX / sizeof *mfunc->namespaces) err_msg_out_of_memory(); /* overflow */
163 mfunc->nslen = len;
164 mfunc->namespaces = (Namespace **)mallocx(len * sizeof *mfunc->namespaces);
165 for (i = 0; i < len; i++) {
166 mfunc->namespaces[i] = ref_namespace(context_stack.stack[context_stack.bottom + i].normal);
167 }
168 }
169
context_set_bottom(size_t n)170 void context_set_bottom(size_t n) {
171 context_stack.bottom = n;
172 }
173
context_get_bottom(void)174 size_t context_get_bottom(void) {
175 size_t old = context_stack.bottom;
176 context_stack.bottom = context_stack.p;
177 return old;
178 }
179
180 /* --------------------------------------------------------------------------- */
181
namespace_update(Namespace * ns,Label * p)182 static Label *namespace_update(Namespace *ns, Label *p) {
183 size_t mask, hash, offs;
184 if (ns->len * 3 / 2 >= ns->mask) {
185 size_t i, max = (ns->data == NULL) ? 8 : (ns->mask + 1) << 1;
186 Label **n = (Label **)calloc(max, sizeof *n);
187 if (n == NULL) err_msg_out_of_memory();
188 mask = max - 1;
189 if (ns->data != NULL) {
190 for (i = 0; i <= ns->mask; i++) if (ns->data[i] != NULL) {
191 hash = (size_t)ns->data[i]->hash;
192 offs = hash & mask;
193 while (n[offs] != NULL) {
194 hash >>= 5;
195 offs = (5 * offs + hash + 1) & mask;
196 }
197 n[offs] = ns->data[i];
198 }
199 free(ns->data);
200 }
201 ns->mask = mask;
202 ns->data = n;
203 }
204 mask = ns->mask;
205 hash = (size_t)p->hash;
206 offs = hash & mask;
207 while (ns->data[offs] != NULL) {
208 Label *d = ns->data[offs];
209 if (p->hash == d->hash && p->strength == d->strength) {
210 const str_t *s1 = &p->cfname;
211 const str_t *s2 = &d->cfname;
212 if (s1->len == s2->len && (s1->data == s2->data || memcmp(s1->data, s2->data, s1->len) == 0)) {
213 return d;
214 }
215 }
216 hash >>= 5;
217 offs = (5 * offs + hash + 1) & mask;
218 }
219 ns->data[offs] = p;
220 ns->len++;
221 return NULL;
222 }
223
namespace_lookup(const Namespace * ns,const Label * p)224 static Label *namespace_lookup(const Namespace *ns, const Label *p) {
225 Label *ret = NULL;
226 size_t mask = ns->mask;
227 size_t hash = (size_t)p->hash;
228 size_t offs = hash & mask;
229 if (ns->data == NULL) return ret;
230 while (ns->data[offs] != NULL) {
231 Label *d = ns->data[offs];
232 if (p->hash == d->hash) {
233 if (d->defpass == pass || (d->constant && (!fixeddig || d->defpass == pass - 1))) {
234 const str_t *s1 = &p->cfname;
235 const str_t *s2 = &d->cfname;
236 if (s1->len == s2->len && (s1->data == s2->data || memcmp(s1->data, s2->data, s1->len) == 0)) {
237 if (d->strength == 0) { ret = d; break; }
238 if (ret == NULL || d->strength < ret->strength) ret = d;
239 }
240 }
241 }
242 hash >>= 5;
243 offs = (5 * offs + hash + 1) & mask;
244 }
245 if (ret != NULL && ret->constant && ret->defpass == pass - 1 && ret->fwpass != pass) {
246 ret->fwpass = pass;
247 fwcount++;
248 }
249 return ret;
250 }
251
namespace_lookup2(const Label * p)252 static Label *namespace_lookup2(const Label *p) {
253 const Namespace *ns = builtin_namespace;
254 size_t mask = ns->mask;
255 size_t hash = (size_t)p->hash;
256 size_t offs = hash & mask;
257 while (ns->data[offs] != NULL) {
258 Label *d = ns->data[offs];
259 if (p->hash == d->hash) {
260 const str_t *s1 = &p->cfname;
261 const str_t *s2 = &d->cfname;
262 if (s1->len == s2->len && memcmp(s1->data, s2->data, s1->len) == 0) {
263 return d;
264 }
265 }
266 hash >>= 5;
267 offs = (5 * offs + hash + 1) & mask;
268 }
269 return NULL;
270 }
271
namespace_lookup3(const Namespace * ns,const Label * p)272 static Label *namespace_lookup3(const Namespace *ns, const Label *p) {
273 size_t mask = ns->mask;
274 size_t hash = (size_t)p->hash;
275 size_t offs = hash & mask;
276 if (ns->data == NULL) return NULL;
277 while (ns->data[offs] != NULL) {
278 Label *d = ns->data[offs];
279 if (p->hash == d->hash && p->strength == d->strength) {
280 const str_t *s1 = &p->cfname;
281 const str_t *s2 = &d->cfname;
282 if (s1->len == s2->len && (s1->data == s2->data || memcmp(s1->data, s2->data, s1->len) == 0)) {
283 return d;
284 }
285 }
286 hash >>= 5;
287 offs = (5 * offs + hash + 1) & mask;
288 }
289 return NULL;
290 }
291
find_label(const str_t * name,Namespace ** here)292 Label *find_label(const str_t *name, Namespace **here) {
293 size_t p = context_stack.p;
294 Label label, *c;
295
296 str_cfcpy(&label.cfname, name);
297 label.hash = str_hash(&label.cfname);
298
299 while (context_stack.bottom < p) {
300 Namespace *context = context_stack.stack[--p].normal;
301 Label *key2 = namespace_lookup(context, &label);
302 if (key2 != NULL) {
303 if (here != NULL) *here = context;
304 if (!diagnostics.shadow || !fixeddig || constcreated || (here != NULL && *here == context)) {
305 return key2;
306 }
307 while (context_stack.bottom < p) {
308 Label *key1 = namespace_lookup(context_stack.stack[--p].normal, &label);
309 if (key1 != NULL) {
310 Obj *o1 = key1->value;
311 Obj *o2 = key2->value;
312 if (o1 != o2 && !o1->obj->same(o1, o2)) {
313 err_msg_shadow_defined(key1, key2);
314 return key2;
315 }
316 }
317 }
318 c = namespace_lookup2(&label);
319 if (c != NULL) {
320 Obj *o1 = c->value;
321 Obj *o2 = key2->value;
322 if (o1 != o2 && !o1->obj->same(o1, o2)) {
323 err_msg_shadow_defined2(key2);
324 }
325 }
326 return key2;
327 }
328 }
329 c = namespace_lookup2(&label);
330 if (here != NULL) *here = (c != NULL) ? builtin_namespace : NULL;
331 return c;
332 }
333
find_label2(const str_t * name,Namespace * context)334 Label *find_label2(const str_t *name, Namespace *context) {
335 Label label;
336
337 str_cfcpy(&label.cfname, name);
338 label.hash = str_hash(&label.cfname);
339
340 return namespace_lookup(context, &label);
341 }
342
343 struct anonsymbol_s {
344 uint8_t dir, pad;
345 uint8_t count[sizeof(uint32_t)];
346 };
347
find_label3(const str_t * name,Namespace * context,uint8_t strength)348 Label *find_label3(const str_t *name, Namespace *context, uint8_t strength) {
349 Label label;
350
351 label.strength = strength;
352 if (name->len > 1 && name->data[1] == 0) label.cfname = *name;
353 else str_cfcpy(&label.cfname, name);
354 label.hash = str_hash(&label.cfname);
355
356 return namespace_lookup3(context, &label);
357 }
358
find_anonlabel(ssize_t count)359 Label *find_anonlabel(ssize_t count) {
360 size_t p = context_stack.p;
361 Namespace *context;
362 Label label, *c;
363 struct anonsymbol_s anonsymbol;
364
365 anonsymbol.dir = (count >= 0) ? '+' : '-';
366 anonsymbol.pad = 0;
367
368 label.cfname.data = (const uint8_t *)&anonsymbol;
369
370 while (context_stack.bottom < p) {
371 uint32_t count2;
372 context = context_stack.stack[--p].normal;
373 if (count < 0) {
374 if (context->backr < (size_t)-count) continue;
375 count2 = context->backr - (uint32_t)-count;
376 } else {
377 count2 = context->forwr + (uint32_t)count;
378 if (count2 < (size_t)count) continue;
379 }
380 label.cfname.len = 2;
381 while (count2 != 0) {
382 anonsymbol.count[label.cfname.len - 2] = (uint8_t)count2;
383 label.cfname.len++;
384 count2 >>= 8;
385 }
386
387 label.hash = str_hash(&label.cfname);
388 c = namespace_lookup(context, &label);
389 if (c != NULL) return c;
390 }
391 return NULL;
392 }
393
find_anonlabel2(ssize_t count,Namespace * context)394 Label *find_anonlabel2(ssize_t count, Namespace *context) {
395 Label label;
396 uint32_t count2;
397 struct anonsymbol_s anonsymbol;
398
399 if (count < 0) {
400 if (context->backr < (size_t)-count) return NULL;
401 count2 = context->backr - (uint32_t)-count;
402 anonsymbol.dir = '-';
403 } else {
404 count2 = context->forwr + (uint32_t)count;
405 if (count2 < (size_t)count) return NULL;
406 anonsymbol.dir = '+';
407 }
408
409 anonsymbol.pad = 0;
410
411 label.cfname.data = (const uint8_t *)&anonsymbol;
412 label.cfname.len = 2;
413 while (count2 != 0) {
414 anonsymbol.count[label.cfname.len - 2] = (uint8_t)count2;
415 label.cfname.len++;
416 count2 >>= 8;
417 }
418 label.hash = str_hash(&label.cfname);
419
420 return namespace_lookup(context, &label);
421 }
422
423 /* --------------------------------------------------------------------------- */
new_label(const str_t * name,Namespace * context,uint8_t strength,bool * exists,const struct file_list_s * cflist)424 Label *new_label(const str_t *name, Namespace *context, uint8_t strength, bool *exists, const struct file_list_s *cflist) {
425 Label *b;
426 if (lastlb == NULL) lastlb = Label(val_alloc(LABEL_OBJ));
427
428 if (name->len > 1 && name->data[1] == 0) lastlb->cfname = *name;
429 else str_cfcpy(&lastlb->cfname, name);
430 lastlb->hash = str_hash(&lastlb->cfname);
431 lastlb->strength = strength;
432
433 b = namespace_update(context, lastlb);
434
435 if (b == NULL) { /* new label */
436 if (not_in_file(name->data, cflist->file)) str_cpy(&lastlb->name, name);
437 else lastlb->name = *name;
438 if (lastlb->cfname.data != name->data) str_cfcpy(&lastlb->cfname, NULL);
439 else lastlb->cfname = lastlb->name;
440 lastlb->file_list = cflist;
441 lastlb->ref = false;
442 lastlb->update_after = false;
443 lastlb->usepass = 0;
444 lastlb->fwpass = 0;
445 lastlb->defpass = pass;
446 *exists = false;
447 b = lastlb;
448 lastlb = NULL;
449 return b;
450 }
451 *exists = true;
452 return b;
453 }
454
label_move(Label * label,const str_t * name,const struct file_list_s * cflist)455 void label_move(Label *label, const str_t *name, const struct file_list_s *cflist) {
456 bool cfsame = (label->cfname.data == label->name.data);
457 if (!not_in_file(label->name.data, label->file_list->file)) {
458 if (not_in_file(name->data, cflist->file)) str_cpy(&label->name, name);
459 else label->name = *name;
460 }
461 if (cfsame) {
462 label->cfname = label->name;
463 }
464 label->file_list = cflist;
465 }
466
unused_check(Namespace * names)467 void unused_check(Namespace *names) {
468 size_t n, ln;
469
470 if (names->len == 0) return;
471 ln = names->len; names->len = 0;
472 for (n = 0; n <= names->mask; n++) {
473 Label *key2 = names->data[n];
474 Obj *o;
475 Namespace *ns;
476
477 if (key2 == NULL || key2->defpass != pass) continue;
478
479 o = key2->value;
480 if (key2->usepass != pass && (key2->name.data[0] != '.' && key2->name.data[0] != '#')) {
481 if (!key2->constant) {
482 if (diagnostics.unused.variable) err_msg_unused_variable(key2);
483 continue;
484 }
485 if (!key2->owner) {
486 if (diagnostics.unused.consts) err_msg_unused_const(key2);
487 continue;
488 }
489 if (o->obj == CODE_OBJ) {
490 if (diagnostics.unused.label) err_msg_unused_label(key2);
491 continue;
492 }
493 if (diagnostics.unused.macro) {
494 err_msg_unused_macro(key2);
495 continue;
496 }
497 }
498 if (!key2->owner) continue;
499 switch (o->obj->type) {
500 case T_CODE:
501 ns = Code(o)->names;
502 break;
503 case T_NAMESPACE:
504 ns = Namespace(o);
505 break;
506 case T_MFUNC:
507 {
508 Mfunc *mfunc = Mfunc(o);
509 List *lst = mfunc->inamespaces;
510 size_t i;
511 for (i = 0; i < lst->len; i++) {
512 ns = Namespace(lst->data[i]);
513 if (ns->len != 0) unused_check(ns);
514 }
515 ns = mfunc->names;
516 }
517 break;
518 default:
519 ns = NULL;
520 break;
521 }
522 if (ns != NULL && ns->len != 0) {
523 push_context(ns);
524 unused_check(ns);
525 pop_context();
526 }
527 }
528 names->len = ln;
529 }
530
padding(size_t l,size_t t,FILE * f)531 static inline void padding(size_t l, size_t t, FILE *f) {
532 if (arguments.tab_size > 1) {
533 size_t l2 = l - l % arguments.tab_size;
534 while (l2 + arguments.tab_size <= t) { l2 += arguments.tab_size; l = l2; putc('\t', f);}
535 }
536 while (l < t) { l++; putc(' ', f);}
537 }
538
labelname_print(const Label * l,FILE * flab,char d)539 static void labelname_print(const Label *l, FILE *flab, char d) {
540 size_t p;
541 for (p = 0; p < label_stack.p; p++) {
542 printable_print2(label_stack.stack[p]->name.data, flab, label_stack.stack[p]->name.len);
543 putc(d, flab);
544 }
545 printable_print2(l->name.data, flab, l->name.len);
546 }
547
labelprint2(Namespace * names,FILE * flab,Symbollist_types labelmode)548 static void labelprint2(Namespace *names, FILE *flab, Symbollist_types labelmode) {
549 size_t n, ln;
550
551 if (names->len == 0) return;
552 ln = names->len; names->len = 0;
553 for (n = 0; n <= names->mask; n++) {
554 Label *l = names->data[n];
555 if (l == NULL || l->name.data == NULL) continue;
556 if (l->name.len > 1 && l->name.data[1] == 0) continue;
557 switch (l->value->obj->type) {
558 case T_LBL:
559 case T_MACRO:
560 case T_SEGMENT:
561 case T_UNION:
562 case T_STRUCT: continue;
563 case T_CODE:
564 if (Code(l->value)->pass != Code(l->value)->apass) continue;
565 break;
566 default:break;
567 }
568 if (l != namespace_lookup(names, l)) continue;
569 if (labelmode == LABEL_VICE || labelmode == LABEL_VICE_NUMERIC) {
570 Obj *val;
571 size_t i, j = l->name.len;
572 const uint8_t *d = l->name.data;
573
574 if (!l->constant) continue;
575 for (i = 0; i < j; i++) {
576 uint8_t c = d[i];
577 if (c < '0') break;
578 if (c <= '9') continue;
579 if (c == '_') continue;
580 c |= 0x20;
581 if (c < 'a') break;
582 if (c <= 'z') continue;
583 break;
584 }
585 if (i != j) continue;
586
587 val = l->value;
588 if (val->obj == ADDRESS_OBJ || val->obj == CODE_OBJ || (labelmode == LABEL_VICE_NUMERIC && (val->obj == BITS_OBJ || val->obj == INT_OBJ))) {
589 struct linepos_s epoint;
590 uval_t uv;
591 Error *err = val->obj->uval(val, &uv, 24, &epoint);
592 if (err == NULL) {
593 fprintf(flab, "al %" PRIx32 " .", uv & 0xffffff);
594 labelname_print(l, flab, ':');
595 putc('\n', flab);
596 } else val_destroy(Obj(err));
597 }
598 if (l->owner) {
599 Namespace *ns = get_namespace(val);
600 if (ns != NULL && ns->len != 0) {
601 push_label(l);
602 labelprint2(ns, flab, labelmode);
603 pop_label();
604 }
605 }
606 } else {
607 Obj *val = l->value;
608 val = val->obj->repr(val, NULL, SIZE_MAX);
609 if (val == NULL) continue;
610 if (val->obj == STR_OBJ) {
611 const Str *str = Str(val);
612 size_t len = printable_print2(l->name.data, flab, l->name.len);
613 padding(len, EQUAL_COLUMN, flab);
614 if (l->constant) fputs("= ", flab);
615 else fputs(&" := "[len < EQUAL_COLUMN], flab);
616 printable_print2(str->data, flab, str->len);
617 putc('\n', flab);
618 }
619 val_destroy(val);
620 }
621 }
622 names->len = ln;
623 }
624
get_line(const struct file_s * file,linenum_t line)625 static inline const uint8_t *get_line(const struct file_s *file, linenum_t line) {
626 return &file->data[file->line[line - 1]];
627 }
628
labeldump(Namespace * names,FILE * flab)629 static void labeldump(Namespace *names, FILE *flab) {
630 size_t n, ln;
631
632 if (names->len == 0) return;
633 ln = names->len; names->len = 0;
634 for (n = 0; n <= names->mask; n++) {
635 Label *l2 = names->data[n];
636 Namespace *ns;
637
638 if (l2 == NULL) continue;
639 if (l2->name.len < 2 || l2->name.data[1] != 0) {
640 Obj *val = l2->value;
641 val = val->obj->repr(val, NULL, SIZE_MAX);
642 if (val != NULL) {
643 if (val->obj == STR_OBJ) {
644 const Str *str = Str(val);
645 const struct file_s *file = l2->file_list->file;
646 linepos_t epoint = &l2->epoint;
647 printable_print((const uint8_t *)file->realname, flab);
648 fprintf(flab, ":%" PRIuline ":%" PRIlinepos ": ", epoint->line, ((file->encoding == E_UTF8) ? (linecpos_t)calcpos(get_line(file, epoint->line), epoint->pos) : epoint->pos) + 1);
649 labelname_print(l2, flab, '.');
650 fputs(l2->constant ? " = " : " := ", flab);
651 printable_print2(str->data, flab, str->len);
652 putc('\n', flab);
653 }
654 val_destroy(val);
655 }
656 }
657 if (!l2->owner) continue;
658
659 ns = get_namespace(l2->value);
660
661 if (ns != NULL && ns->len != 0) {
662 if (l2->name.len < 2 || l2->name.data[1] != 0) {
663 push_label(l2);
664 labeldump(ns, flab);
665 pop_label();
666 }
667 }
668 }
669 names->len = ln;
670 }
671
find_space(const char * here,bool use)672 static Namespace *find_space(const char *here, bool use) {
673 Namespace *space;
674 str_t labelname;
675 Label *l;
676
677 space = root_namespace;
678 if (here == NULL) return space;
679
680 pline = (const uint8_t *)here;
681 lpoint.pos = 0;
682 do {
683 labelname.data = pline + lpoint.pos; labelname.len = get_label(labelname.data);
684 if (labelname.len == 0) return NULL;
685 lpoint.pos += (linecpos_t)labelname.len;
686 l = find_label2(&labelname, space);
687 if (l == NULL) return NULL;
688 space = get_namespace(l->value);
689 if (space == NULL) return NULL;
690 lpoint.pos++;
691 } while (labelname.data[labelname.len] == '.');
692
693 if (labelname.data[labelname.len] != 0) return NULL;
694
695 if (use) {
696 l->usepass = pass;
697 l->ref = true;
698 }
699 return space;
700 }
701
labelprint(const struct symbol_output_s * output)702 void labelprint(const struct symbol_output_s *output) {
703 FILE *flab;
704 struct linepos_s nopoint = {0, 0};
705 int err;
706 Namespace *space;
707
708 flab = dash_name(output->name) ? stdout : file_open(output->name, output->append ? "at" : "wt");
709 if (flab == NULL) {
710 err_msg_file(ERROR_CANT_WRTE_LBL, output->name, &nopoint);
711 return;
712 }
713 clearerr(flab); errno = 0;
714 label_stack.stack = NULL;
715 label_stack.p = label_stack.len = 0;
716 space = find_space(output->space, false);
717 if (space == NULL) {
718 str_t labelname;
719 labelname.data = pline;
720 labelname.len = lpoint.pos;
721 err_msg2(ERROR____LABEL_ROOT, &labelname, &nopoint);
722 } else if (output->mode == LABEL_DUMP) {
723 labeldump(space, flab);
724 } else {
725 labelprint2(space, flab, output->mode);
726 }
727 free(label_stack.stack);
728 err = ferror(flab);
729 err |= (flab != stdout) ? fclose(flab) : fflush(flab);
730 if (err != 0 && errno != 0) {
731 err_msg_file(ERROR_CANT_WRTE_LBL, output->name, &nopoint);
732 }
733 }
734
ref_labels(void)735 void ref_labels(void) {
736 size_t j;
737 for (j = 0; j < arguments.symbol_output_len; j++) {
738 const struct symbol_output_s *output = &arguments.symbol_output[j];
739 Namespace *space;
740 size_t n;
741
742 if (output->mode != LABEL_EXPORT) continue;
743 space = find_space(output->space, true);
744 if (space == NULL || space->len == 0) continue;
745
746 for (n = 0; n <= space->mask; n++) {
747 Label *l = space->data[n];
748 if (l == NULL || l->name.data == NULL) continue;
749 if (l->name.len > 1 && l->name.data[1] == 0) continue;
750 switch (l->value->obj->type) {
751 case T_LBL:
752 case T_MACRO:
753 case T_SEGMENT:
754 case T_UNION:
755 case T_STRUCT: continue;
756 default:break;
757 }
758 if (l != namespace_lookup(space, l)) continue;
759 if (l->value->obj == ERROR_OBJ) err_msg_output(Error(l->value));
760 l->ref = true;
761 l->usepass = pass;
762 }
763 }
764 }
765
new_builtin(const char * symbol,Obj * val)766 void new_builtin(const char *symbol, Obj *val) {
767 struct linepos_s nopoint = {0, 0};
768 str_t name;
769 Label *label;
770 bool label_exists;
771 name.len = strlen(symbol);
772 name.data = (const uint8_t *)symbol;
773 label = new_label(&name, builtin_namespace, 0, &label_exists, dummy_file_list);
774 label->constant = true;
775 label->owner = true;
776 label->value = val;
777 label->epoint = nopoint;
778 }
779
init_variables(void)780 void init_variables(void)
781 {
782 struct linepos_s nopoint = {0, 0};
783
784 builtin_namespace = new_namespace(NULL, &nopoint);
785 root_namespace = new_namespace(NULL, &nopoint);
786 cheap_context = ref_namespace(root_namespace);
787
788 context_stack.stack = NULL;
789 context_stack.p = context_stack.len = context_stack.bottom = 0;
790
791 boolobj_names();
792 registerobj_names();
793 functionobj_names();
794 gapobj_names();
795 listobj_names();
796 strobj_names();
797 intobj_names();
798 floatobj_names();
799 codeobj_names();
800 addressobj_names();
801 dictobj_names();
802 bitsobj_names();
803 bytesobj_names();
804 typeobj_names();
805 namespaceobj_names();
806 }
807
destroy_lastlb(void)808 void destroy_lastlb(void) {
809 if (lastlb != NULL) {
810 lastlb->v.obj = NONE_OBJ;
811 val_destroy(Obj(lastlb));
812 lastlb = NULL;
813 }
814 }
815
destroy_variables(void)816 void destroy_variables(void)
817 {
818 val_destroy(Obj(builtin_namespace));
819 val_destroy(Obj(root_namespace));
820 val_destroy(Obj(cheap_context));
821 destroy_lastlb();
822 while (context_stack.p != 0) {
823 struct cstack_s *c = &context_stack.stack[--context_stack.p];
824 val_destroy(Obj(c->normal));
825 val_destroy(Obj(c->cheap));
826 }
827 free(context_stack.stack);
828 }
829