make depend (part 2 of 3)

Kim Walden kim at enea.UUCP
Thu Apr 11 05:00:40 AEST 1985


#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here-----
#!/bin/sh
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	tool
# This archive created: Wed Apr 10 14:06:20 1985
mkdir tool
chdir tool
sed 's/^XX//' << \SHAR_EOF > READ_ME
XX*******************************************************************
XX**                                                               **
XX**  This distribution implements the algorithm described in      **
XX**                                                               **
XX**      K. Walden, "Automatic Generation of Make Dependencies",  **
XX**      Softw. Practice & Exper., vol. 14, no. 6, June 1984      **
XX**                                                               **
XX**  Copyright (c) 1983  Kim Walden                               **
XX**      ENEA DATA, Sweden and                                    **
XX**      SYSLAB, Department of Computer Science,                  **
XX**      University of Stockholm, Sweden.                         **
XX**                                                               **
XX**  The software may be used and copied freely,                  **
XX**      provided that proper credit is given to the originator   **
XX**      by including this text label in each copy.               **
XX**                                                               **
XX*******************************************************************
XX
XX
XX
XXSOURCES			FUNCTION
XX
XXMakefile		Make script to build the programs.
XXmakedep.c		Main program for extracting include statements
XX			and pipe them to makenorm and depend.
XXmakenorm.y		Include statement normalizer.
XXnormscan.l		Scanner for the normalizer.
XXdepend.y		Main dependency generator.
XXdepscan.l		Scanner for the dependency generator.
XXmpath.c			File name path reduction routine.
XXerror.c			Error handling routine.
XX
XXman			Manuals subdirectory
XXtest			Subdirectory structure with test files.
XX
XX
XX
XX
XXThe programs should be built invoking the Makefile, and the tool
XXdirectory added to the command search path, so the programs can be
XXfound when running the test below.
XX
XXWhen make is invoked on the test directory test/proc, the test
XXexample in the above SP & E paper is run, and the output should be
XXthe same as the contents of the file Dep.mk.
XX
XXMakedep and makenorm extract and normalize include statements that
XXare directed to the C preprocessor.
XXThese programs must be modified if include statements of other
XXlanguages are to be handled, unless the include syntax and semantics
XXhappen to be the same, while depend can be used unchanged.
XX
XXA general recommendation for Berkeley UNIX users is to get hold of
XXthe augmented version of make available under AT & T System III/V,
XXwhich has an include facility.
XXAll generated dependencies can then be put in a separate file,
XXwhich is made part of the ordinary make dependency graph.
XX
XXPorting the augmented make to run under Berkeley UNIX is not very
XXdifficult, and mostly has to do with different formats of archive
XXfiles.
SHAR_EOF
if test 2713 -ne "`wc -c READ_ME`"
then
echo shar: error transmitting READ_ME '(should have been 2713 characters)'
fi
sed 's/^XX//' << \SHAR_EOF > Makefile
XXCFLAGS= -O -s
XX
XXOBJ1= mpath.o 
XXOBJ2= error.o
XX
XXall: makedep makenorm depend 
XX
XXmakedep: makedep.o $(OBJ2)
XX	$(CC) $(CFLAGS) $@.o $(OBJ2) -o $@
XX
XXmakenorm: makenorm.o $(OBJ1) $(OBJ2)
XX	$(CC) $(CFLAGS) $@.o $(OBJ1) $(OBJ2) -ll -o $@
XX
XXdepend: depend.o $(OBJ2)
XX	$(CC) $(CFLAGS) $@.o $(OBJ2) -ll -o $@
XX
XXmakenorm.o: normscan.c
XXdepend.o: depscan.c
XX
XXclean:
XX	rm *.o
XX	rm makedep
XX	rm makenorm makenorm.c normscan.c
XX	rm depend depend.c depscan.c
XX	rm man/*.man
XX
XX.y.o:
XX	$(YACC) $(YFLAGS) $<
XX	@mv -f y.tab.c $*.c
XX	$(CC) $(CFLAGS) -c $*.c
XX
XX.y.c:
XX	$(YACC) $(YFLAGS) $<
XX	@mv -f y.tab.c $@
XX
XX.l.o:
XX	$(LEX) $(LFLAGS) $<
XX	@mv -f lex.yy.c $*.c
XX	$(CC) $(CFLAGS) -c $*.c
XX
XX.l.c:
XX	$(LEX) $(LFLAGS) $<
XX	@mv -f lex.yy.c $@
SHAR_EOF
if test 688 -ne "`wc -c Makefile`"
then
echo shar: error transmitting Makefile '(should have been 688 characters)'
fi
sed 's/^XX//' << \SHAR_EOF > depend.y
XX%{
XX/* -- Make include dependency generator
XX *
XX * $File: depend.y  1.13  1985-03-29  14:06:29 $
XX *
XX *  Copyright (c) 1983  Kim Walden
XX *      ENEA DATA, Sweden and    
XX *      SYSLAB, Department of Computer Science,
XX *      University of Stockholm, Sweden.
XX *
XX *	This software may be used and copied freely,
XX *	provided that proper credit is given to the originator
XX *	by including the above text in each copy.
XX *
XX *	Descr:	This program implements part of the algorithm described in
XX *      	K. Walden, "Automatic Generation of Make Dependencies",
XX *      	Softw. Practice & Exper., vol. 14, no. 6, June 1984 
XX *
XX * $Log:	depend.y,v $
XX * 
XX * Revision 1.13  1985-03-29  14:06:29  kim
XX * New source format
XX * 
XX * Revision 1.12  1985-03-08  01:16:37  kim
XX * Added support for parallell transfer rules.
XX * Added -1 option to makedep and depend.
XX * 
XX * Revision 1.11  1985-02-25  19:40:21  kim
XX * Path reduction moved to earlier stage
XX * 
XX * Revision 1.10  1985-02-19  11:19:59  kim
XX * New default include rules
XX * 
XX * Revision 1.9  1985-02-18  14:23:55  kim
XX * New error handling
XX * 
XX * Revision 1.8  1985-02-14  13:59:52  kim
XX * Changed rules options to -r/-R
XX * 
XX * Revision 1.7  1985-02-14  01:53:19  kim
XX * Converted to RCS format
XX * 
XX * Revision 1.4  1983-10-06  19:50:16  kim
XX * Allow empty include line input
XX * 
XX * Revision 1.3  1983-07-20  19:50:00  kim
XX * Closer to algorithm in SYSLAB Report No. 19 (June 1983)
XX * 
XX * Revision 1.2  1983-02-22  19:49:51  kim
XX * First version with include rules
XX * 
XX * Revision 1.1  1982-12-15  19:49:47  kim
XX * Initial revision
XX */
XX%}
XX
XX%token SPACE RULSEP INCSEP PATH SUFF
XX%{
XX# define PREF    struct pref
XX# define SUF     struct suf
XX# define INCFILE struct incfile
XX# define LHSFILE struct lhsfile
XX# define NAME    struct filename
XX# define OUTSIZ  10
XX# define PATHSIZ 100
XX# define DIRSIZ  14
XX# define LINSIZ  256
XX# define PHASHL  503
XX# define LINE	 80
XX# define INCLUDED  1
XX# define CNULL '\0'
XX# define KOL ':'
XX# define EQU '='
XX# define RULES	 ".o: .c .p .f; .c= .y .l .q; .h= .y"
XX
XX# include <stdio.h>
XX# include <strings.h>
XX
XXstatic char usage[]= "Usage: depend [-1] [-rfile] [-Rrules]";
XX
XX/* File name prefixes
XX */
XXPREF
XX{	
XX	PREF	*	nexthash;
XX	char		path[PATHSIZ+1];
XX};
XX
XX/* File name suffixes:
XX *
XX * If the suffix occurs in the rhs of a rule,
XX * the output file suffix and rule type
XX * (KOL or EQU) is recorded.
XX */
XXSUF
XX{
XX	SUF	*	next,
XX		*	out[OUTSIZ];
XX	char		name[DIRSIZ+1];
XX	int		top,
XX			rule;
XX};
XX
XX/* List of files included by a given file.
XX */
XXINCFILE
XX{
XX	INCFILE	*	next;
XX	PREF	*	pf;
XX	SUF	*	sf;
XX};
XX
XX/* A node for each file found in the lhs of some include statement.
XX * The transfer rules are successively applied to the suffix
XX * before the file is inserted.
XX * Reference to list of included files.
XX */
XXLHSFILE
XX{
XX	LHSFILE	*	next;
XX	PREF	*	pf;
XX	SUF	*	sf;
XX	INCFILE	*	ic;
XX	int		state;
XX};
XX
XXNAME
XX{
XX	PREF	*	pf;
XX	SUF	*	sf;
XX};
XX
XXstruct
XX{
XX	SUF	*	sf;
XX	LHSFILE *	lf;
XX} first;
XX
XX
XXextern char	*	calloc();
XXvoid			yyerror();
XX
XXstatic NAME		getname(),
XX			lhs,
XX			rhs;
XXstatic LHSFILE	*	nodelf(),
XX		*	thislf;
XXstatic PREF	*	nodepf(),
XX		*	phash[PHASHL];
XXstatic SUF	*	nodesf(),
XX		*	lsuf,
XX		*	rsuf;
XXstatic char	*	alloc(),
XX		*	rulstring,
XX		*	yystring;
XXstatic char		line[LINSIZ];
XXstatic void		printdep(),
XX			copyinc(),
XX			nodeic();
XXstatic int		hash(),
XX			lineno,
XX			rule,
XX			onedep;
XX
XX# include "depscan.c"
XX
XXmain(argc, argv)
XX	int		argc;
XX	char	*	argv[];
XX{
XX	char		rulbuf[LINSIZ];
XX
XX	setprogname(argv[0]);
XX	rulstring = rulbuf;
XX	strcpy(rulbuf, RULES);
XX
XX	while (argc > 1 && argv[1][0] == '-')
XX	{
XX		switch (argv[1][1])
XX		{
XX		 case 'r':
XX			strcat(rulbuf, "; ");
XX			strcat(rulbuf, argv[1]+2);
XX			break;
XX
XX		 case 'R':
XX			rulstring = argv[1]+2;
XX			break;
XX
XX		 case '1':
XX			onedep++;
XX			break;
XX
XX		 default:
XX			fatal("unknown option %s", argv[1]);
XX		}
XX
XX		argv++;
XX		argc--;
XX	}
XX
XX	if (argc != 1)
XX		fatalmesg(usage);
XX
XX	yystring = rulstring;
XX	BEGIN rules;
XX
XX	first.lf = NULL;
XX	yyparse();
XX	if (first.lf)
XX		printdep();
XX	exit(0);
XX}
XX%}
XX
XX%%
XX
XXaccept	:	rules includes
XX	;
XXrules	:	rule
XX	|	RULSEP rules
XX	|	rules RULSEP
XX	|	rules RULSEP rule
XX	;
XXrule	:	':' SPACE
XX			{   /* Lhs of inclusion rule, empty output suffix */
XX				lsuf = nodesf("");
XX				rule = KOL;
XX			}
XX		rhssuf
XX	|	lhssuf ':' SPACE
XX			{   /* Lhs of inclusion rule */
XX				rule = KOL;
XX			}
XX		rhssuf
XX	|	lhssuf '=' SPACE
XX			{   /* Lhs of transfer rule */
XX				rule = EQU;
XX			}
XX		rhssuf
XX	|	rule SPACE rhssuf
XX	;
XXlhssuf	:	SUFF
XX			{   /* Lhs of any rule */
XX				lsuf = nodesf(yytext);
XX			}
XX	;
XXrhssuf	:	SUFF
XX			{   /* Rhs of any rule */
XX				rsuf = nodesf(yytext);
XX				if (rsuf->rule && (rsuf->rule != EQU || rule != EQU))
XX				        fatal("ambiguous rules %s", rulstring);
XX				rsuf->rule = rule;
XX				if (rsuf->top >= OUTSIZ)
XX					fatal("to many parallel transfers %s", rulstring);
XX				rsuf->out[rsuf->top++] = lsuf;
XX			}
XX	;
XXincludes:
XX	|	includes INCSEP
XX	|	includes INCSEP include
XX	;
XXinclude	:	PATH
XX			{   /* Lhs of include statement:
XX			     *      Insert in lhsfile list.
XX			     */
XX				lhs = getname(yytext);
XX				thislf = nodelf(lhs.pf, lhs.sf);
XX			}
XX		SPACE '<' SPACE
XX		PATH
XX			{   /* Rhs of include statement:
XX			     *      Append to include list of lhsfile.
XX			     */
XX				rhs = getname(yytext);
XX				nodeic(thislf, rhs.pf, rhs.sf);
XX			}
XX	;
XX
XX%%
XX
XXvoid
XXyyerror(s)
XX	char	*	s;
XX{
XX	if (yystring)
XX		fatal("%s rules: %s", s, rulstring);
XX	else
XX		fatal("%s near line %d: %s", s, lineno, line);
XX}
XX
XX/* Go through lhsfile list and print implied Make dependencies.
XX */
XXstatic void
XXprintdep()
XX{
XX	LHSFILE	*	lf,
XX		*	lf2;
XX	SUF	*	sf;
XX	INCFILE	*	ic;
XX	int		i;
XX
XX    /* Apply transfer rules to the LHS suffixes.
XX     * If there are more than one output suffix,
XX     * make a new LHS node with a copy of the include list for each of them.
XX     *
XX     * Since the new nodes are inserted at the end of the LHS list,
XX     * they will be dealt with again, later in the for-loop.
XX     */
XX	for (lf = first.lf; lf; lf = lf->next)
XX		while (lf->sf->rule == EQU)
XX		{
XX			for (i = 1; i < lf->sf->top; i++)
XX				copyinc(lf, nodelf(lf->pf, lf->sf->out[i]));
XX			
XX			lf->sf = lf->sf->out[0];
XX		}
XX
XX    /* Construct Transitive Closure.
XX     */
XX	for (lf = first.lf; lf; lf = lf->next)
XX		for (lf2 = first.lf; lf2; lf2 = lf2->next)
XX			for (ic = lf2->ic; ic; ic = ic->next)
XX				if (ic->pf == lf->pf && ic->sf == lf->sf)
XX				{
XX					lf->state = INCLUDED;
XX					copyinc(lf, lf2);
XX					break;
XX				}
XX
XX    /* For each lhs file, apply inclusion rules
XX     * and generate Make dependencies.
XX     */
XX	for (lf = first.lf; lf; lf = lf->next)
XX	{
XX		char	lhsdep[PATHSIZ+1], rhsdep[PATHSIZ+1];
XX		int	brk = 0;
XX
XX	    /* If the file was included in some other file,
XX	     * no separate output file will be generated for it.
XX	     * The corresponding dependencies have thus already
XX	     * been taken care of.
XX	     */
XX		if (lf->state == INCLUDED)
XX			continue;
XX
XX		sf = lf->sf;
XX
XX	    /* If the file was not included in any other file,
XX	     * and there is no inclusion rule for its suffix,
XX	     * the file is discarded.
XX	     */
XX		if (sf->rule != KOL)
XX			continue;
XX
XX		sprintf(lhsdep, "%s%s", lf->pf->path, sf->out[0]->name); 
XX		sprintf(line, "%s:", lhsdep); 
XX
XX		for (ic = lf->ic; ic; ic = ic->next)
XX		{
XX			sprintf(rhsdep, "%s%s", ic->pf->path, ic->sf->name);
XX
XX			if (strlen(line)+strlen(rhsdep)+1 > LINE || brk)
XX			{
XX				printf("%s\n", line);
XX				sprintf(line, "%s:", lhsdep); 
XX			}
XX			strcat(line, " ");
XX			strcat(line, rhsdep);
XX			brk = onedep;
XX		}
XX		printf("%s\n", line);
XX	}
XX}
XX
XX/* Copy entire include file list.
XX *
XX */
XXstatic void
XXcopyinc(from, to)
XX	LHSFILE *	from,
XX		*	to;
XX{
XX	INCFILE	*	ic;
XX
XX		for (ic = from->ic; ic; ic = ic->next)
XX			nodeic(to, ic->pf, ic->sf);
XX}
XX
XX/* Return file name.  
XX *
XX */
XXstatic NAME
XXgetname(path)
XX	char	*	path;
XX{
XX	NAME		nm;
XX	char	*	p;
XX	int		c;
XX
XX	if (strlen(path) > PATHSIZ)
XX		fatal("path too long: %s", path);
XX
XX	if ((p = rindex(path, '/')) == NULL)
XX		p = path;
XX
XX	if ((p = rindex(p, '.')) == NULL)
XX		p = path + strlen(path);
XX
XX	nm.sf = nodesf(p);
XX	c = *p;
XX	*p = CNULL;
XX	nm.pf = nodepf(path);
XX	*p = c;
XX
XX	return nm;
XX}
XX
XX/* Return suffix node.
XX * If the given suffix was not in the suffix list,
XX * allocate a new node.
XX */
XXstatic SUF *
XXnodesf(name)
XX	char	*	name;
XX{
XX	SUF	*	node,
XX		*	prev;
XX
XX	for (prev = node = first.sf; node; prev = node, node = node->next)
XX		if (strcmp(name, node->name) == 0)
XX			return node;
XX
XX	node = (SUF *) alloc(sizeof(SUF), name);
XX	strcpy(node->name, name);
XX
XX	if (prev)
XX		prev->next = node;
XX	else
XX		first.sf = node;
XX
XX	return node;
XX}
XX
XX/* Return prefix node.
XX * If the given (reduced) path was not in the prefix list,
XX * allocate a new node.
XX */
XXstatic PREF *
XXnodepf(path)
XX	char	*	path;
XX{
XX	PREF	*	node,
XX		*	prevhash;
XX	int		h;
XX
XX	h = hash(path, PHASHL);
XX
XX	for (node = phash[h]; node; node = node->nexthash)
XX		if (strcmp(path, node->path) == 0)
XX			return node;
XX		else
XX			prevhash = node;
XX
XX	node = (PREF *) alloc(sizeof(PREF), path);
XX	strcpy(node->path, path);
XX
XX	if (phash[h])
XX		prevhash->nexthash = node;
XX	else
XX		phash[h] = node;
XX
XX	return node;
XX}
XX
XX/* Return lhsfile node.
XX * If the given lhsfile was not in the lhsfile list,
XX * allocate a new node.
XX */
XXstatic LHSFILE *
XXnodelf(pf, sf)
XX	PREF	*	pf;
XX	SUF	*	sf;
XX{
XX	LHSFILE *	node,
XX		*	prev;
XX
XX	for (prev = node = first.lf; node; prev = node, node = node->next)
XX		if (node->pf == pf && node->sf == sf)
XX			return node;
XX
XX	node = (LHSFILE *) alloc(sizeof(LHSFILE), line);
XX
XX	node->pf = pf;
XX	node->sf = sf;
XX
XX	if (prev)
XX		prev->next = node;
XX	else
XX		first.lf = node;
XX
XX	return node;
XX}
XX
XX/* Add the given rhsfile to the include list
XX * of the given lhsfile,
XX * if it was not there already.
XX */
XXstatic void
XXnodeic(lf, pf, sf)
XX	LHSFILE	*	lf;
XX	PREF	*	pf;
XX	SUF	*	sf;
XX{
XX	INCFILE *	node,
XX		*	prev;
XX
XX	if (sf->rule == EQU)
XX	   /* Must follow the Suffix Convention for Included Files.
XX	    */
XX		fatal("bad include file suffix %s%s < %s%s",
XX		   lf->pf->path, lf->sf->name, pf->path, sf->name);
XX		
XX	for (prev = node = lf->ic; node; prev = node, node = node->next)
XX		if (node->pf == pf && node->sf == sf)
XX			return;
XX
XX	if (pf == lf->pf && sf == lf->sf)
XX	{
XX		error("infinite recursion on %s%s - dependency ignored", pf->path, sf->name);
XX		return;
XX	}
XX
XX	node = (INCFILE *) alloc(sizeof(INCFILE), line);
XX	node->pf = pf;
XX	node->sf = sf;
XX
XX	if (prev)
XX		prev->next = node;
XX	else
XX		lf->ic = node;
XX}
XX
XX/* Allocate a zero initialized node.
XX */
XXstatic char *
XXalloc(size, obj)
XX	char	*	obj;
XX{
XX	char	*	node;
XX
XX	if ((node = calloc(1, size)) == NULL)
XX		fatal("can't alloc: %s", obj);
XX
XX	return node;
XX}
XX
XX/* Hash a character string, and return the hash value
XX * modulo the given hash length.
XX */
XXstatic int
XXhash(p, hashl)
XX	char	*	p;
XX	int		hashl;
XX{
XX	register 	unsigned sum;
XX	register 	c;
XX
XX	sum = 0;
XX	while ((c = *p++) != 0)
XX	{
XX		if (sum & 01)
XX			sum = (sum >> 1) + 0x8000;
XX		else
XX			sum >>= 1;
XX		sum += c;
XX		sum &= 0xFFFF;
XX	}
XX	return sum % hashl;
XX}
SHAR_EOF
if test 10650 -ne "`wc -c depend.y`"
then
echo shar: error transmitting depend.y '(should have been 10650 characters)'
fi
sed 's/^XX//' << \SHAR_EOF > makenorm.y
XX%{
XX/* -- Normalize include references
XX *
XX * $File: makenorm.y  1.8  1985-03-29  14:11:19 $
XX *
XX *  Copyright (c) 1983  Kim Walden
XX *      ENEA DATA, Sweden and    
XX *      SYSLAB, Department of Computer Science,
XX *      University of Stockholm, Sweden.
XX *
XX *	This software may be used and copied freely,
XX *	provided that proper credit is given to the originator
XX *	by including the above text in each copy.
XX *
XX *	Descr:	This program implements part of the algorithm described
XX *      	in K. Walden, "Automatic Generation of Make Dependencies",
XX *      	Softw. Practice & Exper., vol. 14, no. 6, June 1984 
XX *
XX *
XX * $Log:	makenorm.y,v $
XX * 
XX * Revision 1.8  1985-03-29  14:11:19  kim
XX * New source format
XX * 
XX * Revision 1.7  1985-03-21  09:31:11  kim
XX * Use sprintf in a System V compatible way
XX * 
XX * Revision 1.6  1985-03-08  01:18:35  kim
XX * Added support for parallell transfer rules.
XX * Added -1 option to makedep and depend.
XX * 
XX * Revision 1.5  1985-02-25  19:41:56  kim
XX * Added -a option for absolute directories
XX * 
XX * Revision 1.4  1985-02-20  11:53:09  kim
XX * Bug fix
XX * 
XX * Revision 1.3  1985-02-19  11:21:23  kim
XX * New default include rules
XX * 
XX * Revision 1.2  1985-02-18  14:24:15  kim
XX * New error handling
XX * 
XX * Revision 1.1  1985-02-16  18:57:07  kim
XX * Initial revision
XX */
XX%}
XX
XX%token SPACE RULSEP INCSEP PATH SUFF INCL QUOTE LPAR RPAR
XX%{
XX# define DIRLIST  struct dirlist
XX# define PREF     struct pref
XX# define SUF      struct suf
XX# define SOURCE   struct source
XX# define NAME     struct filename
XX# define PATHSIZ  100
XX# define DIRSIZ   14
XX# define LINSIZ   256
XX# define OUTSIZ   10
XX# define PHASHL   503
XX# define LINE	  80
XX# define EXACT    0
XX# define DERIVED  1
XX# define FORCE	  2
XX# define NOREDUCE 0
XX# define REDUCE   1
XX# define FALSE	  0
XX# define TRUE	  1
XX# define CNULL   '\0'
XX# define KOL     ':'
XX# define EQU     '='
XX# define RULES	 ".o: .c; .c= .y .l .q; .h= .y"
XX
XX# include <stdio.h>
XX# include <strings.h>
XX# include <sys/types.h>
XX# include <sys/stat.h>
XX
XXstatic char usage[]=
XX"Usage: makenorm [-rfile] [-Rrules] [-Ilist] [-alist] [-i] makedir sourcefiles";
XX
XX/* Directory lists
XX */
XXDIRLIST
XX{
XX	DIRLIST	*	next;
XX	char		path[PATHSIZ+1];
XX};
XX
XX/* File name prefixes   (including directory part)
XX */
XXPREF
XX{	
XX	PREF	*	nexthash;
XX	char		path[PATHSIZ+1];
XX};
XX
XX/* File name suffixes:
XX *
XX * If the suffix occurs in the rhs of a rule,
XX * the output file suffix and rule type
XX * (KOL or EQU) is recorded.
XX */
XXSUF
XX{
XX	SUF	*	next,
XX		*	out[OUTSIZ];
XX	char		name[DIRSIZ+1];
XX	int		top,
XX			rule;
XX};
XX
XX/* Declared sources:
XX *
XX * The transfer rules are successively applied
XX * to the suffix before a file is inserted.
XX */
XXSOURCE
XX{
XX	SOURCE	*	next;
XX	PREF	*	pf;
XX	SUF	*	sf;
XX};
XX
XX/* File names
XX */
XXNAME
XX{
XX	PREF	*	pf;
XX	SUF	*	sf;
XX};
XX
XX
XXstruct 
XX{
XX	SOURCE	*	so;		/* source list */
XX	SUF	*	sf;		/* suffix list */
XX	DIRLIST	*	idir, 		/* list of include directories */
XX		*	adir;		/* list of absolute directories */
XX} first;
XX
XXextern char	*	calloc(),
XX		*	mpath();
XXvoid			yyerror();
XXstatic PREF 	*	nodepf(),
XX		*	phash[PHASHL];	/* hash table for prefixes */
XXstatic SUF	*	nodesf(),
XX		*	lsuf,
XX		*	rsuf;
XXstatic NAME		getname(),
XX			lhs,
XX			rhs;
XXstatic char	*	alloc(),
XX		*	makedir,
XX		*	rulstring,
XX		*	yystring;
XXstatic char		line[LINSIZ];
XXstatic int		derived(),
XX			hash(),
XX			findso(),
XX			printcond(),
XX			lineno,
XX			rule,
XX			remote,
XX			sysflag;
XXstatic void		getdirlist(),
XX			nodedl(),
XX			printnorm();
XX
XX# include "normscan.c"
XX
XXmain(argc, argv)
XX	int		argc;
XX	char	*	argv[];
XX{
XX	char		rulbuf[LINSIZ];
XX
XX	setprogname(argv[0]);
XX	rulstring = rulbuf;
XX	strcpy(rulbuf, RULES);
XX	nodedl("/usr/include", &first.adir);
XX	sysflag = 0;
XX
XX	while (argc > 1 && argv[1][0] == '-')
XX	{
XX		switch (argv[1][1])
XX		{
XX		 case 'r':
XX			strcat(rulbuf, "; ");
XX			strcat(rulbuf, argv[1]+2);
XX			break;
XX
XX		 case 'R':
XX			rulstring = argv[1]+2;
XX			break;
XX
XX		 case 'i':
XX			sysflag++;
XX			break;
XX
XX		 case 'a':
XX		 case 'I':
XX			getdirlist(argv[1]);
XX			break;
XX
XX		 default:
XX			error("unknown option %s", argv[1]);
XX			fatalmesg(usage);
XX		}
XX
XX		argv++;
XX		argc--;
XX	}
XX
XX	if (argc < 2)
XX		fatalmesg(usage);
XX	makedir = argv[1];
XX	argv ++;
XX	argc --;
XX
XX	if (argc < 2)
XX		fatal("no source files specified");
XX
XX	while (--argc)
XX		findso(getname(argv++[1], REDUCE), FORCE);
XX
XX	yystring = rulstring;
XX	BEGIN rules;
XX
XX	yyparse();
XX	exit(0);
XX}
XX%}
XX
XX%%
XX
XXaccept	:	rules includes
XX	;
XXrules	:	rule
XX	|	RULSEP rules
XX	|	rules RULSEP
XX	|	rules RULSEP rule
XX	;
XXrule	:	':' SPACE
XX			{   /* Lhs of inclusion rule, empty output suffix */
XX				lsuf = nodesf("");
XX				rule = KOL;
XX			}
XX		rhssuf
XX	|	lhssuf ':' SPACE
XX			{   /* Lhs of inclusion rule */
XX				rule = KOL;
XX			}
XX		rhssuf
XX	|	lhssuf '=' SPACE
XX			{   /* Lhs of transfer rule */
XX				rule = EQU;
XX			}
XX		rhssuf
XX	|	rule SPACE rhssuf
XX	;
XXlhssuf	:	SUFF
XX			{   /* Lhs of any rule */
XX				lsuf = nodesf(yytext);
XX			}
XX	;
XXrhssuf	:	SUFF
XX			{   /* Rhs of any rule */
XX				rsuf = nodesf(yytext);
XX				if (rsuf->rule && (rsuf->rule != EQU || rule != EQU))
XX				        fatal("ambiguous rules %s", rulstring);
XX				rsuf->rule = rule;
XX				if (rsuf->top >= OUTSIZ)
XX					fatal("to many parallel transfers %s", rulstring);
XX				rsuf->out[rsuf->top++] = lsuf;
XX			}
XX	;
XXincludes:
XX	|	includes INCSEP
XX	|	includes INCSEP include
XX	;
XXinclude	:	lhs
XX		QUOTE
XX			{	remote = 0;	}
XX		rhs
XX		QUOTE
XX			{	unput('#');
XX				BEGIN comment;
XX			}
XX	|	lhs
XX		LPAR
XX			{	remote = 1;	}
XX		rhs
XX		RPAR
XX			{	unput('#');
XX				BEGIN comment;
XX			}
XX	;
XXlhs	:	PATH
XX			{   /* Lhs of include statement:
XX			     *      Reduce filename, and check that
XX			     *      file name was in the source list.
XX			     */
XX				lhs = getname(yytext, REDUCE);
XX				if (!findso(lhs, EXACT))
XX					error("%s not in source list",
XX					   yytext);
XX			}
XX		':' INCL 
XX	;
XXrhs	:	PATH
XX			{   /* Rhs of include statement:
XX			     *      Resolve file reference and print
XX			     *      normalized include statement.
XX			     */
XX				rhs = getname(yytext, NOREDUCE);
XX				if (rhs.sf->rule == EQU)
XX					fatal("bad include file suffix: %s",
XX					   line);
XX				printnorm();
XX			}
XX	;
XX
XX%%
XX
XXvoid
XXyyerror(s)
XX	char	*	s;
XX{
XX	if (yystring)
XX		fatal("%s rules: %s", s, rulstring);
XX	else
XX		fatal("%s near line %d: %s", s, lineno, line);
XX}
XX
XX/* Resolve current include file reference and print
XX * the corresponding normalized include statement.
XX */
XXstatic void
XXprintnorm()
XX{
XX	DIRLIST *	dl;
XX	char	*	p;
XX	char		dir[PATHSIZ+1];
XX
XX    /* Try directory of left hand side file when
XX     *    format: #include "file".
XX     */
XX	if (!remote)
XX	{
XX		strcpy(dir, lhs.pf->path);
XX
XX		if ((p = rindex(dir, '/')) == NULL)
XX			p = dir;
XX
XX		*p = CNULL;
XX
XX		if (printcond(dir))
XX			return;
XX	}
XX
XX    /* Try user include libraries */
XX
XX	for (dl = first.idir; dl; dl = dl->next)
XX		if (printcond(dl->path))
XX			return;
XX
XX    /* Try system include library */
XX
XX	if (printcond("/usr/include"))
XX		return;
XX	
XX	error("cannot resolve: %s", line);
XX}
XX
XXstatic int
XXprintcond(dir)
XX	char	*	dir;
XX{
XX	struct stat	stbuf;
XX	NAME		nm;
XX	char		buf[PATHSIZ+1];
XX
XX    /* If include reference is not absolute,
XX     * prepend directory.
XX     */
XX
XX	if (strlen(dir) != 0 && rhs.pf->path[0] != '/')
XX		sprintf(buf, "%s/%s%s", dir, rhs.pf->path, rhs.sf->name);
XX	else
XX		sprintf(buf, "%s%s", rhs.pf->path, rhs.sf->name);
XX
XX	nm = getname(buf, REDUCE);
XX
XX	sprintf(buf, "%s%s", nm.pf->path, nm.sf->name);
XX
XX    /* If the resulting file name path can be derived from a source,
XX     * accept include reference and print dependency.
XX     */
XX	if (findso(nm, DERIVED))
XX	{
XX		printf("%s%s < %s\n", lhs.pf->path, lhs.sf->name, buf); 
XX		return TRUE;
XX	}
XX
XX    /* Ignore system include references not specified as sources,
XX     * unless -i option was specified.
XX     */
XX	if (strncmp(buf, "/usr/include/", strlen("/usr/include/")) == 0
XX	       && !sysflag && (stat(buf, &stbuf) == 0))
XX		return TRUE;
XX
XX	return FALSE;
XX}
XX
XX
XX/* Return file name,
XX *    reduced if flag == REDUCE.
XX */
XXstatic NAME
XXgetname(path, flag)
XX	char	*	path;
XX	int		flag;
XX{
XX	NAME		nm;
XX	DIRLIST *	dl;
XX	char	*	mp,
XX		*	p;
XX	char		buf[PATHSIZ+1];
XX	int		c;
XX
XX	mp = path;
XX
XX	if (flag == REDUCE )
XX	{
XX	    int absdir = 0;
XX
XX	    /* Make reference absolute */
XX		if (*path != '/')
XX		{
XX			sprintf(buf, "%s/%s", makedir, path);
XX			path = buf;
XX		}
XX
XX	    /* If the file name refers to one of the absolute directories,
XX	     * it should be in absolute form.
XX	     */
XX		for (dl = first.adir; dl; dl = dl->next)
XX		{
XX			if ((mp = mpath(path, dl->path)) == NULL)
XX				fatal("can't reduce path");
XX
XX			if (strncmp(mp, "../", 3) != 0)
XX			{
XX				if (strlen(mp)+strlen(dl->path)+1 > PATHSIZ)
XX					fatal("path too long: %s/%s",
XX					   dl->path, mp);
XX
XX				absdir++;
XX				sprintf(buf, "%s/%s", dl->path, mp);
XX				mp = buf;
XX				break;
XX			}
XX		}
XX
XX	    /* If the file name does not refer to any of the
XX	     * absolute directories, it should be in relative form.
XX	     */
XX		if (!absdir)
XX		{
XX			if ((mp = mpath(path, makedir)) == NULL)
XX				fatal("can't reduce path");
XX
XX			if (strlen(mp) > PATHSIZ)
XX				fatal("path too long: %s", mp);
XX		}
XX	}
XX
XX
XX	if ((p = rindex(mp, '/')) == NULL)
XX		p = mp;
XX
XX	if ((p = rindex(p, '.')) == NULL)
XX		p = mp + strlen(mp);
XX
XX	nm.sf = nodesf(p);
XX	c = *p;
XX	*p = CNULL;
XX	nm.pf = nodepf(mp);
XX	*p = c;
XX
XX	return nm;
XX}
XX
XXstatic char *
XXgetword(p, buf)
XX	char	*	p,
XX		*	buf;
XX{
XX	while (*p == ' ' || *p == '\t')
XX		p++;
XX
XX	if (*p == CNULL)
XX		return NULL;
XX
XX	while (*p != ' ' && *p != '\t' && *p != CNULL)
XX		*buf++ = *p++;
XX
XX	*buf = CNULL;
XX	return p;
XX}
XX
XXstatic void
XXgetdirlist(arg)
XX	char	*	arg;
XX{
XX	DIRLIST **	head;
XX	char	*	s;
XX	char		buf[PATHSIZ+1];
XX
XX	if (arg[1] == 'a')
XX		head = &first.adir;
XX	else
XX		head = &first.idir;
XX	
XX	s = arg;
XX	s += 2;
XX	while (s = getword(s, buf))
XX	{
XX		if (arg[1] == 'a' && buf[0] != '/')
XX			fatal("directory list must be absolute: %s", arg);
XX
XX		nodedl(buf, head); 
XX	}
XX}
XX
XX/* Return suffix node.
XX * If the given suffix was not in the suffix list,
XX * allocate a new node.
XX */
XXstatic SUF *
XXnodesf(name)
XX	char	*	name;
XX{
XX	SUF	*	node,
XX		*	prev;
XX
XX	for (prev = node = first.sf; node; prev = node, node = node->next)
XX		if (strcmp(name, node->name) == 0)
XX			return node;
XX
XX	node = (SUF *) alloc(sizeof(SUF), name);
XX	strcpy(node->name, name);
XX
XX	if (prev)
XX		prev->next = node;
XX	else
XX		first.sf = node;
XX
XX	return node;
XX}
XX
XX/* Return prefix node.
XX * If the given (reduced) path was not in the prefix list,
XX * allocate a new node.
XX */
XXstatic PREF *
XXnodepf(path)
XX	char	*	path;
XX{
XX	PREF	*	node,
XX		*	prevhash;
XX	int		h;
XX
XX	h = hash(path, PHASHL);
XX
XX	for (node = phash[h]; node; node = node->nexthash)
XX		if (strcmp(path, node->path) == 0)
XX			return node;
XX		else
XX			prevhash = node;
XX
XX	node = (PREF *) alloc(sizeof(PREF), path);
XX	strcpy(node->path, path);
XX
XX	if (phash[h])
XX		prevhash->nexthash = node;
XX	else
XX		phash[h] = node;
XX
XX	return node;
XX}
XX
XX/* Search the source list for the given file name:
XX *
XX *   1. flag = EXACT		Look for exact match.
XX *				Return TRUE if found, else FALSE
XX *
XX *   2. flag = FORCE		Look for exact match.
XX *				If not found, allocate a new node.
XX *				Always return TRUE.
XX *
XX *   3. flag = DERIVED		Return TRUE if a match can be found by applying
XX *				transfer rules to the file name suffixes in the
XX *			 	source list, else FALSE.
XX */
XXstatic int
XXfindso(nm, flag)
XX	NAME		nm;
XX	int		flag;
XX{
XX	SOURCE	*	node,
XX		*	prev;
XX
XX	for (prev = node = first.so; node; prev = node, node = node->next)
XX		if (node->pf == nm.pf
XX		  && (node->sf == nm.sf || DERIVED && derived(nm.sf, node->sf)))
XX			return TRUE;
XX
XX	if (flag == FORCE)
XX	{
XX		node = (SOURCE *) alloc(sizeof(SOURCE), line);
XX
XX		node->pf = nm.pf;
XX		node->sf = nm.sf;
XX
XX		if (prev)
XX			prev->next = node;
XX		else
XX			first.so = node;
XX
XX		return TRUE;
XX	}
XX	else
XX		return FALSE;
XX}
XX
XX/* If dsf is same as sf, or can be derived from it by applying
XX * a number of transfer rules, return TRUE, else FALSE
XX */
XXstatic int
XXderived(dsf, sf)
XX	SUF	*	dsf,
XX		*	sf;
XX{
XX	int		i;
XX
XX	if (dsf == sf)
XX		return TRUE;
XX
XX	if (sf->rule != EQU)
XX		return FALSE;
XX
XX	for (i = 0; i < sf->top; i++)
XX		if (derived(dsf, sf->out[i]))
XX			return TRUE;
XX
XX	return FALSE;
XX}
XX
XX/* Append directory to search list.
XX */
XXstatic void
XXnodedl(path, head)
XX	char	*	path;
XX	DIRLIST **	head;
XX{
XX	DIRLIST *	node,
XX		*	prev;
XX
XX	for (prev = node = *head; node; prev = node, node = node->next)
XX		if (strcmp(path, node->path) == 0)
XX			return;
XX
XX	node = (DIRLIST *) alloc(sizeof(DIRLIST), path);
XX	strcpy(node->path, path);
XX
XX	if (prev)
XX		prev->next = node;
XX	else
XX		*head = node;
XX
XX	return;
XX}
XX
XX
XX/* Allocate a zero initialized node.
XX */
XXstatic char *
XXalloc(size, obj)
XX	char	*	obj;
XX{
XX	char	*	node;
XX
XX	if ((node = calloc(1, size)) == NULL)
XX		fatal("can't alloc %s", obj);
XX
XX	return node;
XX}
XX
XX/* Hash a character string, and return the hash value
XX * modulo the given hash length.
XX */
XXstatic int
XXhash(p, hashl)
XX	char	*	p;
XX	int		hashl;
XX{
XX	register	unsigned sum;
XX	register	c;
XX
XX	sum = 0;
XX	while ((c = *p++) != 0)
XX	{
XX		if (sum & 01)
XX			sum = (sum >> 1) + 0x8000;
XX		else
XX			sum >>= 1;
XX		sum += c;
XX		sum &= 0xFFFF;
XX	}
XX	return sum % hashl;
XX}
SHAR_EOF
if test 12659 -ne "`wc -c makenorm.y`"
then
echo shar: error transmitting makenorm.y '(should have been 12659 characters)'
fi
chdir ..
#	End of shell archive
exit 0
-- 
	Kim Walden
	ENEA DATA Sweden

	UUCP:	{seismo,decvax,philabs}!{mcvax,ukc,unido}!enea!kim
	ARPA:	decvax!mcvax!enea!kim at berkeley.arpa
		mcvax!enea!kim at seismo.arpa



More information about the Comp.sources.unix mailing list