4.4BSD/usr/src/sys/vax/inline/main.c

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

/*-
 * Copyright (c) 1984, 1986 The Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#ifndef lint
char copyright[] =
"@(#) Copyright (c) 1984, 1986 The Regents of the University of California.\n\
 All rights reserved.\n";
#endif /* not lint */

#ifndef lint
static char sccsid[] = "@(#)main.c	7.2 (Berkeley) 5/8/91";
#endif /* not lint */

#include <stdio.h>
#include <ctype.h>
#include "inline.h"

/*
 * These are the pattern tables to be loaded
 */
struct pats *vax_inittables[] = {
	language_ptab,
	libc_ptab,
	vax_libc_ptab,
	machine_ptab,
	vax_ptab,
	0
};

struct pats *vaxsubset_inittables[] = {
	language_ptab,
	libc_ptab,
	vaxsubset_libc_ptab,
	machine_ptab,
	vaxsubset_ptab,
	0
};

/*
 * Statistics collection
 */
struct stats {
	int	attempted;	/* number of expansion attempts */
	int	finished;	/* expansions done before end of basic block */
	int	lostmodified;	/* mergers inhibited by intervening mod */
	int	savedpush;	/* successful push/pop merger */
} stats;

extern char *strcpy();

char *whoami;
int lineno = 0;
int dflag;

main(argc, argv)
	int argc;
	char *argv[];
{
	register char *cp, *lp;
	register char *bufp;
	register struct pats *pp, **php;
	struct pats **tablep;
	register struct inststoptbl *itp, **ithp;
	int size;
	extern char *index();
	int subset = 0;

	whoami = argv[0];
	argc--;
	argv++;
	while (argc > 0 && argv[0][0] == '-') {
		switch(argv[0][1]) {

		case 's':
			subset++;
			break;

		case 'd':
			dflag++;
			break;

		default:
			break;
		}
		argc--, argv++;
	}
	if (argc > 0)
		freopen(argv[0], "r", stdin);
	if (argc > 1)
		freopen(argv[1], "w", stdout);
	/*
	 * Set up the hash table for the patterns.
	 */
	if (subset)
		tablep = vaxsubset_inittables;
	else
		tablep = vax_inittables;
	for ( ; *tablep; tablep++) {
		for (pp = *tablep; pp->name[0] != '\0'; pp++) {
			php = &patshdr[hash(pp->name, &size)];
			pp->size = size;
			pp->next = *php;
			*php = pp;
		}
	}
	/*
	 * Set up the hash table for the instruction stop table.
	 */
	for (itp = inststoptable; itp->name[0] != '\0'; itp++) {
		ithp = &inststoptblhdr[hash(itp->name, &size)];
		itp->size = size;
		itp->next = *ithp;
		*ithp = itp;
	}
	/*
	 * check each line and replace as appropriate
	 */
	buftail = bufhead = 0;
	bufp = line[0];
	while (fgets(bufp, MAXLINELEN, stdin)) {
		lineno++;
		lp = index(bufp, LABELCHAR);
		if (lp != NULL) {
			for (cp = bufp; cp < lp; cp++)
				if (!isalnum(*cp))
					break;
			if (cp == lp) {
				bufp = newline();
				if (*++lp == '\n') {
					emptyqueue();
					continue;
				}
				(void) strcpy(bufp, lp);
				*lp++ = '\n';
				*lp = '\0';
				emptyqueue();
			}
		}
		for (cp = bufp; isspace(*cp); cp++)
			/* void */;
		if ((cp = doreplaceon(cp)) == 0) {
			bufp = newline();
			continue;
		}
		for (pp = patshdr[hash(cp, &size)]; pp; pp = pp->next) {
			if (pp->size == size && bcmp(pp->name, cp, size) == 0) {
				if (argcounterr(pp->args, countargs(bufp), pp->name)) {
					pp = NULL;
					break;
				}
				expand(pp->replace);
				bufp = line[bufhead];
				break;
			}
		}
		if (!pp) {
			emptyqueue();
			fputs(bufp, stdout);
		}
	}
	emptyqueue();
	if (dflag)
		fprintf(stderr, "%s: %s %d, %s %d, %s %d, %s %d\n",
			whoami,
			"attempts", stats.attempted,
			"finished", stats.finished,
			"inhibited", stats.lostmodified,
			"merged", stats.savedpush);
	exit(0);
}

/*
 * Integrate an expansion into the assembly stream
 */
