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