1 /* PSPP - computes sample statistics.
2 Copyright (C) 1997-9, 2000, 2005 Free Software Foundation, Inc.
3 Written by John Darrington <john@darrington.wattle.id.au>
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., 51 Franklin Street, Fifth Floor, Boston, MA
21 This file is concerned with the definition of the PSPP syntax, NOT the
22 action of scanning/parsing code .
26 #include "identifier.h"
31 #include <libpspp/assertion.h>
33 /* Recognizing identifiers. */
35 /* Returns true if C may be the first character in an
36 identifier in the current locale. */
41 return isalpha (c) || c == '@' || c == '#' || c == '$';
45 /* Returns true if C may be a character in an identifier other
51 return lex_is_id1 (c) || isdigit (c) || c == '.' || c == '_';
54 /* Returns the length of the longest prefix of STRING that forms
55 a valid identifier. Returns zero if STRING does not begin
56 with a valid identifier. */
58 lex_id_get_length (struct substring string)
61 if (!ss_is_empty (string) && lex_is_id1 (ss_first (string)))
64 while (length < ss_length (string)
65 && lex_is_idn (ss_at (string, length)))
71 /* Comparing identifiers. */
73 /* Returns true if TOKEN is a case-insensitive match for KEYWORD.
75 Keywords match if one of the following is true: KEYWORD and
76 TOKEN are identical, or TOKEN is at least 3 characters long
77 and those characters are identical to KEYWORD. */
79 lex_id_match (struct substring keyword, struct substring token)
81 size_t token_len = ss_length (token);
82 size_t keyword_len = ss_length (keyword);
84 if (token_len >= 3 && token_len < keyword_len)
85 return ss_equals_case (ss_head (keyword, token_len), token);
87 return ss_equals_case (keyword, token);
90 /* Table of keywords. */
94 const struct substring identifier;
97 static const struct keyword keywords[] =
99 { T_AND, SS_LITERAL_INITIALIZER ("AND") },
100 { T_OR, SS_LITERAL_INITIALIZER ("OR") },
101 { T_NOT, SS_LITERAL_INITIALIZER ("NOT") },
102 { T_EQ, SS_LITERAL_INITIALIZER ("EQ") },
103 { T_GE, SS_LITERAL_INITIALIZER ("GE") },
104 { T_GT, SS_LITERAL_INITIALIZER ("GT") },
105 { T_LE, SS_LITERAL_INITIALIZER ("LE") },
106 { T_LT, SS_LITERAL_INITIALIZER ("LT") },
107 { T_NE, SS_LITERAL_INITIALIZER ("NE") },
108 { T_ALL, SS_LITERAL_INITIALIZER ("ALL") },
109 { T_BY, SS_LITERAL_INITIALIZER ("BY") },
110 { T_TO, SS_LITERAL_INITIALIZER ("TO") },
111 { T_WITH, SS_LITERAL_INITIALIZER ("WITH") },
113 static const size_t keyword_cnt = sizeof keywords / sizeof *keywords;
115 /* Returns true if TOKEN is representable as a keyword. */
117 lex_is_keyword (int token)
119 const struct keyword *kw;
120 for (kw = keywords; kw < &keywords[keyword_cnt]; kw++)
121 if (kw->token == token)
126 /* Returns the proper token type, either T_ID or a reserved
127 keyword enum, for ID. */
129 lex_id_to_token (struct substring id)
131 if (ss_length (id) >= 2 && ss_length (id) <= 4)
133 const struct keyword *kw;
134 for (kw = keywords; kw < &keywords[keyword_cnt]; kw++)
135 if (ss_equals_case (kw->identifier, id))
142 /* Returns the name for the given keyword token type. */
144 lex_id_name (int token)
146 const struct keyword *kw;
148 for (kw = keywords; kw < &keywords[keyword_cnt]; kw++)
149 if (kw->token == token)
151 /* A "struct substring" is not guaranteed to be
152 null-terminated, as our caller expects, but in this
153 case it always will be. */
154 return ss_data (kw->identifier);