expand(replace)
	char *replace;
{
	register int curptr;
	char *nextreplace, *argv[MAXARGS];
	int argc, argreg, foundarg, mod = 0, args = 0;
	char parsebuf[BUFSIZ];

	stats.attempted++;
	for (curptr = bufhead; ; ) {
		nextreplace = copyline(replace, line[bufhead]);
		argc = parseline(line[bufhead], argv, parsebuf);
		argreg = nextarg(argc, argv);
		if (argreg == -1)
			break;
		args++;
		for (foundarg = 0; curptr != buftail; ) {
			curptr = PRED(curptr);
			argc = parseline(line[curptr], argv, parsebuf);
			if (isendofblock(argc, argv))
				break;
			if (foundarg = ispusharg(argc, argv))
				break;
			mod |= 1 << modifies(argc, argv);
		}
		if (!foundarg)
			break;
		replace = nextreplace;
		if (mod & (1 << argreg)) {
			stats.lostmodified++;
			if (curptr == buftail) {
				(void)newline();
				break;
			}
			(void)newline();
		} else {
			stats.savedpush++;
			rewrite(line[curptr], argc, argv, argreg);
			mod |= 1 << argreg;
		}
	}
	if (argreg == -1)
		stats.finished++;
	emptyqueue();
	fputs(replace, stdout);
	cleanup(args);
}

/*
 * Parse a line of assembly language into opcode and arguments.
 */
parseline(linep, argv, linebuf)
	char *linep;
	char *argv[];
	char *linebuf;
{
	register char *bufp = linebuf, *cp = linep;
	register int argc = 0;

	for (;;) {
		/*
		 * skip over white space
		 */
		while (isspace(*cp))
			cp++;
		if (*cp == '\0')
			return (argc);
		/*
		 * copy argument
		 */
		if (argc == MAXARGS - 1) {
			fprintf(stderr, "instruction too long->%s", linep);
			return (argc);
		}
		argv[argc++] = bufp;
		while (!isspace(*cp) && *cp != ARGSEPCHAR && *cp != COMMENTCHAR)
			*bufp++ = *cp++;
		*bufp++ = '\0';
		if (*cp == COMMENTCHAR)
			return (argc);
		if (*cp == ARGSEPCHAR)
			cp++;
	}
}

/*
 * Check for instructions that end a basic block.
 */
isendofblock(argc, argv)
	int argc;
	char *argv[];
{
	register struct inststoptbl *itp;
	int size;

	if (argc == 0)
		return (0);
	for (itp = inststoptblhdr[hash(argv[0], &size)]; itp; itp = itp->next)
		if (itp->size == size && bcmp(argv[0], itp->name, size) == 0)
			return (1);
	return (0);
}

/*
 * Copy a newline terminated string.
 * Return pointer to character following last character copied.
 */
char *
copyline(from, to)
	register char *from, *to;
{

	while (*from != '\n')
		*to++ = *from++;
	*to++ = *from++;
	*to = '\0';
	return (from);
}

/*
 * Check for a disparity between the number of arguments a function
 * is called with and the number which we expect to see.
 * If the error is unrecoverable, return 1, otherwise 0.
 */
argcounterr(args, callargs, name)
	int args, callargs;
	char *name;
{
	register char *cp;
	char namebuf[MAXLINELEN];

	if (args == callargs)
		return (0);
	cp = strcpy(namebuf, name);
	while (*cp != '\0' && *cp != '\n')
		++cp;
	if (*cp == '\n')
		*cp = '\0';
	if (callargs >= 0) {
		fprintf(stderr,
		"%s: error: arg count mismatch, %d != %d for '%s' at line %d\n",
			whoami, callargs, args, namebuf, lineno);
		return (1);
	}
	fprintf(stderr,
		"%s: warning: can't verify arg count for '%s' at line %d\n",
		whoami, namebuf, lineno);
	return (0);
}

/*
 * open space for next line in the queue
 */
char *
newline()
{
	bufhead = SUCC(bufhead);
	if (bufhead == buftail) {
		fputs(line[buftail], stdout);
		buftail = SUCC(buftail);
	}
	return (line[bufhead]);
}

/*
 * empty the queue by printing out all its lines.
 */
emptyqueue()
{
	while (buftail != bufhead) {
		fputs(line[buftail], stdout);
		buftail = SUCC(buftail);
	}
}

/*
 * Compute the hash of a string.
 * Return the hash and the size of the item hashed
 */
hash(cp, size)
	char *cp;
	int *size;
{
	register char *cp1 = cp;
	register int hash = 0;

	while (*cp1 && *cp1 != '\n')
		hash += (int)*cp1++;
	*size = cp1 - cp + 1;
	hash &= HSHSIZ - 1;
	return (hash);
}