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