tyname.c revision 1.20 1 1.20 rillig /* $NetBSD: tyname.c,v 1.20 2021/01/02 03:49:25 rillig Exp $ */
2 1.3 skrll
3 1.1 christos /*-
4 1.1 christos * Copyright (c) 2005 The NetBSD Foundation, Inc.
5 1.1 christos * All rights reserved.
6 1.1 christos *
7 1.1 christos * This code is derived from software contributed to The NetBSD Foundation
8 1.1 christos * by Christos Zoulas.
9 1.1 christos *
10 1.1 christos * Redistribution and use in source and binary forms, with or without
11 1.1 christos * modification, are permitted provided that the following conditions
12 1.1 christos * are met:
13 1.1 christos * 1. Redistributions of source code must retain the above copyright
14 1.1 christos * notice, this list of conditions and the following disclaimer.
15 1.1 christos * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 christos * notice, this list of conditions and the following disclaimer in the
17 1.1 christos * documentation and/or other materials provided with the distribution.
18 1.1 christos *
19 1.1 christos * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 1.1 christos * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.1 christos * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.1 christos * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 1.1 christos * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 1.1 christos * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.1 christos * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.1 christos * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.1 christos * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.1 christos * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.1 christos * POSSIBILITY OF SUCH DAMAGE.
30 1.1 christos */
31 1.1 christos
32 1.1 christos #if HAVE_NBTOOL_CONFIG_H
33 1.1 christos #include "nbtool_config.h"
34 1.1 christos #endif
35 1.1 christos
36 1.1 christos #include <sys/cdefs.h>
37 1.1 christos #if defined(__RCSID) && !defined(lint)
38 1.20 rillig __RCSID("$NetBSD: tyname.c,v 1.20 2021/01/02 03:49:25 rillig Exp $");
39 1.1 christos #endif
40 1.1 christos
41 1.1 christos #include <limits.h>
42 1.8 christos #include <string.h>
43 1.1 christos #include <stdlib.h>
44 1.1 christos #include <err.h>
45 1.1 christos
46 1.1 christos #include PASS
47 1.1 christos
48 1.1 christos #ifndef LERROR
49 1.15 rillig #define LERROR(fmt, args...) \
50 1.15 rillig do { \
51 1.15 rillig (void)warnx("%s, %d: " fmt, __FILE__, __LINE__, ##args); \
52 1.15 rillig abort(); \
53 1.15 rillig } while (/*CONSTCOND*/0)
54 1.1 christos #endif
55 1.1 christos
56 1.20 rillig /* A tree of strings. */
57 1.20 rillig typedef struct name_tree_node {
58 1.20 rillig char *ntn_name;
59 1.20 rillig struct name_tree_node *ntn_less;
60 1.20 rillig struct name_tree_node *ntn_greater;
61 1.20 rillig } name_tree_node;
62 1.20 rillig
63 1.20 rillig /* A growable string buffer. */
64 1.20 rillig typedef struct buffer {
65 1.20 rillig size_t len;
66 1.20 rillig size_t cap;
67 1.20 rillig char * data;
68 1.20 rillig } buffer;
69 1.20 rillig
70 1.20 rillig static name_tree_node *type_names;
71 1.20 rillig
72 1.20 rillig static name_tree_node *
73 1.20 rillig new_name_tree_node(const char *name)
74 1.20 rillig {
75 1.20 rillig name_tree_node *n;
76 1.20 rillig
77 1.20 rillig n = xmalloc(sizeof(*n));
78 1.20 rillig n->ntn_name = xstrdup(name);
79 1.20 rillig n->ntn_less = NULL;
80 1.20 rillig n->ntn_greater = NULL;
81 1.20 rillig return n;
82 1.20 rillig }
83 1.20 rillig
84 1.20 rillig /* Return the canonical instance of the string, with unlimited life time. */
85 1.20 rillig static const char *
86 1.20 rillig intern(const char *name)
87 1.20 rillig {
88 1.20 rillig name_tree_node *n = type_names;
89 1.20 rillig int cmp;
90 1.20 rillig
91 1.20 rillig if (n == NULL) {
92 1.20 rillig n = new_name_tree_node(name);
93 1.20 rillig type_names = n;
94 1.20 rillig return n->ntn_name;
95 1.20 rillig }
96 1.20 rillig
97 1.20 rillig while ((cmp = strcmp(name, n->ntn_name)) != 0) {
98 1.20 rillig if (cmp < 0) {
99 1.20 rillig if (n->ntn_less == NULL) {
100 1.20 rillig n->ntn_less = new_name_tree_node(name);
101 1.20 rillig return n->ntn_less->ntn_name;
102 1.20 rillig }
103 1.20 rillig n = n->ntn_less;
104 1.20 rillig } else {
105 1.20 rillig if (n->ntn_greater == NULL) {
106 1.20 rillig n->ntn_greater = new_name_tree_node(name);
107 1.20 rillig return n->ntn_greater->ntn_name;
108 1.20 rillig }
109 1.20 rillig n = n->ntn_greater;
110 1.20 rillig }
111 1.20 rillig }
112 1.20 rillig return n->ntn_name;
113 1.20 rillig }
114 1.20 rillig
115 1.20 rillig static void
116 1.20 rillig buf_init(buffer *buf)
117 1.20 rillig {
118 1.20 rillig buf->len = 0;
119 1.20 rillig buf->cap = 128;
120 1.20 rillig buf->data = xmalloc(buf->cap);
121 1.20 rillig buf->data[0] = '\0';
122 1.20 rillig }
123 1.20 rillig
124 1.20 rillig static void
125 1.20 rillig buf_done(buffer *buf)
126 1.20 rillig {
127 1.20 rillig free(buf->data);
128 1.20 rillig }
129 1.20 rillig
130 1.20 rillig static void
131 1.20 rillig buf_add(buffer *buf, const char *s)
132 1.20 rillig {
133 1.20 rillig size_t len = strlen(s);
134 1.20 rillig
135 1.20 rillig while (buf->len + len + 1 >= buf->cap) {
136 1.20 rillig buf->data = xrealloc(buf->data, 2 * buf->cap);
137 1.20 rillig buf->cap = 2 * buf->cap;
138 1.20 rillig }
139 1.20 rillig
140 1.20 rillig memcpy(buf->data + buf->len, s, len + 1);
141 1.20 rillig buf->len += len;
142 1.20 rillig }
143 1.20 rillig
144 1.20 rillig static void
145 1.20 rillig buf_add_int(buffer *buf, int n)
146 1.20 rillig {
147 1.20 rillig char num[1 + sizeof(n) * CHAR_BIT + 1];
148 1.20 rillig
149 1.20 rillig snprintf(num, sizeof num, "%d", n);
150 1.20 rillig buf_add(buf, num);
151 1.20 rillig }
152 1.20 rillig
153 1.1 christos const char *
154 1.18 rillig tspec_name(tspec_t t)
155 1.1 christos {
156 1.1 christos switch (t) {
157 1.19 rillig case SIGNED: return "signed";
158 1.19 rillig case UNSIGN: return "unsigned";
159 1.1 christos case BOOL: return "_Bool";
160 1.1 christos case CHAR: return "char";
161 1.19 rillig case SCHAR: return "signed char";
162 1.1 christos case UCHAR: return "unsigned char";
163 1.1 christos case SHORT: return "short";
164 1.1 christos case USHORT: return "unsigned short";
165 1.1 christos case INT: return "int";
166 1.1 christos case UINT: return "unsigned int";
167 1.1 christos case LONG: return "long";
168 1.1 christos case ULONG: return "unsigned long";
169 1.1 christos case QUAD: return "long long";
170 1.1 christos case UQUAD: return "unsigned long long";
171 1.13 christos #ifdef INT128_SIZE
172 1.13 christos case INT128: return "__int128_t";
173 1.13 christos case UINT128: return "__uint128_t";
174 1.13 christos #endif
175 1.1 christos case FLOAT: return "float";
176 1.1 christos case DOUBLE: return "double";
177 1.1 christos case LDOUBLE: return "long double";
178 1.2 skd case VOID: return "void";
179 1.1 christos case STRUCT: return "struct";
180 1.1 christos case UNION: return "union";
181 1.19 rillig case ENUM: return "enum";
182 1.19 rillig case PTR: return "pointer";
183 1.19 rillig case ARRAY: return "array";
184 1.1 christos case FUNC: return "function";
185 1.19 rillig case COMPLEX: return "_Complex";
186 1.5 christos case FCOMPLEX: return "float _Complex";
187 1.5 christos case DCOMPLEX: return "double _Complex";
188 1.9 matt case LCOMPLEX: return "long double _Complex";
189 1.1 christos default:
190 1.18 rillig LERROR("tspec_name(%d)", t);
191 1.1 christos return NULL;
192 1.1 christos }
193 1.1 christos }
194 1.1 christos
195 1.12 christos int
196 1.12 christos sametype(const type_t *t1, const type_t *t2)
197 1.12 christos {
198 1.12 christos tspec_t t;
199 1.12 christos
200 1.12 christos if (t1->t_tspec != t2->t_tspec)
201 1.12 christos return 0;
202 1.12 christos
203 1.12 christos /* Ignore const/void */
204 1.12 christos
205 1.12 christos switch (t = t1->t_tspec) {
206 1.12 christos case BOOL:
207 1.12 christos case CHAR:
208 1.12 christos case UCHAR:
209 1.12 christos case SCHAR:
210 1.12 christos case SHORT:
211 1.12 christos case USHORT:
212 1.12 christos case INT:
213 1.12 christos case UINT:
214 1.12 christos case LONG:
215 1.12 christos case ULONG:
216 1.12 christos case QUAD:
217 1.12 christos case UQUAD:
218 1.13 christos #ifdef INT128_SIZE
219 1.13 christos case INT128:
220 1.13 christos case UINT128:
221 1.13 christos #endif
222 1.12 christos case FLOAT:
223 1.12 christos case DOUBLE:
224 1.12 christos case LDOUBLE:
225 1.12 christos case VOID:
226 1.12 christos case FUNC:
227 1.12 christos case COMPLEX:
228 1.12 christos case FCOMPLEX:
229 1.12 christos case DCOMPLEX:
230 1.12 christos case LCOMPLEX:
231 1.12 christos return 1;
232 1.12 christos case ARRAY:
233 1.12 christos if (t1->t_dim != t2->t_dim)
234 1.12 christos return 0;
235 1.12 christos /*FALLTHROUGH*/
236 1.12 christos case PTR:
237 1.12 christos return sametype(t1->t_subt, t2->t_subt);
238 1.12 christos case ENUM:
239 1.12 christos #ifdef t_enum
240 1.12 christos return strcmp(t1->t_enum->etag->s_name,
241 1.12 christos t2->t_enum->etag->s_name) == 0;
242 1.12 christos #else
243 1.12 christos return 1;
244 1.12 christos #endif
245 1.12 christos case STRUCT:
246 1.12 christos case UNION:
247 1.12 christos #ifdef t_str
248 1.12 christos return strcmp(t1->t_str->stag->s_name,
249 1.12 christos t2->t_str->stag->s_name) == 0;
250 1.12 christos #else
251 1.12 christos return 1;
252 1.12 christos #endif
253 1.12 christos default:
254 1.12 christos LERROR("tyname(%d)", t);
255 1.12 christos return 0;
256 1.12 christos }
257 1.12 christos }
258 1.12 christos
259 1.1 christos const char *
260 1.20 rillig type_name(const type_t *tp)
261 1.1 christos {
262 1.20 rillig tspec_t t;
263 1.20 rillig buffer buf;
264 1.20 rillig const char *name;
265 1.1 christos
266 1.11 christos if (tp == NULL)
267 1.11 christos return "(null)";
268 1.20 rillig
269 1.20 rillig /*
270 1.20 rillig * XXX: Why is this necessary, and in which cases does this apply?
271 1.20 rillig * Shouldn't the type be an ENUM from the beginning?
272 1.20 rillig */
273 1.1 christos if ((t = tp->t_tspec) == INT && tp->t_isenum)
274 1.1 christos t = ENUM;
275 1.1 christos
276 1.20 rillig buf_init(&buf);
277 1.8 christos if (tp->t_const)
278 1.20 rillig buf_add(&buf, "const ");
279 1.8 christos if (tp->t_volatile)
280 1.20 rillig buf_add(&buf, "volatile ");
281 1.20 rillig buf_add(&buf, tspec_name(t));
282 1.1 christos
283 1.1 christos switch (t) {
284 1.1 christos case BOOL:
285 1.1 christos case CHAR:
286 1.1 christos case UCHAR:
287 1.1 christos case SCHAR:
288 1.1 christos case SHORT:
289 1.1 christos case USHORT:
290 1.1 christos case INT:
291 1.1 christos case UINT:
292 1.1 christos case LONG:
293 1.1 christos case ULONG:
294 1.1 christos case QUAD:
295 1.1 christos case UQUAD:
296 1.13 christos #ifdef INT128_SIZE
297 1.13 christos case INT128:
298 1.13 christos case UINT128:
299 1.13 christos #endif
300 1.1 christos case FLOAT:
301 1.1 christos case DOUBLE:
302 1.1 christos case LDOUBLE:
303 1.2 skd case VOID:
304 1.1 christos case FUNC:
305 1.5 christos case COMPLEX:
306 1.5 christos case FCOMPLEX:
307 1.5 christos case DCOMPLEX:
308 1.10 matt case LCOMPLEX:
309 1.17 rillig case SIGNED:
310 1.17 rillig case UNSIGN:
311 1.1 christos break;
312 1.1 christos case PTR:
313 1.20 rillig buf_add(&buf, " to ");
314 1.20 rillig buf_add(&buf, type_name(tp->t_subt));
315 1.1 christos break;
316 1.1 christos case ENUM:
317 1.20 rillig buf_add(&buf, " ");
318 1.1 christos #ifdef t_enum
319 1.20 rillig buf_add(&buf, tp->t_enum->etag->s_name);
320 1.1 christos #else
321 1.20 rillig buf_add(&buf,
322 1.20 rillig tp->t_isuniqpos ? "*anonymous*" : tp->t_tag->h_name);
323 1.1 christos #endif
324 1.1 christos break;
325 1.1 christos case STRUCT:
326 1.1 christos case UNION:
327 1.20 rillig buf_add(&buf, " ");
328 1.1 christos #ifdef t_str
329 1.20 rillig buf_add(&buf, tp->t_str->stag->s_name);
330 1.1 christos #else
331 1.20 rillig buf_add(&buf,
332 1.20 rillig tp->t_isuniqpos ? "*anonymous*" : tp->t_tag->h_name);
333 1.1 christos #endif
334 1.1 christos break;
335 1.1 christos case ARRAY:
336 1.20 rillig buf_add(&buf, " of ");
337 1.20 rillig buf_add(&buf, type_name(tp->t_subt));
338 1.20 rillig buf_add(&buf, "[");
339 1.20 rillig buf_add_int(&buf, tp->t_dim);
340 1.20 rillig buf_add(&buf, "]");
341 1.1 christos break;
342 1.1 christos default:
343 1.8 christos LERROR("tyname(%d)", t);
344 1.1 christos }
345 1.20 rillig
346 1.20 rillig name = intern(buf.data);
347 1.20 rillig buf_done(&buf);
348 1.20 rillig return name;
349 1.1 christos }
350