"Fossies" - the Fresh Open Source Software Archive

Member "gawk-5.1.0/symbol.c" (20 Mar 2020, 20792 Bytes) of package /linux/misc/gawk-5.1.0.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "symbol.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 5.0.1_vs_5.1.0.

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