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