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