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