xref: /csrg-svn/sys/vax/inline/main.c (revision 24395)
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.9 (Berkeley) 08/22/85";
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 *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), pp->name)) {
119 					pp = NULL;
120 					break;
121 				}
122 				expand(pp->replace);
123 				bufp = line[bufhead];
124 				break;
125 			}
126 		}
127 		if (!pp) {
128 			emptyqueue();
129 			fputs(bufp, stdout);
130 		}
131 	}
132 	emptyqueue();
133 	if (dflag)
134 		fprintf(stderr, "%s: %s %d, %s %d, %s %d, %s %d\n",
135 			whoami,
136 			"attempts", stats.attempted,
137 			"finished", stats.finished,
138 			"inhibited", stats.lostmodified,
139 			"merged", stats.savedpush);
140 	exit(0);
141 }
142 
143 /*
144  * Integrate an expansion into the assembly stream
145  */
146 expand(replace)
147 	char *replace;
148 {
149 	register int curptr;
150 	char *nextreplace, *argv[MAXARGS];
151 	int argc, argreg, foundarg, mod = 0, args = 0;
152 	char parsebuf[BUFSIZ];
153 
154 	stats.attempted++;
155 	for (curptr = bufhead; ; ) {
156 		nextreplace = copyline(replace, line[bufhead]);
157 		argc = parseline(line[bufhead], argv, parsebuf);
158 		argreg = nextarg(argc, argv);
159 		if (argreg == -1)
160 			break;
161 		args++;
162 		for (foundarg = 0; curptr != buftail; ) {
163 			curptr = PRED(curptr);
164 			argc = parseline(line[curptr], argv, parsebuf);
165 			if (isendofblock(argc, argv))
166 				break;
167 			if (foundarg = ispusharg(argc, argv))
168 				break;
169 			mod |= 1 << modifies(argc, argv);
170 		}
171 		if (!foundarg)
172 			break;
173 		replace = nextreplace;
174 		if (mod & (1 << argreg)) {
175 			stats.lostmodified++;
176 			if (curptr == buftail) {
177 				(void)newline();
178 				break;
179 			}
180 			(void)newline();
181 		} else {
182 			stats.savedpush++;
183 			rewrite(line[curptr], argc, argv, argreg);
184 			mod |= 1 << argreg;
185 		}
186 	}
187 	if (argreg == -1)
188 		stats.finished++;
189 	emptyqueue();
190 	fputs(replace, stdout);
191 	cleanup(args);
192 }
193 
194 /*
195  * Parse a line of assembly language into opcode and arguments.
196  */
197 parseline(linep, argv, linebuf)
198 	char *linep;
199 	char *argv[];
200 	char *linebuf;
201 {
202 	register char *bufp = linebuf, *cp = linep;
203 	register int argc = 0;
204 
205 	for (;;) {
206 		/*
207 		 * skip over white space
208 		 */
209 		while (isspace(*cp))
210 			cp++;
211 		if (*cp == '\0')
212 			return (argc);
213 		/*
214 		 * copy argument
215 		 */
216 		if (argc == MAXARGS - 1) {
217 			fprintf(stderr, "instruction too long->%s", linep);
218 			return (argc);
219 		}
220 		argv[argc++] = bufp;
221 		while (!isspace(*cp) && *cp != ARGSEPCHAR && *cp != COMMENTCHAR)
222 			*bufp++ = *cp++;
223 		*bufp++ = '\0';
224 		if (*cp == COMMENTCHAR)
225 			return (argc);
226 		if (*cp == ARGSEPCHAR)
227 			cp++;
228 	}
229 }
230 
231 /*
232  * Check for instructions that end a basic block.
233  */
234 isendofblock(argc, argv)
235 	int argc;
236 	char *argv[];
237 {
238 	register struct inststoptbl *itp;
239 	int size;
240 
241 	if (argc == 0)
242 		return (0);
243 	for (itp = inststoptblhdr[hash(argv[0], &size)]; itp; itp = itp->next)
244 		if (itp->size == size && bcmp(argv[0], itp->name, size) == 0)
245 			return (1);
246 	return (0);
247 }
248 
249 /*
250  * Copy a newline terminated string.
251  * Return pointer to character following last character copied.
252  */
253 char *
254 copyline(from, to)
255 	register char *from, *to;
256 {
257 
258 	while (*from != '\n')
259 		*to++ = *from++;
260 	*to++ = *from++;
261 	*to = '\0';
262 	return (from);
263 }
264 
265 /*
266  * Check for a disparity between the number of arguments a function
267  * is called with and the number which we expect to see.
268  * If the error is unrecoverable, return 1, otherwise 0.
269  */
270 argcounterr(args, callargs, name)
271 	int args, callargs;
272 	char *name;
273 {
274 	register char *cp;
275 	char namebuf[MAXLINELEN];
276 
277 	if (args == callargs)
278 		return (0);
279 	cp = strcpy(namebuf, name);
280 	while (*cp != '\0' && *cp != '\n')
281 		++cp;
282 	if (*cp == '\n')
283 		*cp = '\0';
284 	if (callargs >= 0) {
285 		fprintf(stderr,
286 		"%s: error: arg count mismatch, %d != %d for '%s' at line %d\n",
287 			whoami, callargs, args, namebuf, lineno);
288 		return (1);
289 	}
290 	fprintf(stderr,
291 		"%s: warning: can't verify arg count for '%s' at line %d\n",
292 		whoami, namebuf, lineno);
293 	return (0);
294 }
295 
296 /*
297  * open space for next line in the queue
298  */
299 char *
300 newline()
301 {
302 	bufhead = SUCC(bufhead);
303 	if (bufhead == buftail) {
304 		fputs(line[buftail], stdout);
305 		buftail = SUCC(buftail);
306 	}
307 	return (line[bufhead]);
308 }
309 
310 /*
311  * empty the queue by printing out all its lines.
312  */
313 emptyqueue()
314 {
315 	while (buftail != bufhead) {
316 		fputs(line[buftail], stdout);
317 		buftail = SUCC(buftail);
318 	}
319 }
320 
321 /*
322  * Compute the hash of a string.
323  * Return the hash and the size of the item hashed
324  */
325 hash(cp, size)
326 	char *cp;
327 	int *size;
328 {
329 	register char *cp1 = cp;
330 	register int hash = 0;
331 
332 	while (*cp1 && *cp1 != '\n')
333 		hash += (int)*cp1++;
334 	*size = cp1 - cp + 1;
335 	hash &= HSHSIZ - 1;
336 	return (hash);
337 }
338