tyname.c revision 1.45 1 1.45 rillig /* $NetBSD: tyname.c,v 1.45 2021/08/28 13:29:26 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.45 rillig __RCSID("$NetBSD: tyname.c,v 1.45 2021/08/28 13:29:26 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.39 rillig #if defined(IS_LINT1)
47 1.39 rillig #include "lint1.h"
48 1.39 rillig #else
49 1.39 rillig #include "lint2.h"
50 1.39 rillig #endif
51 1.1 christos
52 1.36 rillig #ifndef INTERNAL_ERROR
53 1.36 rillig #define INTERNAL_ERROR(fmt, args...) \
54 1.15 rillig do { \
55 1.15 rillig (void)warnx("%s, %d: " fmt, __FILE__, __LINE__, ##args); \
56 1.15 rillig abort(); \
57 1.40 rillig } while (false)
58 1.1 christos #endif
59 1.1 christos
60 1.20 rillig /* A tree of strings. */
61 1.20 rillig typedef struct name_tree_node {
62 1.44 rillig const char *ntn_name;
63 1.20 rillig struct name_tree_node *ntn_less;
64 1.20 rillig struct name_tree_node *ntn_greater;
65 1.20 rillig } name_tree_node;
66 1.20 rillig
67 1.20 rillig /* A growable string buffer. */
68 1.20 rillig typedef struct buffer {
69 1.20 rillig size_t len;
70 1.20 rillig size_t cap;
71 1.20 rillig char * data;
72 1.20 rillig } buffer;
73 1.20 rillig
74 1.20 rillig static name_tree_node *type_names;
75 1.20 rillig
76 1.20 rillig static name_tree_node *
77 1.20 rillig new_name_tree_node(const char *name)
78 1.20 rillig {
79 1.20 rillig name_tree_node *n;
80 1.20 rillig
81 1.37 rillig n = xmalloc(sizeof(*n));
82 1.20 rillig n->ntn_name = xstrdup(name);
83 1.20 rillig n->ntn_less = NULL;
84 1.20 rillig n->ntn_greater = NULL;
85 1.20 rillig return n;
86 1.20 rillig }
87 1.20 rillig
88 1.44 rillig /* Return the canonical instance of the string, with unlimited lifetime. */
89 1.26 rillig static const char *
90 1.20 rillig intern(const char *name)
91 1.20 rillig {
92 1.25 rillig name_tree_node *n = type_names, **next;
93 1.20 rillig int cmp;
94 1.20 rillig
95 1.20 rillig if (n == NULL) {
96 1.20 rillig n = new_name_tree_node(name);
97 1.20 rillig type_names = n;
98 1.20 rillig return n->ntn_name;
99 1.20 rillig }
100 1.20 rillig
101 1.20 rillig while ((cmp = strcmp(name, n->ntn_name)) != 0) {
102 1.25 rillig next = cmp < 0 ? &n->ntn_less : &n->ntn_greater;
103 1.25 rillig if (*next == NULL) {
104 1.25 rillig *next = new_name_tree_node(name);
105 1.25 rillig return (*next)->ntn_name;
106 1.20 rillig }
107 1.25 rillig n = *next;
108 1.20 rillig }
109 1.20 rillig return n->ntn_name;
110 1.20 rillig }
111 1.20 rillig
112 1.20 rillig static void
113 1.20 rillig buf_init(buffer *buf)
114 1.20 rillig {
115 1.20 rillig buf->len = 0;
116 1.20 rillig buf->cap = 128;
117 1.20 rillig buf->data = xmalloc(buf->cap);
118 1.20 rillig buf->data[0] = '\0';
119 1.20 rillig }
120 1.20 rillig
121 1.20 rillig static void
122 1.20 rillig buf_done(buffer *buf)
123 1.20 rillig {
124 1.20 rillig free(buf->data);
125 1.20 rillig }
126 1.20 rillig
127 1.20 rillig static void
128 1.20 rillig buf_add(buffer *buf, const char *s)
129 1.20 rillig {
130 1.20 rillig size_t len = strlen(s);
131 1.20 rillig
132 1.20 rillig while (buf->len + len + 1 >= buf->cap) {
133 1.20 rillig buf->data = xrealloc(buf->data, 2 * buf->cap);
134 1.20 rillig buf->cap = 2 * buf->cap;
135 1.20 rillig }
136 1.20 rillig
137 1.20 rillig memcpy(buf->data + buf->len, s, len + 1);
138 1.20 rillig buf->len += len;
139 1.20 rillig }
140 1.20 rillig
141 1.20 rillig static void
142 1.20 rillig buf_add_int(buffer *buf, int n)
143 1.20 rillig {
144 1.37 rillig char num[1 + sizeof(n) * CHAR_BIT + 1];
145 1.20 rillig
146 1.45 rillig (void)snprintf(num, sizeof(num), "%d", n);
147 1.20 rillig buf_add(buf, num);
148 1.20 rillig }
149 1.20 rillig
150 1.1 christos const char *
151 1.18 rillig tspec_name(tspec_t t)
152 1.1 christos {
153 1.1 christos switch (t) {
154 1.19 rillig case SIGNED: return "signed";
155 1.19 rillig case UNSIGN: return "unsigned";
156 1.1 christos case BOOL: return "_Bool";
157 1.1 christos case CHAR: return "char";
158 1.19 rillig case SCHAR: return "signed char";
159 1.1 christos case UCHAR: return "unsigned char";
160 1.1 christos case SHORT: return "short";
161 1.1 christos case USHORT: return "unsigned short";
162 1.1 christos case INT: return "int";
163 1.1 christos case UINT: return "unsigned int";
164 1.1 christos case LONG: return "long";
165 1.1 christos case ULONG: return "unsigned long";
166 1.1 christos case QUAD: return "long long";
167 1.1 christos case UQUAD: return "unsigned long long";
168 1.13 christos #ifdef INT128_SIZE
169 1.13 christos case INT128: return "__int128_t";
170 1.13 christos case UINT128: return "__uint128_t";
171 1.13 christos #endif
172 1.1 christos case FLOAT: return "float";
173 1.1 christos case DOUBLE: return "double";
174 1.1 christos case LDOUBLE: return "long double";
175 1.2 skd case VOID: return "void";
176 1.1 christos case STRUCT: return "struct";
177 1.1 christos case UNION: return "union";
178 1.19 rillig case ENUM: return "enum";
179 1.19 rillig case PTR: return "pointer";
180 1.19 rillig case ARRAY: return "array";
181 1.1 christos case FUNC: return "function";
182 1.19 rillig case COMPLEX: return "_Complex";
183 1.5 christos case FCOMPLEX: return "float _Complex";
184 1.5 christos case DCOMPLEX: return "double _Complex";
185 1.9 matt case LCOMPLEX: return "long double _Complex";
186 1.1 christos default:
187 1.36 rillig INTERNAL_ERROR("tspec_name(%d)", t);
188 1.1 christos return NULL;
189 1.1 christos }
190 1.1 christos }
191 1.1 christos
192 1.21 rillig static void
193 1.21 rillig type_name_of_function(buffer *buf, const type_t *tp)
194 1.21 rillig {
195 1.21 rillig const char *sep = "";
196 1.21 rillig
197 1.21 rillig buf_add(buf, "(");
198 1.21 rillig if (tp->t_proto) {
199 1.21 rillig #ifdef t_enum /* lint1 */
200 1.21 rillig sym_t *arg;
201 1.21 rillig
202 1.42 rillig arg = tp->t_args;
203 1.42 rillig if (arg == NULL)
204 1.42 rillig buf_add(buf, "void");
205 1.42 rillig for (; arg != NULL; arg = arg->s_next) {
206 1.21 rillig buf_add(buf, sep), sep = ", ";
207 1.21 rillig buf_add(buf, type_name(arg->s_type));
208 1.21 rillig }
209 1.21 rillig #else /* lint2 */
210 1.21 rillig type_t **argtype;
211 1.21 rillig
212 1.42 rillig argtype = tp->t_args;
213 1.42 rillig if (argtype == NULL)
214 1.42 rillig buf_add(buf, "void");
215 1.42 rillig for (; *argtype != NULL; argtype++) {
216 1.21 rillig buf_add(buf, sep), sep = ", ";
217 1.21 rillig buf_add(buf, type_name(*argtype));
218 1.21 rillig }
219 1.21 rillig #endif
220 1.21 rillig }
221 1.21 rillig if (tp->t_vararg) {
222 1.22 rillig buf_add(buf, sep);
223 1.21 rillig buf_add(buf, "...");
224 1.21 rillig }
225 1.21 rillig buf_add(buf, ") returning ");
226 1.21 rillig buf_add(buf, type_name(tp->t_subt));
227 1.21 rillig }
228 1.21 rillig
229 1.32 rillig static void
230 1.32 rillig type_name_of_struct_or_union(buffer *buf, const type_t *tp)
231 1.32 rillig {
232 1.32 rillig buf_add(buf, " ");
233 1.32 rillig #ifdef t_str
234 1.32 rillig if (tp->t_str->sou_tag->s_name == unnamed &&
235 1.32 rillig tp->t_str->sou_first_typedef != NULL) {
236 1.32 rillig buf_add(buf, "typedef ");
237 1.32 rillig buf_add(buf, tp->t_str->sou_first_typedef->s_name);
238 1.32 rillig } else {
239 1.32 rillig buf_add(buf, tp->t_str->sou_tag->s_name);
240 1.32 rillig }
241 1.32 rillig #else
242 1.32 rillig buf_add(buf, tp->t_isuniqpos ? "*anonymous*" : tp->t_tag->h_name);
243 1.32 rillig #endif
244 1.32 rillig }
245 1.32 rillig
246 1.32 rillig static void
247 1.32 rillig type_name_of_enum(buffer *buf, const type_t *tp)
248 1.32 rillig {
249 1.32 rillig buf_add(buf, " ");
250 1.32 rillig #ifdef t_enum
251 1.32 rillig if (tp->t_enum->en_tag->s_name == unnamed &&
252 1.32 rillig tp->t_enum->en_first_typedef != NULL) {
253 1.32 rillig buf_add(buf, "typedef ");
254 1.32 rillig buf_add(buf, tp->t_enum->en_first_typedef->s_name);
255 1.32 rillig } else {
256 1.32 rillig buf_add(buf, tp->t_enum->en_tag->s_name);
257 1.32 rillig }
258 1.32 rillig #else
259 1.32 rillig buf_add(buf, tp->t_isuniqpos ? "*anonymous*" : tp->t_tag->h_name);
260 1.32 rillig #endif
261 1.32 rillig }
262 1.32 rillig
263 1.33 rillig static void
264 1.33 rillig type_name_of_array(buffer *buf, const type_t *tp)
265 1.33 rillig {
266 1.33 rillig buf_add(buf, "[");
267 1.33 rillig #ifdef t_str /* lint1 */
268 1.33 rillig if (tp->t_incomplete_array)
269 1.33 rillig buf_add(buf, "unknown_size");
270 1.33 rillig else
271 1.33 rillig buf_add_int(buf, tp->t_dim);
272 1.33 rillig #else
273 1.33 rillig buf_add_int(buf, tp->t_dim);
274 1.33 rillig #endif
275 1.33 rillig buf_add(buf, "]");
276 1.34 rillig buf_add(buf, " of ");
277 1.34 rillig buf_add(buf, type_name(tp->t_subt));
278 1.33 rillig }
279 1.33 rillig
280 1.1 christos const char *
281 1.20 rillig type_name(const type_t *tp)
282 1.1 christos {
283 1.20 rillig tspec_t t;
284 1.20 rillig buffer buf;
285 1.20 rillig const char *name;
286 1.1 christos
287 1.11 christos if (tp == NULL)
288 1.11 christos return "(null)";
289 1.20 rillig
290 1.29 rillig if ((t = tp->t_tspec) == INT && tp->t_is_enum)
291 1.1 christos t = ENUM;
292 1.1 christos
293 1.20 rillig buf_init(&buf);
294 1.8 christos if (tp->t_const)
295 1.20 rillig buf_add(&buf, "const ");
296 1.8 christos if (tp->t_volatile)
297 1.20 rillig buf_add(&buf, "volatile ");
298 1.32 rillig
299 1.38 rillig #ifdef t_str
300 1.38 rillig if ((t == STRUCT || t == UNION) && tp->t_str->sou_incomplete)
301 1.38 rillig buf_add(&buf, "incomplete ");
302 1.38 rillig #endif
303 1.20 rillig buf_add(&buf, tspec_name(t));
304 1.1 christos
305 1.1 christos switch (t) {
306 1.1 christos case BOOL:
307 1.1 christos case CHAR:
308 1.1 christos case UCHAR:
309 1.1 christos case SCHAR:
310 1.1 christos case SHORT:
311 1.1 christos case USHORT:
312 1.1 christos case INT:
313 1.1 christos case UINT:
314 1.1 christos case LONG:
315 1.1 christos case ULONG:
316 1.1 christos case QUAD:
317 1.1 christos case UQUAD:
318 1.13 christos #ifdef INT128_SIZE
319 1.13 christos case INT128:
320 1.13 christos case UINT128:
321 1.13 christos #endif
322 1.1 christos case FLOAT:
323 1.1 christos case DOUBLE:
324 1.1 christos case LDOUBLE:
325 1.2 skd case VOID:
326 1.5 christos case COMPLEX:
327 1.5 christos case FCOMPLEX:
328 1.5 christos case DCOMPLEX:
329 1.10 matt case LCOMPLEX:
330 1.17 rillig case SIGNED:
331 1.17 rillig case UNSIGN:
332 1.1 christos break;
333 1.1 christos case PTR:
334 1.20 rillig buf_add(&buf, " to ");
335 1.20 rillig buf_add(&buf, type_name(tp->t_subt));
336 1.1 christos break;
337 1.1 christos case ENUM:
338 1.32 rillig type_name_of_enum(&buf, tp);
339 1.1 christos break;
340 1.1 christos case STRUCT:
341 1.1 christos case UNION:
342 1.32 rillig type_name_of_struct_or_union(&buf, tp);
343 1.1 christos break;
344 1.1 christos case ARRAY:
345 1.33 rillig type_name_of_array(&buf, tp);
346 1.1 christos break;
347 1.21 rillig case FUNC:
348 1.21 rillig type_name_of_function(&buf, tp);
349 1.21 rillig break;
350 1.1 christos default:
351 1.36 rillig INTERNAL_ERROR("type_name(%d)", t);
352 1.1 christos }
353 1.20 rillig
354 1.20 rillig name = intern(buf.data);
355 1.20 rillig buf_done(&buf);
356 1.20 rillig return name;
357 1.1 christos }
358