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