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