282 lines
		
	
	
	
		
			5.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			282 lines
		
	
	
	
		
			5.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
 | 
						|
 * See the copyright notice in the ACK home directory, in the file "Copyright".
 | 
						|
 */
 | 
						|
/* $Header$ */
 | 
						|
 | 
						|
/******** A R G U M E N T   T Y P E   C H E C K I N G ********/
 | 
						|
 | 
						|
#include	"private.h"
 | 
						|
#include	"inpdef.h"
 | 
						|
 | 
						|
extern char *strcpy();
 | 
						|
 | 
						|
#define	streq(s1,s2)	(strcmp(s1, s2) == 0)
 | 
						|
 | 
						|
/* a format is developed into a normal parameter definition */
 | 
						|
PRIVATE int is_formatargs;		/* present or not */
 | 
						|
PRIVATE char formatargs[1000];		/* the definitions */
 | 
						|
 | 
						|
PRIVATE chk_argtps();
 | 
						|
PRIVATE char *next_argtype();
 | 
						|
PRIVATE int type_match();
 | 
						|
PRIVATE form_type();
 | 
						|
 | 
						|
int
 | 
						|
type_equal(act, form)
 | 
						|
	char *act, *form;
 | 
						|
{
 | 
						|
	return	streq(act, form)
 | 
						|
	||	streq(act, "erroneous")
 | 
						|
	||	streq(form, "erroneous");
 | 
						|
}
 | 
						|
 | 
						|
