1 /*******************************************************************************
2 *
3 * MODULE: type.c
4 *
5 ********************************************************************************
6 *
7 * DESCRIPTION: C::B::C type names
8 *
9 ********************************************************************************
10 *
11 * Copyright (c) 2002-2020 Marcus Holland-Moritz. All rights reserved.
12 * This program is free software; you can redistribute it and/or modify
13 * it under the same terms as Perl itself.
14 *
15 *******************************************************************************/
16
17 /*===== GLOBAL INCLUDES ======================================================*/
18
19 #define PERL_NO_GET_CONTEXT
20 #include <EXTERN.h>
21 #include <perl.h>
22 #include <XSUB.h>
23
24 #include "ppport.h"
25
26
27 /*===== LOCAL INCLUDES =======================================================*/
28
29 #include "cbc/basic.h"
30 #include "cbc/cbc.h"
31 #include "cbc/type.h"
32 #include "cbc/util.h"
33
34
35 /*===== DEFINES ==============================================================*/
36
37 /*===== TYPEDEFS =============================================================*/
38
39 /*===== STATIC FUNCTION PROTOTYPES ===========================================*/
40
41 static void *get_type_pointer(CBC *THIS, const char *name, const char **pEOS);
42
43
44 /*===== EXTERNAL VARIABLES ===================================================*/
45
46 /*===== GLOBAL VARIABLES =====================================================*/
47
48 /*===== STATIC VARIABLES =====================================================*/
49
50 /*===== STATIC FUNCTIONS =====================================================*/
51
52 /*******************************************************************************
53 *
54 * ROUTINE: get_type_pointer
55 *
56 * WRITTEN BY: Marcus Holland-Moritz ON: Jan 2002
57 * CHANGED BY: ON:
58 *
59 ********************************************************************************
60 *
61 * DESCRIPTION:
62 *
63 * ARGUMENTS:
64 *
65 * RETURNS:
66 *
67 *******************************************************************************/
68
get_type_pointer(CBC * THIS,const char * name,const char ** pEOS)69 static void *get_type_pointer(CBC *THIS, const char *name, const char **pEOS)
70 {
71 const char *c = name;
72 void *ptr = NULL;
73 int len = 0;
74 enum { S_UNKNOWN, S_STRUCT, S_UNION, S_ENUM } type = S_UNKNOWN;
75
76 if (!THIS->cpi.available)
77 return NULL;
78
79 while (isSPACE(*c))
80 c++;
81
82 if (*c == '\0')
83 return NULL;
84
85 switch (c[0])
86 {
87 case 's':
88 if (c[1] == 't' &&
89 c[2] == 'r' &&
90 c[3] == 'u' &&
91 c[4] == 'c' &&
92 c[5] == 't' &&
93 isSPACE(c[6]))
94 {
95 type = S_STRUCT;
96 c += 6;
97 }
98 break;
99
100 case 'u':
101 if (c[1] == 'n' &&
102 c[2] == 'i' &&
103 c[3] == 'o' &&
104 c[4] == 'n' &&
105 isSPACE(c[5]))
106 {
107 type = S_UNION;
108 c += 5;
109 }
110 break;
111
112 case 'e':
113 if (c[1] == 'n' &&
114 c[2] == 'u' &&
115 c[3] == 'm' &&
116 isSPACE(c[4]))
117 {
118 type = S_ENUM;
119 c += 4;
120 }
121 break;
122
123 default:
124 break;
125 }
126
127 while (isSPACE(*c))
128 c++;
129
130 while (c[len] == '_' || isALNUM(c[len]))
131 len++;
132
133 if (len == 0)
134 return NULL;
135
136 switch (type)
137 {
138 case S_STRUCT:
139 case S_UNION:
140 {
141 Struct *pStruct = HT_get(THIS->cpi.htStructs, c, len, 0);
142 ptr = (void *) (pStruct && (pStruct->tflags & (type == S_STRUCT
143 ? T_STRUCT : T_UNION)) ? pStruct : NULL);
144 }
145 break;
146
147 case S_ENUM:
148 ptr = HT_get(THIS->cpi.htEnums, c, len, 0);
149 break;
150
151 default:
152 if ((ptr = HT_get(THIS->cpi.htTypedefs, c, len, 0)) == NULL)
153 if ((ptr = HT_get(THIS->cpi.htStructs, c, len, 0)) == NULL)
154 ptr = HT_get(THIS->cpi.htEnums, c, len, 0);
155 break;
156 }
157
158 if (pEOS)
159 {
160 c += len;
161
162 while (isSPACE(*c))
163 c++;
164
165 *pEOS = c;
166 }
167
168 return ptr;
169 }
170
171
172 /*===== FUNCTIONS ============================================================*/
173
174 /*******************************************************************************
175 *
176 * ROUTINE: get_member_info
177 *
178 * WRITTEN BY: Marcus Holland-Moritz ON: Oct 2002
179 * CHANGED BY: ON:
180 *
181 ********************************************************************************
182 *
183 * DESCRIPTION:
184 *
185 * ARGUMENTS:
186 *
187 * RETURNS:
188 *
189 *******************************************************************************/
190
get_member_info(pTHX_ CBC * THIS,const char * name,MemberInfo * pMI,unsigned gmi_flags)191 int get_member_info(pTHX_ CBC *THIS, const char *name, MemberInfo *pMI, unsigned gmi_flags)
192 {
193 const int do_calc = (gmi_flags & CBC_GMI_NO_CALC) == 0;
194 const char *member;
195 MemberInfo mi;
196
197 if (get_type_spec(THIS, name, &member, &mi.type) == 0)
198 return 0;
199
200 if (pMI)
201 {
202 pMI->flags = 0;
203 pMI->parent = NULL;
204
205 if (member && *member)
206 {
207 mi.pDecl = NULL;
208 mi.level = 0;
209 (void) get_member(aTHX_ &mi, member, pMI, do_calc ? 0 : CBC_GM_NO_OFFSET_SIZE_CALC);
210 }
211 else if (mi.type.ptr == NULL)
212 {
213 Declarator *pDecl = basic_types_get_declarator(THIS->basic, mi.type.tflags);
214
215 if (pDecl == NULL)
216 {
217 SV *str = NULL;
218 get_basic_type_spec_string(aTHX_ &str, mi.type.tflags);
219 sv_2mortal(str);
220 Perl_croak(aTHX_ "Unsupported basic type '%s'", SvPV_nolen(str));
221 }
222
223 if (do_calc && pDecl->size < 0)
224 (void) THIS->cfg.get_type_info(&THIS->cfg.layout, &mi.type, NULL,
225 "si", &pDecl->size, &pDecl->item_size);
226
227 pMI->pDecl = pDecl;
228 pMI->type = mi.type;
229 pMI->flags = 0;
230 pMI->level = 0;
231 pMI->offset = 0;
232 pMI->size = do_calc ? pDecl->size : 0;
233 }
234 else
235 {
236 void *ptr = mi.type.ptr; /* TODO: improve this... */
237
238 switch (GET_CTYPE(ptr))
239 {
240 case TYP_TYPEDEF:
241 {
242 /* TODO: get rid of get_type_info, add flags to size */
243 ErrorGTI err;
244 err = THIS->cfg.get_type_info(&THIS->cfg.layout, ((Typedef *) ptr)->pType,
245 ((Typedef *) ptr)->pDecl,
246 "sf", &pMI->size, &pMI->flags);
247
248 if (err != GTI_NO_ERROR)
249 croak_gti(aTHX_ err, name, 0);
250 }
251 break;
252
253 case TYP_STRUCT:
254 if (((Struct *) ptr)->declarations == NULL)
255 CROAK_UNDEF_STRUCT((Struct *) ptr);
256
257 pMI->size = ((Struct *) ptr)->size;
258 pMI->flags = ((Struct *) ptr)->tflags & (T_HASBITFIELD | T_UNSAFE_VAL);
259 break;
260
261 case TYP_ENUM:
262 pMI->size = GET_ENUM_SIZE(&THIS->cfg, (EnumSpecifier *) ptr);
263 break;
264
265 default:
266 fatal("get_type_spec returned an invalid type (%d) in "
267 "get_member_info( '%s' )", GET_CTYPE(ptr), name);
268 break;
269 }
270
271 if (!do_calc)
272 {
273 pMI->size = 0;
274 }
275
276 pMI->type = mi.type;
277 pMI->pDecl = NULL;
278 pMI->level = 0;
279 pMI->offset = 0;
280 }
281 }
282
283 return 1;
284 }
285
286 /*******************************************************************************
287 *
288 * ROUTINE: get_type_spec
289 *
290 * WRITTEN BY: Marcus Holland-Moritz ON: Jan 2002
291 * CHANGED BY: ON:
292 *
293 ********************************************************************************
294 *
295 * DESCRIPTION:
296 *
297 * ARGUMENTS:
298 *
299 * RETURNS:
300 *
301 *******************************************************************************/
302
get_type_spec(CBC * THIS,const char * name,const char ** pEOS,TypeSpec * pTS)303 int get_type_spec(CBC *THIS, const char *name, const char **pEOS, TypeSpec *pTS)
304 {
305 void *ptr = get_type_pointer(THIS, name, pEOS);
306
307 if (ptr == NULL)
308 {
309 if (pEOS)
310 *pEOS = NULL;
311
312 return get_basic_type_spec(name, pTS);
313 }
314
315 switch (GET_CTYPE(ptr))
316 {
317 case TYP_TYPEDEF:
318 pTS->tflags = T_TYPE;
319 break;
320
321 case TYP_STRUCT:
322 pTS->tflags = ((Struct *) ptr)->tflags;
323 break;
324
325 case TYP_ENUM:
326 pTS->tflags = T_ENUM;
327 break;
328
329 default:
330 fatal("Invalid type (%d) in get_type_spec( '%s' )", GET_CTYPE(ptr), name);
331 break;
332 }
333
334 pTS->ptr = ptr;
335
336 return 1;
337 }
338
339 /*******************************************************************************
340 *
341 * ROUTINE: get_type_name_string
342 *
343 * WRITTEN BY: Marcus Holland-Moritz ON: Mar 2003
344 * CHANGED BY: ON:
345 *
346 ********************************************************************************
347 *
348 * DESCRIPTION:
349 *
350 * ARGUMENTS:
351 *
352 * RETURNS:
353 *
354 *******************************************************************************/
355
get_type_name_string(pTHX_ const MemberInfo * pMI)356 SV *get_type_name_string(pTHX_ const MemberInfo *pMI)
357 {
358 SV *sv;
359
360 if (pMI == NULL)
361 fatal("get_type_name_string() called with NULL pointer");
362
363 if (pMI->type.ptr == NULL)
364 {
365 sv = NULL;
366 get_basic_type_spec_string(aTHX_ &sv, pMI->type.tflags);
367 }
368 else
369 {
370 switch (GET_CTYPE(pMI->type.ptr))
371 {
372 case TYP_TYPEDEF:
373 sv = newSVpv(((Typedef *) pMI->type.ptr)->pDecl->identifier, 0);
374 break;
375
376 case TYP_STRUCT:
377 {
378 Struct *pS = (Struct *) pMI->type.ptr;
379 sv = pS->identifier[0] == '\0'
380 ? newSVpv(pS->tflags & T_STRUCT ? "struct" : "union", 0)
381 : newSVpvf("%s %s", pS->tflags & T_STRUCT
382 ? "struct" : "union", pS->identifier);
383 }
384 break;
385
386 case TYP_ENUM:
387 {
388 EnumSpecifier *pE = (EnumSpecifier *) pMI->type.ptr;
389 sv = pE->identifier[0] == '\0'
390 ? newSVpvn("enum", 4)
391 : newSVpvf("enum %s", pE->identifier);
392 }
393 break;
394
395 default:
396 fatal("GET_CTYPE() returned an invalid type (%d) "
397 "in get_type_name_string()", GET_CTYPE(pMI->type.ptr));
398 break;
399 }
400 }
401
402 if (pMI->pDecl != NULL)
403 {
404 if (pMI->pDecl->bitfield_flag)
405 sv_catpvf(sv, " :%d", pMI->pDecl->ext.bitfield.bits);
406 else
407 {
408 if (pMI->pDecl->pointer_flag)
409 sv_catpv(sv, " *");
410
411 if (pMI->pDecl->array_flag)
412 {
413 int level = pMI->level;
414 int count = LL_count(pMI->pDecl->ext.array);
415
416 if (level < count)
417 {
418 sv_catpv(sv, " ");
419 while (level < count)
420 {
421 Value *pValue = LL_get(pMI->pDecl->ext.array, level);
422
423 if (pValue->flags & V_IS_UNDEF)
424 sv_catpvn(sv, "[]", 2);
425 else
426 sv_catpvf(sv, "[%ld]", pValue->iv);
427
428 level++;
429 }
430 }
431 }
432 }
433 }
434
435 return sv;
436 }
437
438 /*******************************************************************************
439 *
440 * ROUTINE: is_typedef_defined
441 *
442 * WRITTEN BY: Marcus Holland-Moritz ON: Mar 2002
443 * CHANGED BY: ON:
444 *
445 ********************************************************************************
446 *
447 * DESCRIPTION:
448 *
449 * ARGUMENTS:
450 *
451 * RETURNS:
452 *
453 *******************************************************************************/
454
is_typedef_defined(Typedef * pTypedef)455 int is_typedef_defined(Typedef *pTypedef)
456 {
457 if (pTypedef->pDecl->pointer_flag)
458 return 1;
459
460 while (pTypedef->pType->tflags & T_TYPE)
461 {
462 pTypedef = (Typedef *) pTypedef->pType->ptr;
463
464 if (pTypedef->pDecl->pointer_flag)
465 return 1;
466 }
467
468 if (pTypedef->pType->tflags & T_COMPOUND)
469 return ((Struct*) pTypedef->pType->ptr)->declarations != NULL;
470
471 if (pTypedef->pType->tflags & T_ENUM)
472 return ((EnumSpecifier*) pTypedef->pType->ptr)->enumerators != NULL;
473
474 return 1;
475 }
476
477 /*******************************************************************************
478 *
479 * ROUTINE: check_allowed_types_string
480 *
481 * WRITTEN BY: Marcus Holland-Moritz ON: Mar 2006
482 * CHANGED BY: ON:
483 *
484 ********************************************************************************
485 *
486 * DESCRIPTION:
487 *
488 * ARGUMENTS:
489 *
490 * RETURNS:
491 *
492 *******************************************************************************/
493
494 #define CHECK_ALLOWED(flag, string) \
495 STMT_START { \
496 if ((allowed_types & ALLOW_ ## flag) == 0) \
497 return string; \
498 return NULL; \
499 } STMT_END
500
check_allowed_types_string(const MemberInfo * pMI,U32 allowed_types)501 const char *check_allowed_types_string(const MemberInfo *pMI, U32 allowed_types)
502 {
503 const Declarator *pDecl = pMI->pDecl;
504 const TypeSpec *pType = &pMI->type;
505 int level = 0;
506
507 if (pType->tflags & T_TYPE &&
508 (pDecl == NULL || (!pDecl->pointer_flag && !pDecl->array_flag)))
509 {
510 do
511 {
512 const Typedef *pTypedef = (Typedef *) pType->ptr;
513 pDecl = pTypedef->pDecl;
514 pType = pTypedef->pType;
515 }
516 while (!pDecl->pointer_flag &&
517 !pDecl->array_flag &&
518 pType->tflags & T_TYPE);
519 }
520 else
521 level = pMI->level;
522
523 if (pDecl != NULL)
524 {
525 if (pDecl->array_flag && level < LL_count(pDecl->ext.array))
526 CHECK_ALLOWED(ARRAYS, "an array type");
527
528 if (pDecl->pointer_flag)
529 CHECK_ALLOWED(POINTERS, "a pointer type");
530 }
531
532 if (pType->ptr == NULL)
533 CHECK_ALLOWED(BASIC_TYPES, "a basic type");
534
535 if (pType->tflags & T_UNION)
536 CHECK_ALLOWED(UNIONS, "a union");
537
538 if (pType->tflags & T_STRUCT)
539 CHECK_ALLOWED(STRUCTS, "a struct");
540
541 if (pType->tflags & T_ENUM)
542 CHECK_ALLOWED(ENUMS, "an enum");
543
544 return NULL;
545 }
546
547 /*******************************************************************************
548 *
549 * ROUTINE: check_allowed_types
550 *
551 * WRITTEN BY: Marcus Holland-Moritz ON: Apr 2003
552 * CHANGED BY: ON:
553 *
554 ********************************************************************************
555 *
556 * DESCRIPTION:
557 *
558 * ARGUMENTS:
559 *
560 * RETURNS:
561 *
562 *******************************************************************************/
563
check_allowed_types(pTHX_ const MemberInfo * pMI,const char * method,U32 allowed_types)564 void check_allowed_types(pTHX_ const MemberInfo *pMI, const char *method, U32 allowed_types)
565 {
566 const char *failed_type = check_allowed_types_string(pMI, allowed_types);
567
568 if (failed_type)
569 Perl_croak(aTHX_ "Cannot use %s on %s", method, failed_type);
570 }
571
572