Blame symbol.c

Packit Service f629e6
/*
Packit Service f629e6
 * symbol.c - routines for symbol table management and code allocation
Packit Service f629e6
 */
Packit Service f629e6
Packit Service f629e6
/*
Packit Service f629e6
 * Copyright (C) 1986, 1988, 1989, 1991-2015, 2017, 2018,
Packit Service f629e6
 * the Free Software Foundation, Inc.
Packit Service f629e6
 *
Packit Service f629e6
 * This file is part of GAWK, the GNU implementation of the
Packit Service f629e6
 * AWK Programming Language.
Packit Service f629e6
 *
Packit Service f629e6
 * GAWK is free software; you can redistribute it and/or modify
Packit Service f629e6
 * it under the terms of the GNU General Public License as published by
Packit Service f629e6
 * the Free Software Foundation; either version 3 of the License, or
Packit Service f629e6
 * (at your option) any later version.
Packit Service f629e6
 *
Packit Service f629e6
 * GAWK is distributed in the hope that it will be useful,
Packit Service f629e6
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service f629e6
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service f629e6
 * GNU General Public License for more details.
Packit Service f629e6
 *
Packit Service f629e6
 * You should have received a copy of the GNU General Public License
Packit Service f629e6
 * along with this program; if not, write to the Free Software
Packit Service f629e6
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
Packit Service f629e6
 */
