xref: /csrg-svn/sys/vax/inline/main.c (revision 18448)
1 /* Copyright (c) 1984 Regents of the University of California */
2 
3 #ifndef lint
4 static char sccsid[] = "@(#)main.c	1.7	(Berkeley)	03/20/85";
5 #endif not lint
6 
7 #include <stdio.h>
8 #include <ctype.h>
9 #include "inline.h"
10 
11 /*
12  * These are the pattern tables to be loaded
13  */
14 struct pats *inittables[] = {
15 	language_ptab,
16 	libc_ptab,
17 	machine_ptab,
18 	0
19 };
20 
21 /*
22  * Statistics collection
23  */
24 struct stats {
25 	int	attempted;	/* number of expansion attempts */
26 	int	finished;	/* expansions done before end of basic block */
27 	int	lostmodified;	/* mergers inhibited by intervening mod */
28 	int	savedpush;	/* successful push/pop merger */
29 } stats;
30 int dflag;
31 
32 main(argc, argv)
33 	int argc;
34 	char *argv[];
35 {
36 	register char *cp, *lp;
37 	register char *bufp;
38 	register struct pats *pp, **php;
39 	struct pats **tablep;
40 	register struct inststoptbl *itp, **ithp;
41 	int size;
42 	extern char *index();
43 
44 	if (argc > 1 && bcmp(argv[1], "-d", 3) == 0)
45 		dflag++, argc--, argv++;
46 	if (argc > 1)
47 		freopen(argv[1], "r", stdin);
48 	if (argc > 2)
49 		freopen(argv[2], "w", stdout);
50 	/*
51 	 * Set up the hash table for the patterns.
52 	 */
53 	for (tablep = inittables; *tablep; tablep++) {
54 		for (pp = *tablep; pp->name[0] != '\0'; pp++) {
55 			php = &patshdr[hash(pp->name, &size)];
56 			pp->size = size;
57 			pp->next = *php;
58 			*php = pp;
59 		}
60 	}
61 	/*
62 	 * Set up the hash table for the instruction stop table.
63 	 */
64 	for (itp = inststoptable; itp->name[0] != '\0'; itp++) {
65 		ithp = &inststoptblhdr[hash(itp->name, &size)];
66 		itp->size = size;
67 		itp->next = *ithp;
68 		*ithp = itp;
69 	}
70 	/*
71 	 * check each line and replace as appropriate
72 	 */
73 	buftail = bufhead = 0;
74 	bufp = line[0];
75 	while (fgets(bufp, MAXLINELEN, stdin)) {
76 		lp = index(bufp, LABELCHAR);
77 		if (lp != NULL) {
78 			for (cp = bufp; cp < lp; cp++)
79 				if (!isalnum(*cp))
80 					break;
81 			if (cp == lp) {
82 				bufp = newline();
83 				if (*++lp == '\n') {
84 					emptyqueue();
85 					continue;
86 				}
87 				strcpy(bufp, lp);
88 				*lp++ = '\n';
89 				*lp = '\0';
90 				emptyqueue();
91 			}
92 		}
93 		for (cp = bufp; isspace(*cp); cp++)
94 			/* void */;
95 		if ((cp = doreplaceon(cp)) == 0) {
96 			bufp = newline();
97 			continue;
98 		}
99 		for (pp = patshdr[hash(cp, &size)]; pp; pp = pp->next) {
100 			if (pp->size == size && bcmp(pp->name, cp, size) == 0) {
101 				expand(pp->replace);
102 				bufp = line[bufhead];
103 				break;
104 			}
105 		}
106 		if (!pp) {
107 			emptyqueue();
108 			fputs(bufp, stdout);
109 		}
110 	}
111 	emptyqueue();
112 	if (dflag)
113 		fprintf(stderr, "inline: %s %d, %s %d, %s %d, %s %d\n",
114 			"attempts", stats.attempted,
115 			"finished", stats.finished,
116 			"inhibited", stats.lostmodified,
117 			"merged", stats.savedpush);
118 	exit(0);
119 }
120 
121 /*
122  * Integrate an expansion into the assembly stream
123  */
124 expand(replace)
125 	char *replace;
126 {
127 	register int curptr;
128 	char *nextreplace, *argv[MAXARGS];
129 	int argc, argreg, foundarg, mod = 0, args = 0;
130 	char parsebuf[BUFSIZ];
131 
132 	stats.attempted++;
133 	for (curptr = bufhead; ; ) {
134 		nextreplace = copyline(replace, line[bufhead]);
135 		argc = parseline(line[bufhead], argv, parsebuf);
136 		argreg = nextarg(argc, argv);
137 		if (argreg == -1)
138 			break;
139 		args++;
140 		for (foundarg = 0; curptr != buftail; ) {
141 			curptr = PRED(curptr);
142 			argc = parseline(line[curptr], argv, parsebuf);
143 			if (isendofblock(argc, argv))
144 				break;
145 			if (foundarg = ispusharg(argc, argv))
146 				break;
147 			mod |= 1 << modifies(argc, argv);
148 		}
149 		if (!foundarg)
150 			break;
151 		replace = nextreplace;
152 		if (mod & (1 << argreg)) {
153 			stats.lostmodified++;
154 			if (curptr == buftail) {
155 				(void)newline();
156 				break;
157 			}
158 			(void)newline();
159 		} else {
160 			stats.savedpush++;
161 			rewrite(line[curptr], argc, argv, argreg);
162 			mod |= 1 << argreg;
163 		}
164 	}
165 	if (argreg == -1)
166 		stats.finished++;
167 	emptyqueue();
168 	fputs(replace, stdout);
169 	cleanup(args);
170 }
171 
172 /*
173  * Parse a line of assembly language into opcode and arguments.
174  */
175 parseline(linep, argv, linebuf)
176 	char *linep;
177 	char *argv[];
178 	char *linebuf;
179 {
180 	register char *bufp = linebuf, *cp = linep;
181 	register int argc = 0;
182 
183 	for (;;) {
184 		/*
185 		 * skip over white space
186 		 */
187 		while (isspace(*cp))
188 			cp++;
189 		if (*cp == '\0')
190 			return (argc);
191 		/*
192 		 * copy argument
193 		 */
194 		if (argc == MAXARGS - 1) {
195 			fprintf(stderr, "instruction too long->%s", linep);
196 			return (argc);
197 		}
198 		argv[argc++] = bufp;
199 		while (!isspace(*cp) && *cp != ARGSEPCHAR && *cp != COMMENTCHAR)
200 			*bufp++ = *cp++;
201 		*bufp++ = '\0';
202 		if (*cp == COMMENTCHAR)
203 			return (argc);
204 		if (*cp == ARGSEPCHAR)
205 			cp++;
206 	}
207 }
208 
209 /*
210  * Check for instructions that end a basic block.
211  */
212 isendofblock(argc, argv)
213 	int argc;
214 	char *argv[];
215 {
216 	register struct inststoptbl *itp;
217 	int size;
218 
219 	if (argc == 0)
220 		return (0);
221 	for (itp = inststoptblhdr[hash(argv[0], &size)]; itp; itp = itp->next)
222 		if (itp->size == size && bcmp(argv[0], itp->name, size) == 0)
223 			return (1);
224 	return (0);
225 }
226 
227 /*
228  * Copy a newline terminated string.
229  * Return pointer to character following last character copied.
230  */
231 char *
232 copyline(from, to)
233 	register char *from, *to;
234 {
235 
236 	while (*from != '\n')
237 		*to++ = *from++;
238 	*to++ = *from++;
239 	*to = '\0';
240 	return (from);
241 }
242 
243 /*
244  * open space for next line in the queue
245  */
246 char *
247 newline()
248 {
249 	bufhead = SUCC(bufhead);
250 	if (bufhead == buftail) {
251 		fputs(line[buftail], stdout);
252 		buftail = SUCC(buftail);
253 	}
254 	return (line[bufhead]);
255 }
256 
257 /*
258  * empty the queue by printing out all its lines.
259  */
260 emptyqueue()
261 {
262 	while (buftail != bufhead) {
263 		fputs(line[buftail], stdout);
264 		buftail = SUCC(buftail);
265 	}
266 }
267 
268 /*
269  * Compute the hash of a string.
270  * Return the hash and the size of the item hashed
271  */
272 hash(cp, size)
273 	char *cp;
274 	int *size;
275 {
276 	register char *cp1 = cp;
277 	register int hash = 0;
278 
279 	while (*cp1 && *cp1 != '\n')
280 		hash += (int)*cp1++;
281 	*size = cp1 - cp + 1;
282 	hash &= HSHSIZ - 1;
283 	return (hash);
284 }
285