V8/usr/src/cmd/cyntax/cem/var.c

Compare this file to the similar file:
Show the results in this format:

#include	"cem.h"
#define	STD_OBJ	1
#include	"stdobj.h"
#include	"types.h"
#include	"equiv.h"
#include	"symbol.h"
#include	"type.h"
#include	"var.h"

/*
 *	Variable routines.
 */

static long	new_var_index	= 1;

/*
 *	We keep a cache of data objects rather than allowing malloc
 *	to inefficiently recycle them.
 */
static arg	*arg_free;
static args	*args_free;
static var	*var_free;

/*
 *	Allocation routines.
 */
static var	*
new_var()
{
	register var	*p;

	if (var_free == NULL)
		return talloc(var);

	p = var_free;
	var_free = p->v_next;
	return p;
}

static void
free_arglist(a)
register arg	*a;
{
	register args	*p;
	register args	*q;

	for (p = a->a_head; p != NULL; p = q)
	{
		q = p->a_next;
		p->a_next = args_free;
		args_free = p;
	}

	a->a_next = arg_free;
	arg_free = a;
}

static arg	*
new_arg()
{
	register arg	*p;

	if ((p = arg_free) == NULL)
		p = talloc(arg);
	else
		arg_free = p->a_next;

	p->a_head = NULL;
	p->a_tail = &p->a_head;
	p->a_count = 0;
	p->a_next = NULL;
	return p;
}

static void
free_arguments(a)
register arg	*a;
{
	register arg	*b;

	while (a != NULL)
	{
		b = a->a_next;
		free_arglist(a);
		a = b;
	}
}

static void
add_argument(a, t)
register arg	*a;
type		*t;
{
	register args	*p;

	if ((p = args_free) == NULL)
		p = talloc(args);
	else
		args_free = p->a_next;

	p->a_type = t;
	p->a_next = NULL;
	*a->a_tail = p;
	a->a_tail = &p->a_next;
	a->a_count++;
}

/*
 *	Make a declaration.
 */
static var	*
declare(v, n, t, f, l)
obj_vars	v;
symbol		*n;
type		*t;
symbol		*f;
long		l;
{
	register var	*p;

	p = new_var();
	p->v_what = v;
	p->v_name = n;
	p->v_type = t;
	p->v_file = f;
	p->v_line = l;
	p->v_ifile = NULL;
	p->v_varargs = -1;
	p->v_argdefn = NULL;
	p->v_args = NULL;
	p->v_tail = &p->v_args;
	p->v_next = NULL;
	return p;
}

/*
 *	Set array size.
 */
static void
array_size(p, t)
var	*p;
type	*t;
{
	p->v_type = t;
}

/*
 *	Note initialisation.
 */
static void
initialisation(p, f, l)
var	*p;
symbol	*f;
long	l;
{
	p->v_ifile = f;
	p->v_iline = l;
}

/*
 *	Note varargs count.
 */
static void
set_varargs(p, l)
var	*p;
long	l;
{
	p->v_varargs = l;
}

/*
 *	Add an instance of a variable to the symbol table instance list.
 */
static void
add_instance(v)
register var	*v;
{
	register inst	*p;
	register defn	*d;
	register init	*i;

	/*
	 *	Don't let library definitions override.
	 */
	if (in_lib && v->v_name->sy_inst != NULL && v->v_name->sy_inst->i_init)
		return;

	if ((p = v->v_name->sy_inst) == NULL)
	{
		p = talloc(inst);
		v->v_name->sy_inst = p;
		p->i_argdefn = v->v_argdefn;

		if ((p->i_args = v->v_args) == NULL)
			p->i_tail = &p->i_args;
		else
			p->i_tail = v->v_tail;

		d = talloc(defn);
		p->i_defn = d;
		p->i_init = NULL;
		p->i_name = v->v_name;
		d->d_what = v->v_what;
		d->d_type = v->v_type;

		if (in_lib)
		{
			d->d_file = src_file;
			d->d_line = 0;
		}
		else
		{
			d->d_file = v->v_file;
			d->d_line = v->v_line;
		}

		d->d_next = NULL;
		p->i_next = global_list;
		global_list = p;
	}
	else
	{
		if (v->v_argdefn != NULL)
			p->i_argdefn = v->v_argdefn;

		if ((*p->i_tail = v->v_args) != NULL)
			p->i_tail = v->v_tail;

		d = p->i_defn;

		loop
		{
			if (d == NULL)
			{
				d = talloc(defn);
				d->d_next = p->i_defn;
				p->i_defn = d;

			elab:
				d->d_what = v->v_what;
				d->d_type = v->v_type;

				if (in_lib)
				{
					d->d_file = src_file;
					d->d_line = 0;
				}
				else
				{
					d->d_file = v->v_file;
					d->d_line = v->v_line;
				}

				break;
			}

			if (d->d_type == v->v_type)
				break;

			if (complex_elaboration(v->v_type, d->d_type))
				goto elab;

			if (array_elaboration(v->v_type, d->d_type))
				goto elab;

			if (compatible(d->d_type, v->v_type))
				break;

			d = d->d_next;
		}
	}

	if (v->v_ifile != NULL)
	{
		i = talloc(init);

		if (in_lib)
		{
			i->i_file = src_file;
			i->i_line = 0;
		}
		else
		{
			i->i_file = v->v_ifile;
			i->i_line = v->v_iline;
		}

		i->i_varargs = v->v_varargs;
		i->i_next = p->i_init;
		p->i_init = i;
	}
}

