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