xref: /original-bsd/sys/tahoe/inline/main.c (revision 53fb7652)
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 
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  */
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  */
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  */
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 *
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  */
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 *
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  */
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  */
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