1 /* PSPP - computes sample statistics.
2 Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
3 Written by Ben Pfaff <blp@gnu.org>.
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.
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.
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
37 /*#define DUMP_TOKENS 1*/
40 /* Global variables. */
45 /* T_NUM: the token's value. */
48 /* T_ID: the identifier. */
51 /* T_ID, T_STRING: token string value.
52 For T_ID, this is not truncated to 8 characters as is tokid. */
55 /* Static variables. */
57 /* Table of keywords. */
58 static const char *keywords[T_N_KEYWORDS + 1] =
61 "EQ", "GE", "GT", "LE", "LT", "NE",
62 "ALL", "BY", "TO", "WITH",
66 /* Pointer to next token in getl_buf. */
69 /* Nonzero only if this line ends with a terminal dot. */
72 /* Nonzero only if the last token returned was T_EOF. */
75 /* If nonzero, next token returned by lex_get().
76 Used only in exceptional circumstances. */
79 static void unexpected_eof (void);
80 static inline int check_id (const char *id, size_t len);
81 static void convert_numeric_string_to_char_string (int type);
82 static int parse_string (int type);
85 static void dump_token (void);
90 /* Initializes the lexer. */
98 /* Common functions. */
100 /* Parses a single token, setting appropriate global variables to
101 indicate the token's attributes. */
105 /* If a token was pushed ahead, return it. */
121 /* Skip whitespace. */
127 while (isspace ((unsigned char) *prog))
141 else if (!lex_get_line ())
162 /* Actually parse the token. */
169 case '0': case '1': case '2': case '3': case '4':
170 case '5': case '6': case '7': case '8': case '9':
174 /* `-' can introduce a negative number, or it can be a
175 token by itself. If it is not followed by a digit or a
176 decimal point, it is definitely not a number.
177 Otherwise, it might be either, but most of the time we
178 want it as a number. When the syntax calls for a `-'
179 token, lex_negative_to_dash() must be used to break
180 negative numbers into two tokens. */
183 ds_putchar (&tokstr, *prog++);
184 while (isspace ((unsigned char) *prog))
187 if (!isdigit ((unsigned char) *prog) && *prog != '.')
194 /* Parse the number, copying it into tokstr. */
195 while (isdigit ((unsigned char) *prog))
196 ds_putchar (&tokstr, *prog++);
199 ds_putchar (&tokstr, *prog++);
200 while (isdigit ((unsigned char) *prog))
201 ds_putchar (&tokstr, *prog++);
203 if (*prog == 'e' || *prog == 'E')
205 ds_putchar (&tokstr, *prog++);
206 if (*prog == '+' || *prog == '-')
207 ds_putchar (&tokstr, *prog++);
208 while (isdigit ((unsigned char) *prog))
209 ds_putchar (&tokstr, *prog++);
212 /* Parse as floating point. */
213 tokval = strtod (ds_value (&tokstr), &tail);
216 msg (SE, _("%s does not form a valid number."),
221 ds_putchar (&tokstr, '0');
229 token = parse_string (0);
232 case '(': case ')': case ',': case '=': case '+': case '/':
252 else if (*prog == '>')
291 case 'a': case 'b': case 'c': case 'd': case 'e':
292 case 'f': case 'g': case 'h': case 'i': case 'j':
293 case 'k': case 'l': case 'm': case 'n': case 'o':
294 case 'p': case 'q': case 'r': case 's': case 't':
295 case 'u': case 'v': case 'w': case 'x': case 'y':
297 case 'A': case 'B': case 'C': case 'D': case 'E':
298 case 'F': case 'G': case 'H': case 'I': case 'J':
299 case 'K': case 'L': case 'M': case 'N': case 'O':
300 case 'P': case 'Q': case 'R': case 'S': case 'T':
301 case 'U': case 'V': case 'W': case 'X': case 'Y':
303 case '#': case '$': case '@':
304 /* Strings can be specified in binary, octal, or hex using
305 this special syntax. */
306 if (prog[1] == '\'' || prog[1] == '"')
308 static const char special[3] = "box";
311 p = strchr (special, tolower ((unsigned char) *prog));
315 token = parse_string (p - special + 1);
320 /* Copy id to tokstr. */
321 ds_putchar (&tokstr, toupper ((unsigned char) *prog++));
322 while (CHAR_IS_IDN (*prog))
323 ds_putchar (&tokstr, toupper ((unsigned char) *prog++));
325 /* Copy tokstr to tokid, truncating it to 8 characters. */
326 strncpy (tokid, ds_value (&tokstr), 8);
329 token = check_id (ds_value (&tokstr), ds_length (&tokstr));
333 if (isgraph ((unsigned char) *prog))
334 msg (SE, _("Bad character in input: `%c'."), *prog++);
336 msg (SE, _("Bad character in input: `\\%o'."), *prog++);
348 /* Prints a syntax error message containing the current token and
349 given message MESSAGE (if non-null). */
351 lex_error (const char *message, ...)
355 token_rep = lex_token_representation ();
356 if (token_rep[0] == 0)
357 msg (SE, _("Syntax error at end of file."));
363 va_start (args, message);
364 vsnprintf (buf, 1024, message, args);
367 msg (SE, _("Syntax error %s at `%s'."), buf, token_rep);
370 msg (SE, _("Syntax error at `%s'."), token_rep);
375 /* Checks that we're at end of command.
376 If so, returns a successful command completion code.
377 If not, flags a syntax error and returns an error command
380 lex_end_of_command (void)
384 lex_error (_("expecting end of command"));
385 return CMD_TRAILING_GARBAGE;
391 /* Token testing functions. */
393 /* Returns nonzero if the current token is an integer. */
397 return (token == T_NUM
398 && tokval != NOT_LONG
399 && tokval >= LONG_MIN
400 && tokval <= LONG_MAX
401 && floor (tokval) == tokval);
404 /* Returns the value of the current token, which must be an
409 assert (lex_integer_p ());
413 /* Token matching functions. */
415 /* If TOK is the current token, skips it and returns nonzero.
416 Otherwise, returns zero. */
429 /* If the current token is the identifier S, skips it and returns
431 Otherwise, returns zero. */
433 lex_match_id (const char *s)
435 if (token == T_ID && lex_id_match (s, tokid))
444 /* If the current token is integer N, skips it and returns nonzero.
445 Otherwise, returns zero. */
447 lex_match_int (int x)
449 if (lex_integer_p () && lex_integer () == x)
458 /* Forced matches. */
460 /* If this token is identifier S, fetches the next token and returns
462 Otherwise, reports an error and returns zero. */
464 lex_force_match_id (const char *s)
466 if (token == T_ID && lex_id_match (s, tokid))
473 lex_error (_("expecting `%s'"), s);
478 /* If the current token is T, skips the token. Otherwise, reports an
479 error and returns from the current function with return value 0. */
481 lex_force_match (int t)
490 lex_error (_("expecting %s"), lex_token_name (t));
495 /* If this token is a string, does nothing and returns nonzero.
496 Otherwise, reports an error and returns zero. */
498 lex_force_string (void)
500 if (token == T_STRING)
504 lex_error (_("expecting string"));
509 /* If this token is an integer, does nothing and returns nonzero.
510 Otherwise, reports an error and returns zero. */
514 if (lex_integer_p ())
518 lex_error (_("expecting integer"));
523 /* If this token is a number, does nothing and returns nonzero.
524 Otherwise, reports an error and returns zero. */
532 lex_error (_("expecting number"));
537 /* If this token is an identifier, does nothing and returns nonzero.
538 Otherwise, reports an error and returns zero. */
546 lex_error (_("expecting identifier"));
551 /* Comparing identifiers. */
553 /* Keywords match if one of the following is true: KW and TOK are
554 identical (barring differences in case), or TOK is at least 3
555 characters long and those characters are identical to KW. KW_LEN
556 is the length of KW, TOK_LEN is the length of TOK. */
558 lex_id_match_len (const char *kw, size_t kw_len,
559 const char *tok, size_t tok_len)
566 if (i == kw_len && i == tok_len)
568 else if (i == tok_len)
570 else if (i == kw_len)
572 else if (toupper ((unsigned char) kw[i])
573 != toupper ((unsigned char) tok[i]))
580 /* Same as lex_id_match_len() minus the need to pass in the lengths. */
582 lex_id_match (const char *kw, const char *tok)
584 return lex_id_match_len (kw, strlen (kw), tok, strlen (tok));
587 /* Weird token functions. */
589 /* Returns the first character of the next token, except that if the
590 next token is not an identifier, the character returned will not be
591 a character that can begin an identifier. Specifically, the
592 hexstring lead-in X' causes lookahead() to return '. Note that an
593 alphanumeric return value doesn't guarantee an ID token, it could
594 also be a reserved-word token. */
596 lex_look_ahead (void)
608 while (isspace ((unsigned char) *prog))
615 else if (!lex_get_line ())
622 if ((toupper ((unsigned char) *prog) == 'X'
623 || toupper ((unsigned char) *prog) == 'B')
624 && (prog[1] == '\'' || prog[1] == '"'))
631 /* Makes the current token become the next token to be read; the
632 current token is set to T. */
640 /* Makes T the next token read. */
642 lex_put_forward (int t)
647 /* Weird line processing functions. */
649 /* Discards the rest of the current input line for tokenization
650 purposes, but returns the entire contents of the line for use by
653 lex_entire_line (void)
655 prog = ds_end (&getl_buf);
657 return ds_value (&getl_buf);
660 /* As lex_entire_line(), but only returns the part of the current line
661 that hasn't already been tokenized.
662 If HAD_DOT is non-null, stores nonzero into *HAD_DOT if the line
663 ends with a terminal dot, or zero if it doesn't. */
665 lex_rest_of_line (int *had_dot)
668 prog = ds_end (&getl_buf);
677 /* Causes the rest of the current input line to be ignored for
678 tokenization purposes. */
680 lex_discard_line (void)
682 msg (SW, _("The rest of this command has been discarded."));
684 ds_clear (&getl_buf);
685 prog = ds_value (&getl_buf);
689 /* Sets the current position in the current line to P, which must be
692 lex_set_prog (char *p)
697 /* Weird line reading functions. */
699 /* Read a line for use by the tokenizer. */
703 if (!getl_read_line ())
706 lex_preprocess_line ();
710 /* Preprocesses getl_buf by removing comments, stripping trailing
711 whitespace and the terminal dot, and removing leading indentors. */
713 lex_preprocess_line (void)
715 /* Strips comments. */
717 /* getl_buf iterator. */
720 /* Nonzero inside a comment. */
723 /* Nonzero inside a quoted string. */
726 /* Remove C-style comments begun by slash-star and terminated by
727 star-slash or newline. */
729 for (cp = ds_value (&getl_buf); *cp; )
731 /* If we're not commented out, toggle quoting. */
736 else if (*cp == '\'' || *cp == '"')
740 /* If we're not quoting, toggle commenting. */
743 if (cp[0] == '/' && cp[1] == '*')
750 else if (cp[0] == '*' && cp[1] == '/' && comment)
759 /* Check commenting. */
767 /* Strip trailing whitespace and terminal dot. */
769 size_t len = ds_length (&getl_buf);
770 char *s = ds_value (&getl_buf);
772 /* Strip trailing whitespace. */
773 while (len > 0 && isspace ((unsigned char) s[len - 1]))
776 /* Check for and remove terminal dot. */
777 if (len > 0 && s[len - 1] == set_endcmd)
782 else if (len == 0 && set_nullline)
788 ds_truncate (&getl_buf, len);
791 /* In batch mode, strip leading indentors and insert a terminal dot
793 if (getl_interactive != 2 && getl_mode == GETL_MODE_BATCH)
795 char *s = ds_value (&getl_buf);
797 if (s[0] == '+' || s[0] == '-' || s[0] == '.')
799 else if (s[0] && !isspace ((unsigned char) s[0]))
800 lex_put_forward ('.');
803 prog = ds_value (&getl_buf);
808 /* Returns the name of a token in a static buffer. */
810 lex_token_name (int token)
812 if (token >= T_FIRST_KEYWORD && token <= T_LAST_KEYWORD)
813 return keywords[token - T_FIRST_KEYWORD];
825 /* Returns an ASCII representation of the current token as a
826 malloc()'d string. */
828 lex_token_representation (void)
836 return xstrdup (ds_value (&tokstr));
844 for (sp = ds_value (&tokstr); sp < ds_end (&tokstr); sp++)
845 if (!isprint ((unsigned char) *sp))
851 token_rep = xmalloc (2 + ds_length (&tokstr) * 2 + 1 + 1);
859 for (sp = ds_value (&tokstr); *sp; )
863 *dp++ = (unsigned char) *sp++;
866 for (sp = ds_value (&tokstr); sp < ds_end (&tokstr); sp++)
868 *dp++ = (((unsigned char) *sp) >> 4)["0123456789ABCDEF"];
869 *dp++ = (((unsigned char) *sp) & 15)["0123456789ABCDEF"];
879 token_rep = xmalloc (1);
884 return xstrdup ("**");
887 if (token >= T_FIRST_KEYWORD && token <= T_LAST_KEYWORD)
888 return xstrdup (keywords [token - T_FIRST_KEYWORD]);
891 token_rep = xmalloc (2);
892 token_rep[0] = token;
901 /* Really weird functions. */
903 /* Most of the time, a `-' is a lead-in to a negative number. But
904 sometimes it's actually part of the syntax. If a dash can be part
905 of syntax then this function is called to rip it off of a
908 lex_negative_to_dash (void)
910 if (token == T_NUM && tokval < 0.0)
914 ds_replace (&tokstr, ds_value (&tokstr) + 1);
915 lex_put_forward (T_NUM);
919 /* We're not at eof any more. */
926 /* Skip a COMMENT command. */
928 lex_skip_comment (void)
936 prog = ds_end (&getl_buf);
942 /* Private functions. */
944 /* Unexpected end of file. */
946 unexpected_eof (void)
948 msg (FE, _("Unexpected end of file."));
951 /* Returns the proper token type, either T_ID or a reserved keyword
952 enum, for ID[], which must contain LEN characters. */
954 check_id (const char *id, size_t len)
958 if (len < 2 || len > 4)
961 for (kwp = keywords; *kwp; kwp++)
962 if (!strcmp (*kwp, id))
963 return T_FIRST_KEYWORD + (kwp - keywords);
968 /* When invoked, tokstr contains a string of binary, octal, or hex
969 digits, for values of TYPE of 0, 1, or 2, respectively. The string
970 is converted to characters having the specified values. */
972 convert_numeric_string_to_char_string (int type)
974 static const char *base_names[] = {N_("binary"), N_("octal"), N_("hex")};
975 static const int bases[] = {2, 8, 16};
976 static const int chars_per_byte[] = {8, 3, 2};
978 const char *const base_name = base_names[type];
979 const int base = bases[type];
980 const int cpb = chars_per_byte[type];
981 const int nb = ds_length (&tokstr) / cpb;
985 assert (type >= 0 && type <= 2);
987 if (ds_length (&tokstr) % cpb)
988 msg (SE, _("String of %s digits has %d characters, which is not a "
990 gettext (base_name), ds_length (&tokstr), cpb);
992 p = ds_value (&tokstr);
993 for (i = 0; i < nb; i++)
999 for (j = 0; j < cpb; j++, p++)
1003 if (*p >= '0' && *p <= '9')
1007 static const char alpha[] = "abcdef";
1008 const char *q = strchr (alpha, tolower ((unsigned char) *p));
1017 msg (SE, _("`%c' is not a valid %s digit."), *p, base_name);
1019 value = value * base + v;
1022 ds_value (&tokstr)[i] = (unsigned char) value;
1025 ds_truncate (&tokstr, nb);
1028 /* Parses a string from the input buffer into tokstr. The input
1029 buffer pointer prog must point to the initial single or double
1030 quote. TYPE is 0 if it is an ordinary string, or 1, 2, or 3 for a
1031 binary, octal, or hexstring, respectively. Returns token type. */
1033 parse_string (int type)
1035 /* Accumulate the entire string, joining sections indicated by +
1039 /* Single or double quote. */
1042 /* Accumulate section. */
1045 /* Check end of line. */
1048 msg (SE, _("Unterminated string constant."));
1052 /* Double quote characters to embed them in strings. */
1061 ds_putchar (&tokstr, *prog++);
1065 /* Skip whitespace after final quote mark. */
1070 while (isspace ((unsigned char) *prog))
1078 if (!lex_get_line ())
1082 /* Skip plus sign. */
1087 /* Skip whitespace after plus sign. */
1092 while (isspace ((unsigned char) *prog))
1100 if (!lex_get_line ())
1104 /* Ensure that a valid string follows. */
1105 if (*prog != '\'' && *prog != '"')
1107 msg (SE, "String expected following `+'.");
1112 /* We come here when we've finished concatenating all the string sections
1113 into one large string. */
1116 convert_numeric_string_to_char_string (type - 1);
1118 if (ds_length (&tokstr) > 255)
1120 msg (SE, _("String exceeds 255 characters in length (%d characters)."),
1121 ds_length (&tokstr));
1122 ds_truncate (&tokstr, 255);
1130 for (i = 0; i < ds_length (&tokstr); i++)
1131 if (ds_value (&tokstr)[i] == 0)
1135 msg (SE, _("Sorry, literal strings may not contain null "
1136 "characters. Replacing with spaces."));
1139 ds_value (&tokstr)[i] = ' ';
1147 /* Reads one token from the lexer and writes a textual representation
1148 on stdout for debugging purposes. */
1156 getl_location (&curfn, &curln);
1158 printf ("%s:%d\t", curfn, curln);
1164 printf ("ID\t%s\n", tokid);
1168 printf ("NUM\t%f\n", tokval);
1172 printf ("STRING\t\"%s\"\n", ds_value (&tokstr));
1188 if (token >= T_FIRST_KEYWORD && token <= T_LAST_KEYWORD)
1189 printf ("KEYWORD\t%s\n", lex_token_name (token));
1191 printf ("PUNCT\t%c\n", token);
1195 #endif /* DEBUGGING */