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