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