ref: f43df64325efb80fc48a85009df016477238b21b
dir: /sys/src/cmd/eqn/input.c/
#include "e.h" #include "y.tab.h" #include <ctype.h> #include <errno.h> Infile infile[10]; Infile *curfile = infile; #define MAXSRC 50 Src src[MAXSRC]; /* input source stack */ Src *srcp = src; extern int getarg(char *); extern void eprint(void); void pushsrc(int type, char *ptr) /* new input source */ { if (++srcp >= src + MAXSRC) ERROR "inputs nested too deep" FATAL; srcp->type = type; srcp->sp = ptr; if (dbg > 1) { printf("\n%3d ", srcp - src); switch (srcp->type) { case File: printf("push file %s\n", ((Infile *)ptr)->fname); break; case Macro: printf("push macro <%s>\n", ptr); break; case Char: printf("push char <%c>\n", *ptr); break; case String: printf("push string <%s>\n", ptr); break; case Free: printf("push free <%s>\n", ptr); break; default: ERROR "pushed bad type %d\n", srcp->type FATAL; } } } void popsrc(void) /* restore an old one */ { if (srcp <= src) ERROR "too many inputs popped" FATAL; if (dbg > 1) { printf("%3d ", srcp - src); switch (srcp->type) { case File: printf("pop file\n"); break; case Macro: printf("pop macro\n"); break; case Char: printf("pop char <%c>\n", *srcp->sp); break; case String: printf("pop string\n"); break; case Free: printf("pop free\n"); break; default: ERROR "pop weird input %d\n", srcp->type FATAL; } } srcp--; } Arg args[10]; /* argument frames */ Arg *argfp = args; /* frame pointer */ int argcnt; /* number of arguments seen so far */ void dodef(tbl *stp) /* collect args and switch input to defn */ { int i, len; char *p; Arg *ap; ap = argfp+1; if (ap >= args+10) ERROR "more than arguments\n" FATAL; argcnt = 0; if (input() != '(') ERROR "disaster in dodef\n"FATAL; if (ap->argval == 0) ap->argval = malloc(1000); for (p = ap->argval; (len = getarg(p)) != -1; p += len) { ap->argstk[argcnt++] = p; if (input() == ')') break; } for (i = argcnt; i < MAXARGS; i++) ap->argstk[i] = ""; if (dbg) for (i = 0; i < argcnt; i++) printf("arg %d.%d = <%s>\n", ap-args, i+1, ap->argstk[i]); argfp = ap; pushsrc(Macro, stp->cval); } getarg(char *p) /* pick up single argument, store in p, return length */ { int n, c, npar; n = npar = 0; for ( ;; ) { c = input(); if (c == EOF) ERROR "end of file in getarg!\n" FATAL; if (npar == 0 && (c == ',' || c == ')')) break; if (c == '"') /* copy quoted stuff intact */ do { *p++ = c; n++; } while ((c = input()) != '"' && c != EOF); else if (c == '(') npar++; else if (c == ')') npar--; n++; *p++ = c; } *p = 0; unput(c); return(n + 1); } #define PBSIZE 2000 char pbuf[PBSIZE]; /* pushback buffer */ char *pb = pbuf-1; /* next pushed back character */ char ebuf[200]; /* collect input here for error reporting */ char *ep = ebuf; input(void) { register int c = 0; loop: switch (srcp->type) { case File: c = getc(curfile->fin); if (c == EOF) { if (curfile == infile) break; if (curfile->fin != stdin) { fclose(curfile->fin); free(curfile->fname); /* assumes allocated */ } curfile--; printf(".lf %d %s\n", curfile->lineno, curfile->fname); popsrc(); goto loop; } if (c == '\n') curfile->lineno++; break; case Char: if (pb >= pbuf) { c = *pb--; popsrc(); break; } else { /* can't happen? */ popsrc(); goto loop; } case String: c = *srcp->sp++; if (c == '\0') { popsrc(); goto loop; } else { if (*srcp->sp == '\0') /* empty, so pop */ popsrc(); break; } case Macro: c = *srcp->sp++; if (c == '\0') { if (--argfp < args) ERROR "argfp underflow" FATAL; popsrc(); goto loop; } else if (c == '$' && isdigit(*srcp->sp)) { int n = 0; while (isdigit(*srcp->sp)) n = 10 * n + *srcp->sp++ - '0'; if (n > 0 && n <= MAXARGS) pushsrc(String, argfp->argstk[n-1]); goto loop; } break; case Free: /* free string */ free(srcp->sp); popsrc(); goto loop; } if (ep >= ebuf + sizeof ebuf) ep = ebuf; *ep++ = c; return c; } unput(int c) { if (++pb >= pbuf + sizeof pbuf) ERROR "pushback overflow\n"FATAL; if (--ep < ebuf) ep = ebuf + sizeof(ebuf) - 1; *pb = c; pushsrc(Char, pb); return c; } void pbstr(char *s) { pushsrc(String, s); } void error(int die, char *s) { extern char *cmdname; if (synerr) return; fprintf(stderr, "%s: ", cmdname); fprintf(stderr, s); if (errno > 0) perror("???"); if (curfile->fin) fprintf(stderr, " near %s:%d", curfile->fname, curfile->lineno+1); fprintf(stderr, "\n"); eprint(); synerr = 1; errno = 0; if (die) { if (dbg) abort(); else exit(1); } } void yyerror(char *s) { error(0, s); /* temporary */ } char errbuf[200]; void eprint(void) /* try to print context around error */ { char *p, *q; if (ep == ebuf) return; /* no context */ p = ep - 1; if (p > ebuf && *p == '\n') p--; for ( ; p >= ebuf && *p != '\n'; p--) ; while (*p == '\n') p++; fprintf(stderr, " context is\n\t"); for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--) ; while (p < q) putc(*p++, stderr); fprintf(stderr, " >>> "); while (p < ep) putc(*p++, stderr); fprintf(stderr, " <<< "); while (pb >= pbuf) putc(*pb--, stderr); if (curfile->fin) fgets(ebuf, sizeof ebuf, curfile->fin); fprintf(stderr, "%s", ebuf); pbstr("\n.EN\n"); /* safety first */ ep = ebuf; }