LCOV - code coverage report
Current view: top level - preproc/pic - lex.cpp (source / functions) Hit Total Coverage
Test: GNU roff Lines: 714 1316 54.3 %
Date: 2026-01-16 17:51:41 Functions: 46 84 54.8 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14