1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <ctype.h> 5 #include <errno.h> 6 #include "pic.h" 7 #include "y.tab.h" 8 9 Infile infile[10]; 10 Infile *curfile = infile; 11 12 #define MAXSRC 50 13 Src src[MAXSRC]; /* input source stack */ 14 Src *srcp = src; 15 16 void do_thru(void); 17 int nextchar(void); 18 int getarg(char *); 19 void freedef(char *); 20 int baldelim(int, char *); 21 22 void pushsrc(int type, char *ptr) /* new input source */ 23 { 24 if (++srcp >= src + MAXSRC) 25 ERROR "inputs nested too deep" FATAL; 26 srcp->type = type; 27 srcp->sp = ptr; 28 if (dbg > 1) { 29 printf("\n%3d ", srcp - src); 30 switch (srcp->type) { 31 case File: 32 printf("push file %s\n", ((Infile *)ptr)->fname); 33 break; 34 case Macro: 35 printf("push macro <%s>\n", ptr); 36 break; 37 case Char: 38 printf("push char <%c>\n", *ptr); 39 break; 40 case Thru: 41 printf("push thru\n"); 42 break; 43 case String: 44 printf("push string <%s>\n", ptr); 45 break; 46 case Free: 47 printf("push free <%s>\n", ptr); 48 break; 49 default: 50 ERROR "pushed bad type %d", srcp->type FATAL; 51 } 52 } 53 } 54 55 void popsrc(void) /* restore an old one */ 56 { 57 if (srcp <= src) 58 ERROR "too many inputs popped" FATAL; 59 if (dbg > 1) { 60 printf("%3d ", srcp - src); 61 switch (srcp->type) { 62 case File: 63 printf("pop file\n"); 64 break; 65 case Macro: 66 printf("pop macro\n"); 67 break; 68 case Char: 69 printf("pop char <%c>\n", *srcp->sp); 70 break; 71 case Thru: 72 printf("pop thru\n"); 73 break; 74 case String: 75 printf("pop string\n"); 76 break; 77 case Free: 78 printf("pop free\n"); 79 break; 80 default: 81 ERROR "pop weird input %d", srcp->type FATAL; 82 } 83 } 84 srcp--; 85 } 86 87 void definition(char *s) /* collect definition for s and install */ 88 /* definitions picked up lexically */ 89 { 90 char *p; 91 struct symtab *stp; 92 93 p = delimstr("definition"); 94 stp = lookup(s); 95 if (stp != NULL) { /* it's there before */ 96 if (stp->s_type != DEFNAME) { 97 ERROR "%s used as variable and definition", s WARNING; 98 return; 99 } 100 free(stp->s_val.p); 101 stp->s_val.p = p; 102 } else { 103 YYSTYPE u; 104 u.p = p; 105 makevar(tostring(s), DEFNAME, u); 106 } 107 dprintf("installing %s as `%s'\n", s, p); 108 } 109 110 char *delimstr(char *s) /* get body of X ... X */ 111 /* message if too big */ 112 { 113 int c, delim, rdelim, n, deep; 114 static char *buf = NULL; 115 static int nbuf = 0; 116 char *p; 117 118 if (buf == NULL) 119 buf = grow(buf, "buf", nbuf += 1000, sizeof(buf[0])); 120 while ((delim = input()) == ' ' || delim == '\t' || delim == '\n') 121 ; 122 rdelim = baldelim(delim, "{}"); /* could be "(){}[]`'" */ 123 deep = 1; 124 for (p = buf; ; ) { 125 c = input(); 126 if (c == rdelim) 127 if (--deep == 0) 128 break; 129 if (c == delim) 130 deep++; 131 if (p >= buf + nbuf) { 132 n = p - buf; 133 buf = grow(buf, "buf", nbuf += 1000, sizeof(buf[0])); 134 p = buf + n; 135 } 136 if (c == EOF) 137 ERROR "end of file in %s %c %.20s... %c", s, delim, buf, delim FATAL; 138 *p++ = c; 139 } 140 *p = '\0'; 141 dprintf("delimstr %s %c <%s> %c\n", s, delim, buf, delim); 142 return tostring(buf); 143 } 144 145 baldelim(int c, char *s) /* replace c by balancing entry in s */ 146 { 147 for ( ; *s; s += 2) 148 if (*s == c) 149 return s[1]; 150 return c; 151 } 152 153 void undefine(char *s) /* undefine macro */ 154 { 155 while (*s != ' ' && *s != '\t') /* skip "undef..." */ 156 s++; 157 while (*s == ' ' || *s == '\t') 158 s++; 159 freedef(s); 160 } 161 162 163 Arg args[10]; /* argument frames */ 164 Arg *argfp = args; /* frame pointer */ 165 int argcnt; /* number of arguments seen so far */ 166 167 void dodef(struct symtab *stp) /* collect args and switch input to defn */ 168 { 169 int i, len; 170 char *p; 171 Arg *ap; 172 173 ap = argfp+1; 174 if (ap >= args+10) 175 ERROR "arguments too deep" FATAL; 176 argcnt = 0; 177 if (input() != '(') 178 ERROR "disaster in dodef" FATAL; 179 if (ap->argval == 0) 180 ap->argval = malloc(1000); 181 for (p = ap->argval; (len = getarg(p)) != -1; p += len) { 182 ap->argstk[argcnt++] = p; 183 if (input() == ')') 184 break; 185 } 186 for (i = argcnt; i < MAXARGS; i++) 187 ap->argstk[i] = ""; 188 if (dbg) 189 for (i = 0; i < argcnt; i++) 190 printf("arg %d.%d = <%s>\n", ap-args, i+1, ap->argstk[i]); 191 argfp = ap; 192 pushsrc(Macro, stp->s_val.p); 193 } 194 195 getarg(char *p) /* pick up single argument, store in p, return length */ 196 { 197 int n, c, npar; 198 199 n = npar = 0; 200 for ( ;; ) { 201 c = input(); 202 if (c == EOF) 203 ERROR "end of file in getarg" FATAL; 204 if (npar == 0 && (c == ',' || c == ')')) 205 break; 206 if (c == '"') /* copy quoted stuff intact */ 207 do { 208 *p++ = c; 209 n++; 210 } while ((c = input()) != '"' && c != EOF); 211 else if (c == '(') 212 npar++; 213 else if (c == ')') 214 npar--; 215 n++; 216 *p++ = c; 217 } 218 *p = 0; 219 unput(c); 220 return(n + 1); 221 } 222 223 #define PBSIZE 2000 224 char pbuf[PBSIZE]; /* pushback buffer */ 225 char *pb = pbuf-1; /* next pushed back character */ 226 227 char ebuf[200]; /* collect input here for error reporting */ 228 char *ep = ebuf; 229 230 int begin = 0; 231 extern int thru; 232 extern struct symtab *thrudef; 233 extern char *untilstr; 234 235 input(void) 236 { 237 register int c; 238 239 if (thru && begin) { 240 do_thru(); 241 begin = 0; 242 } 243 c = nextchar(); 244 if (dbg > 1) 245 printf(" <%c>", c); 246 if (ep >= ebuf + sizeof ebuf) 247 ep = ebuf; 248 return *ep++ = c; 249 } 250 251 nextchar(void) 252 { 253 register int c; 254 255 loop: 256 switch (srcp->type) { 257 case Free: /* free string */ 258 free(srcp->sp); 259 popsrc(); 260 goto loop; 261 case Thru: /* end of pushed back line */ 262 begin = 1; 263 popsrc(); 264 c = '\n'; 265 break; 266 case Char: 267 if (pb >= pbuf) { 268 c = *pb--; 269 popsrc(); 270 break; 271 } else { /* can't happen? */ 272 popsrc(); 273 goto loop; 274 } 275 case String: 276 c = *srcp->sp++; 277 if (c == '\0') { 278 popsrc(); 279 goto loop; 280 } else { 281 if (*srcp->sp == '\0') /* empty, so pop */ 282 popsrc(); 283 break; 284 } 285 case Macro: 286 c = *srcp->sp++; 287 if (c == '\0') { 288 if (--argfp < args) 289 ERROR "argfp underflow" FATAL; 290 popsrc(); 291 goto loop; 292 } else if (c == '$' && isdigit(*srcp->sp)) { 293 int n = 0; 294 while (isdigit(*srcp->sp)) 295 n = 10 * n + *srcp->sp++ - '0'; 296 if (n > 0 && n <= MAXARGS) 297 pushsrc(String, argfp->argstk[n-1]); 298 goto loop; 299 } 300 break; 301 case File: 302 c = getc(curfile->fin); 303 if (c == EOF) { 304 if (curfile == infile) 305 ERROR "end of file inside .PS/.PE" FATAL; 306 if (curfile->fin != stdin) { 307 fclose(curfile->fin); 308 free(curfile->fname); /* assumes allocated */ 309 } 310 curfile--; 311 printlf(curfile->lineno, curfile->fname); 312 popsrc(); 313 thru = 0; /* chicken out */ 314 thrudef = 0; 315 if (untilstr) { 316 free(untilstr); 317 untilstr = 0; 318 } 319 goto loop; 320 } 321 if (c == '\n') 322 curfile->lineno++; 323 break; 324 } 325 return c; 326 } 327 328 void do_thru(void) /* read one line, make into a macro expansion */ 329 { 330 int c, i; 331 char *p; 332 Arg *ap; 333 334 ap = argfp+1; 335 if (ap >= args+10) 336 ERROR "arguments too deep" FATAL; 337 if (ap->argval == NULL) 338 ap->argval = malloc(1000); 339 p = ap->argval; 340 argcnt = 0; 341 c = nextchar(); 342 if (thru == 0) { /* end of file was seen, so thru is done */ 343 unput(c); 344 return; 345 } 346 for ( ; c != '\n' && c != EOF; ) { 347 if (c == ' ' || c == '\t') { 348 c = nextchar(); 349 continue; 350 } 351 ap->argstk[argcnt++] = p; 352 if (c == '"') { 353 do { 354 *p++ = c; 355 if ((c = nextchar()) == '\\') { 356 *p++ = c; 357 *p++ = nextchar(); 358 c = nextchar(); 359 } 360 } while (c != '"' && c != '\n' && c != EOF); 361 *p++ = '"'; 362 if (c == '"') 363 c = nextchar(); 364 } else { 365 do { 366 *p++ = c; 367 } while ((c = nextchar())!=' ' && c!='\t' && c!='\n' && c!=',' && c!=EOF); 368 if (c == ',') 369 c = nextchar(); 370 } 371 *p++ = '\0'; 372 } 373 if (c == EOF) 374 ERROR "unexpected end of file in do_thru" FATAL; 375 if (argcnt == 0) { /* ignore blank line */ 376 pushsrc(Thru, (char *) 0); 377 return; 378 } 379 for (i = argcnt; i < MAXARGS; i++) 380 ap->argstk[i] = ""; 381 if (dbg) 382 for (i = 0; i < argcnt; i++) 383 printf("arg %d.%d = <%s>\n", ap-args, i+1, ap->argstk[i]); 384 if (strcmp(ap->argstk[0], ".PE") == 0) { 385 thru = 0; 386 thrudef = 0; 387 pushsrc(String, "\n.PE\n"); 388 return; 389 } 390 if (untilstr && strcmp(ap->argstk[0], untilstr) == 0) { 391 thru = 0; 392 thrudef = 0; 393 free(untilstr); 394 untilstr = 0; 395 return; 396 } 397 pushsrc(Thru, (char *) 0); 398 dprintf("do_thru pushing back <%s>\n", thrudef->s_val.p); 399 argfp = ap; 400 pushsrc(Macro, thrudef->s_val.p); 401 } 402 403 unput(int c) 404 { 405 if (++pb >= pbuf + sizeof pbuf) 406 ERROR "pushback overflow" FATAL; 407 if (--ep < ebuf) 408 ep = ebuf + sizeof(ebuf) - 1; 409 *pb = c; 410 pushsrc(Char, pb); 411 return c; 412 } 413 414 void pbstr(char *s) 415 { 416 pushsrc(String, s); 417 } 418 419 double errcheck(double x, char *s) 420 { 421 extern int errno; 422 423 if (errno == EDOM) { 424 errno = 0; 425 ERROR "%s argument out of domain", s WARNING; 426 } else if (errno == ERANGE) { 427 errno = 0; 428 ERROR "%s result out of range", s WARNING; 429 } 430 return x; 431 } 432 433 char errbuf[200]; 434 435 void eprint(void); 436 437 void yyerror(char *s) 438 { 439 extern char *cmdname; 440 441 if (synerr) 442 return; 443 fflush(stdout); 444 fprintf(stderr, "%s: %s", cmdname, s); 445 if (errno > 0) 446 perror("?"); 447 if (curfile) 448 fprintf(stderr, " near line %d, file %s", 449 curfile->lineno, curfile->fname); 450 fprintf(stderr, "\n"); 451 if (curfile->fin) 452 eprint(); 453 synerr = 1; 454 errno = 0; 455 } 456 457 void eprint(void) /* try to print context around error */ 458 { 459 char *p, *q; 460 461 p = ep - 1; 462 if (p > ebuf && *p == '\n') 463 p--; 464 for ( ; p >= ebuf && *p != '\n'; p--) 465 ; 466 while (*p == '\n') 467 p++; 468 fprintf(stderr, " context is\n\t"); 469 for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--) 470 ; 471 while (p < q) 472 putc(*p++, stderr); 473 fprintf(stderr, " >>> "); 474 while (p < ep) 475 putc(*p++, stderr); 476 fprintf(stderr, " <<< "); 477 while (pb >= pbuf) 478 putc(*pb--, stderr); 479 fgets(ebuf, sizeof ebuf, curfile->fin); 480 fprintf(stderr, "%s", ebuf); 481 pbstr("\n.PE\n"); /* safety first */ 482 ep = ebuf; 483 } 484 485 void yywrap(void) {} 486 487 char *newfile = 0; /* filename for file copy */ 488 char *untilstr = 0; /* string that terminates a thru */ 489 int thru = 0; /* 1 if copying thru macro */ 490 struct symtab *thrudef = 0; /* macro being used */ 491 492 void copyfile(char *s) /* remember file to start reading from */ 493 { 494 newfile = s; 495 } 496 497 void copydef(struct symtab *p) /* remember macro symtab ptr */ 498 { 499 thrudef = p; 500 } 501 502 struct symtab *copythru(char *s) /* collect the macro name or body for thru */ 503 { 504 struct symtab *p; 505 char *q, *addnewline(char *); 506 507 p = lookup(s); 508 if (p != NULL) { 509 if (p->s_type == DEFNAME) { 510 p->s_val.p = addnewline(p->s_val.p); 511 return p; 512 } else 513 ERROR "%s used as define and name", s FATAL; 514 } 515 /* have to collect the definition */ 516 pbstr(s); /* first char is the delimiter */ 517 q = delimstr("thru body"); 518 s = "nameless"; 519 p = lookup(s); 520 if (p != NULL) { 521 if (p->s_val.p) 522 free(p->s_val.p); 523 p->s_val.p = q; 524 } else { 525 YYSTYPE u; 526 u.p = q; 527 p = makevar(tostring(s), DEFNAME, u); 528 } 529 p->s_val.p = addnewline(p->s_val.p); 530 dprintf("installing %s as `%s'\n", s, p->s_val.p); 531 return p; 532 } 533 534 char *addnewline(char *p) /* add newline to end of p */ 535 { 536 int n; 537 538 n = strlen(p); 539 if (p[n-1] != '\n') { 540 p = realloc(p, n+2); 541 p[n] = '\n'; 542 p[n+1] = '\0'; 543 } 544 return p; 545 } 546 547 void copyuntil(char *s) /* string that terminates a thru */ 548 { 549 untilstr = s; 550 } 551 552 void copy(void) /* begin input from file, etc. */ 553 { 554 FILE *fin; 555 556 if (newfile) { 557 if ((fin = fopen(newfile, "r")) == NULL) 558 ERROR "can't open file %s", newfile FATAL; 559 curfile++; 560 curfile->fin = fin; 561 curfile->fname = newfile; 562 curfile->lineno = 0; 563 printlf(1, curfile->fname); 564 pushsrc(File, curfile->fname); 565 newfile = 0; 566 } 567 if (thrudef) { 568 thru = 1; 569 begin = 1; /* wrong place */ 570 } 571 } 572 573 char shellbuf[1000], *shellp; 574 575 void shell_init(void) /* set up to interpret a shell command */ 576 { 577 sprintf(shellbuf, "sh -c '"); 578 shellp = shellbuf + strlen(shellbuf); 579 } 580 581 void shell_text(char *s) /* add string to command being collected */ 582 { 583 while (*shellp++ = *s++) 584 ; 585 shellp--; 586 } 587 588 void shell_exec(void) /* do it */ 589 { 590 *shellp++ = '\''; 591 *shellp = '\0'; 592 system(shellbuf); 593 } 594