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