many improvements
This commit is contained in:
		
							parent
							
								
									5581bdad15
								
							
						
					
					
						commit
						56fff3d6cd
					
				
					 8 changed files with 535 additions and 429 deletions
				
			
		|  | @ -1,3 +1,21 @@ | |||
|  7-Aug-88  Dick Grune (dick) at dick | ||||
| 	About the class of an inpdef, often set-like questions are asked. | ||||
| 	To speed up answering these questions, a mapping has been created | ||||
| 	of the values of `class' onto answers to these questions.  See | ||||
| 	class.[ch]. | ||||
| 
 | ||||
|  5-Aug-88  Dick Grune (dick) at dick | ||||
| 	Streamlined the program by rearranging the input sequence: | ||||
| 		- library | ||||
| 		- external defs | ||||
| 		- external decls | ||||
| 		- external usage | ||||
| 		- static defs | ||||
| 		- static usage | ||||
| 	This change to a much more natural order has been possible by the | ||||
| 	introduction of the static file number.  Many pieces of code could | ||||
| 	now be taken together and the program is much cleaner now. | ||||
| 
 | ||||
|  8-Jul-88  Dick Grune (dick) at dick | ||||
| 	Added a special meta-type (also in lpaas1) for non-negative | ||||
| 	constant actual arguments, because these may match both the signed | ||||
|  |  | |||
|  | @ -1,26 +1,26 @@ | |||
| #	M A K E F I L E   F O R   L P A S S 2
 | ||||
| 
 | ||||
| # Machine and environ dependent definitions
 | ||||
| EMHOME = /usr/em | ||||
| LPASS1 = ../lpass1 | ||||
| EMHOME =	/usr/em | ||||
| LPASS1 =	../lpass1 | ||||
| 
 | ||||
| # Libraries and EM interface definitions
 | ||||
| SYSLIB = $(EMHOME)/modules/lib/libsystem.a | ||||
| STRLIB = $(EMHOME)/modules/lib/libstring.a | ||||
| PRTLIB = $(EMHOME)/modules/lib/libprint.a | ||||
| INPLIB = $(EMHOME)/modules/lib/libinput.a | ||||
| ALLOCLIB = $(EMHOME)/modules/lib/liballoc.a | ||||
| MALLOC = $(EMHOME)/modules/lib/malloc.o | ||||
| LLIBS = $(INPLIB) $(PRTLIB) $(STRLIB) $(ALLOCLIB) $(MALLOC) $(SYSLIB) | ||||
| SYSLIB =	$(EMHOME)/modules/lib/libsystem.a | ||||
| STRLIB =	$(EMHOME)/modules/lib/libstring.a | ||||
| PRTLIB =	$(EMHOME)/modules/lib/libprint.a | ||||
| INPLIB =	$(EMHOME)/modules/lib/libinput.a | ||||
| ALLOCLIB =	$(EMHOME)/modules/lib/liballoc.a | ||||
| MALLOC =	$(EMHOME)/modules/lib/malloc.o | ||||
| LLIBS =		$(INPLIB) $(PRTLIB) $(STRLIB) $(ALLOCLIB) $(MALLOC) $(SYSLIB) | ||||
| 
 | ||||
| CFLAGS = -I$(EMHOME)/modules/h -I$(EMHOME)/modules/pkg -I/usr/include | ||||
| CFLAGS =	-I$(EMHOME)/modules/h -I$(EMHOME)/modules/pkg -I/usr/include | ||||
| 
 | ||||
| .SUFFIXES: .str .h | ||||
| .str.h: | ||||
| 	$(LPASS1)/make.allocd <$*.str >$*.h | ||||
| 
 | ||||
| SRC =	lpass2.c read.c | ||||
| OBJ =	lpass2.o read.o | ||||
| SRC =	lpass2.c read.c report.c class.c | ||||
| OBJ =	lpass2.o read.o report.o class.o | ||||
| 
 | ||||
| test:	lpass2 | ||||
| 	make lint | ||||
|  | @ -32,7 +32,7 @@ lpass2:	$(OBJ) Makefile next.o | |||
| lint: | ||||
| 	../lint $(CFLAGS) $(SRC) next.c #??? | ||||
| 
 | ||||
| next.c:	inpdef.str | ||||
| next.c:	$(LPASS1)/make.next inpdef.str | ||||
| 	$(LPASS1)/make.next inpdef.str > next.c | ||||
| 
 | ||||
| tags:	$(SRC) | ||||
|  | @ -42,4 +42,7 @@ clean: | |||
| 	rm -f a.out core next.c inpdef.h $(OBJ) next.o | ||||
| 
 | ||||
| #----------------------------------------------------------------
 | ||||
| lpass2.o: ../lpass1/errout.h ../lpass1/lint.h ../lpass1/l_class.h inpdef.h | ||||
| class.o: class.h | ||||
| lpass2.o: ../lpass1/l_class.h ../lpass1/l_lint.h class.h inpdef.h | ||||
| read.o: ../lpass1/l_class.h class.h inpdef.h | ||||
| report.o: inpdef.h | ||||
|  |  | |||
							
								
								
									
										47
									
								
								lang/cem/lint/lpass2/class.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								lang/cem/lint/lpass2/class.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,47 @@ | |||
| #include	"../lpass1/l_class.h" | ||||
| #include	"class.h" | ||||
| 
 | ||||
| int class[] = { | ||||
| 	/* mapping of class values onto bit patterns */ | ||||
| 	/* LFDF */ CL_LIB|CL_FUNC|CL_DEF, | ||||
| 	/* LVDF */ CL_LIB|CL_VAR|CL_DEF, | ||||
| 	/* EFDF */ CL_EXT|CL_FUNC|CL_DEF, | ||||
| 	/* EVDF */ CL_EXT|CL_VAR|CL_DEF, | ||||
| 	/* EFDC */ CL_EXT|CL_FUNC|CL_DECL, | ||||
| 	/* EVDC */ CL_EXT|CL_VAR|CL_DECL, | ||||
| 	/* IFDC */ CL_IMPL|CL_FUNC|CL_DECL, | ||||
| 	/* SFDF */ CL_STAT|CL_FUNC|CL_DEF, | ||||
| 	/* SVDF */ CL_STAT|CL_VAR|CL_DEF, | ||||
| 	/* FC */ CL_FUNC|CL_USAGE, | ||||
| 	/* VU */ CL_VAR|CL_USAGE | ||||
| }; | ||||
| 
 | ||||
| static int val[] = { | ||||
| 	LFDF, | ||||
| 	LVDF, | ||||
| 	EFDF, | ||||
| 	EVDF, | ||||
| 	EFDC, | ||||
| 	EVDC, | ||||
| 	IFDC, | ||||
| 	SFDF, | ||||
| 	SVDF, | ||||
| 	FC, | ||||
| 	VU | ||||
| }; | ||||
| 
 | ||||
| init_class() | ||||
| { | ||||
| 	/*	The initialization of class[] has been taken care of above.
 | ||||
| 		For it to work, we have to test that the class values are | ||||
| 		in the right order.  This is also necessary for the scanning | ||||
| 		sequence in lpass2.c to work properly. | ||||
| 	*/ | ||||
| 	int i; | ||||
| 
 | ||||
| 	for (i = 0; i+1 < sizeof(val)/sizeof(val[0]); i++) { | ||||
| 		if (val[i] >= val[i+1]) | ||||
| 			panic("class values out of sequence"); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										16
									
								
								lang/cem/lint/lpass2/class.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								lang/cem/lint/lpass2/class.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,16 @@ | |||
| #define	CL_DEF		(1<<0) | ||||
| #define	CL_DECL		(1<<1) | ||||
| #define	CL_USAGE	(1<<2) | ||||
| 
 | ||||
| #define	CL_FUNC		(1<<3) | ||||
| #define	CL_VAR		(1<<4) | ||||
| 
 | ||||
| #define	CL_LIB		(1<<5) | ||||
| #define	CL_EXT		(1<<6) | ||||
| #define	CL_IMPL		(1<<7) | ||||
| #define	CL_STAT		(1<<8) | ||||
| 
 | ||||
| extern int class[]; | ||||
| 
 | ||||
| #define	is_class(id,cl)	((class[(id)->id_class-'a'] & (cl)) == (cl)) | ||||
| 
 | ||||
|  | @ -5,14 +5,22 @@ | |||
| 
 | ||||
| struct inpdef { | ||||
| 	struct inpdef *next; | ||||
| 	int id_class; | ||||
| 
 | ||||
| 	/* filled by get_id() */ | ||||
| 	int id_class;			/* see ../lpass1/l_class.h */ | ||||
| 	char id_name[NAMESIZE]; | ||||
| 	int id_statnr; | ||||
| 	char id_file[FNAMESIZE]; | ||||
| 	int id_line; | ||||
| 	int id_nrargs; | ||||
| 	char id_argtps[ARGTPSSIZE]; | ||||
| 	int id_returns; | ||||
| 	char id_type[TYPESIZE]; | ||||
| 
 | ||||
| 	int id_args;			/* set if arguments given */ | ||||
| 	int id_nrargs;			/* number of args, neg. for varargs */ | ||||
| 	char id_argtps[ARGTPSSIZE];	/* argument types, colon separated */ | ||||
| 	int id_valreturned;		/* for def/decl, set if val returned */ | ||||
| 	int id_valused;			/* for FC, see ../lpass1/l_lint.h */ | ||||
| 
 | ||||
| 	/* not filled by get_id() */ | ||||
| 	int id_called; | ||||
| 	int id_used; | ||||
| 	int id_ignored; | ||||
|  |  | |||
|  | @ -1,46 +1,55 @@ | |||
| #include	<varargs.h> | ||||
| #include	<alloc.h> | ||||
| 
 | ||||
| #include	"../lpass1/l_lint.h" | ||||
| #include	"../lpass1/l_class.h" | ||||
| #include	"class.h" | ||||
| #include	"inpdef.h" | ||||
| 
 | ||||
| #include	<alloc.h> | ||||
| #include	<system.h> | ||||
| 
 | ||||
| #define	MSGOUT		STDERR	/* filedes on which to write the messages */ | ||||
| #define	ERROUT		STDERR	/* filedes on which to write the panics */ | ||||
| 
 | ||||
| #define	streq(s1,s2)	(strcmp(s1, s2) == 0) | ||||
| #define	min(a,b)	((a) <= (b) ? (a) : (b)) | ||||
| 
 | ||||
| #define	type_equal(s1,s2)	(streq(s1, s2)) | ||||
| char cur_name[NAMESIZE]; | ||||
| struct inpdef *dot, *lib, *ext, *sta; | ||||
| 
 | ||||
| char *cur_name; | ||||
| struct inpdef *dot_id, | ||||
| 	*ext_def, | ||||
| 	*static_def; | ||||
| struct inpdef *id_read(); | ||||
| #define	same_name()	(dot && streq(cur_name, dot->id_name)) | ||||
| #define	same_obj(stnr)	(same_name() && dot->id_statnr == stnr) | ||||
| 
 | ||||
| #define	same_name()	streq(cur_name, dot_id->id_name) | ||||
| #define	defdec(id)	(is_class(id, CL_DEF) ? "defined" : "declared") | ||||
| 
 | ||||
| 
 | ||||
| /******** M A I N ********/ | ||||
| 
 | ||||
| main(argc, argv) | ||||
| 	char *argv[]; | ||||
| { | ||||
| 	struct inpdef *id; | ||||
| 
 | ||||
| 	init(argc, argv); | ||||
| 
 | ||||
| 	get_dot_id(); | ||||
| 	while (dot_id) { | ||||
| 		cur_name = dot_id->id_name; | ||||
| 		read_defs(); | ||||
| 		while (dot_id && same_name()) { | ||||
| 			id = id_read(); | ||||
| 			check(id); | ||||
| 			free_inpdef(id); | ||||
| 	dot = new_inpdef(); | ||||
| 	get_dot(); | ||||
| 	while (dot) { | ||||
| 		if (lib) { | ||||
| 			free_inpdef(lib); | ||||
| 			lib = 0; | ||||
| 		} | ||||
| 		if (ext) { | ||||
| 			free_inpdef(ext); | ||||
| 			ext = 0; | ||||
| 		} | ||||
| 		strcpy(cur_name, dot->id_name); | ||||
| 		lib_def(); | ||||
| 		ext_def(); | ||||
| 		ext_decls(); | ||||
| 		usage(0); | ||||
| 		if (ext) | ||||
| 			check_def(ext); | ||||
| 		statics(); | ||||
| 		/* inpdefs of class ERRCL are never generated */ | ||||
| 		if (same_name()) { | ||||
| 			/*	there are more lines for this name that have
 | ||||
| 				not been absorbed | ||||
| 			*/ | ||||
| 			panic("sequence error in intermediate file"); | ||||
| 		} | ||||
| 		check_usage(); | ||||
| 		free_defs(); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | @ -50,13 +59,14 @@ static char *table[] = {0}; | |||
| init(argc, argv) | ||||
| 	char *argv[]; | ||||
| { | ||||
| /* Prepare standard input for reading using the input-package
 | ||||
|  * Read first inpdef into dot_id | ||||
| /*
 | ||||
|  * Parse options | ||||
|  * Prepare standard input for reading using the input-package | ||||
|  */ | ||||
| 
 | ||||
| 	char *result; | ||||
| 
 | ||||
| 	init_class(); | ||||
| 
 | ||||
| 	while (argc > 1 && *argv[1] == '-') { | ||||
| 		switch (argv[1][1]) { | ||||
| 		case 'u': | ||||
|  | @ -67,7 +77,7 @@ init(argc, argv) | |||
| 			options[argv[1][1]] = 1; | ||||
| 			break; | ||||
| 		default: | ||||
| 			/* ready to extend */ | ||||
| 			/* ready to be extended */ | ||||
| 			break; | ||||
| 		} | ||||
| 		argc--, argv++; | ||||
|  | @ -77,248 +87,295 @@ init(argc, argv) | |||
| 		panic("InsertFile() fails"); | ||||
| } | ||||
| 
 | ||||
| read_defs() | ||||
| get_dot() | ||||
| { | ||||
| 	struct inpdef *id; | ||||
| 
 | ||||
| 	if (ext_def || static_def) | ||||
| 		panic("read_defs: slate not clean");/*???*/ | ||||
| 
 | ||||
| 	while (dot_id && same_name() && is_def(dot_id)) { | ||||
| 		id = id_read(); | ||||
| 		switch (id->id_class) { | ||||
| 		case EFDF: | ||||
| 		case EVDF: | ||||
| 			if (ext_def) { | ||||
| 				report("%L: %s also defined at %L", | ||||
| 					id, id->id_name, ext_def); | ||||
| 				free_inpdef(id); | ||||
| 			} | ||||
| 			else { | ||||
| 				ext_def = id; | ||||
| 			} | ||||
| 			break; | ||||
| 		case SFDF: | ||||
| 		case SVDF: | ||||
| 			if (ext_def) { | ||||
| 				report("%L: %s also defined at %L", | ||||
| 					id, id->id_name, ext_def); | ||||
| 				free_inpdef(id); | ||||
| 			} | ||||
| 			else { | ||||
| 				static_in_list(id); | ||||
| 			} | ||||
| 			break; | ||||
| 		case LFDF: | ||||
| 		case LVDF: | ||||
| 			if (ext_def) { | ||||
| 				/* Some libraries contain more than one
 | ||||
| 				 * definition | ||||
| 				 */ | ||||
| 				if (is_lib_class(ext_def->id_class)) { | ||||
| 					report("%L: %s redefined in library %L", | ||||
| 						id, id->id_name, ext_def); | ||||
| 				} | ||||
| 				free_inpdef(id); | ||||
| 			} | ||||
| 			else { | ||||
| 				ext_def = id; | ||||
| 			} | ||||
| 			break; | ||||
| 		default: | ||||
| 			panic("invalid class (%c) in read_defs", id->id_class); | ||||
| 		} | ||||
| 	if (!get_id(dot)) { | ||||
| 		free_inpdef(dot); | ||||
| 		dot = 0; | ||||
| 		cur_name[0] = '\0'; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| struct inpdef * | ||||
| id_read() | ||||
| { | ||||
| /* Returns the value of dot_id if present, 0 otherwise.
 | ||||
|  * Reads a new inpdef ahead, to which dot_id will be pointing. | ||||
|  * Cur_name will be pointing to id_name of the returned inpdef. | ||||
|  */ | ||||
| 	struct inpdef *old_id; | ||||
| 
 | ||||
| 	if (!dot_id) | ||||
| 		return (0); | ||||
| 	old_id = dot_id; | ||||
| 	cur_name = old_id->id_name; | ||||
| 	get_dot_id(); | ||||
| 	return (old_id); | ||||
| } | ||||
| /******** L I B R A R Y ********/ | ||||
| 
 | ||||
| get_dot_id() | ||||
| lib_def() | ||||
| { | ||||
| /* Allocates a new inpdef, calls it dot_id and fills it */ | ||||
| 	dot_id = new_inpdef(); | ||||
| 	if (!get_id(dot_id)) { | ||||
| 		free_inpdef(dot_id); | ||||
| 		cur_name = ""; | ||||
| 		dot_id = 0; | ||||
| 	if (same_obj(0) && is_class(dot, CL_LIB)) { | ||||
| 		lib = dot; | ||||
| 		dot = new_inpdef(); | ||||
| 		get_dot(); | ||||
| 	} | ||||
| 
 | ||||
| 	while (same_obj(0) && is_class(dot, CL_LIB)) { | ||||
| 		report("%L: multiple definition of %s in library", | ||||
| 			dot, dot->id_name); | ||||
| 		get_dot(); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| struct inpdef *definition(); | ||||
| 
 | ||||
| check(id) | ||||
| 	struct inpdef *id; | ||||
| /******** E X T E R N ********/ | ||||
| 
 | ||||
| ext_def() | ||||
| { | ||||
| /* Checks a declaration, function call or variable usage, described by id,
 | ||||
|  * against the definitions. | ||||
|  */ | ||||
| 	struct inpdef *idef; | ||||
| 	if (same_obj(0) && is_class(dot, CL_EXT|CL_DEF)) { | ||||
| 		if (lib) { | ||||
| 			report("%L: %s also defined in library %L", | ||||
| 				dot, dot->id_name, lib); | ||||
| 		} | ||||
| 		ext = dot; | ||||
| 		dot = new_inpdef(); | ||||
| 		get_dot(); | ||||
| 	} | ||||
| 
 | ||||
| 	idef = definition(id); | ||||
| 	switch (id->id_class) { | ||||
| 	case EFDC: | ||||
| 		if (!idef) { | ||||
| 			if (!options['u']) { | ||||
| 				report("%L: %s declared but never defined", | ||||
| 					id, id->id_name); | ||||
| 			} | ||||
| 			discard_defs(); | ||||
| 			break; | ||||
| 	while (same_obj(0) && is_class(dot, CL_EXT|CL_DEF)) { | ||||
| 		report("%L: %s also defined at %L", | ||||
| 			dot, dot->id_name, ext); | ||||
| 		get_dot(); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| ext_decls() | ||||
| { | ||||
| 	while (same_obj(0) && dot->id_class == EFDC) { | ||||
| 		one_ext_decl("function", "variable", CL_VAR); | ||||
| 	} | ||||
| 
 | ||||
| 	while (same_obj(0) && dot->id_class == EVDC) { | ||||
| 		one_ext_decl("variable", "function", CL_FUNC); | ||||
| 	} | ||||
| 
 | ||||
| 	while (same_obj(0) && dot->id_class == IFDC) { | ||||
| 		one_ext_decl("function", "variable", CL_VAR); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| one_ext_decl(kind, other_kind, other_class) | ||||
| 	char *kind; | ||||
| 	char *other_kind; | ||||
| 	int other_class; | ||||
| { | ||||
| 	struct inpdef *def = ext ? ext : lib ? lib : 0; | ||||
| 
 | ||||
| 	if (!def) { | ||||
| 		/* the declaration will have to serve */ | ||||
| 		if (!is_class(dot, CL_IMPL) && !options['u']) { | ||||
| 			report("%L: %s %s declared but never defined", | ||||
| 				dot, dot->id_name, kind); | ||||
| 		} | ||||
| 		if (idef->id_class == EVDF || idef->id_class == LVDF) { | ||||
| 			report("%L: function %s declared as variable at %L", | ||||
| 				id, id->id_name, idef); | ||||
| 			break; | ||||
| 		ext = dot; | ||||
| 		dot = new_inpdef(); | ||||
| 		get_dot(); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	if (is_class(def, other_class)) { | ||||
| 		/* e.g.: function FFF declared as variable at ... */ | ||||
| 		report("%L: %s %s %s as %s at %L", | ||||
| 			dot, kind, dot->id_name, defdec(def), other_kind, def); | ||||
| 		/* no further testing possible */ | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	if (!type_equal(dot->id_type, def->id_type)) { | ||||
| 		/* e.g.: type of variable VVV defined differently at ... */ | ||||
| 		report("%L: type of %s %s %s differently at %L", | ||||
| 			dot, kind, dot->id_name, defdec(def), def); | ||||
| 	} | ||||
| 
 | ||||
| 	get_dot(); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /******** U S A G E ********/ | ||||
| 
 | ||||
| usage(stnr) | ||||
| 	int stnr; | ||||
| { | ||||
| 	struct inpdef *def = stnr ? sta : ext ? ext : lib ? lib : 0; | ||||
| 
 | ||||
| 	while (same_obj(stnr) && dot->id_class == FC) { | ||||
| 		one_func_call(def); | ||||
| 	} | ||||
| 
 | ||||
| 	while (same_obj(stnr) && dot->id_class == VU) { | ||||
| 		one_var_usage(def); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| one_func_call(def) | ||||
| 	struct inpdef *def; | ||||
| { | ||||
| 	if (!def) { | ||||
| 		if (!options['u']) { | ||||
| 			report("%L: function %s used but not defined", | ||||
| 				dot, dot->id_name); | ||||
| 		} | ||||
| 		if (!type_equal(id->id_type, idef->id_type)) { | ||||
| 			report("%L: value of function %s declared differently at %L", | ||||
| 				id, id->id_name, idef); | ||||
| 		} | ||||
| 		break; | ||||
| 	case EVDC: | ||||
| 		if (!idef) { | ||||
| 			if (!options['u']) { | ||||
| 				report("%L: %s declared but never defined", | ||||
| 					id, id->id_name); | ||||
| 			} | ||||
| 			discard_defs(); | ||||
| 			break; | ||||
| 		} | ||||
| 		if (idef->id_class == EFDF || idef->id_class == LFDF) { | ||||
| 			report("%L: variable %s declared as function at %L", | ||||
| 				id, id->id_name, idef); | ||||
| 			break; | ||||
| 		} | ||||
| 		if (!type_equal(id->id_type, idef->id_type)) { | ||||
| 			report("%L: variable %s declared differently at %L", | ||||
| 				id, id->id_name, idef); | ||||
| 		} | ||||
| 		break; | ||||
| 	case IFDC: | ||||
| 		if (!idef) | ||||
| 			break;		/* used but not defined */ | ||||
| 		if (idef->id_class == EVDF || idef->id_class == LVDF) { | ||||
| 			report("%L: function %s declared as variable at %L", | ||||
| 				id, id->id_name, idef); | ||||
| 			break; | ||||
| 		} | ||||
| 		if (!type_equal(id->id_type, idef->id_type)) { | ||||
| 			report("%L: function value of %s declared differently at %L", | ||||
| 				id, id->id_name, idef); | ||||
| 		} | ||||
| 		break; | ||||
| 	case FC: | ||||
| 		if (!idef) { | ||||
| 			if (!options['u']) { | ||||
| 				report("%L: function %s used but not defined", | ||||
| 					id, id->id_name); | ||||
| 			} | ||||
| 			discard_defs(); | ||||
| 			break; | ||||
| 		} | ||||
| 		idef->id_called = 1; | ||||
| 		check_args(id, idef); | ||||
| 		if (id->id_returns == USED && !idef->id_returns) { | ||||
| 		get_dot(); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	def->id_called = 1; | ||||
| 
 | ||||
| 	if (def->id_args) { | ||||
| 		check_args(dot, def); | ||||
| 		if (dot->id_valused == USED && !def->id_valreturned) { | ||||
| 			report("%L: value of %s is used, but none is returned at %L", | ||||
| 				id, id->id_name, idef); | ||||
| 		} | ||||
| 		switch (id->id_returns) { | ||||
| 		case USED: | ||||
| 			idef->id_used = 1; | ||||
| 			break; | ||||
| 		case IGNORED: | ||||
| 			idef->id_ignored = 1; | ||||
| 			break; | ||||
| 		case VOIDED: | ||||
| 			idef->id_voided = 1; | ||||
| 			break; | ||||
| 		default: | ||||
| 			panic("invalid id->id_returns in check"); | ||||
| 				dot, dot->id_name, def); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	switch (dot->id_valused) { | ||||
| 	case USED: | ||||
| 		def->id_used = 1; | ||||
| 		break; | ||||
| 	case VU: | ||||
| 		if (!idef) { | ||||
| 			if (!options['u']) { | ||||
| 				report("%L: variable %s used but not defined", | ||||
| 					id, id->id_name); | ||||
| 			} | ||||
| 			discard_defs(); | ||||
| 			break; | ||||
| 		} | ||||
| 		idef->id_called = 1; | ||||
| 	case IGNORED: | ||||
| 		def->id_ignored = 1; | ||||
| 		break; | ||||
| 	case EFDF: | ||||
| 	case SFDF: | ||||
| 	case EVDF: | ||||
| 	case SVDF: | ||||
| 	case LFDF: | ||||
| 	case LVDF: | ||||
| 		panic("check() called for a definition"); | ||||
| 	case VOIDED: | ||||
| 		def->id_voided = 1; | ||||
| 		break; | ||||
| 	default: | ||||
| 		panic("invalid class (%c) in check", id->id_class); | ||||
| 		panic("invalid dot->id_valused in check"); | ||||
| 		break; | ||||
| 	} | ||||
| 
 | ||||
| 	get_dot(); | ||||
| } | ||||
| 
 | ||||
| discard_defs() | ||||
| one_var_usage(def) | ||||
| 	struct inpdef *def; | ||||
| { | ||||
| /* Read until a definition having another name */ | ||||
| 	if (!def) { | ||||
| 		if (!options['u']) { | ||||
| 			report("%L: variable %s used but not defined", | ||||
| 				dot, dot->id_name); | ||||
| 		} | ||||
| 		get_dot(); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	struct inpdef *id; | ||||
| 	def->id_called = 1; | ||||
| 
 | ||||
| 	while (dot_id && same_name()) { | ||||
| 		id = id_read(); | ||||
| 		free_inpdef(id); | ||||
| 	get_dot(); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /******** S T A T I C ********/ | ||||
| 
 | ||||
| statics() | ||||
| { | ||||
| 	while (same_name() && dot->id_statnr != 0) { | ||||
| 		one_static(dot->id_statnr); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| check_args(id, idef) | ||||
| 	struct inpdef *id, *idef; | ||||
| one_static(stnr) | ||||
| 	int stnr; | ||||
| { | ||||
| 	while (same_obj(stnr)) { | ||||
| 		if (sta) { | ||||
| 			free_inpdef(sta); | ||||
| 			sta = 0; | ||||
| 		} | ||||
| 		stat_def(stnr); | ||||
| 		usage(stnr); | ||||
| 		if (sta) | ||||
| 			check_def(sta); | ||||
| 		get_dot(); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| stat_def(stnr) | ||||
| 	int stnr; | ||||
| { | ||||
| 	if (same_obj(stnr) && is_class(dot, CL_STAT|CL_DEF)) { | ||||
| 		if (lib) { | ||||
| 			report("%L: %s also defined in library %L", | ||||
| 				dot, dot->id_name, lib); | ||||
| 		} | ||||
| 		if (ext) { | ||||
| 			report("%L: %s also %s at %L", | ||||
| 				dot, dot->id_name, defdec(ext), ext); | ||||
| 		} | ||||
| 		sta = dot; | ||||
| 		dot = new_inpdef(); | ||||
| 		get_dot(); | ||||
| 	} | ||||
| 
 | ||||
| 	while (same_obj(stnr) && is_class(dot, CL_STAT|CL_DEF)) { | ||||
| 		report("%L: %s also defined at %L", | ||||
| 			dot, dot->id_name, sta); | ||||
| 		get_dot(); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| check_def(def) | ||||
| 	struct inpdef *def; | ||||
| { | ||||
| 	if (!def) | ||||
| 		return; | ||||
| 
 | ||||
| 	if (!def->id_called) { | ||||
| 		if (streq(def->id_name, "main")) { | ||||
| 			/* silent */ | ||||
| 		} | ||||
| 		else if (ext && is_class(ext, CL_LIB)) { | ||||
| 			/* silent */ | ||||
| 		} | ||||
| 		else { | ||||
| 			if (!options['u']) { | ||||
| 				report("%L: %s %s but never used", | ||||
| 					def, def->id_name, defdec(def)); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (is_class(def, CL_DEF|CL_FUNC)) { | ||||
| 		if (def->id_valreturned && def->id_called && def->id_ignored) { | ||||
| 			report("%L: %s returns value which is %s ignored", | ||||
| 				def, def->id_name, | ||||
| 				(def->id_used || def->id_voided) ? | ||||
| 						"sometimes" : "always"); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /******** T Y P E   C H E C K I N G ********/ | ||||
| 
 | ||||
| check_args(id, def) | ||||
| 	struct inpdef *id, *def; | ||||
| { | ||||
| 	register char *act_tp = id->id_argtps; | ||||
| 	register char *def_tp = idef->id_argtps; | ||||
| 	register char *def_tp = def->id_argtps; | ||||
| 	register int i; | ||||
| 	register int nrargs;		/* # of args to be type-checked */ | ||||
| 	register int varargs; | ||||
| 
 | ||||
| 	/* determine nrargs */ | ||||
| 	if (idef->id_nrargs < 0) { | ||||
| 	if (def->id_nrargs < 0) { | ||||
| 		varargs = 1; | ||||
| 		nrargs = -idef->id_nrargs - 1; | ||||
| 		nrargs = -def->id_nrargs - 1; | ||||
| 	} | ||||
| 	else { | ||||
| 		varargs = 0; | ||||
| 		nrargs = idef->id_nrargs; | ||||
| 		nrargs = def->id_nrargs; | ||||
| 	} | ||||
| 
 | ||||
| 	/* adjust nrargs, if necessary */ | ||||
| 	if (varargs) { | ||||
| 		if (nrargs > id->id_nrargs) { | ||||
| 			report("%L: number of args to %s differs from %L", | ||||
| 				id, id->id_name, idef); | ||||
| 				id, id->id_name, def); | ||||
| 			nrargs = id->id_nrargs; | ||||
| 		} | ||||
| 	} | ||||
| 	else { | ||||
| 		if (nrargs != id->id_nrargs) { | ||||
| 			report("%L: number of args to %s differs from %L", | ||||
| 				id, id->id_name, idef); | ||||
| 				id, id->id_name, def); | ||||
| 			nrargs = min(nrargs, id->id_nrargs); | ||||
| 		} | ||||
| 	} | ||||
|  | @ -346,19 +403,27 @@ check_args(id, idef) | |||
| 
 | ||||
| 		if (!type_match(act, def)) { | ||||
| 			report("%L: arg %d of %s differs from that at %L", | ||||
| 				id, i, id->id_name, idef); | ||||
| 				id, i, id->id_name, def); | ||||
| 		} | ||||
| 		*act_tp++ = ':'; | ||||
| 		*def_tp++ = ':'; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| int | ||||
| type_equal(act, def) | ||||
| 	char *act, *def; | ||||
| { | ||||
| 	return streq(act, def); | ||||
| } | ||||
| 
 | ||||
| int | ||||
| type_match(act, def) | ||||
| 	char *act, *def; | ||||
| { | ||||
| 	if (type_equal(act, def)) | ||||
| 		return 1; | ||||
| 
 | ||||
| 	if (act[0] == '+') { | ||||
| 		/* a non-negative constant */ | ||||
| 		/* might be signed or unsigned */ | ||||
|  | @ -373,181 +438,22 @@ type_match(act, def) | |||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| check_usage() | ||||
| { | ||||
| /* Checks if the defined function or variable is used.
 | ||||
|  * There can be several static definitions. | ||||
|  */ | ||||
| 
 | ||||
| 	struct inpdef *sd = static_def; | ||||
| /******** D E B U G G I N G ********/ | ||||
| 
 | ||||
| 	if (ext_def) | ||||
| 		check_def(ext_def); | ||||
| 	while (sd) { | ||||
| 		check_def(sd); | ||||
| 		sd = sd->next; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| check_def(id) | ||||
| 	struct inpdef *id; | ||||
| { | ||||
| 	if (!id->id_called) { | ||||
| 		if (streq(id->id_name, "main")) { | ||||
| 			/* silent */ | ||||
| 		} | ||||
| 		else if (ext_def && is_lib_class(ext_def->id_class)) { | ||||
| 			/* silent */ | ||||
| 		} | ||||
| 		else { | ||||
| 			if (!options['u']) { | ||||
| 				report("%L: %s defined but never used", | ||||
| 					id, id->id_name); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (is_fundef_class(id->id_class)) { | ||||
| 		if (id->id_returns && id->id_called && id->id_ignored) { | ||||
| 			report("%L: %s returns value which is %s ignored", | ||||
| 				id, id->id_name, | ||||
| 				(id->id_used || id->id_voided) ? | ||||
| 						"sometimes" : "always"); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static_in_list(id) | ||||
| 	struct inpdef *id; | ||||
| { | ||||
| /* Put id in the list of static definitions.
 | ||||
|  * static_def points to the first element. | ||||
|  */ | ||||
| 	id->next = static_def; | ||||
| 	static_def = id; | ||||
| } | ||||
| 
 | ||||
| struct inpdef * | ||||
| definition(id) | ||||
| 	struct inpdef *id; | ||||
| { | ||||
| /* If there is a static definition that comes from the same file, a pointer
 | ||||
|  * to this definition will be returned. | ||||
|  * Otherwise a pointer to the ext_def is returned (which may be null). | ||||
|  */ | ||||
| 	struct inpdef *sd = static_def; | ||||
| 
 | ||||
| 	while (sd) { | ||||
| 		if (id->id_statnr == sd->id_statnr) | ||||
| 			return (sd); | ||||
| 		sd = sd->next; | ||||
| 	} | ||||
| 	return (ext_def); | ||||
| } | ||||
| 
 | ||||
| free_defs() | ||||
| { | ||||
| /* Dispose the external definition and the static definitions. */ | ||||
| 	struct inpdef *sd; | ||||
| 
 | ||||
| 	if (ext_def) { | ||||
| 		free_inpdef(ext_def); | ||||
| 		ext_def = 0; | ||||
| 	} | ||||
| 	while (static_def) { | ||||
| 		sd = static_def; | ||||
| 		static_def = static_def->next; | ||||
| 		free_inpdef(sd); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /* VARARGS */ | ||||
| report(va_alist) | ||||
| 	va_dcl | ||||
| { | ||||
| 	va_list ap; | ||||
| 
 | ||||
| 	va_start(ap); | ||||
| 	{ | ||||
| 		char *fmt = va_arg(ap, char*); | ||||
| 		register char *f = fmt; | ||||
| 		register char fc; | ||||
| 
 | ||||
| 		/*	First see if the first arg is an inpdef with
 | ||||
| 			a global file name; if so, skip this message. | ||||
| 		*/ | ||||
| 		if (f[0] == '%' && f[1] == 'L') { | ||||
| 			/* it is an inpdef */ | ||||
| 			register struct inpdef *id = | ||||
| 				va_arg(ap, struct inpdef *); | ||||
| 
 | ||||
| 			f += 2; | ||||
| 			/* is the file name global? */ | ||||
| 			if (id->id_file[0] == '/') | ||||
| 				return; | ||||
| 			/*	if no, we have used up the argument,
 | ||||
| 				so print it here | ||||
| 			*/ | ||||
| 			fprint(MSGOUT, "\"%s\", line %d", | ||||
| 				id->id_file, id->id_line); | ||||
| 		} | ||||
| 		while ((fc = *f++)) { | ||||
| 			if (fc == '%') { | ||||
| 				switch (*f++) { | ||||
| 					register struct inpdef *id; | ||||
| 					register char *s; | ||||
| 					register int i; | ||||
| 				case 'L':	/* a location item */ | ||||
| 					id = va_arg(ap, struct inpdef *); | ||||
| 					fprint(MSGOUT, "\"%s\", line %d", | ||||
| 						id->id_file, id->id_line); | ||||
| 					break; | ||||
| 				case 's':	/* a string item */ | ||||
| 					s = va_arg(ap, char *); | ||||
| 					fprint(MSGOUT, "%s", s); | ||||
| 					break; | ||||
| 				case 'd':	/* an int item */ | ||||
| 					i = va_arg(ap, int); | ||||
| 					fprint(MSGOUT, "%d", i); | ||||
| 					break; | ||||
| 				default: | ||||
| 					panic("bad format %s", fmt); | ||||
| 					break; | ||||
| 				} | ||||
| 			} | ||||
| 			else { | ||||
| 				fprint(MSGOUT, "%c", fc); | ||||
| 			} | ||||
| 		} | ||||
| 		fprint(MSGOUT, "\n"); | ||||
| 	} | ||||
| 	va_end(ap); | ||||
| } | ||||
| 
 | ||||
| /* VARARGS1 */ | ||||
| panic(fmt, args) | ||||
| 	char *fmt; | ||||
| { | ||||
| 	fprint(ERROUT, "PANIC, lint, pass2: "); | ||||
| 	doprnt(ERROUT, fmt, &args); | ||||
| 	fprint(ERROUT, "\n"); | ||||
| 	exit(1); | ||||
| } | ||||
| 
 | ||||
| /* for DEBUGGING */ | ||||
| print_id(id) | ||||
| 	struct inpdef *id; | ||||
| { | ||||
| 	print("inpdef: %s, %s, %04d, \"%s\", %d, %d, %s, %d, %s\n", | ||||
| 		id->id_class == EFDF ? "EFDF" : | ||||
| 		id->id_class == SFDF ? "SFDF" : | ||||
| 		id->id_class == EVDF ? "EVDF" : | ||||
| 		id->id_class == SVDF ? "SVDF" : | ||||
| 	print("inpdef: %s, %s, %04d, \"%s\", %d, %s", | ||||
| 		id->id_class == LFDF ? "LFDF" : | ||||
| 		id->id_class == LVDF ? "LVDF" : | ||||
| 		id->id_class == EFDF ? "EFDF" : | ||||
| 		id->id_class == EVDF ? "EVDF" : | ||||
| 		id->id_class == EFDC ? "EFDC" : | ||||
| 		id->id_class == EVDC ? "EVDC" : | ||||
| 		id->id_class == IFDC ? "IFDC" : | ||||
| 		id->id_class == SFDF ? "SFDF" : | ||||
| 		id->id_class == SVDF ? "SVDF" : | ||||
| 		id->id_class == FC ? "FC" : | ||||
| 		id->id_class == VU ? "VU" : | ||||
| 		id->id_class == ERRCL ? "ERRCL" : "<BADCLASS>", | ||||
|  | @ -555,9 +461,21 @@ print_id(id) | |||
| 		id->id_statnr, | ||||
| 		id->id_file, | ||||
| 		id->id_line, | ||||
| 		id->id_nrargs, | ||||
| 		((id->id_nrargs == 0) ? "" : id->id_argtps), | ||||
| 		id->id_returns, | ||||
| 		id->id_type); | ||||
| 		id->id_type | ||||
| 	); | ||||
| 	if (is_class(id, CL_FUNC|CL_DEF) || is_class(id, CL_FUNC|CL_USAGE)) { | ||||
| 		print(", %d, %s, %s", | ||||
| 			id->id_nrargs, | ||||
| 			id->id_nrargs == 0 ? "" : id->id_argtps, | ||||
| 			id->id_class == FC ? | ||||
| 				(id->id_valused == USED ? "USED" : | ||||
| 				id->id_valused == IGNORED ? "IGNORED" : | ||||
| 				id->id_valused == VOIDED ? "VOIDED" : | ||||
| 				"<BAD VALUSED>") | ||||
| 			:	(id->id_valreturned ? "VALRETURNED" : | ||||
| 				"NOVALRETURNED") | ||||
| 		); | ||||
| 	} | ||||
| 	print("\n"); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,12 +1,13 @@ | |||
| #include "../lpass1/l_class.h" | ||||
| #include "inpdef.h" | ||||
| #include	"../lpass1/l_class.h" | ||||
| #include	"class.h" | ||||
| #include	"inpdef.h" | ||||
| 
 | ||||
| #include <ctype.h> | ||||
| #include	<ctype.h> | ||||
| 
 | ||||
| #define	INP_NPUSHBACK 2 | ||||
| 
 | ||||
| #include <inp_pkg.spec> | ||||
| #include <inp_pkg.body> | ||||
| #include	<inp_pkg.spec> | ||||
| #include	<inp_pkg.body> | ||||
| 
 | ||||
| PRIVATE int LineNr = 1; | ||||
| 
 | ||||
|  | @ -25,37 +26,49 @@ int | |||
| get_id(id) | ||||
| 	struct inpdef *id; | ||||
| { | ||||
| /* A low-level function which just reads a definition */ | ||||
| 	/* A low-level function which just reads a definition */ | ||||
| 
 | ||||
| 	if (!ReadString(id->id_name, ':', NAMESIZE)) | ||||
| 		return 0; | ||||
| 	if (!ReadInt(&id->id_statnr)) | ||||
| 		return 0; | ||||
| 	SkipChar(':'); | ||||
| 
 | ||||
| 	loadchar(id->id_class); | ||||
| 	if (id->id_class == EOI) | ||||
| 		return 0; | ||||
| 	SkipChar(':'); | ||||
| 	switch (id->id_class) { | ||||
| 	case EFDF: | ||||
| 	case SFDF: | ||||
| 	case LFDF: | ||||
| 	case FC: | ||||
| 
 | ||||
| 	if (is_class(id, CL_FUNC|CL_DEF) || is_class(id, CL_FUNC|CL_USAGE)) { | ||||
| 		/* read the argument information */ | ||||
| 		id->id_args = 1; | ||||
| 		if (!ReadInt(&id->id_nrargs)) | ||||
| 			return 0; | ||||
| 		SkipChar(':'); | ||||
| 		if (!ReadArgs(id->id_nrargs, id->id_argtps)) | ||||
| 			return 0; | ||||
| 		if (!ReadInt(&id->id_returns)) | ||||
| 			return 0; | ||||
| 		if (id->id_class == FC) { | ||||
| 			/* function call */ | ||||
| 			if (!ReadInt(&id->id_valused)) | ||||
| 				return 0; | ||||
| 		} | ||||
| 		else { | ||||
| 			/* function definition */ | ||||
| 			if (!ReadInt(&id->id_valreturned)) | ||||
| 				return 0; | ||||
| 		} | ||||
| 		SkipChar(':'); | ||||
| 		break; | ||||
| 	} | ||||
| 	else { | ||||
| 		id->id_args = 0; | ||||
| 	} | ||||
| 
 | ||||
| 	if (!ReadString(id->id_type, ':', TYPESIZE)) | ||||
| 		return 0; | ||||
| 	if (!ReadInt(&id->id_line)) | ||||
| 		return 0; | ||||
| 	SkipChar(':'); | ||||
| 
 | ||||
| 	if (!ReadString(id->id_file, '\n', FNAMESIZE)) | ||||
| 		return 0; | ||||
| 	{	extern char options[]; | ||||
|  | @ -69,14 +82,16 @@ PRIVATE int | |||
| ReadString(buf, delim, maxsize) | ||||
| 	char *buf; | ||||
| { | ||||
| /* Reads a string until 'delim' is encountered.
 | ||||
|  * Delim is discarded. | ||||
|  * If 'maxsize-1' is exceeded, "string too long" is written by panic(). | ||||
|  * A '\0' is appended to the string. | ||||
|  * At EOI 0 is returned, else the length of the string (including | ||||
|  * the appended '\0') is returned. | ||||
|  */ | ||||
| 	int ch; | ||||
| 	/*	Reads a string until 'delim' is encountered.
 | ||||
| 		Delim is discarded. | ||||
| 		If 'maxsize-1' is exceeded, "string too long" is written | ||||
| 		by panic(). | ||||
| 		A '\0' is appended to the string. | ||||
| 		At EOI 0 is returned, else the length of the string (including | ||||
| 		the appended '\0') is returned. | ||||
| 	*/ | ||||
| 
 | ||||
| 	int ch = 0; | ||||
| 	int nread = 0; | ||||
| 
 | ||||
| 	while (nread < maxsize - 1) { | ||||
|  | @ -87,11 +102,11 @@ ReadString(buf, delim, maxsize) | |||
| 			break; | ||||
| 		buf[nread++] = (char)ch; | ||||
| 	} | ||||
| 	buf[nread++] = '\0'; | ||||
| 	if (ch != delim) { | ||||
| 		panic("line %d: string too long: %s", LineNr, buf); | ||||
| 		/*NOTREACHED*/ | ||||
| 	} | ||||
| 	buf[nread++] = '\0'; | ||||
| 	return (nread); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										81
									
								
								lang/cem/lint/lpass2/report.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								lang/cem/lint/lpass2/report.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,81 @@ | |||
| #include	<varargs.h> | ||||
| 
 | ||||
| #include	<system.h> | ||||
| #include	"inpdef.h" | ||||
| 
 | ||||
| #define	MSGOUT		STDERR	/* filedes on which to write the messages */ | ||||
| #define	ERROUT		STDERR	/* filedes on which to write the panics */ | ||||
| 
 | ||||
| /* VARARGS */ | ||||
| report(va_alist) | ||||
| 	va_dcl | ||||
| { | ||||
| 	va_list ap; | ||||
| 
 | ||||
| 	va_start(ap); | ||||
| 	{ | ||||
| 		char *fmt = va_arg(ap, char*); | ||||
| 		register char *f = fmt; | ||||
| 		register char fc; | ||||
| 
 | ||||
| 		/*	First see if the first arg is an inpdef with
 | ||||
| 			a global file name; if so, skip this message. | ||||
| 		*/ | ||||
| 		if (f[0] == '%' && f[1] == 'L') { | ||||
| 			/* it is an inpdef */ | ||||
| 			register struct inpdef *id = | ||||
| 				va_arg(ap, struct inpdef *); | ||||
| 
 | ||||
| 			f += 2; | ||||
| 			/* is the file name global? */ | ||||
| 			if (id->id_file[0] == '/') | ||||
| 				return; | ||||
| 			/*	if no, we have used up the argument,
 | ||||
| 				so print it here | ||||
| 			*/ | ||||
| 			fprint(MSGOUT, "\"%s\", line %d", | ||||
| 				id->id_file, id->id_line); | ||||
| 		} | ||||
| 		while ((fc = *f++)) { | ||||
| 			if (fc == '%') { | ||||
| 				switch (*f++) { | ||||
| 					register struct inpdef *id; | ||||
| 					register char *s; | ||||
| 					register int i; | ||||
| 				case 'L':	/* a location item */ | ||||
| 					id = va_arg(ap, struct inpdef *); | ||||
| 					fprint(MSGOUT, "\"%s\", line %d", | ||||
| 						id->id_file, id->id_line); | ||||
| 					break; | ||||
| 				case 's':	/* a string item */ | ||||
| 					s = va_arg(ap, char *); | ||||
| 					fprint(MSGOUT, "%s", s); | ||||
| 					break; | ||||
| 				case 'd':	/* an int item */ | ||||
| 					i = va_arg(ap, int); | ||||
| 					fprint(MSGOUT, "%d", i); | ||||
| 					break; | ||||
| 				default: | ||||
| 					panic("bad format %s", fmt); | ||||
| 					break; | ||||
| 				} | ||||
| 			} | ||||
| 			else { | ||||
| 				fprint(MSGOUT, "%c", fc); | ||||
| 			} | ||||
| 		} | ||||
| 		fprint(MSGOUT, "\n"); | ||||
| 	} | ||||
| 	va_end(ap); | ||||
| } | ||||
| 
 | ||||
| /* VARARGS1 */ | ||||
| panic(fmt, args) | ||||
| 	char *fmt; | ||||
| { | ||||
| 	fprint(ERROUT, "PANIC, lint, pass2: "); | ||||
| 	doprnt(ERROUT, fmt, &args); | ||||
| 	fprint(ERROUT, "\n"); | ||||
| 	exit(1); | ||||
| } | ||||
| 
 | ||||
		Loading…
	
	Add table
		
		Reference in a new issue