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 12 13 #ifndef lint 14 static char sccsid[] = "@(#)main.c 1.3 (Berkeley) 02/24/86"; 15 #endif 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), 119 pp->name)) { 120 pp = NULL; 121 break; 122 } 123 expand(pp->replace); 124 bufp = line[bufhead]; 125 break; 126 } 127 } 128 if (!pp) { 129 emptyqueue(); 130 fputs(bufp, stdout); 131 } 132 } 133 emptyqueue(); 134 if (dflag) 135 fprintf(stderr, "%s: %s %d, %s %d, %s %d, %s %d\n", 136 whoami, 137 "attempts", stats.attempted, 138 "finished", stats.finished, 139 "inhibited", stats.lostmodified, 140 "merged", stats.savedpush); 141 exit(0); 142 } 143 144 /* 145 * Integrate an expansion into the assembly stream 146 */ 147 expand(replace) 148 char *replace; 149 { 150 register int curptr; 151 char *nextreplace, *argv[MAXARGS]; 152 int argc, argreg, foundarg, mod = 0, args = 0; 153 char parsebuf[BUFSIZ]; 154 155 stats.attempted++; 156 for (curptr = bufhead; ; ) { 157 nextreplace = copyline(replace, line[bufhead]); 158 argc = parseline(line[bufhead], argv, parsebuf); 159 argreg = nextarg(argc, argv); 160 if (argreg == -1) 161 break; 162 args++; 163 for (foundarg = 0; curptr != buftail; ) { 164 curptr = PRED(curptr); 165 argc = parseline(line[curptr], argv, parsebuf); 166 if (isendofblock(argc, argv)) 167 break; 168 if (foundarg = ispusharg(argc, argv)) 169 break; 170 mod |= 1 << modifies(argc, argv); 171 } 172 if (!foundarg) 173 break; 174 replace = nextreplace; 175 if (mod & (1 << argreg)) { 176 stats.lostmodified++; 177 if (curptr == buftail) { 178 (void)newline(); 179 break; 180 } 181 (void)newline(); 182 } else { 183 stats.savedpush++; 184 rewrite(line[curptr], argc, argv, argreg); 185 mod |= 1 << argreg; 186 } 187 } 188 if (argreg == -1) 189 stats.finished++; 190 emptyqueue(); 191 fputs(replace, stdout); 192 cleanup(args); 193 } 194 195 /* 196 * Parse a line of assembly language into opcode and arguments. 197 */ 198 parseline(linep, argv, linebuf) 199 char *linep; 200 char *argv[]; 201 char *linebuf; 202 { 203 register char *bufp = linebuf, *cp = linep; 204 register int argc = 0; 205 206 for (;;) { 207 /* 208 * skip over white space 209 */ 210 while (isspace(*cp)) 211 cp++; 212 if (*cp == '\0') 213 return (argc); 214 /* 215 * copy argument 216 */ 217 if (argc == MAXARGS - 1) { 218 fprintf(stderr, "instruction too long->%s", linep); 219 return (argc); 220 } 221 argv[argc++] = bufp; 222 while (!isspace(*cp) && *cp != ARGSEPCHAR && *cp != COMMENTCHAR) 223 *bufp++ = *cp++; 224 *bufp++ = '\0'; 225 if (*cp == COMMENTCHAR) 226 return (argc); 227 if (*cp == ARGSEPCHAR) 228 cp++; 229 } 230 } 231 232 /* 233 * Check for instructions that end a basic block. 234 */ 235 isendofblock(argc, argv) 236 int argc; 237 char *argv[]; 238 { 239 register struct inststoptbl *itp; 240 int size; 241 242 if (argc == 0) 243 return (0); 244 for (itp = inststoptblhdr[hash(argv[0], &size)]; itp; itp = itp->next) 245 if (itp->size == size && bcmp(argv[0], itp->name, size) == 0) 246 return (1); 247 return (0); 248 } 249 250 /* 251 * Copy a newline terminated string. 252 * Return pointer to character following last character copied. 253 */ 254 char * 255 copyline(from, to) 256 register char *from, *to; 257 { 258 259 while (*from != '\n') 260 *to++ = *from++; 261 *to++ = *from++; 262 *to = '\0'; 263 return (from); 264 } 265 266 /* 267 * Check for a disparity between the number of arguments a function 268 * is called with and the number which we expect to see. 269 * If the error is unrecoverable, return 1, otherwise 0. 270 */ 271 argcounterr(args, callargs, name) 272 int args, callargs; 273 char *name; 274 { 275 register char *cp; 276 char namebuf[MAXLINELEN]; 277 278 if (args == callargs) 279 return (0); 280 cp = strcpy(namebuf, name); 281 while (*cp != '\0' && *cp != '\n') 282 ++cp; 283 if (*cp == '\n') 284 *cp = '\0'; 285 if (callargs >= 0) { 286 fprintf(stderr, 287 "%s: error: arg count mismatch, %d != %d for '%s' at line %d\n", 288 whoami, callargs, args, namebuf, lineno); 289 return (1); 290 } 291 fprintf(stderr, 292 "%s: warning: can't verify arg count for '%s' at line %d\n", 293 whoami, namebuf, lineno); 294 return (0); 295 } 296 297 /* 298 * open space for next line in the queue 299 */ 300 char * 301 newline() 302 { 303 bufhead = SUCC(bufhead); 304 if (bufhead == buftail) { 305 fputs(line[buftail], stdout); 306 buftail = SUCC(buftail); 307 } 308 return (line[bufhead]); 309 } 310 311 /* 312 * empty the queue by printing out all its lines. 313 */ 314 emptyqueue() 315 { 316 while (buftail != bufhead) { 317 fputs(line[buftail], stdout); 318 buftail = SUCC(buftail); 319 } 320 } 321 322 /* 323 * Compute the hash of a string. 324 * Return the hash and the size of the item hashed 325 */ 326 hash(cp, size) 327 char *cp; 328 int *size; 329 { 330 register char *cp1 = cp; 331 register int hash = 0; 332 333 while (*cp1 && *cp1 != '\n') 334 hash += (int)*cp1++; 335 *size = cp1 - cp + 1; 336 hash &= HSHSIZ - 1; 337 return (hash); 338 } 339