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