1*49430Sbostic /*-
2*49430Sbostic * Copyright (c) 1984 The Regents of the University of California.
3*49430Sbostic * All rights reserved.
4*49430Sbostic *
5*49430Sbostic * %sccs.include.redist.c%
624038Ssam */
724038Ssam
824038Ssam #ifndef lint
924038Ssam char copyright[] =
10*49430Sbostic "@(#) Copyright (c) 1984 The Regents of the University of California.\n\
1124038Ssam All rights reserved.\n";
12*49430Sbostic #endif /* not lint */
1324038Ssam
1424038Ssam #ifndef lint
15*49430Sbostic static char sccsid[] = "@(#)main.c 1.4 (Berkeley) 05/08/91";
16*49430Sbostic #endif /* not lint */
1724038Ssam
1824038Ssam #include <stdio.h>
1924038Ssam #include <ctype.h>
2024038Ssam #include "inline.h"
2124038Ssam
2224038Ssam /*
2324038Ssam * These are the pattern tables to be loaded
2424038Ssam */
2524038Ssam struct pats *inittables[] = {
2624038Ssam language_ptab,
2724038Ssam libc_ptab,
2824038Ssam machine_ptab,
2924038Ssam 0
3024038Ssam };
3124038Ssam
3224038Ssam /*
3324038Ssam * Statistics collection
3424038Ssam */
3524038Ssam struct stats {
3624038Ssam int attempted; /* number of expansion attempts */
3724038Ssam int finished; /* expansions done before end of basic block */
3824038Ssam int lostmodified; /* mergers inhibited by intervening mod */
3924038Ssam int savedpush; /* successful push/pop merger */
4024038Ssam } stats;
4124038Ssam
4226405Ssam extern char *strcpy();
4326405Ssam
4426405Ssam char *whoami;
4526405Ssam int lineno = 0;
4626405Ssam int dflag;
4726405Ssam
main(argc,argv)4824038Ssam main(argc, argv)
4924038Ssam int argc;
5024038Ssam char *argv[];
5124038Ssam {
5224038Ssam register char *cp, *lp;
5324038Ssam register char *bufp;
5424038Ssam register struct pats *pp, **php;
5524038Ssam struct pats **tablep;
5624038Ssam register struct inststoptbl *itp, **ithp;
5724038Ssam int size;
5824038Ssam extern char *index();
5924038Ssam
6026405Ssam whoami = argv[0];
6124038Ssam if (argc > 1 && bcmp(argv[1], "-d", 3) == 0)
6224038Ssam dflag++, argc--, argv++;
6324038Ssam if (argc > 1)
6424038Ssam freopen(argv[1], "r", stdin);
6524038Ssam if (argc > 2)
6624038Ssam freopen(argv[2], "w", stdout);
6724038Ssam /*
6824038Ssam * Set up the hash table for the patterns.
6924038Ssam */
7024038Ssam for (tablep = inittables; *tablep; tablep++) {
7124038Ssam for (pp = *tablep; pp->name[0] != '\0'; pp++) {
7224038Ssam php = &patshdr[hash(pp->name, &size)];
7324038Ssam pp->size = size;
7424038Ssam pp->next = *php;
7524038Ssam *php = pp;
7624038Ssam }
7724038Ssam }
7824038Ssam /*
7924038Ssam * Set up the hash table for the instruction stop table.
8024038Ssam */
8124038Ssam for (itp = inststoptable; itp->name[0] != '\0'; itp++) {
8224038Ssam ithp = &inststoptblhdr[hash(itp->name, &size)];
8324038Ssam itp->size = size;
8424038Ssam itp->next = *ithp;
8524038Ssam *ithp = itp;
8624038Ssam }
8724038Ssam /*
8824038Ssam * check each line and replace as appropriate
8924038Ssam */
9024038Ssam buftail = bufhead = 0;
9124038Ssam bufp = line[0];
9224038Ssam while (fgets(bufp, MAXLINELEN, stdin)) {
9326405Ssam lineno++;
9424038Ssam lp = index(bufp, LABELCHAR);
9524038Ssam if (lp != NULL) {
9624038Ssam for (cp = bufp; cp < lp; cp++)
9724038Ssam if (!isalnum(*cp))
9824038Ssam break;
9924038Ssam if (cp == lp) {
10024038Ssam bufp = newline();
10124038Ssam if (*++lp == '\n') {
10224038Ssam emptyqueue();
10324038Ssam continue;
10424038Ssam }
10526405Ssam (void) strcpy(bufp, lp);
10624038Ssam *lp++ = '\n';
10724038Ssam *lp = '\0';
10824038Ssam emptyqueue();
10924038Ssam }
11024038Ssam }
11124038Ssam for (cp = bufp; isspace(*cp); cp++)
11224038Ssam /* void */;
11324038Ssam if ((cp = doreplaceon(cp)) == 0) {
11424038Ssam bufp = newline();
11524038Ssam continue;
11624038Ssam }
11724038Ssam for (pp = patshdr[hash(cp, &size)]; pp; pp = pp->next) {
11824038Ssam if (pp->size == size && bcmp(pp->name, cp, size) == 0) {
11926405Ssam if (argcounterr(pp->args, countargs(bufp),
12026405Ssam pp->name)) {
12126405Ssam pp = NULL;
12226405Ssam break;
12326405Ssam }
12424038Ssam expand(pp->replace);
12524038Ssam bufp = line[bufhead];
12624038Ssam break;
12724038Ssam }
12824038Ssam }
12924038Ssam if (!pp) {
13024038Ssam emptyqueue();
13124038Ssam fputs(bufp, stdout);
13224038Ssam }
13324038Ssam }
13424038Ssam emptyqueue();
13524038Ssam if (dflag)
13626405Ssam fprintf(stderr, "%s: %s %d, %s %d, %s %d, %s %d\n",
13726405Ssam whoami,
13824038Ssam "attempts", stats.attempted,
13924038Ssam "finished", stats.finished,
14024038Ssam "inhibited", stats.lostmodified,
14124038Ssam "merged", stats.savedpush);
14224038Ssam exit(0);
14324038Ssam }
14424038Ssam
14524038Ssam /*
14624038Ssam * Integrate an expansion into the assembly stream
14724038Ssam */
expand(replace)14824038Ssam expand(replace)
14924038Ssam char *replace;
15024038Ssam {
15124038Ssam register int curptr;
15224038Ssam char *nextreplace, *argv[MAXARGS];
15324038Ssam int argc, argreg, foundarg, mod = 0, args = 0;
15424038Ssam char parsebuf[BUFSIZ];
15524038Ssam
15624038Ssam stats.attempted++;
15724038Ssam for (curptr = bufhead; ; ) {
15824038Ssam nextreplace = copyline(replace, line[bufhead]);
15924038Ssam argc = parseline(line[bufhead], argv, parsebuf);
16024038Ssam argreg = nextarg(argc, argv);
16124038Ssam if (argreg == -1)
16224038Ssam break;
16324038Ssam args++;
16424038Ssam for (foundarg = 0; curptr != buftail; ) {
16524038Ssam curptr = PRED(curptr);
16624038Ssam argc = parseline(line[curptr], argv, parsebuf);
16724038Ssam if (isendofblock(argc, argv))
16824038Ssam break;
16924038Ssam if (foundarg = ispusharg(argc, argv))
17024038Ssam break;
17124038Ssam mod |= 1 << modifies(argc, argv);
17224038Ssam }
17324038Ssam if (!foundarg)
17424038Ssam break;
17524038Ssam replace = nextreplace;
17624038Ssam if (mod & (1 << argreg)) {
17724038Ssam stats.lostmodified++;
17824038Ssam if (curptr == buftail) {
17924038Ssam (void)newline();
18024038Ssam break;
18124038Ssam }
18224038Ssam (void)newline();
18324038Ssam } else {
18424038Ssam stats.savedpush++;
18524038Ssam rewrite(line[curptr], argc, argv, argreg);
18624038Ssam mod |= 1 << argreg;
18724038Ssam }
18824038Ssam }
18924038Ssam if (argreg == -1)
19024038Ssam stats.finished++;
19124038Ssam emptyqueue();
19224038Ssam fputs(replace, stdout);
19324038Ssam cleanup(args);
19424038Ssam }
19524038Ssam
19624038Ssam /*
19724038Ssam * Parse a line of assembly language into opcode and arguments.
19824038Ssam */
parseline(linep,argv,linebuf)19924038Ssam parseline(linep, argv, linebuf)
20024038Ssam char *linep;
20124038Ssam char *argv[];
20224038Ssam char *linebuf;
20324038Ssam {
20424038Ssam register char *bufp = linebuf, *cp = linep;
20524038Ssam register int argc = 0;
20624038Ssam
20724038Ssam for (;;) {
20824038Ssam /*
20924038Ssam * skip over white space
21024038Ssam */
21124038Ssam while (isspace(*cp))
21224038Ssam cp++;
21324038Ssam if (*cp == '\0')
21424038Ssam return (argc);
21524038Ssam /*
21624038Ssam * copy argument
21724038Ssam */
21824038Ssam if (argc == MAXARGS - 1) {
21924038Ssam fprintf(stderr, "instruction too long->%s", linep);
22024038Ssam return (argc);
22124038Ssam }
22224038Ssam argv[argc++] = bufp;
22324038Ssam while (!isspace(*cp) && *cp != ARGSEPCHAR && *cp != COMMENTCHAR)
22424038Ssam *bufp++ = *cp++;
22524038Ssam *bufp++ = '\0';
22624038Ssam if (*cp == COMMENTCHAR)
22724038Ssam return (argc);
22824038Ssam if (*cp == ARGSEPCHAR)
22924038Ssam cp++;
23024038Ssam }
23124038Ssam }
23224038Ssam
23324038Ssam /*
23424038Ssam * Check for instructions that end a basic block.
23524038Ssam */
isendofblock(argc,argv)23624038Ssam isendofblock(argc, argv)
23724038Ssam int argc;
23824038Ssam char *argv[];
23924038Ssam {
24024038Ssam register struct inststoptbl *itp;
24124038Ssam int size;
24224038Ssam
24324038Ssam if (argc == 0)
24424038Ssam return (0);
24524038Ssam for (itp = inststoptblhdr[hash(argv[0], &size)]; itp; itp = itp->next)
24624038Ssam if (itp->size == size && bcmp(argv[0], itp->name, size) == 0)
24724038Ssam return (1);
24824038Ssam return (0);
24924038Ssam }
25024038Ssam
25124038Ssam /*
25224038Ssam * Copy a newline terminated string.
25324038Ssam * Return pointer to character following last character copied.
25424038Ssam */
25524038Ssam char *
copyline(from,to)25624038Ssam copyline(from, to)
25724038Ssam register char *from, *to;
25824038Ssam {
25924038Ssam
26024038Ssam while (*from != '\n')
26124038Ssam *to++ = *from++;
26224038Ssam *to++ = *from++;
26324038Ssam *to = '\0';
26424038Ssam return (from);
26524038Ssam }
26624038Ssam
26724038Ssam /*
26826405Ssam * Check for a disparity between the number of arguments a function
26926405Ssam * is called with and the number which we expect to see.
27026405Ssam * If the error is unrecoverable, return 1, otherwise 0.
27126405Ssam */
argcounterr(args,callargs,name)27226405Ssam argcounterr(args, callargs, name)
27326405Ssam int args, callargs;
27426405Ssam char *name;
27526405Ssam {
27626405Ssam register char *cp;
27726405Ssam char namebuf[MAXLINELEN];
27826405Ssam
27926405Ssam if (args == callargs)
28026405Ssam return (0);
28126405Ssam cp = strcpy(namebuf, name);
28226405Ssam while (*cp != '\0' && *cp != '\n')
28326405Ssam ++cp;
28426405Ssam if (*cp == '\n')
28526405Ssam *cp = '\0';
28626405Ssam if (callargs >= 0) {
28726405Ssam fprintf(stderr,
28826405Ssam "%s: error: arg count mismatch, %d != %d for '%s' at line %d\n",
28926405Ssam whoami, callargs, args, namebuf, lineno);
29026405Ssam return (1);
29126405Ssam }
29226405Ssam fprintf(stderr,
29326405Ssam "%s: warning: can't verify arg count for '%s' at line %d\n",
29426405Ssam whoami, namebuf, lineno);
29526405Ssam return (0);
29626405Ssam }
29726405Ssam
29826405Ssam /*
29924038Ssam * open space for next line in the queue
30024038Ssam */
30124038Ssam char *
newline()30224038Ssam newline()
30324038Ssam {
30424038Ssam bufhead = SUCC(bufhead);
30524038Ssam if (bufhead == buftail) {
30624038Ssam fputs(line[buftail], stdout);
30724038Ssam buftail = SUCC(buftail);
30824038Ssam }
30924038Ssam return (line[bufhead]);
31024038Ssam }
31124038Ssam
31224038Ssam /*
31324038Ssam * empty the queue by printing out all its lines.
31424038Ssam */
emptyqueue()31524038Ssam emptyqueue()
31624038Ssam {
31724038Ssam while (buftail != bufhead) {
31824038Ssam fputs(line[buftail], stdout);
31924038Ssam buftail = SUCC(buftail);
32024038Ssam }
32124038Ssam }
32224038Ssam
32324038Ssam /*
32424038Ssam * Compute the hash of a string.
32524038Ssam * Return the hash and the size of the item hashed
32624038Ssam */
hash(cp,size)32724038Ssam hash(cp, size)
32824038Ssam char *cp;
32924038Ssam int *size;
33024038Ssam {
33124038Ssam register char *cp1 = cp;
33224038Ssam register int hash = 0;
33324038Ssam
33424038Ssam while (*cp1 && *cp1 != '\n')
33524038Ssam hash += (int)*cp1++;
33624038Ssam *size = cp1 - cp + 1;
33724038Ssam hash &= HSHSIZ - 1;
33824038Ssam return (hash);
33924038Ssam }
340