Make the testing framework thread safe.
[wine/gsoc_dplay.git] / tools / winedump / msmangle.c
blob9264db4b8d347dffd1e5d5ac7d15082746dbb634
1 /*
2 * Demangle VC++ symbols into C function prototypes
4 * Copyright 2000 Jon Griffiths
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 #include "winedump.h"
22 /* Type for parsing mangled types */
23 typedef struct _compound_type
25 char dest_type;
26 int flags;
27 int have_qualifiers;
28 char *expression;
29 } compound_type;
32 /* Initialise a compound type structure */
33 #define INIT_CT(ct) do { memset (&ct, 0, sizeof (ct)); } while (0)
35 /* free the memory used by a compound structure */
36 #define FREE_CT(ct) do { if (ct.expression) free (ct.expression); } while (0)
38 /* Flags for data types */
39 #define DATA_VTABLE 0x1
41 /* Internal functions */
42 static char *demangle_datatype (char **str, compound_type *ct,
43 parsed_symbol* sym);
45 static char *get_constraints_convention_1 (char **str, compound_type *ct);
47 static char *get_constraints_convention_2 (char **str, compound_type *ct);
49 static char *get_type_string (const char c, const int constraints);
51 static int get_type_constant (const char c, const int constraints);
53 static char *get_pointer_type_string (compound_type *ct,
54 const char *expression);
57 /*******************************************************************
58 * demangle_symbol
60 * Demangle a C++ linker symbol into a C prototype
62 int symbol_demangle (parsed_symbol *sym)
64 compound_type ct;
65 int is_static = 0, is_const = 0;
66 char *function_name = NULL;
67 char *class_name = NULL;
68 char *name, *const_status;
69 static unsigned int hash = 0; /* In case of overloaded functions */
70 unsigned int data_flags = 0;
72 assert (globals.do_code);
73 assert (sym && sym->symbol);
75 hash++;
77 /* MS mangled names always begin with '?' */
78 name = sym->symbol;
79 if (*name++ != '?')
80 return -1;
82 if (VERBOSE)
83 puts ("Attempting to demangle symbol");
85 /* Then function name or operator code */
86 if (*name == '?')
88 /* C++ operator code (one character, or two if the first is '_') */
89 switch (*++name)
91 case '0': function_name = strdup ("ctor"); break;
92 case '1': function_name = strdup ("dtor"); break;
93 case '2': function_name = strdup ("operator_new"); break;
94 case '3': function_name = strdup ("operator_delete"); break;
95 case '4': function_name = strdup ("operator_equals"); break;
96 case '5': function_name = strdup ("operator_shiftright"); break;
97 case '6': function_name = strdup ("operator_shiftleft"); break;
98 case '7': function_name = strdup ("operator_not"); break;
99 case '8': function_name = strdup ("operator_equalsequals"); break;
100 case '9': function_name = strdup ("operator_notequals"); break;
101 case 'A': function_name = strdup ("operator_array"); break;
102 case 'C': function_name = strdup ("operator_dereference"); break;
103 case 'D': function_name = strdup ("operator_multiply"); break;
104 case 'E': function_name = strdup ("operator_plusplus"); break;
105 case 'F': function_name = strdup ("operator_minusminus"); break;
106 case 'G': function_name = strdup ("operator_minus"); break;
107 case 'H': function_name = strdup ("operator_plus"); break;
108 case 'I': function_name = strdup ("operator_address"); break;
109 case 'J': function_name = strdup ("operator_dereferencememberptr"); break;
110 case 'K': function_name = strdup ("operator_divide"); break;
111 case 'L': function_name = strdup ("operator_modulo"); break;
112 case 'M': function_name = strdup ("operator_lessthan"); break;
113 case 'N': function_name = strdup ("operator_lessthanequal"); break;
114 case 'O': function_name = strdup ("operator_greaterthan"); break;
115 case 'P': function_name = strdup ("operator_greaterthanequal"); break;
116 case 'Q': function_name = strdup ("operator_comma"); break;
117 case 'R': function_name = strdup ("operator_functioncall"); break;
118 case 'S': function_name = strdup ("operator_complement"); break;
119 case 'T': function_name = strdup ("operator_xor"); break;
120 case 'U': function_name = strdup ("operator_logicalor"); break;
121 case 'V': function_name = strdup ("operator_logicaland"); break;
122 case 'W': function_name = strdup ("operator_or"); break;
123 case 'X': function_name = strdup ("operator_multiplyequals"); break;
124 case 'Y': function_name = strdup ("operator_plusequals"); break;
125 case 'Z': function_name = strdup ("operator_minusequals"); break;
126 case '_':
127 switch (*++name)
129 case '0': function_name = strdup ("operator_divideequals"); break;
130 case '1': function_name = strdup ("operator_moduloequals"); break;
131 case '2': function_name = strdup ("operator_shiftrightequals"); break;
132 case '3': function_name = strdup ("operator_shiftleftequals"); break;
133 case '4': function_name = strdup ("operator_andequals"); break;
134 case '5': function_name = strdup ("operator_orequals"); break;
135 case '6': function_name = strdup ("operator_xorequals"); break;
136 case '7': function_name = strdup ("vftable"); data_flags = DATA_VTABLE; break;
137 case '8': function_name = strdup ("vbtable"); data_flags = DATA_VTABLE; break;
138 case '9': function_name = strdup ("vcall"); data_flags = DATA_VTABLE; break;
139 case 'A': function_name = strdup ("typeof"); data_flags = DATA_VTABLE; break;
140 case 'B': function_name = strdup ("local_static_guard"); data_flags = DATA_VTABLE; break;
141 case 'C': function_name = strdup ("string"); data_flags = DATA_VTABLE; break;
142 case 'D': function_name = strdup ("vbase_dtor"); data_flags = DATA_VTABLE; break;
143 case 'E': function_name = strdup ("vector_dtor"); break;
144 case 'G': function_name = strdup ("scalar_dtor"); break;
145 case 'H': function_name = strdup ("vector_ctor_iter"); break;
146 case 'I': function_name = strdup ("vector_dtor_iter"); break;
147 case 'J': function_name = strdup ("vector_vbase_ctor_iter"); break;
148 case 'L': function_name = strdup ("eh_vector_ctor_iter"); break;
149 case 'M': function_name = strdup ("eh_vector_dtor_iter"); break;
150 case 'N': function_name = strdup ("eh_vector_vbase_ctor_iter"); break;
151 case 'O': function_name = strdup ("copy_ctor_closure"); break;
152 case 'S': function_name = strdup ("local_vftable"); data_flags = DATA_VTABLE; break;
153 case 'T': function_name = strdup ("local_vftable_ctor_closure"); break;
154 case 'U': function_name = strdup ("operator_new_vector"); break;
155 case 'V': function_name = strdup ("operator_delete_vector"); break;
156 case 'X': function_name = strdup ("placement_new_closure"); break;
157 case 'Y': function_name = strdup ("placement_delete_closure"); break;
158 default:
159 return -1;
161 break;
162 default:
163 /* FIXME: Other operators */
164 return -1;
166 name++;
168 else
170 /* Type or function name terminated by '@' */
171 function_name = name;
172 while (*name && *name++ != '@') ;
173 if (!*name)
174 return -1;
175 function_name = str_substring (function_name, name - 1);
178 /* Either a class name, or '@' if the symbol is not a class member */
179 if (*name == '@')
181 class_name = strdup ("global"); /* Non member function (or a datatype) */
182 name++;
184 else
186 /* Class the function is associated with, terminated by '@@' */
187 class_name = name;
188 while (*name && *name++ != '@') ;
189 if (*name++ != '@')
190 return -1;
191 class_name = str_substring (class_name, name - 2);
194 /* Function/Data type and access level */
195 /* FIXME: why 2 possible letters for each option? */
196 switch(*name++)
198 /* Data */
200 case '0' : /* private static */
201 case '1' : /* protected static */
202 case '2' : /* public static */
203 is_static = 1;
204 /* Fall through */
205 case '3' : /* non static */
206 case '4' : /* non static */
207 /* Data members need to be implemented: report */
208 INIT_CT (ct);
209 if (!demangle_datatype (&name, &ct, sym))
211 if (VERBOSE)
212 printf ("/*FIXME: %s: unknown data*/\n", sym->symbol);
213 return -1;
215 sym->flags |= SYM_DATA;
216 sym->argc = 1;
217 sym->arg_name[0] = str_create (5, OUTPUT_UC_DLL_NAME, "_", class_name,
218 is_static ? "static_" : "_", function_name);
219 sym->arg_text[0] = str_create (3, ct.expression, " ", sym->arg_name[0]);
220 FREE_CT (ct);
221 return 0;
222 break;
224 case '6' : /* compiler generated static */
225 case '7' : /* compiler generated static */
226 if (data_flags & DATA_VTABLE)
228 sym->flags |= SYM_DATA;
229 sym->argc = 1;
230 sym->arg_name[0] = str_create (5, OUTPUT_UC_DLL_NAME, "_", class_name,
231 "_", function_name);
232 sym->arg_text[0] = str_create (2, "void *", sym->arg_name[0]);
234 if (VERBOSE)
235 puts ("Demangled symbol OK [vtable]");
236 return 0;
238 return -1;
239 break;
241 /* Functions */
243 case 'E' : /* private virtual */
244 case 'F' : /* private virtual */
245 case 'M' : /* protected virtual */
246 case 'N' : /* protected virtual */
247 case 'U' : /* public virtual */
248 case 'V' : /* public virtual */
249 /* Virtual functions need to be added to the exported vtable: report */
250 if (VERBOSE)
251 printf ("/*FIXME %s: %s::%s is virtual-add to vftable*/\n", sym->symbol,
252 class_name, function_name);
253 /* Fall through */
254 case 'A' : /* private */
255 case 'B' : /* private */
256 case 'I' : /* protected */
257 case 'J' : /* protected */
258 case 'Q' : /* public */
259 case 'R' : /* public */
260 /* Implicit 'this' pointer */
261 sym->arg_text [sym->argc] = str_create (3, "struct ", class_name, " *");
262 sym->arg_type [sym->argc] = ARG_POINTER;
263 sym->arg_flag [sym->argc] = 0;
264 sym->arg_name [sym->argc++] = strdup ("_this");
265 /* New struct definitions can be 'grep'ed out for making a fixup header */
266 if (VERBOSE)
267 printf ("struct %s { void **vtable; /*FIXME: class definition */ };\n", class_name);
268 break;
269 case 'C' : /* private: static */
270 case 'D' : /* private: static */
271 case 'K' : /* protected: static */
272 case 'L' : /* protected: static */
273 case 'S' : /* public: static */
274 case 'T' : /* public: static */
275 is_static = 1; /* No implicit this pointer */
276 break;
277 case 'Y' :
278 case 'Z' :
279 break;
280 /* FIXME: G,H / O,P / W,X are private / protected / public thunks */
281 default:
282 return -1;
285 /* If there is an implicit this pointer, const status follows */
286 if (sym->argc)
288 switch (*name++)
290 case 'A': break; /* non-const */
291 case 'B': is_const = CT_CONST; break;
292 case 'C': is_const = CT_VOLATILE; break;
293 case 'D': is_const = (CT_CONST | CT_VOLATILE); break;
294 default:
295 return -1;
299 /* Next is the calling convention */
300 switch (*name++)
302 case 'A': /* __cdecl */
303 case 'B': /* __cdecl __declspec(dllexport) */
304 if (!sym->argc)
306 sym->flags |= SYM_CDECL;
307 break;
309 /* Else fall through */
310 case 'C': /* __pascal */
311 case 'D': /* __pascal __declspec(dllexport) */
312 case 'E': /* __thiscall */
313 case 'F': /* __thiscall __declspec(dllexport) */
314 case 'G': /* __stdcall */
315 case 'H': /* __stdcall __declspec(dllexport) */
316 case 'I': /* __fastcall */
317 case 'J': /* __fastcall __declspec(dllexport)*/
318 case 'K': /* default (none given) */
319 if (sym->argc)
320 sym->flags |= SYM_THISCALL;
321 else
322 sym->flags |= SYM_STDCALL;
323 break;
324 default:
325 return -1;
328 /* Return type, or @ if 'void' */
329 if (*name == '@')
331 sym->return_text = strdup ("void");
332 sym->return_type = ARG_VOID;
333 name++;
335 else
337 INIT_CT (ct);
338 if (!demangle_datatype (&name, &ct, sym))
339 return -1;
340 sym->return_text = ct.expression;
341 sym->return_type = get_type_constant(ct.dest_type, ct.flags);
342 ct.expression = NULL;
343 FREE_CT (ct);
346 /* Now come the function arguments */
347 while (*name && *name != 'Z')
349 /* Decode each data type and append it to the argument list */
350 if (*name != '@')
352 INIT_CT (ct);
353 if (!demangle_datatype(&name, &ct, sym))
354 return -1;
356 if (strcmp (ct.expression, "void"))
358 sym->arg_text [sym->argc] = ct.expression;
359 ct.expression = NULL;
360 sym->arg_type [sym->argc] = get_type_constant (ct.dest_type, ct.flags);
361 sym->arg_flag [sym->argc] = ct.flags;
362 sym->arg_name[sym->argc] = str_create_num (1, sym->argc, "arg");
363 sym->argc++;
365 else
366 break; /* 'void' terminates an argument list */
367 FREE_CT (ct);
369 else
370 name++;
373 while (*name == '@')
374 name++;
376 /* Functions are always terminated by 'Z'. If we made it this far and
377 * Don't find it, we have incorrectly identified a data type.
379 if (*name != 'Z')
380 return -1;
382 /* Note: '()' after 'Z' means 'throws', but we don't care here */
384 /* Create the function name. Include a unique number because otherwise
385 * overloaded functions could have the same c signature.
387 switch (is_const)
389 case (CT_CONST | CT_VOLATILE): const_status = "_const_volatile"; break;
390 case CT_CONST: const_status = "_const"; break;
391 case CT_VOLATILE: const_status = "_volatile"; break;
392 default: const_status = "_"; break;
394 sym->function_name = str_create_num (4, hash, class_name, "_",
395 function_name, is_static ? "_static" : const_status);
397 assert (sym->return_text);
398 assert (sym->flags);
399 assert (sym->function_name);
401 free (class_name);
402 free (function_name);
404 if (VERBOSE)
405 puts ("Demangled symbol OK");
407 return 0;
411 /*******************************************************************
412 * demangle_datatype
414 * Attempt to demangle a C++ data type, which may be compound.
415 * a compound type is made up of a number of simple types. e.g:
416 * char** = (pointer to (pointer to (char)))
418 * Uses a simple recursive descent algorithm that is broken
419 * and/or incomplete, without a doubt ;-)
421 static char *demangle_datatype (char **str, compound_type *ct,
422 parsed_symbol* sym)
424 char *iter;
426 assert (str && *str);
427 assert (ct);
429 iter = *str;
431 if (!get_constraints_convention_1 (&iter, ct))
432 return NULL;
434 if (*iter == '_')
436 /* MS type: __int8,__int16 etc */
437 ct->flags |= CT_EXTENDED;
438 iter++;
441 switch (*iter)
443 case 'C': case 'D': case 'E': case 'F': case 'G':
444 case 'H': case 'I': case 'J': case 'K': case 'M':
445 case 'N': case 'O': case 'X': case 'Z':
446 /* Simple data types */
447 ct->dest_type = *iter++;
448 if (!get_constraints_convention_2 (&iter, ct))
449 return NULL;
450 ct->expression = get_type_string (ct->dest_type, ct->flags);
451 break;
452 case 'U':
453 case 'V':
454 /* Class/struct/union */
455 ct->dest_type = *iter++;
456 if (*iter == '0' || *iter == '1')
458 /* Referring to class type (implicit 'this') */
459 char *stripped;
460 if (!sym->argc)
461 return NULL;
463 iter++;
464 /* Apply our constraints to the base type (struct xxx *) */
465 stripped = strdup (sym->arg_text [0]);
466 if (!stripped)
467 fatal ("Out of Memory");
469 /* If we're a reference, re-use the pointer already in the type */
470 if (!(ct->flags & CT_BY_REFERENCE))
471 stripped[ strlen (stripped) - 2] = '\0'; /* otherwise, strip it */
473 ct->expression = str_create (2, ct->flags & CT_CONST ? "const " :
474 ct->flags & CT_VOLATILE ? "volatile " : "", stripped);
475 free (stripped);
477 else if (*iter != '@')
479 /* The name of the class/struct, followed by '@@' */
480 char *struct_name = iter;
481 while (*iter && *iter++ != '@') ;
482 if (*iter++ != '@')
483 return NULL;
484 struct_name = str_substring (struct_name, iter - 2);
485 ct->expression = str_create (4, ct->flags & CT_CONST ? "const " :
486 ct->flags & CT_VOLATILE ? "volatile " : "", "struct ",
487 struct_name, ct->flags & CT_BY_REFERENCE ? " *" : "");
488 free (struct_name);
490 break;
491 case 'Q': /* FIXME: Array Just treated as pointer currently */
492 case 'P': /* Pointer */
494 compound_type sub_ct;
495 INIT_CT (sub_ct);
497 ct->dest_type = *iter++;
498 if (!get_constraints_convention_2 (&iter, ct))
499 return NULL;
501 /* FIXME: P6 = Function pointer, others who knows.. */
502 if (isdigit (*iter))
504 if (*iter == '6')
506 /* FIXME: there are a tons of memory leaks here */
507 /* FIXME: this is still broken in some cases and it has to be
508 * merged with the function prototype parsing above...
510 iter += 3; /* FIXME */
511 if (!demangle_datatype (&iter, &sub_ct, sym))
512 return NULL;
513 ct->expression = str_create(2, sub_ct.expression, " (*)(");
514 if (*iter != '@')
516 while (*iter != 'Z')
518 FREE_CT (sub_ct);
519 INIT_CT (sub_ct);
520 if (!demangle_datatype (&iter, &sub_ct, sym))
521 return NULL;
522 ct->expression = str_create(3, ct->expression, ", ", sub_ct.expression);
523 while (*iter == '@') iter++;
525 } else while (*iter == '@') iter++;
526 iter++;
527 ct->expression = str_create(2, ct->expression, ")");
528 FREE_CT (sub_ct);
530 else
531 return NULL;
533 else
535 /* Recurse to get the pointed-to type */
536 if (!demangle_datatype (&iter, &sub_ct, sym))
537 return NULL;
539 ct->expression = get_pointer_type_string (ct, sub_ct.expression);
542 FREE_CT (sub_ct);
544 break;
545 case '0': case '1': case '2': case '3': case '4':
546 case '5': case '6': case '7': case '8': case '9':
547 /* Referring back to previously parsed type */
548 if (sym->argc >= (size_t)('0' - *iter))
549 return NULL;
550 ct->dest_type = sym->arg_type ['0' - *iter];
551 ct->expression = strdup (sym->arg_text ['0' - *iter]);
552 iter++;
553 break;
554 default :
555 return NULL;
557 if (!ct->expression)
558 return NULL;
560 return (char *)(*str = iter);
564 /* Constraints:
565 * There are two conventions for specifying data type constaints. I
566 * don't know how the compiler chooses between them, but I suspect it
567 * is based on ensuring that linker names are unique.
568 * Convention 1. The data type modifier is given first, followed
569 * by the data type it operates on. '?' means passed by value,
570 * 'A' means passed by reference. Note neither of these characters
571 * is a valid base data type. This is then followed by a character
572 * specifying constness or volatilty.
573 * Convention 2. The base data type (which is never '?' or 'A') is
574 * given first. The character modifier is optionally given after
575 * the base type character. If a valid character mofifier is present,
576 * then it only applies to the current data type if the character
577 * after that is not 'A' 'B' or 'C' (Because this makes a convention 1
578 * constraint for the next data type).
580 * The conventions are usually mixed within the same symbol.
581 * Since 'C' is both a qualifier and a data type, I suspect that
582 * convention 1 allows specifying e.g. 'volatile signed char*'. In
583 * convention 2 this would be 'CC' which is ambigious (i.e. Is it two
584 * pointers, or a single pointer + modifier?). In convention 1 it
585 * is encoded as '?CC' which is not ambigious. This probably
586 * holds true for some other types as well.
589 /*******************************************************************
590 * get_constraints_convention_1
592 * Get type constraint information for a data type
594 static char *get_constraints_convention_1 (char **str, compound_type *ct)
596 char *iter = *str, **retval = str;
598 if (ct->have_qualifiers)
599 return (char *)*str; /* Previously got constraints for this type */
601 if (*iter == '?' || *iter == 'A')
603 ct->have_qualifiers = 1;
604 ct->flags |= (*iter++ == '?' ? 0 : CT_BY_REFERENCE);
606 switch (*iter++)
608 case 'A' :
609 break; /* non-const, non-volatile */
610 case 'B' :
611 ct->flags |= CT_CONST;
612 break;
613 case 'C' :
614 ct->flags |= CT_VOLATILE;
615 break;
616 default :
617 return NULL;
621 return (char *)(*retval = iter);
625 /*******************************************************************
626 * get_constraints_convention_2
628 * Get type constraint information for a data type
630 static char *get_constraints_convention_2 (char **str, compound_type *ct)
632 char *iter = *str, **retval = str;
634 /* FIXME: Why do arrays have both convention 1 & 2 constraints? */
635 if (ct->have_qualifiers && ct->dest_type != 'Q')
636 return (char *)*str; /* Previously got constraints for this type */
638 ct->have_qualifiers = 1; /* Even if none, we've got all we're getting */
640 switch (*iter)
642 case 'A' :
643 if (iter[1] != 'A' && iter[1] != 'B' && iter[1] != 'C')
644 iter++;
645 break;
646 case 'B' :
647 ct->flags |= CT_CONST;
648 iter++;
649 break;
650 case 'C' :
651 /* See note above, if we find 'C' it is _not_ a signed char */
652 ct->flags |= CT_VOLATILE;
653 iter++;
654 break;
657 return (char *)(*retval = iter);
661 /*******************************************************************
662 * get_type_string
664 * Return a string containing the name of a data type
666 static char *get_type_string (const char c, const int constraints)
668 char *type_string;
670 if (constraints & CT_EXTENDED)
672 switch (c)
674 case 'D': type_string = "__int8"; break;
675 case 'E': type_string = "__uint8"; break;
676 case 'F': type_string = "__int16"; break;
677 case 'G': type_string = "__uint16"; break;
678 case 'H': type_string = "__int32"; break;
679 case 'I': type_string = "__uint32"; break;
680 case 'J': type_string = "__int64"; break;
681 case 'K': type_string = "__uint64"; break;
682 case 'L': type_string = "__int128"; break;
683 case 'M': type_string = "__uint128"; break;
684 case 'N': type_string = "int"; break; /* bool */
685 case 'W': type_string = "WCHAR"; break; /* wchar_t */
686 default:
687 return NULL;
690 else
692 switch (c)
694 case 'C': /* Signed char, fall through */
695 case 'D': type_string = "char"; break;
696 case 'E': type_string = "unsigned char"; break;
697 case 'F': type_string = "short int"; break;
698 case 'G': type_string = "unsigned short int"; break;
699 case 'H': type_string = "int"; break;
700 case 'I': type_string = "unsigned int"; break;
701 case 'J': type_string = "long"; break;
702 case 'K': type_string = "unsigned long"; break;
703 case 'M': type_string = "float"; break;
704 case 'N': type_string = "double"; break;
705 case 'O': type_string = "long double"; break;
706 /* FIXME: T = union */
707 case 'U':
708 case 'V': type_string = "struct"; break;
709 case 'X': return strdup ("void");
710 case 'Z': return strdup ("...");
711 default:
712 return NULL;
716 return str_create (3, constraints & CT_CONST ? "const " :
717 constraints & CT_VOLATILE ? "volatile " : "", type_string,
718 constraints & CT_BY_REFERENCE ? " *" : "");
722 /*******************************************************************
723 * get_type_constant
725 * Get the ARG_* constant for this data type
727 static int get_type_constant (const char c, const int constraints)
729 /* Any reference type is really a pointer */
730 if (constraints & CT_BY_REFERENCE)
731 return ARG_POINTER;
733 switch (c)
735 case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I':
736 case 'J': case 'K':
737 return ARG_LONG;
738 case 'M':
739 return -1; /* FIXME */
740 case 'N': case 'O':
741 return ARG_DOUBLE;
742 case 'P': case 'Q':
743 return ARG_POINTER;
744 case 'U': case 'V':
745 return ARG_STRUCT;
746 case 'X':
747 return ARG_VOID;
748 case 'Z':
749 default:
750 return -1;
755 /*******************************************************************
756 * get_pointer_type_string
758 * Return a string containing 'pointer to expression'
760 static char *get_pointer_type_string (compound_type *ct,
761 const char *expression)
763 /* FIXME: set a compound flag for bracketing expression if needed */
764 return str_create (3, ct->flags & CT_CONST ? "const " :
765 ct->flags & CT_VOLATILE ? "volatile " : "", expression,
766 ct->flags & CT_BY_REFERENCE ? " **" : " *");