chk_args(id, def)
 | 
						|
	struct inpdef *id, *def;
 | 
						|
{
 | 
						|
	char *act_tp = id->id_argtps;
 | 
						|
	int nrargs = 0;			/* number of args */
 | 
						|
 | 
						|
	/* void is a special case */
 | 
						|
	if (	/* the definition has one void argument */
 | 
						|
		def->id_nrargs == 1 && streq(def->id_argtps, "void:")
 | 
						|
	&&	/* the referent has no argumants */
 | 
						|
		id->id_nrargs == 0
 | 
						|
	)	/* we have a prefect match */
 | 
						|
		return;
 | 
						|
 | 
						|
	/* clear format */
 | 
						|
	is_formatargs = 0;
 | 
						|
 | 
						|
	/* check normal arguments */
 | 
						|
	chk_argtps(id, def, &nrargs, act_tp, def->id_argtps);
 | 
						|
 | 
						|
	if (is_formatargs) {
 | 
						|
		/* there was a format */
 | 
						|
		register int i;
 | 
						|
 | 
						|
		/* skip over the actuals already covered */
 | 
						|
		for (i = 0; i < nrargs; i++) {
 | 
						|
			act_tp = next_argtype(act_tp);
 | 
						|
		}
 | 
						|
 | 
						|
		/* and check the format arguments */
 | 
						|
		chk_argtps(id, (struct inpdef *)0, &nrargs,
 | 
						|
						act_tp, &formatargs[0]);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
PRIVATE chk_argtps(id, def, nrargs, act_tp, form_tp)
 | 
						|
	struct inpdef *id;		/* the actual call */
 | 
						|
	struct inpdef *def;		/* 0 for format-derived definition */
 | 
						|
	int *nrargs;			/* in-out parameter, counting */
 | 
						|
	char *act_tp;			/* actual types */
 | 
						|
	char *form_tp;			/* formal type definitions */
 | 
						|
{
 | 
						|
	while (*act_tp && *form_tp && *form_tp != '.') {
 | 
						|
		register char *act_start = act_tp;
 | 
						|
		register char *form_start = form_tp;
 | 
						|
 | 
						|
		/* isolate actual argument type */
 | 
						|
		act_tp = next_argtype(act_tp);
 | 
						|
		act_tp[-1] = '\0';
 | 
						|
 | 
						|
		/* isolate formal argument type */
 | 
						|
		form_tp = next_argtype(form_tp);
 | 
						|
		form_tp[-1] = '\0';
 | 
						|
 | 
						|
		(*nrargs)++;
 | 
						|
		if (!type_match(id, act_start, form_start)) {
 | 
						|
			char act_form[100];
 | 
						|
			char form_form[100];
 | 
						|
 | 
						|
			form_type(act_form, act_start);
 | 
						|
			form_type(form_form, form_start);
 | 
						|
			report("%L: arg %d of %s (%s) differs from that in %L (%s)",
 | 
						|
				id, *nrargs, id->id_name,
 | 
						|
				act_form, def, form_form);
 | 
						|
		}
 | 
						|
		act_tp[-1] = ':';
 | 
						|
		form_tp[-1] = ':';
 | 
						|
	}
 | 
						|
 | 
						|
	if (*form_tp == '.')	/* ellipsis */
 | 
						|
		return;
 | 
						|
 | 
						|
	if (*form_tp) {
 | 
						|
		/* formal type definitions not exhausted */
 | 
						|
		report("%L: %s has fewer arguments than in %L",
 | 
						|
			id, id->id_name, def);
 | 
						|
	}
 | 
						|
	if (*act_tp) {
 | 
						|
		/* actual types not exhausted */
 | 
						|
		if (def && def->id_nrargs < 0) {
 | 
						|
			/* the function had VARARGS */
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			report("%L: %s has more arguments than in %L",
 | 
						|
				id, id->id_name, def);
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
PRIVATE char *
 | 
						|
next_argtype(tp)
 | 
						|
	char *tp;
 | 
						|
{
 | 
						|
	while (*tp && *tp != ':') {
 | 
						|
		tp++;
 | 
						|
	}
 | 
						|
	if (*tp == ':') {
 | 
						|
		tp++;
 | 
						|
	}
 | 
						|
	return tp;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
PRIVATE type_match(id, act, form)
 | 
						|
	struct inpdef *id;
 | 
						|
	char *act, *form;
 | 
						|
{
 | 
						|
	if (form[0] == '"' && act[0] == '"') {
 | 
						|
		conv_format(id, act, form);
 | 
						|
		return 1;
 | 
						|
	}
 | 
						|
 | 
						|
	if (	(form[0] == '"' && streq(act, "char*"))
 | 
						|
	||	(act[0] == '"' && streq(form, "char*"))
 | 
						|
	) {
 | 
						|
		return 1;
 | 
						|
	}
 | 
						|
 | 
						|
	if (type_equal(act, form))
 | 
						|
		return 1;
 | 
						|
 | 
						|
	if (act[0] == '+') {
 | 
						|
		/* a non-negative constant */
 | 
						|
		/* might be signed or unsigned */
 | 
						|
		if (type_equal(&act[1], form))
 | 
						|
			return 1;
 | 
						|
		if (	strncmp(form, "unsigned ", strlen("unsigned ")) == 0
 | 
						|
		&&	type_equal(&act[1], &form[strlen("unsigned ")])
 | 
						|
		) {
 | 
						|
			return 1;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
PRIVATE conv_format(id, act, form)
 | 
						|
	struct inpdef *id;
 | 
						|
	char *act, *form;
 | 
						|
{
 | 
						|
	/*	convert the actual format into a def-list, using the
 | 
						|
		formal format (form) as a map to convert from %X to type
 | 
						|
	*/
 | 
						|
	register char *fmt = &formatargs[0];
 | 
						|
 | 
						|
	is_formatargs = 1;
 | 
						|
	while (*act) {
 | 
						|
		register char *map;
 | 
						|
 | 
						|
		/* find next conversion specification */
 | 
						|
		while (*act && *act != '%') {
 | 
						|
			act++;
 | 
						|
		}
 | 
						|
		if (*act++ != '%')
 | 
						|
			break;
 | 
						|
		if (*act == '%') {
 | 
						|
			/* %% */
 | 
						|
			act++;
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
 | 
						|
		/* process options */
 | 
						|
		if (*act && *act == '-') {
 | 
						|
			act++;
 | 
						|
		}
 | 
						|
		while (*act && ('0' <= *act && *act <= '9')) {
 | 
						|
			act++;
 | 
						|
		}
 | 
						|
		if (*act == '*') {
 | 
						|
			act++;
 | 
						|
			strcpy(fmt, "int:");
 | 
						|
			fmt += 4;
 | 
						|
		}
 | 
						|
		if (*act && *act == '.') {
 | 
						|
			act++;
 | 
						|
		}
 | 
						|
		while (*act && ('0' <= *act && *act <= '9')) {
 | 
						|
			act++;
 | 
						|
		}
 | 
						|
		if (*act == '*') {
 | 
						|
			act++;
 | 
						|
			strcpy(fmt, "int:");
 | 
						|
			fmt += 4;
 | 
						|
		}
 | 
						|
 | 
						|
		map = form;
 | 
						|
		while (*map) {
 | 
						|
			register char *cs = act;
 | 
						|
 | 
						|
			/* find next conversion mapping */
 | 
						|
			while (*map && *map != '%') {
 | 
						|
				map++;
 | 
						|
			}
 | 
						|
			if (*map++ != '%') {
 | 
						|
				/* we ran off the map */
 | 
						|
				report("%L: unknown conversion specification in format",
 | 
						|
					id);
 | 
						|
				break;
 | 
						|
			}
 | 
						|
 | 
						|
			while (*map && *map != '=') {
 | 
						|
				register int match = 0;
 | 
						|
 | 
						|
				if (*map == '[') {
 | 
						|
					while (*map && *map != ']') {
 | 
						|
						if (*map == *cs) {
 | 
						|
							match = 1;
 | 
						|
						}
 | 
						|
						map++;
 | 
						|
					}
 | 
						|
				}
 | 
						|
				else {
 | 
						|
					match = (*map == *cs);
 | 
						|
				}
 | 
						|
 | 
						|
				if (match) {
 | 
						|
					map++, cs++;
 | 
						|
				}
 | 
						|
				else	break;
 | 
						|
			}
 | 
						|
			if (*map++ == '=') {
 | 
						|
				/* found the type belonging to %*cs */
 | 
						|
				while (*map && *map != '%' && *map != '"') {
 | 
						|
					*fmt++ = *map++;
 | 
						|
				}
 | 
						|
				*fmt++ = ':';
 | 
						|
				act = cs;
 | 
						|
				break;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	*fmt++ = '\0';
 | 
						|
}
 | 
						|
 | 
						|
PRIVATE form_type(buff, tp)
 | 
						|
	char buff[];
 | 
						|
	char *tp;
 | 
						|
{	/*	store a formatted version of tp in buff
 | 
						|
	*/
 | 
						|
	if (tp[0] == '"') {
 | 
						|
		strcpy(buff, "char*");
 | 
						|
	}
 | 
						|
	else if (tp[0] == '+') {
 | 
						|
		sprintf(buff, "[unsigned] %s", &tp[1]);
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		strcpy(buff, tp);
 | 
						|
	}
 | 
						|
}
 | 
						|
 |