1 /*-
2 * Copyright (c) 1984 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 */
7
8 #ifndef lint
9 char copyright[] =
10 "@(#) Copyright (c) 1984 The Regents of the University of California.\n\
11 All rights reserved.\n";
12 #endif /* not lint */
13
14 #ifndef lint
15 static char sccsid[] = "@(#)main.c 1.4 (Berkeley) 05/08/91";
16 #endif /* not lint */
17
18 #include <stdio.h>
19 #include <ctype.h>
20 #include "inline.h"
21
22 /*
23 * These are the pattern tables to be loaded
24 */
25 struct pats *inittables[] = {
26 language_ptab,
27 libc_ptab,
28 machine_ptab,
29 0
30 };
31
32 /*
33 * Statistics collection
34 */
35 struct stats {
36 int attempted; /* number of expansion attempts */
37 int finished; /* expansions done before end of basic block */
38 int lostmodified; /* mergers inhibited by intervening mod */
39 int savedpush; /* successful push/pop merger */
40 } stats;
41
42 extern char *strcpy();
43
44 char *whoami;
45 int lineno = 0;
46 int dflag;
47
main(argc,argv)48 main(argc, argv)
49 int argc;
50 char *argv[];
51 {
52 register char *cp, *lp;
53 register char *bufp;
54 register struct pats *pp, **php;
55 struct pats **tablep;
56 register struct inststoptbl *itp, **ithp;
57 int size;
58 extern char *index();
59
60 whoami = argv[0];
61 if (argc > 1 && bcmp(argv[1], "-d", 3) == 0)
62 dflag++, argc--, argv++;
63 if (argc > 1)
64 freopen(argv[1], "r", stdin);
65 if (argc > 2)
66 freopen(argv[2], "w", stdout);
67 /*
68 * Set up the hash table for the patterns.
69 */
70 for (tablep = inittables; *tablep; tablep++) {
71 for (pp = *tablep; pp->name[0] != '\0'; pp++) {
72 php = &patshdr[hash(pp->name, &size)];
73 pp->size = size;
74 pp->next = *php;
75 *php = pp;
76 }
77 }
78 /*
79 * Set up the hash table for the instruction stop table.
80 */
81 for (itp = inststoptable; itp->name[0] != '\0'; itp++) {
82 ithp = &inststoptblhdr[hash(itp->name, &size)];
83 itp->size = size;
84 itp->next = *ithp;
85 *ithp = itp;
86 }
87 /*
88 * check each line and replace as appropriate
89 */
90 buftail = bufhead = 0;
91 bufp = line[0];
92 while (fgets(bufp, MAXLINELEN, stdin)) {
93 lineno++;
94 lp = index(bufp, LABELCHAR);
95 if (lp != NULL) {
96 for (cp = bufp; cp < lp; cp++)
97 if (!isalnum(*cp))
98 break;
99 if (cp == lp) {
100 bufp = newline();
101 if (*++lp == '\n') {
102 emptyqueue();
103 continue;
104 }
105 (void) strcpy(bufp, lp);
106 *lp++ = '\n';
107 *lp = '\0';
108 emptyqueue();
109 }
110 }
111 for (cp = bufp; isspace(*cp); cp++)
112 /* void */;
113 if ((cp = doreplaceon(cp)) == 0) {
114 bufp = newline();
115 continue;
116 }
117 for (pp = patshdr[hash(cp, &size)]; pp; pp = pp->next) {
118 if (pp->size == size && bcmp(pp->name, cp, size) == 0) {
119 if (argcounterr(pp->args, countargs(bufp),
120 pp->name)) {
121 pp = NULL;
122 break;
123 }
124 expand(pp->replace);
125 bufp = line[bufhead];
126 break;
127 }
128 }
129 if (!pp) {
130 emptyqueue();
131 fputs(bufp, stdout);
132 }
133 }
134 emptyqueue();
135 if (dflag)
136 fprintf(stderr, "%s: %s %d, %s %d, %s %d, %s %d\n",
137 whoami,
138 "attempts", stats.attempted,
139 "finished", stats.finished,
140 "inhibited", stats.lostmodified,
141 "merged", stats.savedpush);
142 exit(0);
143 }
144
145 /*
146 * Integrate an expansion into the assembly stream
147 */
expand(replace)148 expand(replace)
149 char *replace;
150 {
151 register int curptr;
152 char *nextreplace, *argv[MAXARGS];
153 int argc, argreg, foundarg, mod = 0, args = 0;
154 char parsebuf[BUFSIZ];
155
156 stats.attempted++;
157 for (curptr = bufhead; ; ) {
158 nextreplace = copyline(replace, line[bufhead]);
159 argc = parseline(line[bufhead], argv, parsebuf);
160 argreg = nextarg(argc, argv);
161 if (argreg == -1)
162 break;
163 args++;
164 for (foundarg = 0; curptr != buftail; ) {
165 curptr = PRED(curptr);
166 argc = parseline(line[curptr], argv, parsebuf);
167 if (isendofblock(argc, argv))
168 break;
169 if (foundarg = ispusharg(argc, argv))
170 break;
171 mod |= 1 << modifies(argc, argv);
172 }
173 if (!foundarg)
174 break;
175 replace = nextreplace;
176 if (mod & (1 << argreg)) {
177 stats.lostmodified++;
178 if (curptr == buftail) {
179 (void)newline();
180 break;
181 }
182 (void)newline();
183 } else {
184 stats.savedpush++;
185 rewrite(line[curptr], argc, argv, argreg);
186 mod |= 1 << argreg;
187 }
188 }
189 if (argreg == -1)
190 stats.finished++;
191 emptyqueue();
192 fputs(replace, stdout);
193 cleanup(args);
194 }
195
196 /*
197 * Parse a line of assembly language into opcode and arguments.
198 */
parseline(linep,argv,linebuf)199 parseline(linep, argv, linebuf)
200 char *linep;
201 char *argv[];
202 char *linebuf;
203 {
204 register char *bufp = linebuf, *cp = linep;
205 register int argc = 0;
206
207 for (;;) {
208 /*
209 * skip over white space
210 */
211 while (isspace(*cp))
212 cp++;
213 if (*cp == '\0')
214 return (argc);
215 /*
216 * copy argument
217 */
218 if (argc == MAXARGS - 1) {
219 fprintf(stderr, "instruction too long->%s", linep);
220 return (argc);
221 }
222 argv[argc++] = bufp;
223 while (!isspace(*cp) && *cp != ARGSEPCHAR && *cp != COMMENTCHAR)
224 *bufp++ = *cp++;
225 *bufp++ = '\0';
226 if (*cp == COMMENTCHAR)
227 return (argc);
228 if (*cp == ARGSEPCHAR)
229 cp++;
230 }
231 }
232
233 /*
234 * Check for instructions that end a basic block.
235 */
isendofblock(argc,argv)236 isendofblock(argc, argv)
237 int argc;
238 char *argv[];
239 {
240 register struct inststoptbl *itp;
241 int size;
242
243 if (argc == 0)
244 return (0);
245 for (itp = inststoptblhdr[hash(argv[0], &size)]; itp; itp = itp->next)
246 if (itp->size == size && bcmp(argv[0], itp->name, size) == 0)
247 return (1);
248 return (0);
249 }
250
251 /*
252 * Copy a newline terminated string.
253 * Return pointer to character following last character copied.
254 */
255 char *
copyline(from,to)256 copyline(from, to)
257 register char *from, *to;
258 {
259
260 while (*from != '\n')
261 *to++ = *from++;
262 *to++ = *from++;
263 *to = '\0';
264 return (from);
265 }
266
267 /*
268 * Check for a disparity between the number of arguments a function
269 * is called with and the number which we expect to see.
270 * If the error is unrecoverable, return 1, otherwise 0.
271 */
argcounterr(args,callargs,name)272 argcounterr(args, callargs, name)
273 int args, callargs;
274 char *name;
275 {
276 register char *cp;
277 char namebuf[MAXLINELEN];
278
279 if (args == callargs)
280 return (0);
281 cp = strcpy(namebuf, name);
282 while (*cp != '\0' && *cp != '\n')
283 ++cp;
284 if (*cp == '\n')
285 *cp = '\0';
286 if (callargs >= 0) {
287 fprintf(stderr,
288 "%s: error: arg count mismatch, %d != %d for '%s' at line %d\n",
289 whoami, callargs, args, namebuf, lineno);
290 return (1);
291 }
292 fprintf(stderr,
293 "%s: warning: can't verify arg count for '%s' at line %d\n",
294 whoami, namebuf, lineno);
295 return (0);
296 }
297
298 /*
299 * open space for next line in the queue
300 */
301 char *
newline()302 newline()
303 {
304 bufhead = SUCC(bufhead);
305 if (bufhead == buftail) {
306 fputs(line[buftail], stdout);
307 buftail = SUCC(buftail);
308 }
309 return (line[bufhead]);
310 }
311
312 /*
313 * empty the queue by printing out all its lines.
314 */
emptyqueue()315 emptyqueue()
316 {
317 while (buftail != bufhead) {
318 fputs(line[buftail], stdout);
319 buftail = SUCC(buftail);
320 }
321 }
322
323 /*
324 * Compute the hash of a string.
325 * Return the hash and the size of the item hashed
326 */
hash(cp,size)327 hash(cp, size)
328 char *cp;
329 int *size;
330 {
331 register char *cp1 = cp;
332 register int hash = 0;
333
334 while (*cp1 && *cp1 != '\n')
335 hash += (int)*cp1++;
336 *size = cp1 - cp + 1;
337 hash &= HSHSIZ - 1;
338 return (hash);
339 }
340