e4b6aaee308901a2ec7bb44f052aa6195b7050bb
[pspp-builds.git] / src / lexer.c
1 /* PSPP - computes sample statistics.
2    Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
3    Written by Ben Pfaff <blp@gnu.org>.
4
5    This program is free software; you can redistribute it and/or
6    modify it under the terms of the GNU General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    License, or (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful, but
11    WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
18    02111-1307, USA. */
19
20 #include <config.h>
21 #include "lexer.h"
22 #include "error.h"
23 #include <ctype.h>
24 #include <errno.h>
25 #include <limits.h>
26 #include <math.h>
27 #include <stdarg.h>
28 #include <stdlib.h>
29 #include "alloc.h"
30 #include "command.h"
31 #include "error.h"
32 #include "getline.h"
33 #include "magic.h"
34 #include "settings.h"
35 #include "str.h"
36
37 /*
38 #define DUMP_TOKENS 1
39 */
40
41 \f
42 /* Global variables. */
43
44 /* Current token. */
45 int token;
46
47 /* T_POS_NUM, T_NEG_NUM: the token's value. */
48 double tokval;
49
50 /* T_ID: the identifier. */
51 char tokid[9];
52
53 /* T_ID, T_STRING: token string value.
54    For T_ID, this is not truncated to 8 characters as is tokid. */
55 struct string tokstr;
56 \f
57 /* Static variables. */
58
59 /* Table of keywords. */
60 static const char *keywords[T_N_KEYWORDS + 1] = 
61   {
62     "AND", "OR", "NOT",
63     "EQ", "GE", "GT", "LE", "LT", "NE",
64     "ALL", "BY", "TO", "WITH",
65     NULL,
66   };
67
68 /* Pointer to next token in getl_buf. */
69 static char *prog;
70
71 /* Nonzero only if this line ends with a terminal dot. */
72 static int dot;
73
74 /* Nonzero only if the last token returned was T_STOP. */
75 static int eof;
76
77 /* If nonzero, next token returned by lex_get().
78    Used only in exceptional circumstances. */
79 static int put_token;
80 static struct string put_tokstr;
81 static double put_tokval;
82
83 static void unexpected_eof (void);
84 static void convert_numeric_string_to_char_string (int type);
85 static int parse_string (int type);
86
87 #if DUMP_TOKENS
88 static void dump_token (void);
89 #endif
90 \f
91 /* Initialization. */
92
93 /* Initializes the lexer. */
94 void
95 lex_init (void)
96 {
97   ds_init (&put_tokstr, 64);
98   if (!lex_get_line ())
99     unexpected_eof ();
100 }
101
102 void
103 lex_done (void)
104 {
105   ds_destroy(&put_tokstr);
106 }
107
108 \f
109 /* Common functions. */
110
111 /* Copies put_token, put_tokstr, put_tokval into token, tokstr,
112    tokval, respectively, and sets tokid appropriately. */
113 static void
114 restore_token (void) 
115 {
116   assert (put_token != 0);
117   token = put_token;
118   ds_replace (&tokstr, ds_c_str (&put_tokstr));
119   strncpy (tokid, ds_c_str (&put_tokstr), 8);
120   tokid[8] = 0;
121   tokval = put_tokval;
122   put_token = 0;
123 }
124
125 /* Copies token, tokstr, tokval into put_token, put_tokstr,
126    put_tokval respectively. */
127 static void
128 save_token (void) 
129 {
130   put_token = token;
131   ds_replace (&put_tokstr, ds_c_str (&tokstr));
132   put_tokval = tokval;
133 }
134
135 /* Parses a single token, setting appropriate global variables to
136    indicate the token's attributes. */
137 void
138 lex_get (void)
139 {
140   /* If a token was pushed ahead, return it. */
141   if (put_token)
142     {
143       restore_token ();
144 #if DUMP_TOKENS
145       dump_token ();
146 #endif
147       return;
148     }
149
150   /* Find a token. */
151   for (;;)
152     {
153       char *cp;
154
155       /* Skip whitespace. */
156       if (eof)
157         unexpected_eof ();
158
159       for (;;)
160         {
161           while (isspace ((unsigned char) *prog))
162             prog++;
163           if (*prog)
164             break;
165
166           if (dot)
167             {
168               dot = 0;
169               token = '.';
170 #if DUMP_TOKENS
171               dump_token ();
172 #endif
173               return;
174             }
175           else if (!lex_get_line ())
176             {
177               eof = 1;
178               token = T_STOP;
179 #if DUMP_TOKENS
180               dump_token ();
181 #endif
182               return;
183             }
184
185           if (put_token)
186             {
187               restore_token ();
188 #if DUMP_TOKENS
189               dump_token ();
190 #endif
191               return;
192             }
193         }
194
195
196       /* Actually parse the token. */
197       cp = prog;
198       ds_clear (&tokstr);
199       
200       switch (*prog)
201         {
202         case '-': case '.':
203         case '0': case '1': case '2': case '3': case '4':
204         case '5': case '6': case '7': case '8': case '9':
205           {
206             char *tail;
207
208             /* `-' can introduce a negative number, or it can be a
209                token by itself.  If it is not followed by a digit or a
210                decimal point, it is definitely not a number.
211                Otherwise, it might be either, but most of the time we
212                want it as a number.  When the syntax calls for a `-'
213                token, lex_negative_to_dash() must be used to break
214                negative numbers into two tokens. */
215             if (*cp == '-')
216               {
217                 ds_putc (&tokstr, *prog++);
218                 while (isspace ((unsigned char) *prog))
219                   prog++;
220
221                 if (!isdigit ((unsigned char) *prog) && *prog != '.')
222                   {
223                     token = '-';
224                     break;
225                   }
226                 token = T_NEG_NUM;
227               }
228             else 
229               token = T_POS_NUM;
230                 
231             /* Parse the number, copying it into tokstr. */
232             while (isdigit ((unsigned char) *prog))
233               ds_putc (&tokstr, *prog++);
234             if (*prog == '.')
235               {
236                 ds_putc (&tokstr, *prog++);
237                 while (isdigit ((unsigned char) *prog))
238                   ds_putc (&tokstr, *prog++);
239               }
240             if (*prog == 'e' || *prog == 'E')
241               {
242                 ds_putc (&tokstr, *prog++);
243                 if (*prog == '+' || *prog == '-')
244                   ds_putc (&tokstr, *prog++);
245                 while (isdigit ((unsigned char) *prog))
246                   ds_putc (&tokstr, *prog++);
247               }
248
249             /* Parse as floating point. */
250             tokval = strtod (ds_c_str (&tokstr), &tail);
251             if (*tail)
252               {
253                 msg (SE, _("%s does not form a valid number."),
254                      ds_c_str (&tokstr));
255                 tokval = 0.0;
256
257                 ds_clear (&tokstr);
258                 ds_putc (&tokstr, '0');
259               }
260
261             break;
262           }
263
264         case '\'': case '"':
265           token = parse_string (0);
266           break;
267
268         case '(': case ')': case ',': case '=': case '+': case '/':
269           token = *prog++;
270           break;
271
272         case '*':
273           if (*++prog == '*')
274             {
275               prog++;
276               token = T_EXP;
277             }
278           else
279             token = '*';
280           break;
281
282         case '<':
283           if (*++prog == '=')
284             {
285               prog++;
286               token = T_LE;
287             }
288           else if (*prog == '>')
289             {
290               prog++;
291               token = T_NE;
292             }
293           else
294             token = T_LT;
295           break;
296
297         case '>':
298           if (*++prog == '=')
299             {
300               prog++;
301               token = T_GE;
302             }
303           else
304             token = T_GT;
305           break;
306
307         case '~':
308           if (*++prog == '=')
309             {
310               prog++;
311               token = T_NE;
312             }
313           else
314             token = T_NOT;
315           break;
316
317         case '&':
318           prog++;
319           token = T_AND;
320           break;
321
322         case '|':
323           prog++;
324           token = T_OR;
325           break;
326
327         case 'a': case 'b': case 'c': case 'd': case 'e':
328         case 'f': case 'g': case 'h': case 'i': case 'j':
329         case 'k': case 'l': case 'm': case 'n': case 'o':
330         case 'p': case 'q': case 'r': case 's': case 't':
331         case 'u': case 'v': case 'w': case 'x': case 'y':
332         case 'z':
333         case 'A': case 'B': case 'C': case 'D': case 'E':
334         case 'F': case 'G': case 'H': case 'I': case 'J':
335         case 'K': case 'L': case 'M': case 'N': case 'O':
336         case 'P': case 'Q': case 'R': case 'S': case 'T':
337         case 'U': case 'V': case 'W': case 'X': case 'Y':
338         case 'Z':
339         case '#': case '$': case '@': 
340           /* Strings can be specified in binary, octal, or hex using
341                this special syntax. */
342           if (prog[1] == '\'' || prog[1] == '"')
343             {
344               static const char special[3] = "box";
345               const char *p;
346
347               p = strchr (special, tolower ((unsigned char) *prog));
348               if (p)
349                 {
350                   prog++;
351                   token = parse_string (p - special + 1);
352                   break;
353                 }
354             }
355
356           /* Copy id to tokstr. */
357           ds_putc (&tokstr, toupper ((unsigned char) *prog++));
358           while (CHAR_IS_IDN (*prog))
359             ds_putc (&tokstr, toupper ((unsigned char) *prog++));
360
361           /* Copy tokstr to tokid, truncating it to 8 characters. */
362           strncpy (tokid, ds_c_str (&tokstr), 8);
363           tokid[8] = 0;
364
365           token = lex_id_to_token (ds_c_str (&tokstr), ds_length (&tokstr));
366           break;
367
368         default:
369           if (isgraph ((unsigned char) *prog))
370             msg (SE, _("Bad character in input: `%c'."), *prog++);
371           else
372             msg (SE, _("Bad character in input: `\\%o'."), *prog++);
373           continue;
374         }
375
376       break;
377     }
378
379 #if DUMP_TOKENS
380   dump_token ();
381 #endif
382 }
383
384 /* Prints a syntax error message containing the current token and
385    given message MESSAGE (if non-null). */
386 void
387 lex_error (const char *message, ...)
388 {
389   char *token_rep;
390
391   token_rep = lex_token_representation ();
392   if (token_rep[0] == 0)
393     msg (SE, _("Syntax error at end of file."));
394   else if (message)
395     {
396       char buf[1024];
397       va_list args;
398       
399       va_start (args, message);
400       vsnprintf (buf, 1024, message, args);
401       va_end (args);
402
403       msg (SE, _("Syntax error %s at `%s'."), buf, token_rep);
404     }
405   else
406     msg (SE, _("Syntax error at `%s'."), token_rep);
407   
408   free (token_rep);
409 }
410
411 /* Checks that we're at end of command.
412    If so, returns a successful command completion code.
413    If not, flags a syntax error and returns an error command
414    completion code. */
415 int
416 lex_end_of_command (void)
417 {
418   if (token != '.')
419     {
420       lex_error (_("expecting end of command"));
421       return CMD_TRAILING_GARBAGE;
422     }
423   else
424     return CMD_SUCCESS;
425 }
426 \f
427 /* Token testing functions. */
428
429 /* Returns true if the current token is a number. */
430 bool
431 lex_is_number (void) 
432 {
433   return token == T_POS_NUM || token == T_NEG_NUM;
434 }
435
436 /* Returns the value of the current token, which must be a
437    floating point number. */
438 double
439 lex_number (void)
440 {
441   assert (lex_is_number ());
442   return tokval;
443 }
444
445 /* Returns true iff the current token is an integer. */
446 bool
447 lex_is_integer (void)
448 {
449   return (lex_is_number ()
450           && tokval != NOT_LONG
451           && tokval >= LONG_MIN
452           && tokval <= LONG_MAX
453           && floor (tokval) == tokval);
454 }
455
456 /* Returns the value of the current token, which must be an
457    integer. */
458 long
459 lex_integer (void)
460 {
461   assert (lex_is_integer ());
462   return tokval;
463 }
464 \f  
465 /* Token matching functions. */
466
467 /* If TOK is the current token, skips it and returns nonzero.
468    Otherwise, returns zero. */
469 int
470 lex_match (int t)
471 {
472   if (token == t)
473     {
474       lex_get ();
475       return 1;
476     }
477   else
478     return 0;
479 }
480
481 /* If the current token is the identifier S, skips it and returns
482    nonzero.
483    Otherwise, returns zero. */
484 int
485 lex_match_id (const char *s)
486 {
487   if (token == T_ID && lex_id_match (s, tokid))
488     {
489       lex_get ();
490       return 1;
491     }
492   else
493     return 0;
494 }
495
496 /* If the current token is integer N, skips it and returns nonzero.
497    Otherwise, returns zero. */
498 int
499 lex_match_int (int x)
500 {
501   if (lex_is_integer () && lex_integer () == x)
502     {
503       lex_get ();
504       return 1;
505     }
506   else
507     return 0;
508 }
509 \f
510 /* Forced matches. */
511
512 /* If this token is identifier S, fetches the next token and returns
513    nonzero.
514    Otherwise, reports an error and returns zero. */
515 int
516 lex_force_match_id (const char *s)
517 {
518   if (token == T_ID && lex_id_match (s, tokid))
519     {
520       lex_get ();
521       return 1;
522     }
523   else
524     {
525       lex_error (_("expecting `%s'"), s);
526       return 0;
527     }
528 }
529
530 /* If the current token is T, skips the token.  Otherwise, reports an
531    error and returns from the current function with return value 0. */
532 int
533 lex_force_match (int t)
534 {
535   if (token == t)
536     {
537       lex_get ();
538       return 1;
539     }
540   else
541     {
542       lex_error (_("expecting %s"), lex_token_name (t));
543       return 0;
544     }
545 }
546
547 /* If this token is a string, does nothing and returns nonzero.
548    Otherwise, reports an error and returns zero. */
549 int
550 lex_force_string (void)
551 {
552   if (token == T_STRING)
553     return 1;
554   else
555     {
556       lex_error (_("expecting string"));
557       return 0;
558     }
559 }
560
561 /* If this token is an integer, does nothing and returns nonzero.
562    Otherwise, reports an error and returns zero. */
563 int
564 lex_force_int (void)
565 {
566   if (lex_is_integer ())
567     return 1;
568   else
569     {
570       lex_error (_("expecting integer"));
571       return 0;
572     }
573 }
574         
575 /* If this token is a number, does nothing and returns nonzero.
576    Otherwise, reports an error and returns zero. */
577 int
578 lex_force_num (void)
579 {
580   if (lex_is_number ())
581     return 1;
582   else
583     {
584       lex_error (_("expecting number"));
585       return 0;
586     }
587 }
588         
589 /* If this token is an identifier, does nothing and returns nonzero.
590    Otherwise, reports an error and returns zero. */
591 int
592 lex_force_id (void)
593 {
594   if (token == T_ID)
595     return 1;
596   else
597     {
598       lex_error (_("expecting identifier"));
599       return 0;
600     }
601 }
602 \f
603 /* Comparing identifiers. */
604
605 /* Keywords match if one of the following is true: KW and TOK are
606    identical (barring differences in case), or TOK is at least 3
607    characters long and those characters are identical to KW.  KW_LEN
608    is the length of KW, TOK_LEN is the length of TOK. */
609 int
610 lex_id_match_len (const char *kw, size_t kw_len,
611                   const char *tok, size_t tok_len)
612 {
613   size_t i = 0;
614
615   assert (kw && tok);
616   for (;;)
617     {
618       if (i == kw_len && i == tok_len)
619         return 1;
620       else if (i == tok_len)
621         return i >= 3;
622       else if (i == kw_len)
623         return 0;
624       else if (toupper ((unsigned char) kw[i])
625                != toupper ((unsigned char) tok[i]))
626         return 0;
627
628       i++;
629     }
630 }
631
632 /* Same as lex_id_match_len() minus the need to pass in the lengths. */
633 int
634 lex_id_match (const char *kw, const char *tok)
635 {
636   return lex_id_match_len (kw, strlen (kw), tok, strlen (tok));
637 }
638
639 /* Returns the proper token type, either T_ID or a reserved keyword
640    enum, for ID[], which must contain LEN characters. */
641 int
642 lex_id_to_token (const char *id, size_t len)
643 {
644   const char **kwp;
645
646   if (len < 2 || len > 4)
647     return T_ID;
648   
649   for (kwp = keywords; *kwp; kwp++)
650     if (!strcasecmp (*kwp, id))
651       return T_FIRST_KEYWORD + (kwp - keywords);
652
653   return T_ID;
654 }
655 \f
656 /* Weird token functions. */
657
658 /* Returns the first character of the next token, except that if the
659    next token is not an identifier, the character returned will not be
660    a character that can begin an identifier.  Specifically, the
661    hexstring lead-in X' causes lookahead() to return '.  Note that an
662    alphanumeric return value doesn't guarantee an ID token, it could
663    also be a reserved-word token. */
664 int
665 lex_look_ahead (void)
666 {
667   if (put_token)
668     return put_token;
669
670   for (;;)
671     {
672       if (eof)
673         unexpected_eof ();
674
675       for (;;)
676         {
677           while (isspace ((unsigned char) *prog))
678             prog++;
679           if (*prog)
680             break;
681
682           if (dot)
683             return '.';
684           else if (!lex_get_line ())
685             unexpected_eof ();
686
687           if (put_token) 
688             return put_token;
689         }
690
691       if ((toupper ((unsigned char) *prog) == 'X'
692            || toupper ((unsigned char) *prog) == 'B')
693           && (prog[1] == '\'' || prog[1] == '"'))
694         return '\'';
695
696       return *prog;
697     }
698 }
699
700 /* Makes the current token become the next token to be read; the
701    current token is set to T. */
702 void
703 lex_put_back (int t)
704 {
705   save_token ();
706   token = t;
707 }
708
709 /* Makes the current token become the next token to be read; the
710    current token is set to the identifier ID. */
711 void
712 lex_put_back_id (const char *id)
713 {
714   save_token ();
715   token = T_ID;
716   ds_replace (&tokstr, id);
717   strncpy (tokid, ds_c_str (&tokstr), 8);
718   tokid[8] = 0;
719 }
720 \f
721 /* Weird line processing functions. */
722
723 /* Returns the entire contents of the current line. */
724 const char *
725 lex_entire_line (void)
726 {
727   return ds_c_str (&getl_buf);
728 }
729
730 /* As lex_entire_line(), but only returns the part of the current line
731    that hasn't already been tokenized.
732    If END_DOT is non-null, stores nonzero into *END_DOT if the line
733    ends with a terminal dot, or zero if it doesn't. */
734 const char *
735 lex_rest_of_line (int *end_dot)
736 {
737   if (end_dot)
738     *end_dot = dot;
739   return prog;
740 }
741
742 /* Causes the rest of the current input line to be ignored for
743    tokenization purposes. */
744 void
745 lex_discard_line (void)
746 {
747   prog = ds_end (&getl_buf);
748   dot = put_token = 0;
749 }
750
751 /* Sets the current position in the current line to P, which must be
752    in getl_buf. */
753 void
754 lex_set_prog (char *p)
755 {
756   prog = p;
757 }
758 \f
759 /* Weird line reading functions. */
760
761 /* Read a line for use by the tokenizer. */
762 int
763 lex_get_line (void)
764 {
765   if (!getl_read_line ())
766     return 0;
767
768   lex_preprocess_line ();
769   return 1;
770 }
771
772 /* Preprocesses getl_buf by removing comments, stripping trailing
773    whitespace and the terminal dot, and removing leading indentors. */
774 void
775 lex_preprocess_line (void)
776 {
777   /* Strips comments. */
778   {
779     /* getl_buf iterator. */
780     char *cp;
781
782     /* Nonzero inside a comment. */
783     int comment;
784
785     /* Nonzero inside a quoted string. */
786     int quote;
787
788     /* Remove C-style comments begun by slash-star and terminated by
789      star-slash or newline. */
790     quote = comment = 0;
791     for (cp = ds_c_str (&getl_buf); *cp; )
792       {
793         /* If we're not commented out, toggle quoting. */
794         if (!comment)
795           {
796             if (*cp == quote)
797               quote = 0;
798             else if (*cp == '\'' || *cp == '"')
799               quote = *cp;
800           }
801       
802         /* If we're not quoting, toggle commenting. */
803         if (!quote)
804           {
805             if (cp[0] == '/' && cp[1] == '*')
806               {
807                 comment = 1;
808                 *cp++ = ' ';
809                 *cp++ = ' ';
810                 continue;
811               }
812             else if (cp[0] == '*' && cp[1] == '/' && comment)
813               {
814                 comment = 0;
815                 *cp++ = ' ';
816                 *cp++ = ' ';
817                 continue;
818               }
819           }
820       
821         /* Check commenting. */
822         if (!comment)
823           cp++;
824         else
825           *cp++ = ' ';
826       }
827   }
828   
829   /* Strip trailing whitespace and terminal dot. */
830   {
831     size_t len = ds_length (&getl_buf);
832     char *s = ds_c_str (&getl_buf);
833     
834     /* Strip trailing whitespace. */
835     while (len > 0 && isspace ((unsigned char) s[len - 1]))
836       len--;
837
838     /* Check for and remove terminal dot. */
839     if (len > 0 && s[len - 1] == get_endcmd() )
840       {
841         dot = 1;
842         len--;
843       }
844     else if (len == 0 && get_nullline() )
845       dot = 1;
846     else
847       dot = 0;
848
849     /* Set length. */
850     ds_truncate (&getl_buf, len);
851   }
852   
853   /* In batch mode, strip leading indentors and insert a terminal dot
854      as necessary. */
855   if (getl_interactive != 2 && getl_mode == GETL_MODE_BATCH)
856     {
857       char *s = ds_c_str (&getl_buf);
858       
859       if (s[0] == '+' || s[0] == '-' || s[0] == '.')
860         s[0] = ' ';
861       else if (s[0] && !isspace ((unsigned char) s[0]))
862         put_token = '.';
863     }
864
865   prog = ds_c_str (&getl_buf);
866 }
867 \f
868 /* Token names. */
869
870 /* Returns the name of a token in a static buffer. */
871 const char *
872 lex_token_name (int token)
873 {
874   if (token >= T_FIRST_KEYWORD && token <= T_LAST_KEYWORD)
875     return keywords[token - T_FIRST_KEYWORD];
876
877   if (token < 256)
878     {
879       static char t[2];
880       t[0] = token;
881       return t;
882     }
883
884   return _("<ERROR>");
885 }
886
887 /* Returns an ASCII representation of the current token as a
888    malloc()'d string. */
889 char *
890 lex_token_representation (void)
891 {
892   char *token_rep;
893   
894   switch (token)
895     {
896     case T_ID:
897     case T_POS_NUM:
898     case T_NEG_NUM:
899       return xstrdup (ds_c_str (&tokstr));
900       break;
901
902     case T_STRING:
903       {
904         int hexstring = 0;
905         char *sp, *dp;
906
907         for (sp = ds_c_str (&tokstr); sp < ds_end (&tokstr); sp++)
908           if (!isprint ((unsigned char) *sp))
909             {
910               hexstring = 1;
911               break;
912             }
913               
914         token_rep = xmalloc (2 + ds_length (&tokstr) * 2 + 1 + 1);
915
916         dp = token_rep;
917         if (hexstring)
918           *dp++ = 'X';
919         *dp++ = '\'';
920
921         if (!hexstring)
922           for (sp = ds_c_str (&tokstr); *sp; )
923             {
924               if (*sp == '\'')
925                 *dp++ = '\'';
926               *dp++ = (unsigned char) *sp++;
927             }
928         else
929           for (sp = ds_c_str (&tokstr); sp < ds_end (&tokstr); sp++)
930             {
931               *dp++ = (((unsigned char) *sp) >> 4)["0123456789ABCDEF"];
932               *dp++ = (((unsigned char) *sp) & 15)["0123456789ABCDEF"];
933             }
934         *dp++ = '\'';
935         *dp = '\0';
936         
937         return token_rep;
938       }
939     break;
940
941     case T_STOP:
942       token_rep = xmalloc (1);
943       *token_rep = '\0';
944       return token_rep;
945
946     case T_EXP:
947       return xstrdup ("**");
948
949     default:
950       if (token >= T_FIRST_KEYWORD && token <= T_LAST_KEYWORD)
951         return xstrdup (keywords [token - T_FIRST_KEYWORD]);
952       else
953         {
954           token_rep = xmalloc (2);
955           token_rep[0] = token;
956           token_rep[1] = '\0';
957           return token_rep;
958         }
959     }
960         
961   assert (0);
962 }
963 \f
964 /* Really weird functions. */
965
966 /* Most of the time, a `-' is a lead-in to a negative number.  But
967    sometimes it's actually part of the syntax.  If a dash can be part
968    of syntax then this function is called to rip it off of a
969    number. */
970 void
971 lex_negative_to_dash (void)
972 {
973   if (token == T_NEG_NUM)
974     {
975       token = T_POS_NUM;
976       tokval = -tokval;
977       ds_replace (&tokstr, ds_c_str (&tokstr) + 1);
978       save_token ();
979       token = '-';
980     }
981 }
982    
983 /* We're not at eof any more. */
984 void
985 lex_reset_eof (void)
986 {
987   eof = 0;
988 }
989
990 /* Skip a COMMENT command. */
991 void
992 lex_skip_comment (void)
993 {
994   for (;;)
995     {
996       if (!lex_get_line ()) 
997         {
998           put_token = T_STOP;
999           eof = 1;
1000           return;
1001         }
1002       
1003       if (put_token == '.')
1004         break;
1005
1006       prog = ds_end (&getl_buf);
1007       if (dot)
1008         break;
1009     }
1010 }
1011 \f
1012 /* Private functions. */
1013
1014 /* Unexpected end of file. */
1015 static void
1016 unexpected_eof (void)
1017 {
1018   msg (FE, _("Unexpected end of file."));
1019 }
1020
1021 /* When invoked, tokstr contains a string of binary, octal, or hex
1022    digits, for values of TYPE of 0, 1, or 2, respectively.  The string
1023    is converted to characters having the specified values. */
1024 static void
1025 convert_numeric_string_to_char_string (int type)
1026 {
1027   static const char *base_names[] = {N_("binary"), N_("octal"), N_("hex")};
1028   static const int bases[] = {2, 8, 16};
1029   static const int chars_per_byte[] = {8, 3, 2};
1030
1031   const char *const base_name = base_names[type];
1032   const int base = bases[type];
1033   const int cpb = chars_per_byte[type];
1034   const int nb = ds_length (&tokstr) / cpb;
1035   int i;
1036   char *p;
1037
1038   assert (type >= 0 && type <= 2);
1039
1040   if (ds_length (&tokstr) % cpb)
1041     msg (SE, _("String of %s digits has %d characters, which is not a "
1042                "multiple of %d."),
1043          gettext (base_name), ds_length (&tokstr), cpb);
1044
1045   p = ds_c_str (&tokstr);
1046   for (i = 0; i < nb; i++)
1047     {
1048       int value;
1049       int j;
1050           
1051       value = 0;
1052       for (j = 0; j < cpb; j++, p++)
1053         {
1054           int v;
1055
1056           if (*p >= '0' && *p <= '9')
1057             v = *p - '0';
1058           else
1059             {
1060               static const char alpha[] = "abcdef";
1061               const char *q = strchr (alpha, tolower ((unsigned char) *p));
1062
1063               if (q)
1064                 v = q - alpha + 10;
1065               else
1066                 v = base;
1067             }
1068
1069           if (v >= base)
1070             msg (SE, _("`%c' is not a valid %s digit."), *p, base_name);
1071
1072           value = value * base + v;
1073         }
1074
1075       ds_c_str (&tokstr)[i] = (unsigned char) value;
1076     }
1077
1078   ds_truncate (&tokstr, nb);
1079 }
1080
1081 /* Parses a string from the input buffer into tokstr.  The input
1082    buffer pointer prog must point to the initial single or double
1083    quote.  TYPE is 0 if it is an ordinary string, or 1, 2, or 3 for a
1084    binary, octal, or hexstring, respectively.  Returns token type. */
1085 static int 
1086 parse_string (int type)
1087 {
1088   /* Accumulate the entire string, joining sections indicated by +
1089      signs. */
1090   for (;;)
1091     {
1092       /* Single or double quote. */
1093       int c = *prog++;
1094       
1095       /* Accumulate section. */
1096       for (;;)
1097         {
1098           /* Check end of line. */
1099           if (*prog == 0)
1100             {
1101               msg (SE, _("Unterminated string constant."));
1102               goto finish;
1103             }
1104           
1105           /* Double quote characters to embed them in strings. */
1106           if (*prog == c)
1107             {
1108               if (prog[1] == c)
1109                 prog++;
1110               else
1111                 break;
1112             }
1113
1114           ds_putc (&tokstr, *prog++);
1115         }
1116       prog++;
1117
1118       /* Skip whitespace after final quote mark. */
1119       if (eof)
1120         break;
1121       for (;;)
1122         {
1123           while (isspace ((unsigned char) *prog))
1124             prog++;
1125           if (*prog)
1126             break;
1127
1128           if (dot)
1129             goto finish;
1130
1131           if (!lex_get_line ())
1132             unexpected_eof ();
1133         }
1134
1135       /* Skip plus sign. */
1136       if (*prog != '+')
1137         break;
1138       prog++;
1139
1140       /* Skip whitespace after plus sign. */
1141       if (eof)
1142         break;
1143       for (;;)
1144         {
1145           while (isspace ((unsigned char) *prog))
1146             prog++;
1147           if (*prog)
1148             break;
1149
1150           if (dot)
1151             goto finish;
1152
1153           if (!lex_get_line ())
1154             unexpected_eof ();
1155         }
1156
1157       /* Ensure that a valid string follows. */
1158       if (*prog != '\'' && *prog != '"')
1159         {
1160           msg (SE, "String expected following `+'.");
1161           goto finish;
1162         }
1163     }
1164
1165   /* We come here when we've finished concatenating all the string sections
1166      into one large string. */
1167 finish:
1168   if (type != 0)
1169     convert_numeric_string_to_char_string (type - 1);
1170
1171   if (ds_length (&tokstr) > 255)
1172     {
1173       msg (SE, _("String exceeds 255 characters in length (%d characters)."),
1174            ds_length (&tokstr));
1175       ds_truncate (&tokstr, 255);
1176     }
1177       
1178   {
1179     /* FIXME. */
1180     size_t i;
1181     int warned = 0;
1182
1183     for (i = 0; i < ds_length (&tokstr); i++)
1184       if (ds_c_str (&tokstr)[i] == 0)
1185         {
1186           if (!warned)
1187             {
1188               msg (SE, _("Sorry, literal strings may not contain null "
1189                          "characters.  Replacing with spaces."));
1190               warned = 1;
1191             }
1192           ds_c_str (&tokstr)[i] = ' ';
1193         }
1194   }
1195
1196   return T_STRING;
1197 }
1198 \f       
1199 #if DUMP_TOKENS
1200 /* Reads one token from the lexer and writes a textual representation
1201    on stdout for debugging purposes. */
1202 static void
1203 dump_token (void)
1204 {
1205   {
1206     const char *curfn;
1207     int curln;
1208
1209     getl_location (&curfn, &curln);
1210     if (curfn)
1211       fprintf (stderr, "%s:%d\t", curfn, curln);
1212   }
1213   
1214   switch (token)
1215     {
1216     case T_ID:
1217       fprintf (stderr, "ID\t%s\n", tokid);
1218       break;
1219
1220     case T_POS_NUM:
1221     case T_NEG_NUM:
1222       fprintf (stderr, "NUM\t%f\n", tokval);
1223       break;
1224
1225     case T_STRING:
1226       fprintf (stderr, "STRING\t\"%s\"\n", ds_c_str (&tokstr));
1227       break;
1228
1229     case T_STOP:
1230       fprintf (stderr, "STOP\n");
1231       break;
1232
1233     case T_EXP:
1234       fprintf (stderr, "MISC\tEXP\"");
1235       break;
1236
1237     case 0:
1238       fprintf (stderr, "MISC\tEOF\n");
1239       break;
1240
1241     default:
1242       if (token >= T_FIRST_KEYWORD && token <= T_LAST_KEYWORD)
1243         fprintf (stderr, "KEYWORD\t%s\n", lex_token_name (token));
1244       else
1245         fprintf (stderr, "PUNCT\t%c\n", token);
1246       break;
1247     }
1248 }
1249 #endif /* DUMP_TOKENS */