xref: /netbsd-src/external/gpl2/groff/dist/src/preproc/pic/lex.cpp (revision 89a07cf815a29524268025a1139fac4c5190f765)
1 /*	$NetBSD: lex.cpp,v 1.1.1.1 2016/01/13 18:41:48 christos Exp $	*/
2 
3 // -*- C++ -*-
4 /* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2002, 2003, 2004
5      Free Software Foundation, Inc.
6      Written by James Clark (jjc@jclark.com)
7 
8 This file is part of groff.
9 
10 groff is free software; you can redistribute it and/or modify it under
11 the terms of the GNU General Public License as published by the Free
12 Software Foundation; either version 2, or (at your option) any later
13 version.
14 
15 groff is distributed in the hope that it will be useful, but WITHOUT ANY
16 WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
18 for more details.
19 
20 You should have received a copy of the GNU General Public License along
21 with groff; see the file COPYING.  If not, write to the Free Software
22 Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
23 
24 #include "pic.h"
25 #include "ptable.h"
26 #include "object.h"
27 #include "pic_tab.h"
28 
29 declare_ptable(char)
30 implement_ptable(char)
31 
32 PTABLE(char) macro_table;
33 
34 class macro_input : public input {
35   char *s;
36   char *p;
37 public:
38   macro_input(const char *);
39   ~macro_input();
40   int get();
41   int peek();
42 };
43 
44 class argument_macro_input : public input {
45   char *s;
46   char *p;
47   char *ap;
48   int argc;
49   char *argv[9];
50 public:
51   argument_macro_input(const char *, int, char **);
52   ~argument_macro_input();
53   int get();
54   int peek();
55 };
56 
input()57 input::input() : next(0)
58 {
59 }
60 
~input()61 input::~input()
62 {
63 }
64 
get_location(const char **,int *)65 int input::get_location(const char **, int *)
66 {
67   return 0;
68 }
69 
file_input(FILE * f,const char * fn)70 file_input::file_input(FILE *f, const char *fn)
71 : fp(f), filename(fn), lineno(0), ptr("")
72 {
73 }
74 
~file_input()75 file_input::~file_input()
76 {
77   fclose(fp);
78 }
79 
read_line()80 int file_input::read_line()
81 {
82   for (;;) {
83     line.clear();
84     lineno++;
85     for (;;) {
86       int c = getc(fp);
87       if (c == EOF)
88 	break;
89       else if (invalid_input_char(c))
90 	lex_error("invalid input character code %1", c);
91       else {
92 	line += char(c);
93 	if (c == '\n')
94 	  break;
95       }
96     }
97     if (line.length() == 0)
98       return 0;
99     if (!(line.length() >= 3 && line[0] == '.' && line[1] == 'P'
100 	  && (line[2] == 'S' || line[2] == 'E' || line[2] == 'F')
101 	  && (line.length() == 3 || line[3] == ' ' || line[3] == '\n'
102 	      || compatible_flag))) {
103       line += '\0';
104       ptr = line.contents();
105       return 1;
106     }
107   }
108 }
109 
get()110 int file_input::get()
111 {
112   if (*ptr != '\0' || read_line())
113     return (unsigned char)*ptr++;
114   else
115     return EOF;
116 }
117 
peek()118 int file_input::peek()
119 {
120   if (*ptr != '\0' || read_line())
121     return (unsigned char)*ptr;
122   else
123     return EOF;
124 }
125 
get_location(const char ** fnp,int * lnp)126 int file_input::get_location(const char **fnp, int *lnp)
127 {
128   *fnp = filename;
129   *lnp = lineno;
130   return 1;
131 }
132 
macro_input(const char * str)133 macro_input::macro_input(const char *str)
134 {
135   p = s = strsave(str);
136 }
137 
~macro_input()138 macro_input::~macro_input()
139 {
140   a_delete s;
141 }
142 
get()143 int macro_input::get()
144 {
145   if (p == 0 || *p == '\0')
146     return EOF;
147   else
148     return (unsigned char)*p++;
149 }
150 
peek()151 int macro_input::peek()
152 {
153   if (p == 0 || *p == '\0')
154     return EOF;
155   else
156     return (unsigned char)*p;
157 }
158 
159 // Character representing $1.  Must be invalid input character.
160 #define ARG1 14
161 
process_body(const char * body)162 char *process_body(const char *body)
163 {
164   char *s = strsave(body);
165   int j = 0;
166   for (int i = 0; s[i] != '\0'; i++)
167     if (s[i] == '$' && s[i+1] >= '0' && s[i+1] <= '9') {
168       if (s[i+1] != '0')
169 	s[j++] = ARG1 + s[++i] - '1';
170     }
171     else
172       s[j++] = s[i];
173   s[j] = '\0';
174   return s;
175 }
176 
177 
argument_macro_input(const char * body,int ac,char ** av)178 argument_macro_input::argument_macro_input(const char *body, int ac, char **av)
179 : ap(0), argc(ac)
180 {
181   for (int i = 0; i < argc; i++)
182     argv[i] = av[i];
183   p = s = process_body(body);
184 }
185 
186 
~argument_macro_input()187 argument_macro_input::~argument_macro_input()
188 {
189   for (int i = 0; i < argc; i++)
190     a_delete argv[i];
191   a_delete s;
192 }
193 
get()194 int argument_macro_input::get()
195 {
196   if (ap) {
197     if (*ap != '\0')
198       return (unsigned char)*ap++;
199     ap = 0;
200   }
201   if (p == 0)
202     return EOF;
203   while (*p >= ARG1 && *p <= ARG1 + 8) {
204     int i = *p++ - ARG1;
205     if (i < argc && argv[i] != 0 && argv[i][0] != '\0') {
206       ap = argv[i];
207       return (unsigned char)*ap++;
208     }
209   }
210   if (*p == '\0')
211     return EOF;
212   return (unsigned char)*p++;
213 }
214 
peek()215 int argument_macro_input::peek()
216 {
217   if (ap) {
218     if (*ap != '\0')
219       return (unsigned char)*ap;
220     ap = 0;
221   }
222   if (p == 0)
223     return EOF;
224   while (*p >= ARG1 && *p <= ARG1 + 8) {
225     int i = *p++ - ARG1;
226     if (i < argc && argv[i] != 0 && argv[i][0] != '\0') {
227       ap = argv[i];
228       return (unsigned char)*ap;
229     }
230   }
231   if (*p == '\0')
232     return EOF;
233   return (unsigned char)*p;
234 }
235 
236 class input_stack {
237   static input *current_input;
238   static int bol_flag;
239 public:
240   static void push(input *);
241   static void clear();
242   static int get_char();
243   static int peek_char();
244   static int get_location(const char **fnp, int *lnp);
245   static void push_back(unsigned char c, int was_bol = 0);
246   static int bol();
247 };
248 
249 input *input_stack::current_input = 0;
250 int input_stack::bol_flag = 0;
251 
bol()252 inline int input_stack::bol()
253 {
254   return bol_flag;
255 }
256 
clear()257 void input_stack::clear()
258 {
259   while (current_input != 0) {
260     input *tem = current_input;
261     current_input = current_input->next;
262     delete tem;
263   }
264   bol_flag = 1;
265 }
266 
push(input * in)267 void input_stack::push(input *in)
268 {
269   in->next = current_input;
270   current_input = in;
271 }
272 
lex_init(input * top)273 void lex_init(input *top)
274 {
275   input_stack::clear();
276   input_stack::push(top);
277 }
278 
lex_cleanup()279 void lex_cleanup()
280 {
281   while (input_stack::get_char() != EOF)
282     ;
283 }
284 
get_char()285 int input_stack::get_char()
286 {
287   while (current_input != 0) {
288     int c = current_input->get();
289     if (c != EOF) {
290       bol_flag = c == '\n';
291       return c;
292     }
293     // don't pop the top-level input off the stack
294     if (current_input->next == 0)
295       return EOF;
296     input *tem = current_input;
297     current_input = current_input->next;
298     delete tem;
299   }
300   return EOF;
301 }
302 
peek_char()303 int input_stack::peek_char()
304 {
305   while (current_input != 0) {
306     int c = current_input->peek();
307     if (c != EOF)
308       return c;
309     if (current_input->next == 0)
310       return EOF;
311     input *tem = current_input;
312     current_input = current_input->next;
313     delete tem;
314   }
315   return EOF;
316 }
317 
318 class char_input : public input {
319   int c;
320 public:
321   char_input(int);
322   int get();
323   int peek();
324 };
325 
char_input(int n)326 char_input::char_input(int n) : c((unsigned char)n)
327 {
328 }
329 
get()330 int char_input::get()
331 {
332   int n = c;
333   c = EOF;
334   return n;
335 }
336 
peek()337 int char_input::peek()
338 {
339   return c;
340 }
341 
push_back(unsigned char c,int was_bol)342 void input_stack::push_back(unsigned char c, int was_bol)
343 {
344   push(new char_input(c));
345   bol_flag = was_bol;
346 }
347 
get_location(const char ** fnp,int * lnp)348 int input_stack::get_location(const char **fnp, int *lnp)
349 {
350   for (input *p = current_input; p; p = p->next)
351     if (p->get_location(fnp, lnp))
352       return 1;
353   return 0;
354 }
355 
356 string context_buffer;
357 
358 string token_buffer;
359 double token_double;
360 int token_int;
361 
interpolate_macro_with_args(const char * body)362 void interpolate_macro_with_args(const char *body)
363 {
364   char *argv[9];
365   int argc = 0;
366   int i;
367   for (i = 0; i < 9; i++)
368     argv[i] = 0;
369   int level = 0;
370   int c;
371   enum { NORMAL, IN_STRING, IN_STRING_QUOTED } state = NORMAL;
372   do {
373     token_buffer.clear();
374     for (;;) {
375       c = input_stack::get_char();
376       if (c == EOF) {
377 	lex_error("end of input while scanning macro arguments");
378 	break;
379       }
380       if (state == NORMAL && level == 0 && (c == ',' || c == ')')) {
381 	if (token_buffer.length() > 0) {
382 	  token_buffer +=  '\0';
383 	  argv[argc] = strsave(token_buffer.contents());
384 	}
385 	// for `foo()', argc = 0
386 	if (argc > 0 || c != ')' || i > 0)
387 	  argc++;
388 	break;
389       }
390       token_buffer += char(c);
391       switch (state) {
392       case NORMAL:
393 	if (c == '"')
394 	  state = IN_STRING;
395 	else if (c == '(')
396 	  level++;
397 	else if (c == ')')
398 	  level--;
399 	break;
400       case IN_STRING:
401 	if (c == '"')
402 	  state = NORMAL;
403 	else if (c == '\\')
404 	  state = IN_STRING_QUOTED;
405 	break;
406       case IN_STRING_QUOTED:
407 	state = IN_STRING;
408 	break;
409       }
410     }
411   } while (c != ')' && c != EOF);
412   input_stack::push(new argument_macro_input(body, argc, argv));
413 }
414 
docmp(const char * s1,int n1,const char * s2,int n2)415 static int docmp(const char *s1, int n1, const char *s2, int n2)
416 {
417   if (n1 < n2) {
418     int r = memcmp(s1, s2, n1);
419     return r ? r : -1;
420   }
421   else if (n1 > n2) {
422     int r = memcmp(s1, s2, n2);
423     return r ? r : 1;
424   }
425   else
426     return memcmp(s1, s2, n1);
427 }
428 
lookup_keyword(const char * str,int len)429 int lookup_keyword(const char *str, int len)
430 {
431   static struct keyword {
432     const char *name;
433     int token;
434   } table[] = {
435     { "Here", HERE },
436     { "above", ABOVE },
437     { "aligned", ALIGNED },
438     { "and", AND },
439     { "arc", ARC },
440     { "arrow", ARROW },
441     { "at", AT },
442     { "atan2", ATAN2 },
443     { "below", BELOW },
444     { "between", BETWEEN },
445     { "bottom", BOTTOM },
446     { "box", BOX },
447     { "by", BY },
448     { "ccw", CCW },
449     { "center", CENTER },
450     { "chop", CHOP },
451     { "circle", CIRCLE },
452     { "color", COLORED },
453     { "colored", COLORED },
454     { "colour", COLORED },
455     { "coloured", COLORED },
456     { "command", COMMAND },
457     { "copy", COPY },
458     { "cos", COS },
459     { "cw", CW },
460     { "dashed", DASHED },
461     { "define", DEFINE },
462     { "diam", DIAMETER },
463     { "diameter", DIAMETER },
464     { "do", DO },
465     { "dotted", DOTTED },
466     { "down", DOWN },
467     { "east", EAST },
468     { "ellipse", ELLIPSE },
469     { "else", ELSE },
470     { "end", END },
471     { "exp", EXP },
472     { "figname", FIGNAME },
473     { "fill", FILL },
474     { "filled", FILL },
475     { "for", FOR },
476     { "from", FROM },
477     { "height", HEIGHT },
478     { "ht", HEIGHT },
479     { "if", IF },
480     { "int", INT },
481     { "invis", INVISIBLE },
482     { "invisible", INVISIBLE },
483     { "last", LAST },
484     { "left", LEFT },
485     { "line", LINE },
486     { "ljust", LJUST },
487     { "log", LOG },
488     { "lower", LOWER },
489     { "max", K_MAX },
490     { "min", K_MIN },
491     { "move", MOVE },
492     { "north", NORTH },
493     { "of", OF },
494     { "outline", OUTLINED },
495     { "outlined", OUTLINED },
496     { "plot", PLOT },
497     { "print", PRINT },
498     { "rad", RADIUS },
499     { "radius", RADIUS },
500     { "rand", RAND },
501     { "reset", RESET },
502     { "right", RIGHT },
503     { "rjust", RJUST },
504     { "same", SAME },
505     { "sh", SH },
506     { "shaded", SHADED },
507     { "sin", SIN },
508     { "solid", SOLID },
509     { "south", SOUTH },
510     { "spline", SPLINE },
511     { "sprintf", SPRINTF },
512     { "sqrt", SQRT },
513     { "srand", SRAND },
514     { "start", START },
515     { "the", THE },
516     { "then", THEN },
517     { "thick", THICKNESS },
518     { "thickness", THICKNESS },
519     { "thru", THRU },
520     { "to", TO },
521     { "top", TOP },
522     { "undef", UNDEF },
523     { "until", UNTIL },
524     { "up", UP },
525     { "upper", UPPER },
526     { "way", WAY },
527     { "west", WEST },
528     { "wid", WIDTH },
529     { "width", WIDTH },
530     { "with", WITH },
531   };
532 
533   const keyword *start = table;
534   const keyword *end = table + sizeof(table)/sizeof(table[0]);
535   while (start < end) {
536     // start <= target < end
537     const keyword *mid = start + (end - start)/2;
538 
539     int cmp = docmp(str, len, mid->name, strlen(mid->name));
540     if (cmp == 0)
541       return mid->token;
542     if (cmp < 0)
543       end = mid;
544     else
545       start = mid + 1;
546   }
547   return 0;
548 }
549 
get_token_after_dot(int c)550 int get_token_after_dot(int c)
551 {
552   // get_token deals with the case where c is a digit
553   switch (c) {
554   case 'h':
555     input_stack::get_char();
556     c = input_stack::peek_char();
557     if (c == 't') {
558       input_stack::get_char();
559       context_buffer = ".ht";
560       return DOT_HT;
561     }
562     else if (c == 'e') {
563       input_stack::get_char();
564       c = input_stack::peek_char();
565       if (c == 'i') {
566 	input_stack::get_char();
567 	c = input_stack::peek_char();
568 	if (c == 'g') {
569 	  input_stack::get_char();
570 	  c = input_stack::peek_char();
571 	  if (c == 'h') {
572 	    input_stack::get_char();
573 	    c = input_stack::peek_char();
574 	    if (c == 't') {
575 	      input_stack::get_char();
576 	      context_buffer = ".height";
577 	      return DOT_HT;
578 	    }
579 	    input_stack::push_back('h');
580 	  }
581 	  input_stack::push_back('g');
582 	}
583 	input_stack::push_back('i');
584       }
585       input_stack::push_back('e');
586     }
587     input_stack::push_back('h');
588     return '.';
589   case 'x':
590     input_stack::get_char();
591     context_buffer = ".x";
592     return DOT_X;
593   case 'y':
594     input_stack::get_char();
595     context_buffer = ".y";
596     return DOT_Y;
597   case 'c':
598     input_stack::get_char();
599     c = input_stack::peek_char();
600     if (c == 'e') {
601       input_stack::get_char();
602       c = input_stack::peek_char();
603       if (c == 'n') {
604 	input_stack::get_char();
605 	c = input_stack::peek_char();
606 	if (c == 't') {
607 	  input_stack::get_char();
608 	  c = input_stack::peek_char();
609 	  if (c == 'e') {
610 	    input_stack::get_char();
611 	    c = input_stack::peek_char();
612 	    if (c == 'r') {
613 	      input_stack::get_char();
614 	      context_buffer = ".center";
615 	      return DOT_C;
616 	    }
617 	    input_stack::push_back('e');
618 	  }
619 	  input_stack::push_back('t');
620 	}
621 	input_stack::push_back('n');
622       }
623       input_stack::push_back('e');
624     }
625     context_buffer = ".c";
626     return DOT_C;
627   case 'n':
628     input_stack::get_char();
629     c = input_stack::peek_char();
630     if (c == 'e') {
631       input_stack::get_char();
632       context_buffer = ".ne";
633       return DOT_NE;
634     }
635     else if (c == 'w') {
636       input_stack::get_char();
637       context_buffer = ".nw";
638       return DOT_NW;
639     }
640     else {
641       context_buffer = ".n";
642       return DOT_N;
643     }
644     break;
645   case 'e':
646     input_stack::get_char();
647     c = input_stack::peek_char();
648     if (c == 'n') {
649       input_stack::get_char();
650       c = input_stack::peek_char();
651       if (c == 'd') {
652 	input_stack::get_char();
653 	context_buffer = ".end";
654 	return DOT_END;
655       }
656       input_stack::push_back('n');
657       context_buffer = ".e";
658       return DOT_E;
659     }
660     context_buffer = ".e";
661     return DOT_E;
662   case 'w':
663     input_stack::get_char();
664     c = input_stack::peek_char();
665     if (c == 'i') {
666       input_stack::get_char();
667       c = input_stack::peek_char();
668       if (c == 'd') {
669 	input_stack::get_char();
670 	c = input_stack::peek_char();
671 	if (c == 't') {
672 	  input_stack::get_char();
673 	  c = input_stack::peek_char();
674 	  if (c == 'h') {
675 	    input_stack::get_char();
676 	    context_buffer = ".width";
677 	    return DOT_WID;
678 	  }
679 	  input_stack::push_back('t');
680 	}
681 	context_buffer = ".wid";
682 	return DOT_WID;
683       }
684       input_stack::push_back('i');
685     }
686     context_buffer = ".w";
687     return DOT_W;
688   case 's':
689     input_stack::get_char();
690     c = input_stack::peek_char();
691     if (c == 'e') {
692       input_stack::get_char();
693       context_buffer = ".se";
694       return DOT_SE;
695     }
696     else if (c == 'w') {
697       input_stack::get_char();
698       context_buffer = ".sw";
699       return DOT_SW;
700     }
701     else {
702       if (c == 't') {
703 	input_stack::get_char();
704 	c = input_stack::peek_char();
705 	if (c == 'a') {
706 	  input_stack::get_char();
707 	  c = input_stack::peek_char();
708 	  if (c == 'r') {
709 	    input_stack::get_char();
710 	    c = input_stack::peek_char();
711 	    if (c == 't') {
712 	      input_stack::get_char();
713 	      context_buffer = ".start";
714 	      return DOT_START;
715 	    }
716 	    input_stack::push_back('r');
717 	  }
718 	  input_stack::push_back('a');
719 	}
720 	input_stack::push_back('t');
721       }
722       context_buffer = ".s";
723       return DOT_S;
724     }
725     break;
726   case 't':
727     input_stack::get_char();
728     c = input_stack::peek_char();
729     if (c == 'o') {
730       input_stack::get_char();
731       c = input_stack::peek_char();
732       if (c == 'p') {
733 	input_stack::get_char();
734 	context_buffer = ".top";
735 	return DOT_N;
736       }
737       input_stack::push_back('o');
738     }
739     context_buffer = ".t";
740     return DOT_N;
741   case 'l':
742     input_stack::get_char();
743     c = input_stack::peek_char();
744     if (c == 'e') {
745       input_stack::get_char();
746       c = input_stack::peek_char();
747       if (c == 'f') {
748 	input_stack::get_char();
749 	c = input_stack::peek_char();
750 	if (c == 't') {
751 	  input_stack::get_char();
752 	  context_buffer = ".left";
753 	  return DOT_W;
754 	}
755 	input_stack::push_back('f');
756       }
757       input_stack::push_back('e');
758     }
759     context_buffer = ".l";
760     return DOT_W;
761   case 'r':
762     input_stack::get_char();
763     c = input_stack::peek_char();
764     if (c == 'a') {
765       input_stack::get_char();
766       c = input_stack::peek_char();
767       if (c == 'd') {
768 	input_stack::get_char();
769 	context_buffer = ".rad";
770 	return DOT_RAD;
771       }
772       input_stack::push_back('a');
773     }
774     else if (c == 'i') {
775       input_stack::get_char();
776       c = input_stack::peek_char();
777       if (c == 'g') {
778 	input_stack::get_char();
779 	c = input_stack::peek_char();
780 	if (c == 'h') {
781 	  input_stack::get_char();
782 	  c = input_stack::peek_char();
783 	  if (c == 't') {
784 	    input_stack::get_char();
785 	    context_buffer = ".right";
786 	    return DOT_E;
787 	  }
788 	  input_stack::push_back('h');
789 	}
790 	input_stack::push_back('g');
791       }
792       input_stack::push_back('i');
793     }
794     context_buffer = ".r";
795     return DOT_E;
796   case 'b':
797     input_stack::get_char();
798     c = input_stack::peek_char();
799     if (c == 'o') {
800       input_stack::get_char();
801       c = input_stack::peek_char();
802       if (c == 't') {
803 	input_stack::get_char();
804 	c = input_stack::peek_char();
805 	if (c == 't') {
806 	  input_stack::get_char();
807 	  c = input_stack::peek_char();
808 	  if (c == 'o') {
809 	    input_stack::get_char();
810 	    c = input_stack::peek_char();
811 	    if (c == 'm') {
812 	      input_stack::get_char();
813 	      context_buffer = ".bottom";
814 	      return DOT_S;
815 	    }
816 	    input_stack::push_back('o');
817 	  }
818 	  input_stack::push_back('t');
819 	}
820 	context_buffer = ".bot";
821 	return DOT_S;
822       }
823       input_stack::push_back('o');
824     }
825     context_buffer = ".b";
826     return DOT_S;
827   default:
828     context_buffer = '.';
829     return '.';
830   }
831 }
832 
get_token(int lookup_flag)833 int get_token(int lookup_flag)
834 {
835   context_buffer.clear();
836   for (;;) {
837     int n = 0;
838     int bol = input_stack::bol();
839     int c = input_stack::get_char();
840     if (bol && c == command_char) {
841       token_buffer.clear();
842       token_buffer += c;
843       // the newline is not part of the token
844       for (;;) {
845 	c = input_stack::peek_char();
846 	if (c == EOF || c == '\n')
847 	  break;
848 	input_stack::get_char();
849 	token_buffer += char(c);
850       }
851       context_buffer = token_buffer;
852       return COMMAND_LINE;
853     }
854     switch (c) {
855     case EOF:
856       return EOF;
857     case ' ':
858     case '\t':
859       break;
860     case '\\':
861       {
862 	int d = input_stack::peek_char();
863 	if (d != '\n') {
864 	  context_buffer = '\\';
865 	  return '\\';
866 	}
867 	input_stack::get_char();
868 	break;
869       }
870     case '#':
871       do {
872 	c = input_stack::get_char();
873       } while (c != '\n' && c != EOF);
874       if (c == '\n')
875 	context_buffer = '\n';
876       return c;
877     case '"':
878       context_buffer = '"';
879       token_buffer.clear();
880       for (;;) {
881 	c = input_stack::get_char();
882 	if (c == '\\') {
883 	  context_buffer += '\\';
884 	  c = input_stack::peek_char();
885 	  if (c == '"') {
886 	    input_stack::get_char();
887 	    token_buffer += '"';
888 	    context_buffer += '"';
889 	  }
890 	  else
891 	    token_buffer += '\\';
892 	}
893 	else if (c == '\n') {
894 	  error("newline in string");
895 	  break;
896 	}
897 	else if (c == EOF) {
898 	  error("missing `\"'");
899 	  break;
900 	}
901 	else if (c == '"') {
902 	  context_buffer += '"';
903 	  break;
904 	}
905 	else {
906 	  context_buffer += char(c);
907 	  token_buffer += char(c);
908 	}
909       }
910       return TEXT;
911     case '0':
912     case '1':
913     case '2':
914     case '3':
915     case '4':
916     case '5':
917     case '6':
918     case '7':
919     case '8':
920     case '9':
921       {
922 	int overflow = 0;
923 	n = 0;
924 	for (;;) {
925 	  if (n > (INT_MAX - 9)/10) {
926 	    overflow = 1;
927 	    break;
928 	  }
929 	  n *= 10;
930 	  n += c - '0';
931 	  context_buffer += char(c);
932 	  c = input_stack::peek_char();
933 	  if (c == EOF || !csdigit(c))
934 	    break;
935 	  c = input_stack::get_char();
936 	}
937 	token_double = n;
938 	if (overflow) {
939 	  for (;;) {
940 	    token_double *= 10.0;
941 	    token_double += c - '0';
942 	    context_buffer += char(c);
943 	    c = input_stack::peek_char();
944 	    if (c == EOF || !csdigit(c))
945 	      break;
946 	    c = input_stack::get_char();
947 	  }
948 	  // if somebody asks for 1000000000000th, we will silently
949 	  // give them INT_MAXth
950 	  double temp = token_double; // work around gas 1.34/sparc bug
951 	  if (token_double > INT_MAX)
952 	    n = INT_MAX;
953 	  else
954 	    n = int(temp);
955 	}
956       }
957       switch (c) {
958       case 'i':
959       case 'I':
960 	context_buffer += char(c);
961 	input_stack::get_char();
962 	return NUMBER;
963       case '.':
964 	{
965 	  context_buffer += '.';
966 	  input_stack::get_char();
967 	got_dot:
968 	  double factor = 1.0;
969 	  for (;;) {
970 	    c = input_stack::peek_char();
971 	    if (c == EOF || !csdigit(c))
972 	      break;
973 	    input_stack::get_char();
974 	    context_buffer += char(c);
975 	    factor /= 10.0;
976 	    if (c != '0')
977 	      token_double += factor*(c - '0');
978 	  }
979 	  if (c != 'e' && c != 'E') {
980 	    if (c == 'i' || c == 'I') {
981 	      context_buffer += char(c);
982 	      input_stack::get_char();
983 	    }
984 	    return NUMBER;
985 	  }
986 	}
987 	// fall through
988       case 'e':
989       case 'E':
990 	{
991 	  int echar = c;
992 	  input_stack::get_char();
993 	  c = input_stack::peek_char();
994 	  int sign = '+';
995 	  if (c == '+' || c == '-') {
996 	    sign = c;
997 	    input_stack::get_char();
998 	    c = input_stack::peek_char();
999 	    if (c == EOF || !csdigit(c)) {
1000 	      input_stack::push_back(sign);
1001 	      input_stack::push_back(echar);
1002 	      return NUMBER;
1003 	    }
1004 	    context_buffer += char(echar);
1005 	    context_buffer += char(sign);
1006 	  }
1007 	  else {
1008 	    if (c == EOF || !csdigit(c)) {
1009 	      input_stack::push_back(echar);
1010 	      return NUMBER;
1011 	    }
1012 	    context_buffer += char(echar);
1013 	  }
1014 	  input_stack::get_char();
1015 	  context_buffer += char(c);
1016 	  n = c - '0';
1017 	  for (;;) {
1018 	    c = input_stack::peek_char();
1019 	    if (c == EOF || !csdigit(c))
1020 	      break;
1021 	    input_stack::get_char();
1022 	    context_buffer += char(c);
1023 	    n = n*10 + (c - '0');
1024 	  }
1025 	  if (sign == '-')
1026 	    n = -n;
1027 	  if (c == 'i' || c == 'I') {
1028 	    context_buffer += char(c);
1029 	    input_stack::get_char();
1030 	  }
1031 	  token_double *= pow(10.0, n);
1032 	  return NUMBER;
1033 	}
1034       case 'n':
1035 	input_stack::get_char();
1036 	c = input_stack::peek_char();
1037 	if (c == 'd') {
1038 	  input_stack::get_char();
1039 	  token_int = n;
1040 	  context_buffer += "nd";
1041 	  return ORDINAL;
1042 	}
1043 	input_stack::push_back('n');
1044 	return NUMBER;
1045       case 'r':
1046 	input_stack::get_char();
1047 	c = input_stack::peek_char();
1048 	if (c == 'd') {
1049 	  input_stack::get_char();
1050 	  token_int = n;
1051 	  context_buffer += "rd";
1052 	  return ORDINAL;
1053 	}
1054 	input_stack::push_back('r');
1055 	return NUMBER;
1056       case 't':
1057 	input_stack::get_char();
1058 	c = input_stack::peek_char();
1059 	if (c == 'h') {
1060 	  input_stack::get_char();
1061 	  token_int = n;
1062 	  context_buffer += "th";
1063 	  return ORDINAL;
1064 	}
1065 	input_stack::push_back('t');
1066 	return NUMBER;
1067       case 's':
1068 	input_stack::get_char();
1069 	c = input_stack::peek_char();
1070 	if (c == 't') {
1071 	  input_stack::get_char();
1072 	  token_int = n;
1073 	  context_buffer += "st";
1074 	  return ORDINAL;
1075 	}
1076 	input_stack::push_back('s');
1077 	return NUMBER;
1078       default:
1079 	return NUMBER;
1080       }
1081       break;
1082     case '\'':
1083       {
1084 	c = input_stack::peek_char();
1085 	if (c == 't') {
1086 	  input_stack::get_char();
1087 	  c = input_stack::peek_char();
1088 	  if (c == 'h') {
1089 	    input_stack::get_char();
1090 	    context_buffer = "'th";
1091 	    return TH;
1092 	  }
1093 	  else
1094 	    input_stack::push_back('t');
1095 	}
1096 	context_buffer = "'";
1097 	return '\'';
1098       }
1099     case '.':
1100       {
1101 	c = input_stack::peek_char();
1102 	if (c != EOF && csdigit(c)) {
1103 	  n = 0;
1104 	  token_double = 0.0;
1105 	  context_buffer = '.';
1106 	  goto got_dot;
1107 	}
1108 	return get_token_after_dot(c);
1109       }
1110     case '<':
1111       c = input_stack::peek_char();
1112       if (c == '-') {
1113 	input_stack::get_char();
1114 	c = input_stack::peek_char();
1115 	if (c == '>') {
1116 	  input_stack::get_char();
1117 	  context_buffer = "<->";
1118 	  return DOUBLE_ARROW_HEAD;
1119 	}
1120 	context_buffer = "<-";
1121 	return LEFT_ARROW_HEAD;
1122       }
1123       else if (c == '=') {
1124 	input_stack::get_char();
1125 	context_buffer = "<=";
1126 	return LESSEQUAL;
1127       }
1128       context_buffer = "<";
1129       return '<';
1130     case '-':
1131       c = input_stack::peek_char();
1132       if (c == '>') {
1133 	input_stack::get_char();
1134 	context_buffer = "->";
1135 	return RIGHT_ARROW_HEAD;
1136       }
1137       context_buffer = "-";
1138       return '-';
1139     case '!':
1140       c = input_stack::peek_char();
1141       if (c == '=') {
1142 	input_stack::get_char();
1143 	context_buffer = "!=";
1144 	return NOTEQUAL;
1145       }
1146       context_buffer = "!";
1147       return '!';
1148     case '>':
1149       c = input_stack::peek_char();
1150       if (c == '=') {
1151 	input_stack::get_char();
1152 	context_buffer = ">=";
1153 	return GREATEREQUAL;
1154       }
1155       context_buffer = ">";
1156       return '>';
1157     case '=':
1158       c = input_stack::peek_char();
1159       if (c == '=') {
1160 	input_stack::get_char();
1161 	context_buffer = "==";
1162 	return EQUALEQUAL;
1163       }
1164       context_buffer = "=";
1165       return '=';
1166     case '&':
1167       c = input_stack::peek_char();
1168       if (c == '&') {
1169 	input_stack::get_char();
1170 	context_buffer = "&&";
1171 	return ANDAND;
1172       }
1173       context_buffer = "&";
1174       return '&';
1175     case '|':
1176       c = input_stack::peek_char();
1177       if (c == '|') {
1178 	input_stack::get_char();
1179 	context_buffer = "||";
1180 	return OROR;
1181       }
1182       context_buffer = "|";
1183       return '|';
1184     default:
1185       if (c != EOF && csalpha(c)) {
1186 	token_buffer.clear();
1187 	token_buffer = c;
1188 	for (;;) {
1189 	  c = input_stack::peek_char();
1190 	  if (c == EOF || (!csalnum(c) && c != '_'))
1191 	    break;
1192 	  input_stack::get_char();
1193 	  token_buffer += char(c);
1194 	}
1195 	int tok = lookup_keyword(token_buffer.contents(),
1196 				 token_buffer.length());
1197 	if (tok != 0) {
1198 	  context_buffer = token_buffer;
1199 	  return tok;
1200 	}
1201 	char *def = 0;
1202 	if (lookup_flag) {
1203 	  token_buffer += '\0';
1204 	  def = macro_table.lookup(token_buffer.contents());
1205 	  token_buffer.set_length(token_buffer.length() - 1);
1206 	  if (def) {
1207 	    if (c == '(') {
1208 	      input_stack::get_char();
1209 	      interpolate_macro_with_args(def);
1210 	    }
1211 	    else
1212 	      input_stack::push(new macro_input(def));
1213 	  }
1214 	}
1215 	if (!def) {
1216 	  context_buffer = token_buffer;
1217 	  if (csupper(token_buffer[0]))
1218 	    return LABEL;
1219 	  else
1220 	    return VARIABLE;
1221 	}
1222       }
1223       else {
1224 	context_buffer = char(c);
1225 	return (unsigned char)c;
1226       }
1227       break;
1228     }
1229   }
1230 }
1231 
get_delimited()1232 int get_delimited()
1233 {
1234   token_buffer.clear();
1235   int c = input_stack::get_char();
1236   while (c == ' ' || c == '\t' || c == '\n')
1237     c = input_stack::get_char();
1238   if (c == EOF) {
1239     lex_error("missing delimiter");
1240     return 0;
1241   }
1242   context_buffer = char(c);
1243   int had_newline = 0;
1244   int start = c;
1245   int level = 0;
1246   enum { NORMAL, IN_STRING, IN_STRING_QUOTED, DELIM_END } state = NORMAL;
1247   for (;;) {
1248     c = input_stack::get_char();
1249     if (c == EOF) {
1250       lex_error("missing closing delimiter");
1251       return 0;
1252     }
1253     if (c == '\n')
1254       had_newline = 1;
1255     else if (!had_newline)
1256       context_buffer += char(c);
1257     switch (state) {
1258     case NORMAL:
1259       if (start == '{') {
1260 	if (c == '{') {
1261 	  level++;
1262 	  break;
1263 	}
1264 	if (c == '}') {
1265 	  if (--level < 0)
1266 	    state = DELIM_END;
1267 	  break;
1268 	}
1269       }
1270       else {
1271 	if (c == start) {
1272 	  state = DELIM_END;
1273 	  break;
1274 	}
1275       }
1276       if (c == '"')
1277 	state = IN_STRING;
1278       break;
1279     case IN_STRING_QUOTED:
1280       if (c == '\n')
1281 	state = NORMAL;
1282       else
1283 	state = IN_STRING;
1284       break;
1285     case IN_STRING:
1286       if (c == '"' || c == '\n')
1287 	state = NORMAL;
1288       else if (c == '\\')
1289 	state = IN_STRING_QUOTED;
1290       break;
1291     case DELIM_END:
1292       // This case it just to shut cfront 2.0 up.
1293     default:
1294       assert(0);
1295     }
1296     if (state == DELIM_END)
1297       break;
1298     token_buffer += c;
1299   }
1300   return 1;
1301 }
1302 
do_define()1303 void do_define()
1304 {
1305   int t = get_token(0);		// do not expand what we are defining
1306   if (t != VARIABLE && t != LABEL) {
1307     lex_error("can only define variable or placename");
1308     return;
1309   }
1310   token_buffer += '\0';
1311   string nm = token_buffer;
1312   const char *name = nm.contents();
1313   if (!get_delimited())
1314     return;
1315   token_buffer += '\0';
1316   macro_table.define(name, strsave(token_buffer.contents()));
1317 }
1318 
do_undef()1319 void do_undef()
1320 {
1321   int t = get_token(0);		// do not expand what we are undefining
1322   if (t != VARIABLE && t != LABEL) {
1323     lex_error("can only define variable or placename");
1324     return;
1325   }
1326   token_buffer += '\0';
1327   macro_table.define(token_buffer.contents(), 0);
1328 }
1329 
1330 
1331 class for_input : public input {
1332   char *var;
1333   char *body;
1334   double from;
1335   double to;
1336   int by_is_multiplicative;
1337   double by;
1338   const char *p;
1339   int done_newline;
1340 public:
1341   for_input(char *, double, double, int, double, char *);
1342   ~for_input();
1343   int get();
1344   int peek();
1345 };
1346 
for_input(char * vr,double f,double t,int bim,double b,char * bd)1347 for_input::for_input(char *vr, double f, double t,
1348 		     int bim, double b, char *bd)
1349 : var(vr), body(bd), from(f), to(t), by_is_multiplicative(bim), by(b),
1350   p(body), done_newline(0)
1351 {
1352 }
1353 
~for_input()1354 for_input::~for_input()
1355 {
1356   a_delete var;
1357   a_delete body;
1358 }
1359 
get()1360 int for_input::get()
1361 {
1362   if (p == 0)
1363     return EOF;
1364   for (;;) {
1365     if (*p != '\0')
1366       return (unsigned char)*p++;
1367     if (!done_newline) {
1368       done_newline = 1;
1369       return '\n';
1370     }
1371     double val;
1372     if (!lookup_variable(var, &val)) {
1373       lex_error("body of `for' terminated enclosing block");
1374       return EOF;
1375     }
1376     if (by_is_multiplicative)
1377       val *= by;
1378     else
1379       val += by;
1380     define_variable(var, val);
1381     if ((from <= to && val > to)
1382 	|| (from >= to && val < to)) {
1383       p = 0;
1384       return EOF;
1385     }
1386     p = body;
1387     done_newline = 0;
1388   }
1389 }
1390 
peek()1391 int for_input::peek()
1392 {
1393   if (p == 0)
1394     return EOF;
1395   if (*p != '\0')
1396     return (unsigned char)*p;
1397   if (!done_newline)
1398     return '\n';
1399   double val;
1400   if (!lookup_variable(var, &val))
1401     return EOF;
1402   if (by_is_multiplicative) {
1403     if (val * by > to)
1404       return EOF;
1405   }
1406   else {
1407     if ((from <= to && val + by > to)
1408 	|| (from >= to && val + by < to))
1409       return EOF;
1410   }
1411   if (*body == '\0')
1412     return EOF;
1413   return (unsigned char)*body;
1414 }
1415 
do_for(char * var,double from,double to,int by_is_multiplicative,double by,char * body)1416 void do_for(char *var, double from, double to, int by_is_multiplicative,
1417 	    double by, char *body)
1418 {
1419   define_variable(var, from);
1420   if ((by_is_multiplicative && by <= 0)
1421       || (by > 0 && from > to)
1422       || (by < 0 && from < to))
1423     return;
1424   input_stack::push(new for_input(var, from, to,
1425 				  by_is_multiplicative, by, body));
1426 }
1427 
1428 
do_copy(const char * filename)1429 void do_copy(const char *filename)
1430 {
1431   errno = 0;
1432   FILE *fp = fopen(filename, "r");
1433   if (fp == 0) {
1434     lex_error("can't open `%1': %2", filename, strerror(errno));
1435     return;
1436   }
1437   input_stack::push(new file_input(fp, filename));
1438 }
1439 
1440 class copy_thru_input : public input {
1441   int done;
1442   char *body;
1443   char *until;
1444   const char *p;
1445   const char *ap;
1446   int argv[9];
1447   int argc;
1448   string line;
1449   int get_line();
1450   virtual int inget() = 0;
1451 public:
1452   copy_thru_input(const char *b, const char *u);
1453   ~copy_thru_input();
1454   int get();
1455   int peek();
1456 };
1457 
1458 class copy_file_thru_input : public copy_thru_input {
1459   input *in;
1460 public:
1461   copy_file_thru_input(input *, const char *b, const char *u);
1462   ~copy_file_thru_input();
1463   int inget();
1464 };
1465 
copy_file_thru_input(input * i,const char * b,const char * u)1466 copy_file_thru_input::copy_file_thru_input(input *i, const char *b,
1467 					   const char *u)
1468 : copy_thru_input(b, u), in(i)
1469 {
1470 }
1471 
~copy_file_thru_input()1472 copy_file_thru_input::~copy_file_thru_input()
1473 {
1474   delete in;
1475 }
1476 
inget()1477 int copy_file_thru_input::inget()
1478 {
1479   if (!in)
1480     return EOF;
1481   else
1482     return in->get();
1483 }
1484 
1485 class copy_rest_thru_input : public copy_thru_input {
1486 public:
1487   copy_rest_thru_input(const char *, const char *u);
1488   int inget();
1489 };
1490 
copy_rest_thru_input(const char * b,const char * u)1491 copy_rest_thru_input::copy_rest_thru_input(const char *b, const char *u)
1492 : copy_thru_input(b, u)
1493 {
1494 }
1495 
inget()1496 int copy_rest_thru_input::inget()
1497 {
1498   while (next != 0) {
1499     int c = next->get();
1500     if (c != EOF)
1501       return c;
1502     if (next->next == 0)
1503       return EOF;
1504     input *tem = next;
1505     next = next->next;
1506     delete tem;
1507   }
1508   return EOF;
1509 
1510 }
1511 
copy_thru_input(const char * b,const char * u)1512 copy_thru_input::copy_thru_input(const char *b, const char *u)
1513 : done(0)
1514 {
1515   ap = 0;
1516   body = process_body(b);
1517   p = 0;
1518   until = strsave(u);
1519 }
1520 
1521 
~copy_thru_input()1522 copy_thru_input::~copy_thru_input()
1523 {
1524   a_delete body;
1525   a_delete until;
1526 }
1527 
get()1528 int copy_thru_input::get()
1529 {
1530   if (ap) {
1531     if (*ap != '\0')
1532       return (unsigned char)*ap++;
1533     ap = 0;
1534   }
1535   for (;;) {
1536     if (p == 0) {
1537       if (!get_line())
1538 	break;
1539       p = body;
1540     }
1541     if (*p == '\0') {
1542       p = 0;
1543       return '\n';
1544     }
1545     while (*p >= ARG1 && *p <= ARG1 + 8) {
1546       int i = *p++ - ARG1;
1547       if (i < argc && line[argv[i]] != '\0') {
1548 	ap = line.contents() + argv[i];
1549 	return (unsigned char)*ap++;
1550       }
1551     }
1552     if (*p != '\0')
1553       return (unsigned char)*p++;
1554   }
1555   return EOF;
1556 }
1557 
peek()1558 int copy_thru_input::peek()
1559 {
1560   if (ap) {
1561     if (*ap != '\0')
1562       return (unsigned char)*ap;
1563     ap = 0;
1564   }
1565   for (;;) {
1566     if (p == 0) {
1567       if (!get_line())
1568 	break;
1569       p = body;
1570     }
1571     if (*p == '\0')
1572       return '\n';
1573     while (*p >= ARG1 && *p <= ARG1 + 8) {
1574       int i = *p++ - ARG1;
1575       if (i < argc && line[argv[i]] != '\0') {
1576 	ap = line.contents() + argv[i];
1577 	return (unsigned char)*ap;
1578       }
1579     }
1580     if (*p != '\0')
1581       return (unsigned char)*p;
1582   }
1583   return EOF;
1584 }
1585 
get_line()1586 int copy_thru_input::get_line()
1587 {
1588   if (done)
1589     return 0;
1590   line.clear();
1591   argc = 0;
1592   int c = inget();
1593   for (;;) {
1594     while (c == ' ')
1595       c = inget();
1596     if (c == EOF || c == '\n')
1597       break;
1598     if (argc == 9) {
1599       do {
1600 	c = inget();
1601       } while (c != '\n' && c != EOF);
1602       break;
1603     }
1604     argv[argc++] = line.length();
1605     do {
1606       line += char(c);
1607       c = inget();
1608     } while (c != ' ' && c != '\n');
1609     line += '\0';
1610   }
1611   if (until != 0 && argc > 0 && strcmp(&line[argv[0]], until) == 0) {
1612     done = 1;
1613     return 0;
1614   }
1615   return argc > 0 || c == '\n';
1616 }
1617 
1618 class simple_file_input : public input {
1619   const char *filename;
1620   int lineno;
1621   FILE *fp;
1622 public:
1623   simple_file_input(FILE *, const char *);
1624   ~simple_file_input();
1625   int get();
1626   int peek();
1627   int get_location(const char **, int *);
1628 };
1629 
simple_file_input(FILE * p,const char * s)1630 simple_file_input::simple_file_input(FILE *p, const char *s)
1631 : filename(s), lineno(1), fp(p)
1632 {
1633 }
1634 
~simple_file_input()1635 simple_file_input::~simple_file_input()
1636 {
1637   // don't delete the filename
1638   fclose(fp);
1639 }
1640 
get()1641 int simple_file_input::get()
1642 {
1643   int c = getc(fp);
1644   while (invalid_input_char(c)) {
1645     error("invalid input character code %1", c);
1646     c = getc(fp);
1647   }
1648   if (c == '\n')
1649     lineno++;
1650   return c;
1651 }
1652 
peek()1653 int simple_file_input::peek()
1654 {
1655   int c = getc(fp);
1656   while (invalid_input_char(c)) {
1657     error("invalid input character code %1", c);
1658     c = getc(fp);
1659   }
1660   if (c != EOF)
1661     ungetc(c, fp);
1662   return c;
1663 }
1664 
get_location(const char ** fnp,int * lnp)1665 int simple_file_input::get_location(const char **fnp, int *lnp)
1666 {
1667   *fnp = filename;
1668   *lnp = lineno;
1669   return 1;
1670 }
1671 
1672 
copy_file_thru(const char * filename,const char * body,const char * until)1673 void copy_file_thru(const char *filename, const char *body, const char *until)
1674 {
1675   errno = 0;
1676   FILE *fp = fopen(filename, "r");
1677   if (fp == 0) {
1678     lex_error("can't open `%1': %2", filename, strerror(errno));
1679     return;
1680   }
1681   input *in = new copy_file_thru_input(new simple_file_input(fp, filename),
1682 				       body, until);
1683   input_stack::push(in);
1684 }
1685 
copy_rest_thru(const char * body,const char * until)1686 void copy_rest_thru(const char *body, const char *until)
1687 {
1688   input_stack::push(new copy_rest_thru_input(body, until));
1689 }
1690 
push_body(const char * s)1691 void push_body(const char *s)
1692 {
1693   input_stack::push(new char_input('\n'));
1694   input_stack::push(new macro_input(s));
1695 }
1696 
1697 int delim_flag = 0;
1698 
get_thru_arg()1699 char *get_thru_arg()
1700 {
1701   int c = input_stack::peek_char();
1702   while (c == ' ') {
1703     input_stack::get_char();
1704     c = input_stack::peek_char();
1705   }
1706   if (c != EOF && csalpha(c)) {
1707     // looks like a macro
1708     input_stack::get_char();
1709     token_buffer = c;
1710     for (;;) {
1711       c = input_stack::peek_char();
1712       if (c == EOF || (!csalnum(c) && c != '_'))
1713 	break;
1714       input_stack::get_char();
1715       token_buffer += char(c);
1716     }
1717     context_buffer = token_buffer;
1718     token_buffer += '\0';
1719     char *def = macro_table.lookup(token_buffer.contents());
1720     if (def)
1721       return strsave(def);
1722     // I guess it wasn't a macro after all; so push the macro name back.
1723     // -2 because we added a '\0'
1724     for (int i = token_buffer.length() - 2; i >= 0; i--)
1725       input_stack::push_back(token_buffer[i]);
1726   }
1727   if (get_delimited()) {
1728     token_buffer += '\0';
1729     return strsave(token_buffer.contents());
1730   }
1731   else
1732     return 0;
1733 }
1734 
1735 int lookahead_token = -1;
1736 string old_context_buffer;
1737 
do_lookahead()1738 void do_lookahead()
1739 {
1740   if (lookahead_token == -1) {
1741     old_context_buffer = context_buffer;
1742     lookahead_token = get_token(1);
1743   }
1744 }
1745 
yylex()1746 int yylex()
1747 {
1748   if (delim_flag) {
1749     assert(lookahead_token == -1);
1750     if (delim_flag == 2) {
1751       if ((yylval.str = get_thru_arg()) != 0)
1752 	return DELIMITED;
1753       else
1754 	return 0;
1755     }
1756     else {
1757       if (get_delimited()) {
1758 	token_buffer += '\0';
1759 	yylval.str = strsave(token_buffer.contents());
1760 	return DELIMITED;
1761       }
1762       else
1763 	return 0;
1764     }
1765   }
1766   for (;;) {
1767     int t;
1768     if (lookahead_token >= 0) {
1769       t = lookahead_token;
1770       lookahead_token = -1;
1771     }
1772     else
1773       t = get_token(1);
1774     switch (t) {
1775     case '\n':
1776       return ';';
1777     case EOF:
1778       return 0;
1779     case DEFINE:
1780       do_define();
1781       break;
1782     case UNDEF:
1783       do_undef();
1784       break;
1785     case ORDINAL:
1786       yylval.n = token_int;
1787       return t;
1788     case NUMBER:
1789       yylval.x = token_double;
1790       return t;
1791     case COMMAND_LINE:
1792     case TEXT:
1793       token_buffer += '\0';
1794       if (!input_stack::get_location(&yylval.lstr.filename,
1795 				     &yylval.lstr.lineno)) {
1796 	yylval.lstr.filename = 0;
1797 	yylval.lstr.lineno = -1;
1798       }
1799       yylval.lstr.str = strsave(token_buffer.contents());
1800       return t;
1801     case LABEL:
1802     case VARIABLE:
1803       token_buffer += '\0';
1804       yylval.str = strsave(token_buffer.contents());
1805       return t;
1806     case LEFT:
1807       // change LEFT to LEFT_CORNER when followed by OF
1808       old_context_buffer = context_buffer;
1809       lookahead_token = get_token(1);
1810       if (lookahead_token == OF)
1811 	return LEFT_CORNER;
1812       else
1813 	return t;
1814     case RIGHT:
1815       // change RIGHT to RIGHT_CORNER when followed by OF
1816       old_context_buffer = context_buffer;
1817       lookahead_token = get_token(1);
1818       if (lookahead_token == OF)
1819 	return RIGHT_CORNER;
1820       else
1821 	return t;
1822     case UPPER:
1823       // recognise UPPER only before LEFT or RIGHT
1824       old_context_buffer = context_buffer;
1825       lookahead_token = get_token(1);
1826       if (lookahead_token != LEFT && lookahead_token != RIGHT) {
1827 	yylval.str = strsave("upper");
1828 	return VARIABLE;
1829       }
1830       else
1831 	return t;
1832     case LOWER:
1833       // recognise LOWER only before LEFT or RIGHT
1834       old_context_buffer = context_buffer;
1835       lookahead_token = get_token(1);
1836       if (lookahead_token != LEFT && lookahead_token != RIGHT) {
1837 	yylval.str = strsave("lower");
1838 	return VARIABLE;
1839       }
1840       else
1841 	return t;
1842     case NORTH:
1843       // recognise NORTH only before OF
1844       old_context_buffer = context_buffer;
1845       lookahead_token = get_token(1);
1846       if (lookahead_token != OF) {
1847 	yylval.str = strsave("north");
1848 	return VARIABLE;
1849       }
1850       else
1851 	return t;
1852     case SOUTH:
1853       // recognise SOUTH only before OF
1854       old_context_buffer = context_buffer;
1855       lookahead_token = get_token(1);
1856       if (lookahead_token != OF) {
1857 	yylval.str = strsave("south");
1858 	return VARIABLE;
1859       }
1860       else
1861 	return t;
1862     case EAST:
1863       // recognise EAST only before OF
1864       old_context_buffer = context_buffer;
1865       lookahead_token = get_token(1);
1866       if (lookahead_token != OF) {
1867 	yylval.str = strsave("east");
1868 	return VARIABLE;
1869       }
1870       else
1871 	return t;
1872     case WEST:
1873       // recognise WEST only before OF
1874       old_context_buffer = context_buffer;
1875       lookahead_token = get_token(1);
1876       if (lookahead_token != OF) {
1877 	yylval.str = strsave("west");
1878 	return VARIABLE;
1879       }
1880       else
1881 	return t;
1882     case TOP:
1883       // recognise TOP only before OF
1884       old_context_buffer = context_buffer;
1885       lookahead_token = get_token(1);
1886       if (lookahead_token != OF) {
1887 	yylval.str = strsave("top");
1888 	return VARIABLE;
1889       }
1890       else
1891 	return t;
1892     case BOTTOM:
1893       // recognise BOTTOM only before OF
1894       old_context_buffer = context_buffer;
1895       lookahead_token = get_token(1);
1896       if (lookahead_token != OF) {
1897 	yylval.str = strsave("bottom");
1898 	return VARIABLE;
1899       }
1900       else
1901 	return t;
1902     case CENTER:
1903       // recognise CENTER only before OF
1904       old_context_buffer = context_buffer;
1905       lookahead_token = get_token(1);
1906       if (lookahead_token != OF) {
1907 	yylval.str = strsave("center");
1908 	return VARIABLE;
1909       }
1910       else
1911 	return t;
1912     case START:
1913       // recognise START only before OF
1914       old_context_buffer = context_buffer;
1915       lookahead_token = get_token(1);
1916       if (lookahead_token != OF) {
1917 	yylval.str = strsave("start");
1918 	return VARIABLE;
1919       }
1920       else
1921 	return t;
1922     case END:
1923       // recognise END only before OF
1924       old_context_buffer = context_buffer;
1925       lookahead_token = get_token(1);
1926       if (lookahead_token != OF) {
1927 	yylval.str = strsave("end");
1928 	return VARIABLE;
1929       }
1930       else
1931 	return t;
1932     default:
1933       return t;
1934     }
1935   }
1936 }
1937 
lex_error(const char * message,const errarg & arg1,const errarg & arg2,const errarg & arg3)1938 void lex_error(const char *message,
1939 	       const errarg &arg1,
1940 	       const errarg &arg2,
1941 	       const errarg &arg3)
1942 {
1943   const char *filename;
1944   int lineno;
1945   if (!input_stack::get_location(&filename, &lineno))
1946     error(message, arg1, arg2, arg3);
1947   else
1948     error_with_file_and_line(filename, lineno, message, arg1, arg2, arg3);
1949 }
1950 
lex_warning(const char * message,const errarg & arg1,const errarg & arg2,const errarg & arg3)1951 void lex_warning(const char *message,
1952 		 const errarg &arg1,
1953 		 const errarg &arg2,
1954 		 const errarg &arg3)
1955 {
1956   const char *filename;
1957   int lineno;
1958   if (!input_stack::get_location(&filename, &lineno))
1959     warning(message, arg1, arg2, arg3);
1960   else
1961     warning_with_file_and_line(filename, lineno, message, arg1, arg2, arg3);
1962 }
1963 
yyerror(const char * s)1964 void yyerror(const char *s)
1965 {
1966   const char *filename;
1967   int lineno;
1968   const char *context = 0;
1969   if (lookahead_token == -1) {
1970     if (context_buffer.length() > 0) {
1971       context_buffer += '\0';
1972       context = context_buffer.contents();
1973     }
1974   }
1975   else {
1976     if (old_context_buffer.length() > 0) {
1977       old_context_buffer += '\0';
1978       context = old_context_buffer.contents();
1979     }
1980   }
1981   if (!input_stack::get_location(&filename, &lineno)) {
1982     if (context) {
1983       if (context[0] == '\n' && context[1] == '\0')
1984 	error("%1 before newline", s);
1985       else
1986 	error("%1 before `%2'", s, context);
1987     }
1988     else
1989       error("%1 at end of picture", s);
1990   }
1991   else {
1992     if (context) {
1993       if (context[0] == '\n' && context[1] == '\0')
1994 	error_with_file_and_line(filename, lineno, "%1 before newline", s);
1995       else
1996 	error_with_file_and_line(filename, lineno, "%1 before `%2'",
1997 				 s, context);
1998     }
1999     else
2000       error_with_file_and_line(filename, lineno, "%1 at end of picture", s);
2001   }
2002 }
2003 
2004