diff options
Diffstat (limited to 'src/cmd/eqn/input.c')
-rw-r--r-- | src/cmd/eqn/input.c | 289 |
1 files changed, 289 insertions, 0 deletions
diff --git a/src/cmd/eqn/input.c b/src/cmd/eqn/input.c new file mode 100644 index 00000000..3b865671 --- /dev/null +++ b/src/cmd/eqn/input.c @@ -0,0 +1,289 @@ +#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; +} |