1*6a081d30Sbostic /*-
2*6a081d30Sbostic * Copyright (c) 1984 The Regents of the University of California.
3*6a081d30Sbostic * All rights reserved.
4*6a081d30Sbostic *
5*6a081d30Sbostic * %sccs.include.redist.c%
642fa1082Ssam */
742fa1082Ssam
842fa1082Ssam #ifndef lint
942fa1082Ssam char copyright[] =
10*6a081d30Sbostic "@(#) Copyright (c) 1984 The Regents of the University of California.\n\
1142fa1082Ssam All rights reserved.\n";
12*6a081d30Sbostic #endif /* not lint */
1342fa1082Ssam
1442fa1082Ssam #ifndef lint
15*6a081d30Sbostic static char sccsid[] = "@(#)main.c 1.4 (Berkeley) 05/08/91";
16*6a081d30Sbostic #endif /* not lint */
1742fa1082Ssam
1842fa1082Ssam #include <stdio.h>
1942fa1082Ssam #include <ctype.h>
2042fa1082Ssam #include "inline.h"
2142fa1082Ssam
2242fa1082Ssam /*
2342fa1082Ssam * These are the pattern tables to be loaded
2442fa1082Ssam */
2542fa1082Ssam struct pats *inittables[] = {
2642fa1082Ssam language_ptab,
2742fa1082Ssam libc_ptab,
2842fa1082Ssam machine_ptab,
2942fa1082Ssam 0
3042fa1082Ssam };
3142fa1082Ssam
3242fa1082Ssam /*
3342fa1082Ssam * Statistics collection
3442fa1082Ssam */
3542fa1082Ssam struct stats {
3642fa1082Ssam int attempted; /* number of expansion attempts */
3742fa1082Ssam int finished; /* expansions done before end of basic block */
3842fa1082Ssam int lostmodified; /* mergers inhibited by intervening mod */
3942fa1082Ssam int savedpush; /* successful push/pop merger */
4042fa1082Ssam } stats;
4154094f50Ssam
4254094f50Ssam extern char *strcpy();
4354094f50Ssam
4454094f50Ssam char *whoami;
4554094f50Ssam int lineno = 0;
4642fa1082Ssam int dflag;
4742fa1082Ssam
main(argc,argv)4842fa1082Ssam main(argc, argv)
4942fa1082Ssam int argc;
5042fa1082Ssam char *argv[];
5142fa1082Ssam {
5242fa1082Ssam register char *cp, *lp;
5342fa1082Ssam register char *bufp;
5442fa1082Ssam register struct pats *pp, **php;
5542fa1082Ssam struct pats **tablep;
5642fa1082Ssam register struct inststoptbl *itp, **ithp;
5742fa1082Ssam int size;
5842fa1082Ssam extern char *index();
5942fa1082Ssam
6054094f50Ssam whoami = argv[0];
6142fa1082Ssam if (argc > 1 && bcmp(argv[1], "-d", 3) == 0)
6242fa1082Ssam dflag++, argc--, argv++;
6342fa1082Ssam if (argc > 1)
6442fa1082Ssam freopen(argv[1], "r", stdin);
6542fa1082Ssam if (argc > 2)
6642fa1082Ssam freopen(argv[2], "w", stdout);
6742fa1082Ssam /*
6842fa1082Ssam * Set up the hash table for the patterns.
6942fa1082Ssam */
7042fa1082Ssam for (tablep = inittables; *tablep; tablep++) {
7142fa1082Ssam for (pp = *tablep; pp->name[0] != '\0'; pp++) {
7242fa1082Ssam php = &patshdr[hash(pp->name, &size)];
7342fa1082Ssam pp->size = size;
7442fa1082Ssam pp->next = *php;
7542fa1082Ssam *php = pp;
7642fa1082Ssam }
7742fa1082Ssam }
7842fa1082Ssam /*
7942fa1082Ssam * Set up the hash table for the instruction stop table.
8042fa1082Ssam */
8142fa1082Ssam for (itp = inststoptable; itp->name[0] != '\0'; itp++) {
8242fa1082Ssam ithp = &inststoptblhdr[hash(itp->name, &size)];
8342fa1082Ssam itp->size = size;
8442fa1082Ssam itp->next = *ithp;
8542fa1082Ssam *ithp = itp;
8642fa1082Ssam }
8742fa1082Ssam /*
8842fa1082Ssam * check each line and replace as appropriate
8942fa1082Ssam */
9042fa1082Ssam buftail = bufhead = 0;
9142fa1082Ssam bufp = line[0];
9242fa1082Ssam while (fgets(bufp, MAXLINELEN, stdin)) {
9354094f50Ssam lineno++;
9442fa1082Ssam lp = index(bufp, LABELCHAR);
9542fa1082Ssam if (lp != NULL) {
9642fa1082Ssam for (cp = bufp; cp < lp; cp++)
9742fa1082Ssam if (!isalnum(*cp))
9842fa1082Ssam break;
9942fa1082Ssam if (cp == lp) {
10042fa1082Ssam bufp = newline();
10142fa1082Ssam if (*++lp == '\n') {
10242fa1082Ssam emptyqueue();
10342fa1082Ssam continue;
10442fa1082Ssam }
10554094f50Ssam (void) strcpy(bufp, lp);
10642fa1082Ssam *lp++ = '\n';
10742fa1082Ssam *lp = '\0';
10842fa1082Ssam emptyqueue();
10942fa1082Ssam }
11042fa1082Ssam }
11142fa1082Ssam for (cp = bufp; isspace(*cp); cp++)
11242fa1082Ssam /* void */;
11342fa1082Ssam if ((cp = doreplaceon(cp)) == 0) {
11442fa1082Ssam bufp = newline();
11542fa1082Ssam continue;
11642fa1082Ssam }
11742fa1082Ssam for (pp = patshdr[hash(cp, &size)]; pp; pp = pp->next) {
11842fa1082Ssam if (pp->size == size && bcmp(pp->name, cp, size) == 0) {
11954094f50Ssam if (argcounterr(pp->args, countargs(bufp),
12054094f50Ssam pp->name)) {
12154094f50Ssam pp = NULL;
12254094f50Ssam break;
12354094f50Ssam }
12442fa1082Ssam expand(pp->replace);
12542fa1082Ssam bufp = line[bufhead];
12642fa1082Ssam break;
12742fa1082Ssam }
12842fa1082Ssam }
12942fa1082Ssam if (!pp) {
13042fa1082Ssam emptyqueue();
13142fa1082Ssam fputs(bufp, stdout);
13242fa1082Ssam }
13342fa1082Ssam }
13442fa1082Ssam emptyqueue();
13542fa1082Ssam if (dflag)
13654094f50Ssam fprintf(stderr, "%s: %s %d, %s %d, %s %d, %s %d\n",
13754094f50Ssam whoami,
13842fa1082Ssam "attempts", stats.attempted,
13942fa1082Ssam "finished", stats.finished,
14042fa1082Ssam "inhibited", stats.lostmodified,
14142fa1082Ssam "merged", stats.savedpush);
14242fa1082Ssam exit(0);
14342fa1082Ssam }
14442fa1082Ssam
14542fa1082Ssam /*
14642fa1082Ssam * Integrate an expansion into the assembly stream
14742fa1082Ssam */
expand(replace)14842fa1082Ssam expand(replace)
14942fa1082Ssam char *replace;
15042fa1082Ssam {
15142fa1082Ssam register int curptr;
15242fa1082Ssam char *nextreplace, *argv[MAXARGS];
15342fa1082Ssam int argc, argreg, foundarg, mod = 0, args = 0;
15442fa1082Ssam char parsebuf[BUFSIZ];
15542fa1082Ssam
15642fa1082Ssam stats.attempted++;
15742fa1082Ssam for (curptr = bufhead; ; ) {
15842fa1082Ssam nextreplace = copyline(replace, line[bufhead]);
15942fa1082Ssam argc = parseline(line[bufhead], argv, parsebuf);
16042fa1082Ssam argreg = nextarg(argc, argv);
16142fa1082Ssam if (argreg == -1)
16242fa1082Ssam break;
16342fa1082Ssam args++;
16442fa1082Ssam for (foundarg = 0; curptr != buftail; ) {
16542fa1082Ssam curptr = PRED(curptr);
16642fa1082Ssam argc = parseline(line[curptr], argv, parsebuf);
16742fa1082Ssam if (isendofblock(argc, argv))
16842fa1082Ssam break;
16942fa1082Ssam if (foundarg = ispusharg(argc, argv))
17042fa1082Ssam break;
17142fa1082Ssam mod |= 1 << modifies(argc, argv);
17242fa1082Ssam }
17342fa1082Ssam if (!foundarg)
17442fa1082Ssam break;
17542fa1082Ssam replace = nextreplace;
17642fa1082Ssam if (mod & (1 << argreg)) {
17742fa1082Ssam stats.lostmodified++;
17842fa1082Ssam if (curptr == buftail) {
17942fa1082Ssam (void)newline();
18042fa1082Ssam break;
18142fa1082Ssam }
18242fa1082Ssam (void)newline();
18342fa1082Ssam } else {
18442fa1082Ssam stats.savedpush++;
18542fa1082Ssam rewrite(line[curptr], argc, argv, argreg);
18642fa1082Ssam mod |= 1 << argreg;
18742fa1082Ssam }
18842fa1082Ssam }
18942fa1082Ssam if (argreg == -1)
19042fa1082Ssam stats.finished++;
19142fa1082Ssam emptyqueue();
19242fa1082Ssam fputs(replace, stdout);
19342fa1082Ssam cleanup(args);
19442fa1082Ssam }
19542fa1082Ssam
19642fa1082Ssam /*
19742fa1082Ssam * Parse a line of assembly language into opcode and arguments.
19842fa1082Ssam */
parseline(linep,argv,linebuf)19942fa1082Ssam parseline(linep, argv, linebuf)
20042fa1082Ssam char *linep;
20142fa1082Ssam char *argv[];
20242fa1082Ssam char *linebuf;
20342fa1082Ssam {
20442fa1082Ssam register char *bufp = linebuf, *cp = linep;
20542fa1082Ssam register int argc = 0;
20642fa1082Ssam
20742fa1082Ssam for (;;) {
20842fa1082Ssam /*
20942fa1082Ssam * skip over white space
21042fa1082Ssam */
21142fa1082Ssam while (isspace(*cp))
21242fa1082Ssam cp++;
21342fa1082Ssam if (*cp == '\0')
21442fa1082Ssam return (argc);
21542fa1082Ssam /*
21642fa1082Ssam * copy argument
21742fa1082Ssam */
21842fa1082Ssam if (argc == MAXARGS - 1) {
21942fa1082Ssam fprintf(stderr, "instruction too long->%s", linep);
22042fa1082Ssam return (argc);
22142fa1082Ssam }
22242fa1082Ssam argv[argc++] = bufp;
22342fa1082Ssam while (!isspace(*cp) && *cp != ARGSEPCHAR && *cp != COMMENTCHAR)
22442fa1082Ssam *bufp++ = *cp++;
22542fa1082Ssam *bufp++ = '\0';
22642fa1082Ssam if (*cp == COMMENTCHAR)
22742fa1082Ssam return (argc);
22842fa1082Ssam if (*cp == ARGSEPCHAR)
22942fa1082Ssam cp++;
23042fa1082Ssam }
23142fa1082Ssam }
23242fa1082Ssam
23342fa1082Ssam /*
23442fa1082Ssam * Check for instructions that end a basic block.
23542fa1082Ssam */
isendofblock(argc,argv)23642fa1082Ssam isendofblock(argc, argv)
23742fa1082Ssam int argc;
23842fa1082Ssam char *argv[];
23942fa1082Ssam {
24042fa1082Ssam register struct inststoptbl *itp;
24142fa1082Ssam int size;
24242fa1082Ssam
24342fa1082Ssam if (argc == 0)
24442fa1082Ssam return (0);
24542fa1082Ssam for (itp = inststoptblhdr[hash(argv[0], &size)]; itp; itp = itp->next)
24642fa1082Ssam if (itp->size == size && bcmp(argv[0], itp->name, size) == 0)
24742fa1082Ssam return (1);
24842fa1082Ssam return (0);
24942fa1082Ssam }
25042fa1082Ssam
25142fa1082Ssam /*
25242fa1082Ssam * Copy a newline terminated string.
25342fa1082Ssam * Return pointer to character following last character copied.
25442fa1082Ssam */
25542fa1082Ssam char *
copyline(from,to)25642fa1082Ssam copyline(from, to)
25742fa1082Ssam register char *from, *to;
25842fa1082Ssam {
25942fa1082Ssam
26042fa1082Ssam while (*from != '\n')
26142fa1082Ssam *to++ = *from++;
26242fa1082Ssam *to++ = *from++;
26342fa1082Ssam *to = '\0';
26442fa1082Ssam return (from);
26542fa1082Ssam }
26642fa1082Ssam
26742fa1082Ssam /*
26854094f50Ssam * Check for a disparity between the number of arguments a function
26954094f50Ssam * is called with and the number which we expect to see.
27054094f50Ssam * If the error is unrecoverable, return 1, otherwise 0.
27154094f50Ssam */
argcounterr(args,callargs,name)27254094f50Ssam argcounterr(args, callargs, name)
27354094f50Ssam int args, callargs;
27454094f50Ssam char *name;
27554094f50Ssam {
27654094f50Ssam register char *cp;
27754094f50Ssam char namebuf[MAXLINELEN];
27854094f50Ssam
27954094f50Ssam if (args == callargs)
28054094f50Ssam return (0);
28154094f50Ssam cp = strcpy(namebuf, name);
28254094f50Ssam while (*cp != '\0' && *cp != '\n')
28354094f50Ssam ++cp;
28454094f50Ssam if (*cp == '\n')
28554094f50Ssam *cp = '\0';
28654094f50Ssam if (callargs >= 0) {
28754094f50Ssam fprintf(stderr,
28854094f50Ssam "%s: error: arg count mismatch, %d != %d for '%s' at line %d\n",
28954094f50Ssam whoami, callargs, args, namebuf, lineno);
29054094f50Ssam return (1);
29154094f50Ssam }
29254094f50Ssam fprintf(stderr,
29354094f50Ssam "%s: warning: can't verify arg count for '%s' at line %d\n",
29454094f50Ssam whoami, namebuf, lineno);
29554094f50Ssam return (0);
29654094f50Ssam }
29754094f50Ssam
29854094f50Ssam /*
29942fa1082Ssam * open space for next line in the queue
30042fa1082Ssam */
30142fa1082Ssam char *
newline()30242fa1082Ssam newline()
30342fa1082Ssam {
30442fa1082Ssam bufhead = SUCC(bufhead);
30542fa1082Ssam if (bufhead == buftail) {
30642fa1082Ssam fputs(line[buftail], stdout);
30742fa1082Ssam buftail = SUCC(buftail);
30842fa1082Ssam }
30942fa1082Ssam return (line[bufhead]);
31042fa1082Ssam }
31142fa1082Ssam
31242fa1082Ssam /*
31342fa1082Ssam * empty the queue by printing out all its lines.
31442fa1082Ssam */
emptyqueue()31542fa1082Ssam emptyqueue()
31642fa1082Ssam {
31742fa1082Ssam while (buftail != bufhead) {
31842fa1082Ssam fputs(line[buftail], stdout);
31942fa1082Ssam buftail = SUCC(buftail);
32042fa1082Ssam }
32142fa1082Ssam }
32242fa1082Ssam
32342fa1082Ssam /*
32442fa1082Ssam * Compute the hash of a string.
32542fa1082Ssam * Return the hash and the size of the item hashed
32642fa1082Ssam */
hash(cp,size)32742fa1082Ssam hash(cp, size)
32842fa1082Ssam char *cp;
32942fa1082Ssam int *size;
33042fa1082Ssam {
33142fa1082Ssam register char *cp1 = cp;
33242fa1082Ssam register int hash = 0;
33342fa1082Ssam
33442fa1082Ssam while (*cp1 && *cp1 != '\n')
33542fa1082Ssam hash += (int)*cp1++;
33642fa1082Ssam *size = cp1 - cp + 1;
33742fa1082Ssam hash &= HSHSIZ - 1;
33842fa1082Ssam return (hash);
33942fa1082Ssam }
340