/*
 *	Add an arglist (call) to args list.  If it is ceorcible to
 *	the definition don't bother.
 */
static void
add_arglist(v, a)
register var	*v;
register arg	*a;
{
	if (v->v_argdefn != NULL && coercible_arglist(v->v_argdefn, a, -1))
	{
		free_arglist(a);
		return;
	}

	*v->v_tail = a;
	v->v_tail = &a->a_next;
	a->a_next = NULL;
}

/*
 *	Complain about improper calls.
 */
static void
put_improper_calls(d, u, v, af, tf)
register arg	*d;
register arg	*u;
int		v;
int		(*af)();
int		(*tf)();
{
	register args	*p;
	register args	*q;
	register char	*sep;
	register int	n;
	int		i;
	int		force;

	while (u != NULL)
	{
		if (!(*af)(d, u, v))
		{
			putchar('\t');
			put_file(u->a_file, u->a_line);

			if (v >= 0 && u->a_count < v)
				printf(", expected at least %d arg%s, found %d\n", v, v == 1 ? "" : "s", u->a_count);
			else if (d->a_count != u->a_count)
				printf(", expected %d arg%s, found %d\n", d->a_count, d->a_count == 1 ? "" : "s", u->a_count);
			else
			{
				if (v < 0)
					n = d->a_count;
				else
					n = v;

				i = 1;
				sep = ", ";
				p = d->a_head;
				q = u->a_head;

				while (--n >= 0)
				{
					if (p->a_type != q->a_type && !(*tf)(p->a_type, q->a_type))
					{
						force = different_vintage(p->a_type, q->a_type);
						printf("%sarg %d expected ", sep, i);
						put_type(p->a_type, force);
						printf(", found ");
						put_type(q->a_type, force);
						sep = "\n\t\t";
					}

					i++;
					p = p->a_next;
					q = q->a_next;
				}

				putchar('\n');
			}
		}

		u = u->a_next;
	}
}

/*
 *	Enter vars from input file.  Check statics and enter instances.
 */