Packit Service f629e6
Packit Service f629e6
#include "awk.h"
Packit Service f629e6
Packit Service f629e6
extern SRCFILE *srcfiles;
Packit Service f629e6
extern INSTRUCTION *rule_list;
Packit Service f629e6
Packit Service f629e6
#define HASHSIZE	1021
Packit Service f629e6
Packit Service f629e6
static int func_count;	/* total number of functions */
Packit Service f629e6
static int var_count;	/* total number of global variables and functions */
Packit Service f629e6
Packit Service f629e6
static NODE *symbol_list;
Packit Service f629e6
static void (*install_func)(NODE *) = NULL;
Packit Service f629e6
static NODE *make_symbol(const char *name, NODETYPE type);
Packit Service f629e6
static NODE *install(const char *name, NODE *parm, NODETYPE type);
Packit Service f629e6
static void free_bcpool(INSTRUCTION_POOL *pl);
Packit Service f629e6
Packit Service f629e6
static AWK_CONTEXT *curr_ctxt = NULL;
Packit Service f629e6
static int ctxt_level;
Packit Service f629e6
Packit Service f629e6
static NODE *global_table, *param_table;
Packit Service f629e6
NODE *symbol_table, *func_table;
Packit Service f629e6
Packit Service f629e6
/* Use a flag to avoid a strcmp() call inside install() */
Packit Service f629e6
static bool installing_specials = false;
Packit Service f629e6
Packit Service f629e6
/* init_symbol_table --- make sure the symbol tables are initialized */
Packit Service f629e6
Packit Service f629e6
void
Packit Service f629e6
init_symbol_table()
Packit Service f629e6
{
Packit Service f629e6
	getnode(global_table);
Packit Service f629e6
	memset(global_table, '\0', sizeof(NODE));
Packit Service f629e6
	null_array(global_table);
Packit Service f629e6
Packit Service f629e6
	getnode(param_table);
Packit Service f629e6
	memset(param_table, '\0', sizeof(NODE));
Packit Service f629e6
	null_array(param_table);
Packit Service f629e6
Packit Service f629e6
	installing_specials = true;
Packit Service f629e6
	func_table = install_symbol(estrdup("FUNCTAB", 7), Node_var_array);
Packit Service f629e6
Packit Service f629e6
	symbol_table = install_symbol(estrdup("SYMTAB", 6), Node_var_array);
Packit Service f629e6
	installing_specials = false;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/*
Packit Service f629e6
 * install_symbol:
Packit Service f629e6
 * Install a global name in the symbol table, even if it is already there.
Packit Service f629e6
 * Caller must check against redefinition if that is desired.
Packit Service f629e6
 */
Packit Service f629e6
Packit Service f629e6
NODE *
Packit Service f629e6
install_symbol(const char *name, NODETYPE type)
Packit Service f629e6
{
Packit Service f629e6
	return install(name, NULL, type);
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
Packit Service f629e6
/*
Packit Service f629e6
 * lookup --- find the most recent global or param node for name
Packit Service f629e6
 *	installed by install_symbol
Packit Service f629e6
 */
Packit Service f629e6
Packit Service f629e6
NODE *
Packit Service f629e6
lookup(const char *name)
Packit Service f629e6
{
Packit Service f629e6
	NODE *n;
Packit Service f629e6
	NODE *tmp;
Packit Service f629e6
	NODE *tables[5];	/* manual init below, for z/OS */
Packit Service f629e6
	int i;
Packit Service f629e6
Packit Service f629e6
	/* ``It's turtles, all the way down.'' */
Packit Service f629e6
	tables[0] = param_table;	/* parameters shadow everything */
Packit Service f629e6
	tables[1] = global_table;	/* SYMTAB and FUNCTAB found first, can't be redefined */
Packit Service f629e6
	tables[2] = func_table;		/* then functions */
Packit Service f629e6
	tables[3] = symbol_table;	/* then globals */
Packit Service f629e6
	tables[4] = NULL;
Packit Service f629e6
Packit Service f629e6
	tmp = make_string(name, strlen(name));
Packit Service f629e6
Packit Service f629e6
	n = NULL;
Packit Service f629e6
	for (i = 0; tables[i] != NULL; i++) {
Packit Service f629e6
		if (tables[i]->table_size == 0)
Packit Service f629e6
			continue;
Packit Service f629e6
Packit Service f629e6
		if ((do_posix || do_traditional) && tables[i] == global_table)
Packit Service f629e6
			continue;
Packit Service f629e6
Packit Service f629e6
		n = in_array(tables[i], tmp);
Packit Service f629e6
		if (n != NULL)
Packit Service f629e6
			break;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	unref(tmp);
Packit Service f629e6
	if (n == NULL || n->type == Node_val)	/* non-variable in SYMTAB */
Packit Service f629e6
		return NULL;
Packit Service f629e6
	return n;	/* new place */
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* make_params --- allocate function parameters for the symbol table */
Packit Service f629e6
Packit Service f629e6
NODE *
Packit Service f629e6
make_params(char **pnames, int pcount)
Packit Service f629e6
{
Packit Service f629e6
	NODE *p, *parms;
Packit Service f629e6
	int i;
Packit Service f629e6
Packit Service f629e6
	if (pcount <= 0 || pnames == NULL)
Packit Service f629e6
		return NULL;
Packit Service f629e6
Packit Service f629e6
	ezalloc(parms, NODE *, pcount * sizeof(NODE), "make_params");
Packit Service f629e6
Packit Service f629e6
	for (i = 0, p = parms; i < pcount; i++, p++) {
Packit Service f629e6
		p->type = Node_param_list;
Packit Service f629e6
		p->param = pnames[i];	/* shadows pname and vname */
Packit Service f629e6
		p->param_cnt = i;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	return parms;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* install_params --- install function parameters into the symbol table */
Packit Service f629e6
Packit Service f629e6
void
Packit Service f629e6
install_params(NODE *func)
Packit Service f629e6
{
Packit Service f629e6
	int i, pcount;
Packit Service f629e6
	NODE *parms;
Packit Service f629e6
Packit Service f629e6
	if (func == NULL)
Packit Service f629e6
		return;
Packit Service f629e6
Packit Service f629e6
	assert(func->type == Node_func);
Packit Service f629e6
Packit Service f629e6
	if (   (pcount = func->param_cnt) <= 0
Packit Service f629e6
	    || (parms = func->fparms) == NULL)
Packit Service f629e6
		return;
Packit Service f629e6
Packit Service f629e6
	for (i = 0; i < pcount; i++)
Packit Service f629e6
		(void) install(parms[i].param, parms + i, Node_param_list);
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
Packit Service f629e6
/*
Packit Service f629e6
 * remove_params --- remove function parameters out of the symbol table.
Packit Service f629e6
 */
Packit Service f629e6
Packit Service f629e6
void
Packit Service f629e6
remove_params(NODE *func)
Packit Service f629e6
{
Packit Service f629e6
	NODE *parms, *p;
Packit Service f629e6
	int i, pcount;
Packit Service f629e6
Packit Service f629e6
	if (func == NULL)
Packit Service f629e6
		return;
Packit Service f629e6
Packit Service f629e6
	assert(func->type == Node_func);
Packit Service f629e6
Packit Service f629e6
	if (   (pcount = func->param_cnt) <= 0
Packit Service f629e6
	    || (parms = func->fparms) == NULL)
Packit Service f629e6
		return;
Packit Service f629e6
Packit Service f629e6
	for (i = pcount - 1; i >= 0; i--) {
Packit Service f629e6
		NODE *tmp;
Packit Service f629e6
		NODE *tmp2;
Packit Service f629e6
Packit Service f629e6
		p = parms + i;
Packit Service f629e6
		assert(p->type == Node_param_list);
Packit Service f629e6
		tmp = make_string(p->vname, strlen(p->vname));
Packit Service f629e6
		tmp2 = in_array(param_table, tmp);
Packit Service f629e6
		if (tmp2 != NULL && tmp2->dup_ent != NULL)
Packit Service f629e6
			tmp2->dup_ent = tmp2->dup_ent->dup_ent;
Packit Service f629e6
		else
Packit Service f629e6
			(void) assoc_remove(param_table, tmp);
Packit Service f629e6
Packit Service f629e6
		unref(tmp);
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	assoc_clear(param_table);	/* shazzam! */
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
Packit Service f629e6
/* remove_symbol --- remove a symbol from the symbol table */
Packit Service f629e6
Packit Service f629e6
NODE *
Packit Service f629e6
remove_symbol(NODE *r)
Packit Service f629e6
{
Packit Service f629e6
	NODE *n = in_array(symbol_table, r);
Packit Service f629e6
Packit Service f629e6
	if (n == NULL)
Packit Service f629e6
		return n;
Packit Service f629e6
Packit Service f629e6
	n = dupnode(n);
Packit Service f629e6
Packit Service f629e6
	(void) assoc_remove(symbol_table, r);
Packit Service f629e6
Packit Service f629e6
	return n;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
Packit Service f629e6
/*
Packit Service f629e6
 * destroy_symbol --- remove a symbol from symbol table
Packit Service f629e6
 *	and free all associated memory.
Packit Service f629e6
 */
Packit Service f629e6
Packit Service f629e6
void
Packit Service f629e6
destroy_symbol(NODE *r)
Packit Service f629e6
{
Packit Service f629e6
	r = remove_symbol(r);
Packit Service f629e6
	if (r == NULL)
Packit Service f629e6
		return;
Packit Service f629e6
Packit Service f629e6
	switch (r->type) {
Packit Service f629e6
	case Node_func:
Packit Service f629e6
		if (r->param_cnt > 0) {
Packit Service f629e6
			NODE *n;
Packit Service f629e6
			int i;
Packit Service f629e6
			int pcount = r->param_cnt;
Packit Service f629e6
Packit Service f629e6
			/* function parameters of type Node_param_list */
Packit Service f629e6
			for (i = 0; i < pcount; i++) {
Packit Service f629e6
				n = r->fparms + i;
Packit Service f629e6
				efree(n->param);
Packit Service f629e6
			}
Packit Service f629e6
			efree(r->fparms);
Packit Service f629e6
		}
Packit Service f629e6
		break;
Packit Service f629e6
Packit Service f629e6
	case Node_ext_func:
Packit Service f629e6
		bcfree(r->code_ptr);
Packit Service f629e6
		break;
Packit Service f629e6
Packit Service f629e6
	case Node_var_array:
Packit Service f629e6
		assoc_clear(r);
Packit Service f629e6
		break;
Packit Service f629e6
Packit Service f629e6
	case Node_var:
Packit Service f629e6
		unref(r->var_value);
Packit Service f629e6
		break;
Packit Service f629e6
Packit Service f629e6
	default:
Packit Service f629e6
		/* Node_param_list -- YYABORT */
Packit Service f629e6
		break;	/* use break so that storage is freed */
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	efree(r->vname);
Packit Service f629e6
	freenode(r);
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
Packit Service f629e6
/* make_symbol --- allocates a global symbol for the symbol table. */
Packit Service f629e6
Packit Service f629e6
static NODE *
Packit Service f629e6
make_symbol(const char *name, NODETYPE type)
Packit Service f629e6
{
Packit Service f629e6
	NODE *r;
Packit Service f629e6
Packit Service f629e6
	getnode(r);
Packit Service f629e6
	memset(r, '\0', sizeof(NODE));
Packit Service f629e6
	if (type == Node_var_array)
Packit Service f629e6
		null_array(r);
Packit Service f629e6
	else if (type == Node_var)
Packit Service f629e6
		r->var_value = dupnode(Nnull_string);
Packit Service f629e6
	r->vname = (char *) name;
Packit Service f629e6
	r->type = type;
Packit Service f629e6
Packit Service f629e6
	return r;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* install --- install a global name or function parameter in the symbol table */
Packit Service f629e6
Packit Service f629e6
static NODE *
Packit Service f629e6
install(const char *name, NODE *parm, NODETYPE type)
Packit Service f629e6
{
Packit Service f629e6
	NODE *r;
Packit Service f629e6
	NODE **aptr;
Packit Service f629e6
	NODE *table;
Packit Service f629e6
	NODE *n_name;
Packit Service f629e6
	NODE *prev;
Packit Service f629e6
Packit Service f629e6
	n_name = make_string(name, strlen(name));
Packit Service f629e6
	table = symbol_table;
Packit Service f629e6
Packit Service f629e6
	if (type == Node_param_list) {
Packit Service f629e6
		table = param_table;
Packit Service f629e6
	} else if (   type == Node_func
Packit Service f629e6
		   || type == Node_ext_func
Packit Service f629e6
		   || type == Node_builtin_func) {
Packit Service f629e6
		table = func_table;
Packit Service f629e6
	} else if (installing_specials) {
Packit Service f629e6
		table = global_table;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	if (parm != NULL)
Packit Service f629e6
		r = parm;
Packit Service f629e6
	else {
Packit Service f629e6
		/* global symbol */
Packit Service f629e6
		r = make_symbol(name, type);
Packit Service f629e6
		if (type == Node_func)
Packit Service f629e6
			func_count++;
Packit Service f629e6
		if (type != Node_ext_func && type != Node_builtin_func && table != global_table)
Packit Service f629e6
			var_count++;	/* total, includes Node_func */
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	if (type == Node_param_list) {
Packit Service f629e6
		prev = in_array(table, n_name);
Packit Service f629e6
		if (prev == NULL)
Packit Service f629e6
			goto simple;
Packit Service f629e6
		r->dup_ent = prev->dup_ent;
Packit Service f629e6
		prev->dup_ent = r;
Packit Service f629e6
	} else {
Packit Service f629e6
simple:
Packit Service f629e6
		/* the simple case */
Packit Service f629e6
		aptr = assoc_lookup(table, n_name);
Packit Service f629e6
		unref(*aptr);
Packit Service f629e6
		*aptr = r;
Packit Service f629e6
	}
Packit Service f629e6
	unref(n_name);
Packit Service f629e6
Packit Service f629e6
	if (install_func)
Packit Service f629e6
		(*install_func)(r);
Packit Service f629e6
Packit Service f629e6
	return r;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* comp_symbol --- compare two (variable or function) names */
Packit Service f629e6
Packit Service f629e6
static int
Packit Service f629e6
comp_symbol(const void *v1, const void *v2)
Packit Service f629e6
{
Packit Service f629e6
	const NODE *const *npp1, *const *npp2;
Packit Service f629e6
	const NODE *n1, *n2;
Packit Service f629e6
Packit Service f629e6
	npp1 = (const NODE *const *) v1;
Packit Service f629e6
	npp2 = (const NODE *const *) v2;
Packit Service f629e6
	n1 = *npp1;
Packit Service f629e6
	n2 = *npp2;
Packit Service f629e6
Packit Service f629e6
	return strcmp(n1->vname, n2->vname);
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
Packit Service f629e6
typedef enum { FUNCTION = 1, VARIABLE } SYMBOL_TYPE;
Packit Service f629e6
Packit Service f629e6
/* get_symbols --- return a list of optionally sorted symbols */
Packit Service f629e6
Packit Service f629e6
static NODE **
Packit Service f629e6
get_symbols(SYMBOL_TYPE what, bool sort)
Packit Service f629e6
{
Packit Service f629e6
	int i;
Packit Service f629e6
	NODE **table;
Packit Service f629e6
	NODE **list;
Packit Service f629e6
	NODE *r;
Packit Service f629e6
	long count = 0;
Packit Service f629e6
	long max;
Packit Service f629e6
	NODE *the_table;
Packit Service f629e6
Packit Service f629e6
	/*
Packit Service f629e6
	 * assoc_list() returns an array with two elements per awk array
Packit Service f629e6
	 * element. Elements i and i+1 in the C array represent the key
Packit Service f629e6
	 * and value of element j in the awk array. Thus the loops use += 2
Packit Service f629e6
	 * to go through the awk array.
Packit Service f629e6
	 */
Packit Service f629e6
Packit Service f629e6
	if (what == FUNCTION) {
Packit Service f629e6
		the_table = func_table;
Packit Service f629e6
		max = the_table->table_size * 2;
Packit Service f629e6
Packit Service f629e6
		list = assoc_list(the_table, "@unsorted", ASORTI);
Packit Service f629e6
		emalloc(table, NODE **, (func_count + 1) * sizeof(NODE *), "get_symbols");
Packit Service f629e6
Packit Service f629e6
		for (i = count = 0; i < max; i += 2) {
Packit Service f629e6
			r = list[i+1];
Packit Service f629e6
			if (r->type == Node_ext_func || r->type == Node_builtin_func)
Packit Service f629e6
				continue;
Packit Service f629e6
			assert(r->type == Node_func);
Packit Service f629e6
			table[count++] = r;
Packit Service f629e6
		}
Packit Service f629e6
	} else {	/* what == VARIABLE */
Packit Service f629e6
		update_global_values();
Packit Service f629e6
Packit Service f629e6
		the_table = symbol_table;
Packit Service f629e6
		max = the_table->table_size * 2;
Packit Service f629e6
Packit Service f629e6
		list = assoc_list(the_table, "@unsorted", ASORTI);
Packit Service f629e6
		/* add three: one for FUNCTAB, one for SYMTAB, and one for a final NULL */
Packit Service f629e6
		emalloc(table, NODE **, (var_count + 1 + 1 + 1) * sizeof(NODE *), "get_symbols");
Packit Service f629e6
Packit Service f629e6
		for (i = count = 0; i < max; i += 2) {
Packit Service f629e6
			r = list[i+1];
Packit Service f629e6
			if (r->type == Node_val)	/* non-variable in SYMTAB */
Packit Service f629e6
				continue;
Packit Service f629e6
			table[count++] = r;
Packit Service f629e6
		}
Packit Service f629e6
Packit Service f629e6
		table[count++] = func_table;
Packit Service f629e6
		table[count++] = symbol_table;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	efree(list);
Packit Service f629e6
Packit Service f629e6
	if (sort && count > 1)
Packit Service f629e6
		qsort(table, count, sizeof(NODE *), comp_symbol);	/* Shazzam! */
Packit Service f629e6
	table[count] = NULL; /* null terminate the list */
Packit Service f629e6
	return table;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
Packit Service f629e6
/* variable_list --- list of global variables */
Packit Service f629e6
Packit Service f629e6
NODE **
Packit Service f629e6
variable_list()
Packit Service f629e6
{
Packit Service f629e6
	return get_symbols(VARIABLE, true);
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* function_list --- list of functions */
Packit Service f629e6
Packit Service f629e6
NODE **
Packit Service f629e6
function_list(bool sort)
Packit Service f629e6
{
Packit Service f629e6
	return get_symbols(FUNCTION, sort);
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* print_vars --- print names and values of global variables */
Packit Service f629e6
Packit Service f629e6
void
Packit Service f629e6
print_vars(NODE **table, int (*print_func)(FILE *, const char *, ...), FILE *fp)
Packit Service f629e6
{
Packit Service f629e6
	int i;
Packit Service f629e6
	NODE *r;
Packit Service f629e6
Packit Service f629e6
	assert(table != NULL);
Packit Service f629e6
Packit Service f629e6
	for (i = 0; (r = table[i]) != NULL; i++) {
Packit Service f629e6
		if (r->type == Node_func || r->type == Node_ext_func)
Packit Service f629e6
			continue;
Packit Service f629e6
		print_func(fp, "%s: ", r->vname);
Packit Service f629e6
		if (r->type == Node_var_array)
Packit Service f629e6
			print_func(fp, "array, %ld elements\n", assoc_length(r));
Packit Service f629e6
		else if (r->type == Node_var_new)
Packit Service f629e6
			print_func(fp, "untyped variable\n");
Packit Service f629e6
		else if (r->type == Node_var)
Packit Service f629e6
			valinfo(r->var_value, print_func, fp);
Packit Service f629e6
	}
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
Packit Service f629e6
/* foreach_func --- execute given function for each awk function in table. */
Packit Service f629e6
Packit Service f629e6
int
Packit Service f629e6
foreach_func(NODE **table, int (*pfunc)(INSTRUCTION *, void *), void *data)
Packit Service f629e6
{
Packit Service f629e6
	int i;
Packit Service f629e6
	NODE *r;
Packit Service f629e6
	int ret = 0;
Packit Service f629e6
Packit Service f629e6
	assert(table != NULL);
Packit Service f629e6
Packit Service f629e6
	for (i = 0; (r = table[i]) != NULL; i++) {
Packit Service f629e6
		if ((ret = pfunc(r->code_ptr, data)) != 0)
Packit Service f629e6
			break;
Packit Service f629e6
	}
Packit Service f629e6
	return ret;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* release_all_vars --- free all variable memory */
Packit Service f629e6
Packit Service f629e6
void
Packit Service f629e6
release_all_vars()
Packit Service f629e6
{
Packit Service f629e6
	assoc_clear(symbol_table);
Packit Service f629e6
	assoc_clear(func_table);
Packit Service f629e6
	assoc_clear(global_table);
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
Packit Service f629e6
/* append_symbol --- append symbol to the list of symbols
Packit Service f629e6
 *	installed in the symbol table.
Packit Service f629e6
 */
Packit Service f629e6
Packit Service f629e6
void
Packit Service f629e6
append_symbol(NODE *r)
Packit Service f629e6
{
Packit Service f629e6
	NODE *p;
Packit Service f629e6
Packit Service f629e6
	getnode(p);
Packit Service f629e6
	p->lnode = r;
Packit Service f629e6
	p->rnode = symbol_list->rnode;
Packit Service f629e6
	symbol_list->rnode = p;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* release_symbols --- free symbol list and optionally remove symbol from symbol table */
Packit Service f629e6
Packit Service f629e6
void
Packit Service f629e6
release_symbols(NODE *symlist, int keep_globals)
Packit Service f629e6
{
Packit Service f629e6
	NODE *p, *next;
Packit Service f629e6
Packit Service f629e6
	for (p = symlist->rnode; p != NULL; p = next) {
Packit Service f629e6
		if (! keep_globals) {
Packit Service f629e6
			/*
Packit Service f629e6
			 * destroys globals, function, and params
Packit Service f629e6
			 * if still in symbol table
Packit Service f629e6
			 */
Packit Service f629e6
			destroy_symbol(p->lnode);
Packit Service f629e6
		}
Packit Service f629e6
		next = p->rnode;
Packit Service f629e6
		freenode(p);
Packit Service f629e6
	}
Packit Service f629e6
	symlist->rnode = NULL;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* load_symbols --- fill in symbols' information */
Packit Service f629e6
Packit Service f629e6
void
Packit Service f629e6
load_symbols()
Packit Service f629e6
{
Packit Service f629e6
	NODE *r;
Packit Service f629e6
	NODE *tmp;
Packit Service f629e6
	NODE *sym_array;
Packit Service f629e6
	NODE **aptr;
Packit Service f629e6
	long i, j, max;
Packit Service f629e6
	NODE *user, *extension, *untyped, *scalar, *array, *built_in;
Packit Service f629e6
	NODE **list;
Packit Service f629e6
	NODE *tables[4];
Packit Service f629e6
Packit Service f629e6
	if (PROCINFO_node == NULL)
Packit Service f629e6
		return;
Packit Service f629e6
Packit Service f629e6
	tables[0] = func_table;
Packit Service f629e6
	tables[1] = symbol_table;
Packit Service f629e6
	tables[2] = global_table;
Packit Service f629e6
	tables[3] = NULL;
Packit Service f629e6
Packit Service f629e6
	tmp = make_string("identifiers", 11);
Packit Service f629e6
	aptr = assoc_lookup(PROCINFO_node, tmp);
Packit Service f629e6
Packit Service f629e6
	getnode(sym_array);
Packit Service f629e6
	memset(sym_array, '\0', sizeof(NODE));	/* PPC Mac OS X wants this */
Packit Service f629e6
	null_array(sym_array);
Packit Service f629e6
Packit Service f629e6
	unref(tmp);
Packit Service f629e6
	unref(*aptr);
Packit Service f629e6
	*aptr = sym_array;
Packit Service f629e6
Packit Service f629e6
	sym_array->parent_array = PROCINFO_node;
Packit Service f629e6
	sym_array->vname = estrdup("identifiers", 11);
Packit Service f629e6
Packit Service f629e6
	user = make_string("user", 4);
Packit Service f629e6
	extension = make_string("extension", 9);
Packit Service f629e6
	scalar = make_string("scalar", 6);
Packit Service f629e6
	untyped = make_string("untyped", 7);
Packit Service f629e6
	array = make_string("array", 5);
Packit Service f629e6
	built_in = make_string("builtin", 7);
Packit Service f629e6
Packit Service f629e6
	for (i = 0; tables[i] != NULL; i++) {
Packit Service f629e6
		list = assoc_list(tables[i], "@unsorted", ASORTI);
Packit Service f629e6
		max = tables[i]->table_size * 2;
Packit Service f629e6
		if (max == 0)
Packit Service f629e6
			continue;
Packit Service f629e6
		for (j = 0; j < max; j += 2) {
Packit Service f629e6
			r = list[j+1];
Packit Service f629e6
			if (   r->type == Node_ext_func
Packit Service f629e6
			    || r->type == Node_func
Packit Service f629e6
			    || r->type == Node_builtin_func
Packit Service f629e6
			    || r->type == Node_var
Packit Service f629e6
			    || r->type == Node_var_array
Packit Service f629e6
			    || r->type == Node_var_new) {
Packit Service f629e6
				tmp = make_string(r->vname, strlen(r->vname));
Packit Service f629e6
				aptr = assoc_lookup(sym_array, tmp);
Packit Service f629e6
				unref(tmp);
Packit Service f629e6
				unref(*aptr);
Packit Service f629e6
				switch (r->type) {
Packit Service f629e6
				case Node_ext_func:
Packit Service f629e6
					*aptr = dupnode(extension);
Packit Service f629e6
					break;
Packit Service f629e6
				case Node_func:
Packit Service f629e6
					*aptr = dupnode(user);
Packit Service f629e6
					break;
Packit Service f629e6
				case Node_builtin_func:
Packit Service f629e6
					*aptr = dupnode(built_in);
Packit Service f629e6
					break;
Packit Service f629e6
				case Node_var:
Packit Service f629e6
					*aptr = dupnode(scalar);
Packit Service f629e6
					break;
Packit Service f629e6
				case Node_var_array:
Packit Service f629e6
					*aptr = dupnode(array);
Packit Service f629e6
					break;
Packit Service f629e6
				case Node_var_new:
Packit Service f629e6
					*aptr = dupnode(untyped);
Packit Service f629e6
					break;
Packit Service f629e6
				default:
Packit Service f629e6
					cant_happen();
Packit Service f629e6
					break;
Packit Service f629e6
				}
Packit Service f629e6
			}
Packit Service f629e6
		}
Packit Service f629e6
		efree(list);
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	unref(user);
Packit Service f629e6
	unref(extension);
Packit Service f629e6
	unref(scalar);
Packit Service f629e6
	unref(untyped);
Packit Service f629e6
	unref(array);
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* check_param_names --- make sure no parameter is the name of a function */
Packit Service f629e6
Packit Service f629e6
bool
Packit Service f629e6
check_param_names(void)
Packit Service f629e6
{
Packit Service f629e6
	int i, j;
Packit Service f629e6
	NODE **list;
Packit Service f629e6
	NODE *f;
Packit Service f629e6
	long max;
Packit Service f629e6
	bool result = true;
Packit Service f629e6
	NODE n;
Packit Service f629e6
Packit Service f629e6
	if (func_table->table_size == 0)
Packit Service f629e6
		return result;
Packit Service f629e6
Packit Service f629e6
	max = func_table->table_size * 2;
Packit Service f629e6
Packit Service f629e6
	memset(& n, 0, sizeof n);
Packit Service f629e6
	n.type = Node_val;
Packit Service f629e6
	n.flags = STRING|STRCUR;
Packit Service f629e6
	n.stfmt = STFMT_UNUSED;
Packit Service f629e6
#ifdef HAVE_MPFR
Packit Service f629e6
	n.strndmode = MPFR_round_mode;
Packit Service f629e6
#endif
Packit Service f629e6
Packit Service f629e6
	/*
Packit Service f629e6
	 * assoc_list() returns an array with two elements per awk array
Packit Service f629e6
	 * element. Elements i and i+1 in the C array represent the key
Packit Service f629e6
	 * and value of element j in the awk array. Thus the loops use += 2
Packit Service f629e6
	 * to go through the awk array.
Packit Service f629e6
	 *
Packit Service f629e6
	 * In this case, the name is in list[i], and the function is
Packit Service f629e6
	 * in list[i+1]. Just what we need.
Packit Service f629e6
	 */
Packit Service f629e6
Packit Service f629e6
	list = assoc_list(func_table, "@unsorted", ASORTI);
Packit Service f629e6
Packit Service f629e6
	for (i = 0; i < max; i += 2) {
Packit Service f629e6
		f = list[i+1];
Packit Service f629e6
		if (f->type == Node_builtin_func || f->param_cnt == 0)
Packit Service f629e6
			continue;
Packit Service f629e6
Packit Service f629e6
		/* loop over each param in function i */
Packit Service f629e6
		for (j = 0; j < f->param_cnt; j++) {
Packit Service f629e6
			/* compare to function names */
Packit Service f629e6
Packit Service f629e6
			/* use a fake node to avoid malloc/free of make_string */
Packit Service f629e6
			n.stptr = f->fparms[j].param;
Packit Service f629e6
			n.stlen = strlen(f->fparms[j].param);
Packit Service f629e6
Packit Service f629e6
			if (in_array(func_table, & n)) {
Packit Service f629e6
				error(
Packit Service f629e6
			_("function `%s': can't use function `%s' as a parameter name"),
Packit Service f629e6
					list[i]->stptr,
Packit Service f629e6
					f->fparms[j].param);
Packit Service f629e6
				result = false;
Packit Service f629e6
			}
Packit Service f629e6
		}
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	efree(list);
Packit Service f629e6
	return result;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
static INSTRUCTION_POOL *pools;
Packit Service f629e6
Packit Service f629e6
/*
Packit Service f629e6
 * For best performance, the INSTR_CHUNK value should be divisible by all
Packit Service f629e6
 * possible sizes, i.e. 1 through MAX_INSTRUCTION_ALLOC. Otherwise, there
Packit Service f629e6
 * will be wasted space at the end of the block.
Packit Service f629e6
 */
Packit Service f629e6
#define INSTR_CHUNK (2*3*21)
Packit Service f629e6
Packit Service f629e6
struct instruction_block {
Packit Service f629e6
	struct instruction_block *next;
Packit Service f629e6
	INSTRUCTION i[INSTR_CHUNK];
Packit Service f629e6
};
Packit Service f629e6
Packit Service f629e6
/* bcfree --- deallocate instruction */
Packit Service f629e6
Packit Service f629e6
void
Packit Service f629e6
bcfree(INSTRUCTION *cp)
Packit Service f629e6
{
Packit Service f629e6
	assert(cp->pool_size >= 1 && cp->pool_size <= MAX_INSTRUCTION_ALLOC);
Packit Service f629e6
Packit Service f629e6
	cp->opcode = Op_illegal;
Packit Service f629e6
	cp->nexti = pools->pool[cp->pool_size - 1].free_list;
Packit Service f629e6
	pools->pool[cp->pool_size - 1].free_list = cp;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* bcalloc --- allocate a new instruction */
Packit Service f629e6
Packit Service f629e6
INSTRUCTION *
Packit Service f629e6
bcalloc(OPCODE op, int size, int srcline)
Packit Service f629e6
{
Packit Service f629e6
	INSTRUCTION *cp;
Packit Service f629e6
	struct instruction_mem_pool *pool;
Packit Service f629e6
Packit Service f629e6
	assert(size >= 1 && size <= MAX_INSTRUCTION_ALLOC);
Packit Service f629e6
	pool = &pools->pool[size - 1];
Packit Service f629e6
Packit Service f629e6
	if (pool->free_list != NULL) {
Packit Service f629e6
		cp = pool->free_list;
Packit Service f629e6
		pool->free_list = cp->nexti;
Packit Service f629e6
	} else if (pool->free_space && pool->free_space + size <= & pool->block_list->i[INSTR_CHUNK]) {
Packit Service f629e6
		cp = pool->free_space;
Packit Service f629e6
		pool->free_space += size;
Packit Service f629e6
	} else {
Packit Service f629e6
		struct instruction_block *block;
Packit Service f629e6
		emalloc(block, struct instruction_block *, sizeof(struct instruction_block), "bcalloc");
Packit Service f629e6
		block->next = pool->block_list;
Packit Service f629e6
		pool->block_list = block;
Packit Service f629e6
		cp = &block->i[0];
Packit Service f629e6
		pool->free_space = &block->i[size];
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	memset(cp, 0, size * sizeof(INSTRUCTION));
Packit Service f629e6
	cp->pool_size = size;
Packit Service f629e6
	cp->opcode = op;
Packit Service f629e6
	cp->source_line = srcline;
Packit Service f629e6
	return cp;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* new_context --- create a new execution context. */
Packit Service f629e6
Packit Service f629e6
AWK_CONTEXT *
Packit Service f629e6
new_context()
Packit Service f629e6
{
Packit Service f629e6
	AWK_CONTEXT *ctxt;
Packit Service f629e6
Packit Service f629e6
	ezalloc(ctxt, AWK_CONTEXT *, sizeof(AWK_CONTEXT), "new_context");
Packit Service f629e6
	ctxt->srcfiles.next = ctxt->srcfiles.prev = & ctxt->srcfiles;
Packit Service f629e6
	ctxt->rule_list.opcode = Op_list;
Packit Service f629e6
	ctxt->rule_list.lasti = & ctxt->rule_list;
Packit Service f629e6
	return ctxt;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* set_context --- change current execution context. */
Packit Service f629e6
Packit Service f629e6
static void
Packit Service f629e6
set_context(AWK_CONTEXT *ctxt)
Packit Service f629e6
{
Packit Service f629e6
	pools = & ctxt->pools;
Packit Service f629e6
	symbol_list = & ctxt->symbols;
Packit Service f629e6
	srcfiles = & ctxt->srcfiles;
Packit Service f629e6
	rule_list = & ctxt->rule_list;
Packit Service f629e6
	install_func = ctxt->install_func;
Packit Service f629e6
	curr_ctxt = ctxt;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/*
Packit Service f629e6
 * push_context:
Packit Service f629e6
 *
Packit Service f629e6
 * Switch to the given context after saving the current one. The set
Packit Service f629e6
 * of active execution contexts forms a stack; the global or main context
Packit Service f629e6
 * is at the bottom of the stack.
Packit Service f629e6
 */
Packit Service f629e6
Packit Service f629e6
void
Packit Service f629e6
push_context(AWK_CONTEXT *ctxt)
Packit Service f629e6
{
Packit Service f629e6
	ctxt->prev = curr_ctxt;
Packit Service f629e6
	/* save current source and sourceline */
Packit Service f629e6
	if (curr_ctxt != NULL) {
Packit Service f629e6
		curr_ctxt->sourceline = sourceline;
Packit Service f629e6
		curr_ctxt->source = source;
Packit Service f629e6
	}
Packit Service f629e6
	sourceline = 0;
Packit Service f629e6
	source = NULL;
Packit Service f629e6
	set_context(ctxt);
Packit Service f629e6
	ctxt_level++;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* pop_context --- switch to previous execution context. */
Packit Service f629e6
Packit Service f629e6
void
Packit Service f629e6
pop_context()
Packit Service f629e6
{
Packit Service f629e6
	AWK_CONTEXT *ctxt;
Packit Service f629e6
Packit Service f629e6
	assert(curr_ctxt != NULL);
Packit Service f629e6
	if (curr_ctxt->prev == NULL)
Packit Service f629e6
		fatal(_("can not pop main context"));
Packit Service f629e6
	ctxt = curr_ctxt->prev;
Packit Service f629e6
	/* restore source and sourceline */
Packit Service f629e6
	sourceline = ctxt->sourceline;
Packit Service f629e6
	source = ctxt->source;
Packit Service f629e6
	set_context(ctxt);
Packit Service f629e6
	ctxt_level--;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* in_main_context --- are we in the main context ? */
Packit Service f629e6
Packit Service f629e6
int
Packit Service f629e6
in_main_context()
Packit Service f629e6
{
Packit Service f629e6
	assert(ctxt_level > 0);
Packit Service f629e6
	return (ctxt_level == 1);
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* free_context --- free context structure and related data. */
Packit Service f629e6
Packit Service f629e6
void
Packit Service f629e6
free_context(AWK_CONTEXT *ctxt, bool keep_globals)
Packit Service f629e6
{
Packit Service f629e6
	SRCFILE *s, *sn;
Packit Service f629e6
Packit Service f629e6
	if (ctxt == NULL)
Packit Service f629e6
		return;
Packit Service f629e6
Packit Service f629e6
	assert(curr_ctxt != ctxt);
Packit Service f629e6
Packit Service f629e6
 	/* free all code including function codes */
Packit Service f629e6
Packit Service f629e6
	free_bcpool(& ctxt->pools);
Packit Service f629e6
Packit Service f629e6
	/* free symbols */
Packit Service f629e6
Packit Service f629e6
	release_symbols(& ctxt->symbols, keep_globals);
Packit Service f629e6
Packit Service f629e6
	/* free srcfiles */
Packit Service f629e6
Packit Service f629e6
	for (s = & ctxt->srcfiles; s != & ctxt->srcfiles; s = sn) {
Packit Service f629e6
		sn = s->next;
Packit Service f629e6
		if (s->stype != SRC_CMDLINE && s->stype != SRC_STDIN)
Packit Service f629e6
			efree(s->fullpath);
Packit Service f629e6
		efree(s->src);
Packit Service f629e6
		efree(s);
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	efree(ctxt);
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* free_bc_internal --- free internal memory of an instruction. */
Packit Service f629e6
Packit Service f629e6
static void
Packit Service f629e6
free_bc_internal(INSTRUCTION *cp)
Packit Service f629e6
{
Packit Service f629e6
	NODE *m;
Packit Service f629e6
Packit Service f629e6
	switch(cp->opcode) {
Packit Service f629e6
	case Op_func_call:
Packit Service f629e6
		if (cp->func_name != NULL)
Packit Service f629e6
			efree(cp->func_name);
Packit Service f629e6
		break;
Packit Service f629e6
	case Op_push_re:
Packit Service f629e6
	case Op_match_rec:
Packit Service f629e6
	case Op_match:
Packit Service f629e6
	case Op_nomatch:
Packit Service f629e6
		m = cp->memory;
Packit Service f629e6
		if (m->re_reg[0] != NULL)
Packit Service f629e6
			refree(m->re_reg[0]);
Packit Service f629e6
		if (m->re_reg[1] != NULL)
Packit Service f629e6
			refree(m->re_reg[1]);
Packit Service f629e6
		if (m->re_exp != NULL)
Packit Service f629e6
			unref(m->re_exp);
Packit Service f629e6
		if (m->re_text != NULL)
Packit Service f629e6
			unref(m->re_text);
Packit Service f629e6
		freenode(m);
Packit Service f629e6
		break;
Packit Service f629e6
	case Op_token:
Packit Service f629e6
		/* token lost during error recovery in yyparse */
Packit Service f629e6
		if (cp->lextok != NULL)
Packit Service f629e6
			efree(cp->lextok);
Packit Service f629e6
		break;
Packit Service f629e6
	case Op_push_i:
Packit Service f629e6
		m = cp->memory;
Packit Service f629e6
		unref(m);
Packit Service f629e6
		break;
Packit Service f629e6
	case Op_store_var:
Packit Service f629e6
		m = cp->initval;
Packit Service f629e6
		if (m != NULL)
Packit Service f629e6
			unref(m);
Packit Service f629e6
		break;
Packit Service f629e6
	case Op_illegal:
Packit Service f629e6
		cant_happen();
Packit Service f629e6
	default:
Packit Service f629e6
		break;
Packit Service f629e6
	}
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* free_bc_mempool --- free a single pool */
Packit Service f629e6
Packit Service f629e6
static void
Packit Service f629e6
free_bc_mempool(struct instruction_mem_pool *pool, int size)
Packit Service f629e6
{
Packit Service f629e6
	bool first = true;
Packit Service f629e6
	struct instruction_block *block, *next;
Packit Service f629e6
Packit Service f629e6
	for (block = pool->block_list; block; block = next) {
Packit Service f629e6
		INSTRUCTION *cp, *end;
Packit Service f629e6
Packit Service f629e6
		end = (first ? pool->free_space : & block->i[INSTR_CHUNK]);
Packit Service f629e6
		for (cp = & block->i[0]; cp + size <= end; cp += size) {
Packit Service f629e6
			if (cp->opcode != Op_illegal)
Packit Service f629e6
				free_bc_internal(cp);
Packit Service f629e6
		}
Packit Service f629e6
		next = block->next;
Packit Service f629e6
		efree(block);
Packit Service f629e6
		first = false;
Packit Service f629e6
	}
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
Packit Service f629e6
/* free_bcpool --- free list of instruction memory pools */
Packit Service f629e6
Packit Service f629e6
static void
Packit Service f629e6
free_bcpool(INSTRUCTION_POOL *pl)
Packit Service f629e6
{
Packit Service f629e6
	int i;
Packit Service f629e6
Packit Service f629e6
	for (i = 0; i < MAX_INSTRUCTION_ALLOC; i++)
Packit Service f629e6
		free_bc_mempool(& pl->pool[i], i + 1);
Packit Service f629e6
}