DEFINE command can now be parsed.
[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 static char *
55 number_token_to_string (const struct token *token)
56 {
57   char buffer[DBL_BUFSIZE_BOUND];
58
59   c_dtoastr (buffer, sizeof buffer, 0, 0, fabs (token->number));
60   return (token->type == T_POS_NUM
61           ? xstrdup (buffer)
62           : xasprintf ("-%s", buffer));
63 }
64
65 static char *
66 quoted_string_representation (struct substring ss, size_t n_quotes)
67 {
68   char *rep;
69   size_t i;
70   char *p;
71
72   p = rep = xmalloc (1 + ss.length + n_quotes + 1 + 1);
73   *p++ = '\'';
74   for (i = 0; i < ss.length; i++)
75     {
76       uint8_t c = ss.string[i];
77       if (c == '\'')
78         *p++ = c;
79       *p++ = c;
80     }
81   *p++ = '\'';
82   *p = '\0';
83
84   return rep;
85 }
86
87 static char *
88 hex_string_representation (struct substring ss)
89 {
90   char *rep;
91   size_t i;
92   char *p;
93
94   p = rep = xmalloc (2 + 2 * ss.length + 1 + 1);
95   *p++ = 'X';
96   *p++ = '\'';
97   for (i = 0; i < ss.length; i++)
98     {
99       static const char hex_digits[] = "0123456789abcdef";
100       uint8_t c = ss.string[i];
101       *p++ = hex_digits[c >> 4];
102       *p++ = hex_digits[c & 15];
103     }
104   *p++ = '\'';
105   *p = '\0';
106
107   return rep;
108 }
109
110 static char *
111 string_representation (struct substring ss)
112 {
113   size_t n_quotes;
114   size_t ofs;
115   int mblen;
116
117   n_quotes = 0;
118   for (ofs = 0; ofs < ss.length; ofs += mblen)
119     {
120       ucs4_t uc;
121
122       mblen = u8_mbtoucr (&uc,
123                           CHAR_CAST (const uint8_t *, ss.string + ofs),
124                           ss.length - ofs);
125       if (mblen < 0 || !uc_is_print (uc))
126         return hex_string_representation (ss);
127       else if (uc == '\'')
128         n_quotes++;
129     }
130   return quoted_string_representation (ss, n_quotes);
131 }
132
133 /* Returns a UTF-8 string that would yield TOKEN if it appeared in a syntax
134    file.  The caller should free the returned string, with free(), when it is
135    no longer needed.
136
137    The T_STOP token has no representation, so this function returns NULL. */
138 char *
139 token_to_string (const struct token *token)
140 {
141   switch (token->type)
142     {
143     case T_POS_NUM:
144     case T_NEG_NUM:
145       return number_token_to_string (token);
146
147     case T_ID:
148     case T_MACRO_ID:
149     case T_MACRO_PUNCT:
150       return ss_xstrdup (token->string);
151
152     case T_STRING:
153       return string_representation (token->string);
154
155     default:
156       return xstrdup_if_nonnull (token_type_to_name (token->type));
157     }
158 }
159
160 /* Prints TOKEN on STREAM, for debugging. */
161 void
162 token_print (const struct token *token, FILE *stream)
163 {
164   fputs (token_type_to_name (token->type), stream);
165   if (token->type == T_POS_NUM || token->type == T_NEG_NUM
166       || token->number != 0.0)
167     {
168       char s[DBL_BUFSIZE_BOUND];
169
170       c_dtoastr (s, sizeof s, 0, 0, token->number);
171       fprintf (stream, "\t%s", s);
172     }
173   if (token->type == T_ID || token->type == T_STRING || token->string.length)
174     fprintf (stream, "\t\"%.*s\"",
175              (int) token->string.length, token->string.string);
176   putc ('\n', stream);
177 }