void
enter_vars(n)
register long	n;
{
	register int	i;
	register long	j;
	register var	*p;
	register var	**v;

	v = (var **)salloc(n * sizeof (var *));
	var_trans = v;

	for (j = 0; j < n; j++)
		*v++ = NULL;

	v = var_trans;

	while (data_ptr < data_end)
	{
		register long	l0;
		register long	l1;
		register long	l2;
		arg		*ap;

		i = getd();

		switch (obj_item(i))
		{
		case i_data:
			l0 = getv();
			l1 = getv();
			initialisation(var_trans[l0], str_trans[l1], getv());

			loop
			{
				i = getd();

				switch (obj_item(i))
				{
				case d_addr:
					skip4();
					continue;

				case d_bytes:
					if (obj_id(i) == 0)
						l0 = getv();
					else
						l0 = obj_id(i);

					data_ptr += l0;
					continue;

				case d_end:
					break;

				case d_istring:
					if (obj_id(i) == 0)
						l0 = getv();
					else
						l0 = obj_id(i);

					str_num++;
					data_ptr += l0;
					continue;

				case d_irstring:
					if (obj_id(i) == 0)
						l0 = getv();
					else
						l0 = obj_id(i);

					str_num++;
					data_ptr += l0;
					skip4();
					continue;

				case d_space:
					if (obj_id(i) == 0)
						skip();

					continue;

				case d_string:
					skip();
					continue;

				case d_reloc:
				case d_rstring:
					skip();
					skip4();
					continue;

				default:
					fprintf(stderr, "%s: unknown data id %d\n", my_name, i);
					exit(1);
				}

				break;
			}

			break;

		case i_lib:
		case i_src:
			skip();
			break;

		case i_string:
			if (obj_id(i) == 0)
				l0 = getv();
			else
				l0 = obj_id(i);

			str_num++;
			data_ptr += l0;
			break;

		case i_type:
			switch (obj_id(i))
			{
			case t_arrayof:
			case t_bitfield:
				skip();
				skip();
				break;

			case t_basetype:
				(void)getd();
				break;

			case t_dimless:
			case t_ftnreturning:
			case t_ptrto:
				skip();
				break;

			case t_elaboration:
				skip();
				skip();
				skip();
				
				switch (i = obj_id(getd()))
				{
				case t_enum:
					skip();
					goto elab_enum;

				case t_structof:
					skip();

					do
					{
						skip();
						skip();
					}
					while (getv() != 0);

					skip();
					break;

				case t_unionof:
					skip();

					do
						skip();
					while (getv() != 0);

					skip();
					break;

				default:
					fprintf(stderr, "%s: unknown elaboration id %d\n", my_name, i);
					exit(1);
				}

				break;

			case t_enum:
				skip();
				skip();
				skip();

				if (getv() == 0)
					break;

			elab_enum:
				do
					skip();
				while (getv() != 0);

				skip();
				skip();
				break;

			case t_structof:
			case t_unionof:
				skip();
				skip();
				skip();
				break;

			default:
				fprintf(stderr, "%s: unknown type id %d\n", my_name, obj_id(i));
				exit(1);
			}

			break;

		case i_var:
			switch (obj_id(i))
			{
			case v_arglist:
				l0 = getv();
				l1 = getv();
				initialisation(var_trans[l0], str_trans[l1], getv());
				ap = new_arg();

				while (getv() != 0)
				{
					add_argument(ap, type_trans[getv()]);
					skip();
					skip();
					var_index++;
				}

				var_trans[l0]->v_argdefn = ap;
				break;

			case v_array_size:
				l0 = getv();
				array_size(var_trans[l0], type_trans[getv()]);
				break;

			case v_auto:
				var_index++;
				skip();
				skip();
				skip();
				skip();
				break;

			case v_call:
				l0 = getv();
				ap = new_arg();
				ap->a_file = str_trans[getv()];
				ap->a_line = getv();

				while ((l1 = getv()) != 0)
					add_argument(ap, type_trans[l1]);

				add_arglist(var_trans[l0], ap);
				break;

			case v_block_static:
			case v_global:
			case v_implicit_function:
			case v_static:
				l0 = getv();
				l1 = getv();
				l2 = getv();
				var_trans[var_index++] = declare(obj_id(i), str_trans[l0], type_trans[l1], str_trans[l2], getv());
				break;

			case v_varargs:
				l0 = getv();
				set_varargs(var_trans[l0], getv());
				break;

			default:
				fprintf(stderr, "%s: unknown var id %d\n", my_name, obj_id(i));
				exit(1);
			}

			break;

		default:
			fprintf(stderr, "%s: unknown obj_item %d\n", my_name, obj_item(i));
			exit(1);
		}
	}

	for (j = 1; j < n; j++)
	{
		register arg	*a;

		if ((p = v[j]) == NULL)
			continue;

		switch (p->v_what)
		{
		case v_block_static:
			break;

		case v_global:
		case v_implicit_function:
			add_instance(p);
			break;

		case v_static:
			switch (p->v_type->t_type)
			{
				char	*diag;

			error:
				say_file();
				printf(", static %s %s, ", diag, p->v_name->sy_name);
				put_file(p->v_file, p->v_line);
				printf(", never defined\n");
				errors++;
				break;

			case t_dimless:
				diag = "array[]";
				goto error;

			case t_ftnreturning:
				if (p->v_ifile == NULL)
				{
					diag = "function";
					goto error;
				}

				for (a = p->v_args; a != NULL; a = a->a_next)
				{
					if (!coercible_arglist(p->v_argdefn, a, p->v_varargs))
					{
						say_file();
						printf(": static function %s: ", p->v_name->sy_name);
						put_file(p->v_file, p->v_line);
						printf("\n");
						put_improper_calls(p->v_argdefn, a, p->v_varargs, coercible_arglist, coercible);
						errors++;
						break;
					}
				}

				free_arguments(p->v_args);
				free_arguments(p->v_argdefn);
			}

			break;

		default:
			fprintf(stderr, "%s: bad var type\n", my_name);
			exit(1);
		}

		p->v_next = var_free;
		var_free = p;
	}
}

/*
 *	Check for mutliple declarations and definitions.
 *	Also check arglist compatibility.
 */
static void
check_instance(p)
register inst	*p;
{
	register defn	*d;
	register init	*i;
	register arg	*a;

	if (p->i_defn->d_next != NULL)
	{
		printf("%s multiply declared:\n", p->i_name->sy_name);

		for (d = p->i_defn; d != NULL; d = d->d_next)
		{
			putchar('\t');
			put_file(d->d_file, d->d_line);

			if (d->d_what == v_implicit_function)
				printf(" implicitly");

			printf(" as ");
			put_type(d->d_type, 0);
			putchar('\n');
		}

		errors++;
	}

	if (p->i_init != NULL)
	{
		if (p->i_init->i_next != NULL)
		{
			printf("%s multiply defined:\n", p->i_name->sy_name);

			for (i = p->i_init; i != NULL; i = i->i_next)
			{
				putchar('\t');
				put_file(i->i_file, i->i_line);
				putchar('\n');
			}

			errors++;
			return;
		}

		if (p->i_argdefn != NULL)
		{
			for (a = p->i_args; a != NULL; a = a->a_next)
			{
				if (!compatible_arglist(p->i_argdefn, a, p->i_init->i_varargs))
				{
					printf("function %s: ", p->i_name->sy_name);
					put_file(p->i_init->i_file, p->i_init->i_line);
					printf("\n");
					put_improper_calls(p->i_argdefn, a, p->i_init->i_varargs, compatible_arglist, compatible);
					errors++;
					break;
				}
			}
		}
	}
}

void
check_externs()
{
	register inst	*p;

	for (p = global_list; p != NULL; p = p->i_next)
		check_instance(p);
}