1 #ifndef lint 2 static char sccsid[] = "@(#)input.c 2.2 (CWI) 87/04/01"; 3 #endif lint 4 #include <stdio.h> 5 #include <ctype.h> 6 #include <errno.h> 7 #include "e.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 pushsrc(type, ptr) /* new input source */ 18 int type; 19 char *ptr; 20 { 21 if (++srcp >= src + MAXSRC) 22 fatal("inputs nested too deep"); 23 srcp->type = type; 24 srcp->sp = ptr; 25 if (dbg > 1) { 26 printf("\n%3d ", srcp - src); 27 switch (srcp->type) { 28 case File: 29 printf("push file %s\n", ((Infile *)ptr)->fname); 30 break; 31 case Macro: 32 printf("push macro <%s>\n", ptr); 33 break; 34 case Char: 35 printf("push char <%c>\n", *ptr); 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 fatal("pushed bad type %d\n", srcp->type); 45 } 46 } 47 } 48 49 popsrc() /* restore an old one */ 50 { 51 if (srcp <= src) 52 fatal("too many inputs popped"); 53 if (dbg > 1) { 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 String: 66 printf("pop string\n"); 67 break; 68 case Free: 69 printf("pop free\n"); 70 break; 71 default: 72 fatal("pop weird input %d\n", srcp->type); 73 } 74 } 75 srcp--; 76 } 77 78 Arg args[10]; /* argument frames */ 79 Arg *argfp = args; /* frame pointer */ 80 int argcnt; /* number of arguments seen so far */ 81 82 dodef(stp) /* collect args and switch input to defn */ 83 tbl *stp; 84 { 85 int i, len; 86 char *p; 87 Arg *ap; 88 89 ap = argfp+1; 90 if (ap >= args+10) 91 fatal("arguments too deep"); 92 argcnt = 0; 93 if (input() != '(') 94 fatal("disaster in dodef\n"); 95 if (ap->argval == 0) 96 ap->argval = malloc(1000); 97 for (p = ap->argval; (len = getarg(p)) != -1; p += len) { 98 ap->argstk[argcnt++] = p; 99 if (input() == ')') 100 break; 101 } 102 for (i = argcnt; i < MAXARGS; i++) 103 ap->argstk[i] = ""; 104 if (dbg) 105 for (i = 0; i < argcnt; i++) 106 printf("arg %d.%d = <%s>\n", ap-args, i+1, ap->argstk[i]); 107 argfp = ap; 108 pushsrc(Macro, stp->defn); 109 } 110 111 getarg(p) /* pick up single argument, store in p, return length */ 112 char *p; 113 { 114 int n, c, npar; 115 116 n = npar = 0; 117 for ( ;; ) { 118 c = input(); 119 if (c == EOF) 120 fatal("end of file in getarg!\n"); 121 if (npar == 0 && (c == ',' || c == ')')) 122 break; 123 if (c == '"') /* copy quoted stuff intact */ 124 do { 125 *p++ = c; 126 n++; 127 } while ((c = input()) != '"' && c != EOF); 128 else if (c == '(') 129 npar++; 130 else if (c == ')') 131 npar--; 132 n++; 133 *p++ = c; 134 } 135 *p = 0; 136 unput(c); 137 return(n + 1); 138 } 139 140 #define PBSIZE 2000 141 char pbuf[PBSIZE]; /* pushback buffer */ 142 char *pb = pbuf-1; /* next pushed back character */ 143 144 char ebuf[200]; /* collect input here for error reporting */ 145 char *ep = ebuf; 146 147 input() 148 { 149 register int c; 150 151 loop: 152 switch (srcp->type) { 153 case File: 154 c = getc(curfile->fin); 155 if (c == EOF) { 156 if (curfile == infile) 157 break; 158 if (curfile->fin != stdin) { 159 fclose(curfile->fin); 160 free(curfile->fname); /* assumes allocated */ 161 } 162 curfile--; 163 printf(".lf %d %s\n", curfile->lineno, curfile->fname); 164 popsrc(); 165 goto loop; 166 } 167 if (c == '\n') 168 curfile->lineno++; 169 break; 170 case Char: 171 if (pb >= pbuf) { 172 c = *pb--; 173 popsrc(); 174 break; 175 } else { /* can't happen? */ 176 popsrc(); 177 goto loop; 178 } 179 case String: 180 c = *srcp->sp++; 181 if (c == '\0') { 182 popsrc(); 183 goto loop; 184 } else { 185 if (*srcp->sp == '\0') /* empty, so pop */ 186 popsrc(); 187 break; 188 } 189 case Macro: 190 c = *srcp->sp++; 191 if (c == '\0') { 192 if (--argfp < args) 193 fatal("argfp underflow"); 194 popsrc(); 195 goto loop; 196 } else if (c == '$' && isdigit(*srcp->sp)) { 197 int n = 0; 198 while (isdigit(*srcp->sp)) 199 n = 10 * n + *srcp->sp++ - '0'; 200 if (n > 0 && n <= MAXARGS) 201 pushsrc(String, argfp->argstk[n-1]); 202 goto loop; 203 } 204 break; 205 case Free: /* free string */ 206 free(srcp->sp); 207 popsrc(); 208 goto loop; 209 } 210 if (ep >= ebuf + sizeof ebuf) 211 ep = ebuf; 212 *ep++ = c; 213 return c; 214 } 215 216 217 unput(c) 218 { 219 if (++pb >= pbuf + sizeof pbuf) 220 fatal("pushback overflow\n"); 221 if (--ep < ebuf) 222 ep = ebuf + sizeof(ebuf) - 1; 223 *pb = c; 224 pushsrc(Char, pb); 225 return c; 226 } 227 228 pbstr(s) 229 char *s; 230 { 231 pushsrc(String, s); 232 } 233 234 fatal(s, s1, s2, s3, s4) /* should be a flag on error */ 235 char *s, *s1, *s2, *s3, *s4; 236 { 237 error(FATAL, s, s1, s2, s3, s4); 238 } 239 240 error(die, s, s1, s2, s3, s4) 241 int die; 242 char *s, *s1, *s2, *s3, *s4; 243 { 244 extern char *cmdname, *sys_errlist[]; 245 extern int errno, sys_nerr; 246 247 if (synerr) 248 return; 249 fprintf(stderr, "%s: ", cmdname); 250 fprintf(stderr, s, s1, s2, s3, s4); 251 if (errno > 0 && errno < sys_nerr) 252 fprintf(stderr, " (%s)", sys_errlist[errno]); 253 if (curfile->fin) 254 fprintf(stderr, " near line %d, file %s", 255 curfile->lineno, curfile->fname); 256 fprintf(stderr, "\n"); 257 eprint(); 258 synerr = 1; 259 errno = 0; 260 if (die) { 261 if (dbg) 262 abort(); 263 else 264 exit(1); 265 } 266 } 267 268 yyerror() {;} 269 270 eprint() /* try to print context around error */ 271 { 272 char *p, *q; 273 int c; 274 275 if (ep == ebuf) 276 return; /* no context */ 277 p = ep - 1; 278 if (p > ebuf && *p == '\n') 279 p--; 280 for ( ; p >= ebuf && *p != '\n'; p--) 281 ; 282 while (*p == '\n') 283 p++; 284 fprintf(stderr, " context is\n\t"); 285 for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--) 286 ; 287 while (p < q) 288 putc(*p++, stderr); 289 fprintf(stderr, " >>> "); 290 while (p < ep) 291 putc(*p++, stderr); 292 fprintf(stderr, " <<< "); 293 while (pb >= pbuf) 294 putc(*pb--, stderr); 295 if (curfile->fin) 296 fgets(ebuf, sizeof ebuf, curfile->fin); 297 fprintf(stderr, "%s", ebuf); 298 pbstr("\n.EN\n"); /* safety first */ 299 ep = ebuf; 300 } 301