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