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