1 /*
2 * symbol.c - routines for symbol table management and code allocation
3 */
4
5 /*
6 * Copyright (C) 1986, 1988, 1989, 1991-2015, 2017-2020, 2022, 2023,
7 * the Free Software Foundation, Inc.
8 *
9 * This file is part of GAWK, the GNU implementation of the
10 * AWK Programming Language.
11 *
12 * GAWK is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 3 of the License, or
15 * (at your option) any later version.
16 *
17 * GAWK is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25 */
26
27 #include "awk.h"
28
29 extern SRCFILE *srcfiles;
30 extern INSTRUCTION *rule_list;
31
32 #define HASHSIZE 1021
33
34 static NODE *symbol_list;
35 static void (*install_func)(NODE *) = NULL;
36 static NODE *make_symbol(const char *name, NODETYPE type);
37 static NODE *install(const char *name, NODE *parm, NODETYPE type);
38 static void free_bcpool(INSTRUCTION_POOL *pl);
39 static NODE *get_name_from_awk_ns(const char *name);
40
41 static AWK_CONTEXT *curr_ctxt = NULL;
42 static int ctxt_level;
43
44 static NODE *global_table, *param_table;
45 NODE *symbol_table, *func_table;
46
47 /* Use a flag to avoid a strcmp() call inside install() */
48 static bool installing_specials = false;
49
50 // Using persistent memory, manage the root pointer
51 // which holds this struct:
52 struct root_pointers {
53 NODE *global_table;
54 NODE *func_table;
55 NODE *symbol_table;
56 struct block_header nextfree[BLOCK_MAX];
57 int mpfr;
58 bool first;
59 } *root_pointers = NULL;
60
61 /* init_the_tables --- deal with the tables for in memory use */
62
63 static void
64 init_the_tables(void)
65 {
66 getnode(global_table);
67 memset(global_table, '\0', sizeof(NODE));
68 null_array(global_table);
69
70 getnode(param_table);
71 memset(param_table, '\0', sizeof(NODE));
72 null_array(param_table);
73
74 installing_specials = true;
75 func_table = install_symbol(estrdup("FUNCTAB", 7), Node_var_array);
76 symbol_table = install_symbol(estrdup("SYMTAB", 6), Node_var_array);
77 installing_specials = false;
78 }
79
80 /* init_symbol_table --- make sure the symbol tables are initialized */
81
82 void
83 init_symbol_table()
84 {
85 if (! using_persistent_malloc) {
86 // normal case, initialize regularly, return
87 init_the_tables();
88 return;
89 }
90
91 root_pointers = (struct root_pointers *) pma_get_root();
92
93 if (root_pointers == NULL) {
94 // very first time!
95
96 // set up the tables
97 init_the_tables();
98
99 // save the pointers for the next time.
100 emalloc(root_pointers, struct root_pointers *, sizeof(struct root_pointers), "init_symbol_table");
101 memset(root_pointers, 0, sizeof(struct root_pointers));
102 root_pointers->global_table = global_table;
103 root_pointers->func_table = func_table;
104 root_pointers->symbol_table = symbol_table;
105 root_pointers->first = true;
106 root_pointers->mpfr = 0;
107 pma_set_root(root_pointers);
108 } else {
109 // this is the next time, get the saved pointers and put them back in place
110 global_table = root_pointers->global_table;
111 func_table = root_pointers->func_table;
112 symbol_table = root_pointers->symbol_table;
113 memcpy(nextfree, root_pointers->nextfree, sizeof(nextfree));
114
115 // still need to set this one up as usual
116 getnode(param_table);
117 memset(param_table, '\0', sizeof(NODE));
118 null_array(param_table);
119 }
120 }
121
122 /* pma_mpfr_check --- check that -M is same between invocations */
123
124 void
125 pma_mpfr_check(void)
126 {
127 if (! using_persistent_malloc)
128 return;
129
130 if (root_pointers->first) {
131 root_pointers->first = false;
132 root_pointers->mpfr = do_mpfr;
133 return;
134 }
135
136 if (root_pointers->mpfr != do_mpfr)
137 fatal(_("current setting of -M/--bignum does not match saved setting in PMA backing file"));
138 }
139
140 /* pma_save_free_lists --- save the free lists in the root pointer */
141
142 void
143 pma_save_free_lists(void)
144 {
145 if (! using_persistent_malloc)
146 return;
147
148 assert(! root_pointers->first);
149
150 memcpy(root_pointers->nextfree, nextfree, sizeof(nextfree));
151 }
152
153 /*
154 * install_symbol:
155 * Install a global name in the symbol table, even if it is already there.
156 * Caller must check against redefinition if that is desired.
157 */
158
159 NODE *
160 install_symbol(const char *name, NODETYPE type)
161 {
162 return install(name, NULL, type);
163 }
164
165
166 /*
167 * lookup --- find the most recent global or param node for name
168 * installed by install_symbol
169 */
170
171 NODE *
172 lookup(const char *name)
173 {
174 NODE *n;
175 NODE *tmp;
176 NODE *tables[5]; /* manual init below, for z/OS */
177 int i;
178
179 /* ``It's turtles, all the way down.'' */
180 tables[0] = param_table; /* parameters shadow everything */
181 tables[1] = global_table; /* SYMTAB and FUNCTAB found first, can't be redefined */
182 tables[2] = func_table; /* then functions */
183 tables[3] = symbol_table; /* then globals */
184 tables[4] = NULL;
185
186 tmp = get_name_from_awk_ns(name);
187
188 n = NULL;
189 for (i = 0; tables[i] != NULL; i++) {
190 if (assoc_empty(tables[i]))
191 continue;
192
193 if ((do_posix || do_traditional) && tables[i] == global_table)
194 continue;
195
196 n = in_array(tables[i], tmp);
197 if (n != NULL)
198 break;
199 }
200
201 unref(tmp);
202 if (n == NULL || n->type == Node_val) /* non-variable in SYMTAB */
203 return NULL;
204 return n; /* new place */
205 }
206
207 /* make_params --- allocate function parameters for the symbol table */
208
209 NODE *
210 make_params(char **pnames, int pcount)
211 {
212 NODE *p, *parms;
213 int i;
214
215 if (pcount <= 0 || pnames == NULL)
216 return NULL;
217
218 ezalloc(parms, NODE *, pcount * sizeof(NODE), "make_params");
219
220 for (i = 0, p = parms; i < pcount; i++, p++) {
221 p->type = Node_param_list;
222 p->param = pnames[i]; /* shadows pname and vname */
223 p->param_cnt = i;
224 }
225
226 return parms;
227 }
228
229 /* install_params --- install function parameters into the symbol table */
230
231 void
232 install_params(NODE *func)
233 {
234 int i, pcount;
235 NODE *parms;
236
237 if (func == NULL)
238 return;
239
240 assert(func->type == Node_func);
241
242 if ( (pcount = func->param_cnt) <= 0
243 || (parms = func->fparms) == NULL)
244 return;
245
246 for (i = 0; i < pcount; i++)
247 (void) install(parms[i].param, parms + i, Node_param_list);
248 }
249
250
251 /*
252 * remove_params --- remove function parameters out of the symbol table.
253 */
254
255 void
256 remove_params(NODE *func)
257 {
258 NODE *parms, *p;
259 int i, pcount;
260
261 if (func == NULL)
262 return;
263
264 assert(func->type == Node_func);
265
266 if ( (pcount = func->param_cnt) <= 0
267 || (parms = func->fparms) == NULL)
268 return;
269
270 for (i = pcount - 1; i >= 0; i--) {
271 NODE *tmp;
272 NODE *tmp2;
273
274 p = parms + i;
275 assert(p->type == Node_param_list);
276 tmp = make_string(p->vname, strlen(p->vname));
277 tmp2 = in_array(param_table, tmp);
278 if (tmp2 != NULL && tmp2->dup_ent != NULL)
279 tmp2->dup_ent = tmp2->dup_ent->dup_ent;
280 else
281 (void) assoc_remove(param_table, tmp);
282
283 unref(tmp);
284 }
285
286 assoc_clear(param_table); /* shazzam! */
287 }
288
289
290 /* remove_symbol --- remove a symbol from the symbol table */
291
292 NODE *
293 remove_symbol(NODE *r)
294 {
295 NODE *n = in_array(symbol_table, r);
296
297 if (n == NULL)
298 return n;
299
300 n = dupnode(n);
301
302 (void) assoc_remove(symbol_table, r);
303
304 return n;
305 }
306
307
308 /*
309 * destroy_symbol --- remove a symbol from symbol table
310 * and free all associated memory.
311 */
312
313 void
314 destroy_symbol(NODE *r)
315 {
316 r = remove_symbol(r);
317 if (r == NULL)
318 return;
319
320 switch (r->type) {
321 case Node_func:
322 if (r->param_cnt > 0) {
323 NODE *n;
324 int i;
325 int pcount = r->param_cnt;
326
327 /* function parameters of type Node_param_list */
328 for (i = 0; i < pcount; i++) {
329 n = r->fparms + i;
330 efree(n->param);
331 }
332 efree(r->fparms);
333 }
334 break;
335
336 case Node_ext_func:
337 bcfree(r->code_ptr);
338 break;
339
340 case Node_var_array:
341 assoc_clear(r);
342 break;
343
344 case Node_var:
345 unref(r->var_value);
346 break;
347
348 default:
349 /* Node_param_list -- YYABORT */
350 break; /* use break so that storage is freed */
351 }
352
353 efree(r->vname);
354 freenode(r);
355 }
356
357
358 /* make_symbol --- allocates a global symbol for the symbol table. */
359
360 static NODE *
361 make_symbol(const char *name, NODETYPE type)
362 {
363 NODE *r;
364
365 getnode(r);
366 memset(r, '\0', sizeof(NODE));
367 if (type == Node_var_array)
368 null_array(r);
369 else if (type == Node_var)
370 r->var_value = dupnode(Nnull_string);
371 r->vname = (char *) name;
372 r->type = type;
373 r->valref = 1;
374
375 return r;
376 }
377
378 /* install --- install a global name or function parameter in the symbol table */
379
380 static NODE *
381 install(const char *name, NODE *parm, NODETYPE type)
382 {
383 NODE *r;
384 NODE *table;
385 NODE *n_name;
386 NODE *prev;
387
388 n_name = get_name_from_awk_ns(name);
389
390 table = symbol_table;
391
392 if (type == Node_param_list) {
393 table = param_table;
394 } else if ( type == Node_func
395 || type == Node_ext_func
396 || type == Node_builtin_func) {
397 table = func_table;
398 } else if (installing_specials) {
399 table = global_table;
400 }
401
402 if (parm != NULL)
403 r = parm;
404 else {
405 /* global symbol */
406 r = make_symbol(name, type);
407 }
408
409 if (type == Node_param_list) {
410 prev = in_array(table, n_name);
411 if (prev == NULL)
412 goto simple;
413 r->dup_ent = prev->dup_ent;
414 prev->dup_ent = r;
415 unref(n_name);
416 } else {
417 simple:
418 /* the simple case */
419 assoc_set(table, n_name, r);
420 }
421
422 if (install_func)
423 (*install_func)(r);
424
425 return r;
426 }
427
428 /* comp_symbol --- compare two (variable or function) names */
429
430 static int
431 comp_symbol(const void *v1, const void *v2)
432 {
433 const NODE *const *npp1, *const *npp2;
434 const NODE *n1, *n2;
435
436 npp1 = (const NODE *const *) v1;
437 npp2 = (const NODE *const *) v2;
438 n1 = *npp1;
439 n2 = *npp2;
440
441 // names in awk namespace come out first
442 bool n1_is_in_ns = (strchr(n1->vname, ':') != NULL);
443 bool n2_is_in_ns = (strchr(n2->vname, ':') != NULL);
444
445 if (n1_is_in_ns && n2_is_in_ns)
446 return strcmp(n1->vname, n2->vname);
447 else if (n1_is_in_ns && ! n2_is_in_ns)
448 return 1;
449 else if (! n1_is_in_ns && n2_is_in_ns)
450 return -1;
451 else
452 return strcmp(n1->vname, n2->vname);
453 }
454
455
456 typedef enum { FUNCTION = 1, VARIABLE } SYMBOL_TYPE;
457
458 /* get_symbols --- return a list of optionally sorted symbols */
459
460 static NODE **
461 get_symbols(SYMBOL_TYPE what, bool sort)
462 {
463 int i;
464 NODE **table;
465 NODE **list;
466 NODE *r;
467 long count = 0;
468 long max;
469 NODE *the_table;
470
471 /*
472 * assoc_list() returns an array with two elements per awk array
473 * element. Elements i and i+1 in the C array represent the key
474 * and value of element j in the awk array. Thus the loops use += 2
475 * to go through the awk array.
476 */
477
478 if (what == FUNCTION) {
479 the_table = func_table;
480 max = the_table->table_size * 2;
481
482 list = assoc_list(the_table, "@unsorted", ASORTI);
483 emalloc(table, NODE **, (the_table->table_size + 1) * sizeof(NODE *), "get_symbols");
484
485 for (i = count = 0; i < max; i += 2) {
486 r = list[i+1];
487 if (r->type == Node_ext_func || r->type == Node_builtin_func)
488 continue;
489 assert(r->type == Node_func);
490 table[count++] = r;
491 }
492 } else { /* what == VARIABLE */
493 update_global_values();
494
495 the_table = symbol_table;
496 max = the_table->table_size * 2;
497
498 list = assoc_list(the_table, "@unsorted", ASORTI);
499 /* add three: one for FUNCTAB, one for SYMTAB, and one for a final NULL */
500 emalloc(table, NODE **, (the_table->table_size + 1 + 1 + 1) * sizeof(NODE *), "get_symbols");
501
502 for (i = count = 0; i < max; i += 2) {
503 r = list[i+1];
504 if (r->type == Node_val) /* non-variable in SYMTAB */
505 continue;
506 table[count++] = r;
507 }
508
509 table[count++] = func_table;
510 table[count++] = symbol_table;
511 }
512
513 efree(list);
514
515 if (sort && count > 1)
516 qsort(table, count, sizeof(NODE *), comp_symbol); /* Shazzam! */
517 table[count] = NULL; /* null terminate the list */
518 return table;
519 }
520
521
522 /* variable_list --- list of global variables */
523
524 NODE **
525 variable_list()
526 {
527 return get_symbols(VARIABLE, true);
528 }
529
530 /* function_list --- list of functions */
531
532 NODE **
533 function_list(bool sort)
534 {
535 return get_symbols(FUNCTION, sort);
536 }
537
538 /* print_vars --- print names and values of global variables */
539
540 void
541 print_vars(NODE **table, int (*print_func)(FILE *, const char *, ...), FILE *fp)
542 {
543 int i;
544 NODE *r;
545
546 assert(table != NULL);
547
548 for (i = 0; (r = table[i]) != NULL; i++) {
549 if (r->type == Node_func || r->type == Node_ext_func)
550 continue;
551 print_func(fp, "%s: ", r->vname);
552 if (r->type == Node_var_array)
553 print_func(fp, "array, %ld elements\n", assoc_length(r));
554 else if (r->type == Node_var_new)
555 print_func(fp, "untyped variable\n");
556 else if (r->type == Node_var)
557 valinfo(r->var_value, print_func, fp);
558 else
559 cant_happen("unexpected node type: %s", nodetype2str(r->type));
560 }
561 }
562
563
564 /* foreach_func --- execute given function for each awk function in table. */
565
566 int
567 foreach_func(NODE **table, int (*pfunc)(INSTRUCTION *, void *), void *data)
568 {
569 int i;
570 NODE *r;
571 int ret = 0;
572
573 assert(table != NULL);
574
575 for (i = 0; (r = table[i]) != NULL; i++) {
576 if ((ret = pfunc(r->code_ptr, data)) != 0)
577 break;
578 }
579 return ret;
580 }
581
582 /* release_all_vars --- free all variable memory */
583
584 void
585 release_all_vars()
586 {
587 assoc_clear(symbol_table);
588 assoc_clear(func_table);
589 assoc_clear(global_table);
590 }
591
592
593 /* append_symbol --- append symbol to the list of symbols
594 * installed in the symbol table.
595 */
596
597 void
598 append_symbol(NODE *r)
599 {
600 NODE *p;
601
602 getnode(p);
603 p->lnode = r;
604 p->rnode = symbol_list->rnode;
605 symbol_list->rnode = p;
606 }
607
608 /* release_symbols --- free symbol list and optionally remove symbol from symbol table */
609
610 void
611 release_symbols(NODE *symlist, int keep_globals)
612 {
613 NODE *p, *next;
614
615 for (p = symlist->rnode; p != NULL; p = next) {
616 if (! keep_globals) {
617 /*
618 * destroys globals, function, and params
619 * if still in symbol table
620 */
621 destroy_symbol(p->lnode);
622 }
623 next = p->rnode;
624 freenode(p);
625 }
626 symlist->rnode = NULL;
627 }
628
629 /* load_symbols --- fill in symbols' information */
630
631 void
632 load_symbols()
633 {
634 NODE *r;
635 NODE *tmp;
636 NODE *sym_array;
637 NODE **aptr;
638 long i, j, max;
639 NODE *user, *extension, *untyped, *scalar, *array, *built_in;
640 NODE **list;
641 NODE *tables[4];
642
643 if (PROCINFO_node == NULL)
644 return;
645
646 tables[0] = func_table;
647 tables[1] = symbol_table;
648 tables[2] = global_table;
649 tables[3] = NULL;
650
651 tmp = make_string("identifiers", 11);
652 aptr = assoc_lookup(PROCINFO_node, tmp);
653
654 getnode(sym_array);
655 memset(sym_array, '\0', sizeof(NODE)); /* PPC Mac OS X wants this */
656 null_array(sym_array);
657
658 unref(tmp);
659 unref(*aptr);
660 *aptr = sym_array;
661
662 sym_array->parent_array = PROCINFO_node;
663 sym_array->vname = estrdup("identifiers", 11);
664
665 user = make_string("user", 4);
666 extension = make_string("extension", 9);
667 scalar = make_string("scalar", 6);
668 untyped = make_string("untyped", 7);
669 array = make_string("array", 5);
670 built_in = make_string("builtin", 7);
671
672 for (i = 0; tables[i] != NULL; i++) {
673 list = assoc_list(tables[i], "@unsorted", ASORTI);
674 max = tables[i]->table_size * 2;
675 if (max == 0)
676 continue;
677 for (j = 0; j < max; j += 2) {
678 r = list[j+1];
679 if ( r->type == Node_ext_func
680 || r->type == Node_func
681 || r->type == Node_builtin_func
682 || r->type == Node_var
683 || r->type == Node_var_array
684 || r->type == Node_var_new) {
685 if (strncmp(r->vname, "awk::", 5) == 0)
686 tmp = make_string(r->vname + 5, strlen(r->vname) - 5);
687 else
688 tmp = make_string(r->vname, strlen(r->vname));
689 aptr = assoc_lookup(sym_array, tmp);
690 unref(tmp);
691 unref(*aptr);
692 switch (r->type) {
693 case Node_ext_func:
694 *aptr = dupnode(extension);
695 break;
696 case Node_func:
697 *aptr = dupnode(user);
698 break;
699 case Node_builtin_func:
700 *aptr = dupnode(built_in);
701 break;
702 case Node_var:
703 *aptr = dupnode(scalar);
704 break;
705 case Node_var_array:
706 *aptr = dupnode(array);
707 break;
708 case Node_var_new:
709 *aptr = dupnode(untyped);
710 break;
711 default:
712 cant_happen("unexpected node type %s", nodetype2str(r->type));
713 break;
714 }
715 }
716 }
717 efree(list);
718 }
719
720 unref(user);
721 unref(extension);
722 unref(scalar);
723 unref(untyped);
724 unref(array);
725 unref(built_in);
726 }
727
728 /* check_param_names --- make sure no parameter is the name of a function */
729
730 bool
731 check_param_names(void)
732 {
733 int i, j;
734 NODE **list;
735 NODE *f;
736 long max;
737 bool result = true;
738 NODE n;
739
740 if (assoc_empty(func_table))
741 return result;
742
743 max = func_table->table_size * 2;
744
745 memset(& n, 0, sizeof n);
746 n.type = Node_val;
747 n.flags = STRING|STRCUR;
748 n.stfmt = STFMT_UNUSED;
749 #ifdef HAVE_MPFR
750 n.strndmode = MPFR_round_mode;
751 #endif
752
753 /*
754 * assoc_list() returns an array with two elements per awk array
755 * element. Elements i and i+1 in the C array represent the key
756 * and value of element j in the awk array. Thus the loops use += 2
757 * to go through the awk array.
758 *
759 * In this case, the name is in list[i], and the function is
760 * in list[i+1]. Just what we need.
761 */
762
763 list = assoc_list(func_table, "@unsorted", ASORTI);
764
765 for (i = 0; i < max; i += 2) {
766 f = list[i+1];
767 if (f->type == Node_builtin_func || f->param_cnt == 0)
768 continue;
769
770 /* loop over each param in function i */
771 for (j = 0; j < f->param_cnt; j++) {
772 /* compare to function names */
773
774 /* use a fake node to avoid malloc/free of make_string */
775 n.stptr = f->fparms[j].param;
776 n.stlen = strlen(f->fparms[j].param);
777
778 if (in_array(func_table, & n)) {
779 error(
780 _("function `%s': cannot use function `%s' as a parameter name"),
781 list[i]->stptr,
782 f->fparms[j].param);
783 result = false;
784 }
785 }
786 }
787
788 efree(list);
789 return result;
790 }
791
792 static INSTRUCTION_POOL *pools;
793
794 /*
795 * For best performance, the INSTR_CHUNK value should be divisible by all
796 * possible sizes, i.e. 1 through MAX_INSTRUCTION_ALLOC. Otherwise, there
797 * will be wasted space at the end of the block.
798 */
799 #define INSTR_CHUNK (2*3*21)
800
801 struct instruction_block {
802 struct instruction_block *next;
803 INSTRUCTION i[INSTR_CHUNK];
804 };
805
806 /* bcfree --- deallocate instruction */
807
808 void
809 bcfree(INSTRUCTION *cp)
810 {
811 assert(cp->pool_size >= 1 && cp->pool_size <= MAX_INSTRUCTION_ALLOC);
812
813 cp->opcode = Op_illegal;
814 cp->nexti = pools->pool[cp->pool_size - 1].free_list;
815 pools->pool[cp->pool_size - 1].free_list = cp;
816 }
817
818 /* bcalloc --- allocate a new instruction */
819
820 INSTRUCTION *
821 bcalloc(OPCODE op, int size, int srcline)
822 {
823 INSTRUCTION *cp;
824 struct instruction_mem_pool *pool;
825
826 assert(size >= 1 && size <= MAX_INSTRUCTION_ALLOC);
827 pool = &pools->pool[size - 1];
828
829 if (pool->free_list != NULL) {
830 cp = pool->free_list;
831 pool->free_list = cp->nexti;
832 } else if (pool->free_space && pool->free_space + size <= & pool->block_list->i[INSTR_CHUNK]) {
833 cp = pool->free_space;
834 pool->free_space += size;
835 } else {
836 struct instruction_block *block;
837 emalloc(block, struct instruction_block *, sizeof(struct instruction_block), "bcalloc");
838 block->next = pool->block_list;
839 pool->block_list = block;
840 cp = &block->i[0];
841 pool->free_space = &block->i[size];
842 }
843
844 memset(cp, 0, size * sizeof(INSTRUCTION));
845 cp->pool_size = size;
846 cp->opcode = op;
847 cp->source_line = srcline;
848 return cp;
849 }
850
851 /* new_context --- create a new execution context. */
852
853 AWK_CONTEXT *
854 new_context()
855 {
856 AWK_CONTEXT *ctxt;
857
858 ezalloc(ctxt, AWK_CONTEXT *, sizeof(AWK_CONTEXT), "new_context");
859 ctxt->srcfiles.next = ctxt->srcfiles.prev = & ctxt->srcfiles;
860 ctxt->rule_list.opcode = Op_list;
861 ctxt->rule_list.lasti = & ctxt->rule_list;
862 return ctxt;
863 }
864
865 /* set_context --- change current execution context. */
866
867 static void
868 set_context(AWK_CONTEXT *ctxt)
869 {
870 pools = & ctxt->pools;
871 symbol_list = & ctxt->symbols;
872 srcfiles = & ctxt->srcfiles;
873 rule_list = & ctxt->rule_list;
874 install_func = ctxt->install_func;
875 curr_ctxt = ctxt;
876 }
877
878 /*
879 * push_context:
880 *
881 * Switch to the given context after saving the current one. The set
882 * of active execution contexts forms a stack; the global or main context
883 * is at the bottom of the stack.
884 */
885
886 void
887 push_context(AWK_CONTEXT *ctxt)
888 {
889 ctxt->prev = curr_ctxt;
890 /* save current source and sourceline */
891 if (curr_ctxt != NULL) {
892 curr_ctxt->sourceline = sourceline;
893 curr_ctxt->source = source;
894 }
895 sourceline = 0;
896 source = NULL;
897 set_context(ctxt);
898 ctxt_level++;
899 }
900
901 /* pop_context --- switch to previous execution context. */
902
903 void
904 pop_context()
905 {
906 AWK_CONTEXT *ctxt;
907
908 assert(curr_ctxt != NULL);
909 if (curr_ctxt->prev == NULL)
910 fatal(_("cannot pop main context"));
911 ctxt = curr_ctxt->prev;
912 /* restore source and sourceline */
913 sourceline = ctxt->sourceline;
914 source = ctxt->source;
915 set_context(ctxt);
916 ctxt_level--;
917 }
918
919 /* in_main_context --- are we in the main context ? */
920
921 int
922 in_main_context()
923 {
924 assert(ctxt_level > 0);
925 return (ctxt_level == 1);
926 }
927
928 /* free_context --- free context structure and related data. */
929
930 void
931 free_context(AWK_CONTEXT *ctxt, bool keep_globals)
932 {
933 SRCFILE *s, *sn;
934
935 if (ctxt == NULL)
936 return;
937
938 assert(curr_ctxt != ctxt);
939
940 /* free all code including function codes */
941
942 free_bcpool(& ctxt->pools);
943
944 /* free symbols */
945
946 release_symbols(& ctxt->symbols, keep_globals);
947
948 /* free srcfiles */
949
950 for (s = & ctxt->srcfiles; s != & ctxt->srcfiles; s = sn) {
951 sn = s->next;
952 if (s->stype != SRC_CMDLINE && s->stype != SRC_STDIN)
953 efree(s->fullpath);
954 efree(s->src);
955 efree(s);
956 }
957
958 efree(ctxt);
959 }
960
961 /* free_bc_internal --- free internal memory of an instruction. */
962
963 static void
964 free_bc_internal(INSTRUCTION *cp)
965 {
966 NODE *m;
967
968 switch(cp->opcode) {
969 case Op_func_call:
970 if (cp->func_name != NULL)
971 efree(cp->func_name);
972 break;
973 case Op_push_re:
974 case Op_match_rec:
975 case Op_match:
976 case Op_nomatch:
977 m = cp->memory;
978 if (m->re_reg[0] != NULL)
979 refree(m->re_reg[0]);
980 if (m->re_reg[1] != NULL)
981 refree(m->re_reg[1]);
982 if (m->re_exp != NULL)
983 unref(m->re_exp);
984 if (m->re_text != NULL)
985 unref(m->re_text);
986 freenode(m);
987 break;
988 case Op_token:
989 /* token lost during error recovery in yyparse */
990 if (cp->lextok != NULL)
991 efree(cp->lextok);
992 break;
993 case Op_push_i:
994 m = cp->memory;
995 unref(m);
996 break;
997 case Op_store_var:
998 m = cp->initval;
999 if (m != NULL)
1000 unref(m);
1001 break;
1002 case Op_illegal:
1003 cant_happen("unexpected opcode %s", opcode2str(cp->opcode));
1004 default:
1005 break;
1006 }
1007 }
1008
1009 /* free_bc_mempool --- free a single pool */
1010
1011 static void
1012 free_bc_mempool(struct instruction_mem_pool *pool, int size)
1013 {
1014 bool first = true;
1015 struct instruction_block *block, *next;
1016
1017 for (block = pool->block_list; block; block = next) {
1018 INSTRUCTION *cp, *end;
1019
1020 end = (first ? pool->free_space : & block->i[INSTR_CHUNK]);
1021 for (cp = & block->i[0]; cp + size <= end; cp += size) {
1022 if (cp->opcode != Op_illegal)
1023 free_bc_internal(cp);
1024 }
1025 next = block->next;
1026 efree(block);
1027 first = false;
1028 }
1029 }
1030
1031
1032 /* free_bcpool --- free list of instruction memory pools */
1033
1034 static void
1035 free_bcpool(INSTRUCTION_POOL *pl)
1036 {
1037 int i;
1038
1039 for (i = 0; i < MAX_INSTRUCTION_ALLOC; i++)
1040 free_bc_mempool(& pl->pool[i], i + 1);
1041 }
1042
1043 /* is_all_upper --- return true if name is all uppercase letters */
1044
1045 /*
1046 * DON'T use isupper(), it's locale aware!
1047 */
1048
1049 bool
1050 is_all_upper(const char *name)
1051 {
1052 for (; *name != '\0'; name++) {
1053 switch (*name) {
1054 case 'A': case 'B': case 'C': case 'D': case 'E':
1055 case 'F': case 'G': case 'H': case 'I': case 'J':
1056 case 'K': case 'L': case 'M': case 'N': case 'O':
1057 case 'P': case 'Q': case 'R': case 'S': case 'T':
1058 case 'U': case 'V': case 'W': case 'X': case 'Y':
1059 case 'Z':
1060 break;
1061 default:
1062 return false;
1063 }
1064 }
1065
1066 return true;
1067 }
1068
1069 /* get_name_from_awk_ns --- get the name after awk:: or the full name */
1070
1071 static NODE *
1072 get_name_from_awk_ns(const char *name)
1073 {
1074 NODE *tmp;
1075
1076 if (strncmp(name, "awk::", 5) == 0)
1077 tmp = make_string(name + 5, strlen(name) - 5);
1078 else
1079 tmp = make_string(name, strlen(name));
1080
1081 return tmp;
1082 }