blob: a0c0c34e454067ddbaebbf5753a584e26f6fdbb7 [file] [log] [blame]
#include "e.h"
#include "y.tab.h"
#include <ctype.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%3ld ", (long)(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("%3ld ", (long)(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 %ld.%d = <%s>\n", (long)(ap-args), i+1, ap->argstk[i]);
argfp = ap;
pushsrc(Macro, stp->cval);
}
int
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;
int
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((unsigned char)*srcp->sp)) {
int n = 0;
while (isdigit((unsigned char)*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;
}
int
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: %s", cmdname, 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;
}