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