Work on DEFINE command.
[pspp] / src / language / lexer / token.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2010, 2011 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17 #include <config.h>
18
19 #include "language/lexer/token.h"
20
21 #include <math.h>
22 #include <unictype.h>
23 #include <unistr.h>
24
25 #include "data/identifier.h"
26 #include "libpspp/assertion.h"
27 #include "libpspp/cast.h"
28 #include "libpspp/misc.h"
29
30 #include "gl/ftoastr.h"
31 #include "gl/xalloc.h"
32
33 void
34 token_copy (struct token *dst, const struct token *src)
35 {
36   *dst = (struct token) {
37     .type = src->type,
38     .number = src->number,
39   };
40   ss_alloc_substring (&dst->string, src->string);
41 }
42
43 /* Frees the string that TOKEN contains. */
44 void
45 token_uninit (struct token *token)
46 {
47   if (token != NULL)
48     {
49       ss_dealloc (&token->string);
50       *token = (struct token) { .type = T_STOP };
51     }
52 }
53
54 bool
55 token_equal (const struct token *a, const struct token *b)
56 {
57   if (a->type != b->type)
58     return false;
59
60   switch (a->type)
61     {
62     case T_POS_NUM:
63     case T_NEG_NUM:
64       return a->number == b->number;
65
66     case T_ID:
67     case T_MACRO_ID:
68     case T_MACRO_PUNCT:
69     case T_STRING:
70       return ss_equals (a->string, b->string);
71
72     default:
73       return true;
74     }
75 }
76
77 static char *
78 number_token_to_string (const struct token *token)
79 {
80   char buffer[DBL_BUFSIZE_BOUND];
81
82   c_dtoastr (buffer, sizeof buffer, 0, 0, fabs (token->number));
83   return (token->type == T_POS_NUM
84           ? xstrdup (buffer)
85           : xasprintf ("-%s", buffer));
86 }
87
88 static char *
89 quoted_string_representation (struct substring ss, size_t n_quotes)
90 {
91   char *rep;
92   size_t i;
93   char *p;
94
95   p = rep = xmalloc (1 + ss.length + n_quotes + 1 + 1);
96   *p++ = '\'';
97   for (i = 0; i < ss.length; i++)
98     {
99       uint8_t c = ss.string[i];
100       if (c == '\'')
101         *p++ = c;
102       *p++ = c;
103     }
104   *p++ = '\'';
105   *p = '\0';
106
107   return rep;
108 }
109
110 static char *
111 hex_string_representation (struct substring ss)
112 {
113   char *rep;
114   size_t i;
115   char *p;
116
117   p = rep = xmalloc (2 + 2 * ss.length + 1 + 1);
118   *p++ = 'X';
119   *p++ = '\'';
120   for (i = 0; i < ss.length; i++)
121     {
122       static const char hex_digits[] = "0123456789abcdef";
123       uint8_t c = ss.string[i];
124       *p++ = hex_digits[c >> 4];
125       *p++ = hex_digits[c & 15];
126     }
127   *p++ = '\'';
128   *p = '\0';
129
130   return rep;
131 }
132
133 static char *
134 string_representation (struct substring ss)
135 {
136   size_t n_quotes;
137   size_t ofs;
138   int mblen;
139
140   n_quotes = 0;
141   for (ofs = 0; ofs < ss.length; ofs += mblen)
142     {
143       ucs4_t uc;
144
145       mblen = u8_mbtoucr (&uc,
146                           CHAR_CAST (const uint8_t *, ss.string + ofs),
147                           ss.length - ofs);
148       if (mblen < 0 || !uc_is_print (uc))
149         return hex_string_representation (ss);
150       else if (uc == '\'')
151         n_quotes++;
152     }
153   return quoted_string_representation (ss, n_quotes);
154 }
155
156 /* Returns a UTF-8 string that would yield TOKEN if it appeared in a syntax
157    file.  The caller should free the returned string, with free(), when it is
158    no longer needed.
159
160    The T_STOP token has no representation, so this function returns NULL. */
161 char *
162 token_to_string (const struct token *token)
163 {
164   switch (token->type)
165     {
166     case T_POS_NUM:
167     case T_NEG_NUM:
168       return number_token_to_string (token);
169
170     case T_ID:
171     case T_MACRO_ID:
172     case T_MACRO_PUNCT:
173       return ss_xstrdup (token->string);
174
175     case T_STRING:
176       return string_representation (token->string);
177
178     default:
179       return xstrdup_if_nonnull (token_type_to_string (token->type));
180     }
181 }
182
183 /* Prints TOKEN on STREAM, for debugging. */
184 void
185 token_print (const struct token *token, FILE *stream)
186 {
187   fputs (token_type_to_name (token->type), stream);
188   if (token->type == T_POS_NUM || token->type == T_NEG_NUM
189       || token->number != 0.0)
190     {
191       char s[DBL_BUFSIZE_BOUND];
192
193       c_dtoastr (s, sizeof s, 0, 0, token->number);
194       fprintf (stream, "\t%s", s);
195     }
196   if (token->type == T_ID || token->type == T_STRING || token->string.length)
197     fprintf (stream, "\t\"%.*s\"",
198              (int) token->string.length, token->string.string);
199   putc ('\n', stream);
200 }
201 \f
202 void
203 tokens_copy (struct tokens *dst, const struct tokens *src)
204 {
205   *dst = (struct tokens) {
206     .tokens = xnmalloc (src->n, sizeof *dst->tokens),
207     .n = src->n,
208     .allocated = src->n,
209   };
210
211   for (size_t i = 0; i < src->n; i++)
212     token_copy (&dst->tokens[i], &src->tokens[i]);
213 }
214
215 void
216 tokens_uninit (struct tokens *tokens)
217 {
218   for (size_t i = 0; i < tokens->n; i++)
219     token_uninit (&tokens->tokens[i]);
220   free (tokens->tokens);
221 }
222
223 void
224 tokens_add (struct tokens *tokens, const struct token *t)
225 {
226   if (tokens->allocated >= tokens->n)
227     tokens->tokens = x2nrealloc (tokens->tokens, &tokens->allocated,
228                                  sizeof *tokens->tokens);
229
230   token_copy (&tokens->tokens[tokens->n++], t);
231 }
232
233 void
234 tokens_print (const struct tokens *tokens, FILE *stream)
235 {
236   for (size_t i = 0; i < tokens->n; i++)
237     token_print (&tokens->tokens[i], stream);
238 }