diff mbox

limited C++ parsing support for gengtype

Message ID CANkmNDcrHFOoi+jXGNXjS3e_7L74GYyo0jtfDFmxo5atRPcGHw@mail.gmail.com
State New
Headers show

Commit Message

Aaron Gray Aug. 30, 2012, 12:31 a.m. UTC
First of two patches for class'ized cp/parser.c|h gives limited
support for gengtype to parse C++ classes and enums as first class
citizens.

Patch to SVN HEAD

2012-08-30 Aaron Gray <aaronngray.lists@gmail.com>

        * gengtype-lex.l: Support for FILE
        Support for C++ single line Comments
        Support for classes
        Support for enums
        ignore 'static'
        ignore 'inline'
        ignore 'public:'
        ignore 'protected:'
        ignore 'private:'
        ignore 'friend'
        support for 'operator' token
        support for 'new'
        support for 'delete'
        added support for '+' as a token for summations in enum bodies

        * gengtype.h: added 'TYPE_ENUM' to 'enum typekind'
        added enum TYPE_ENUM to 'struct type' union
        added OPERATOR_KEYWORD and OPERATOR keywords to Token Code enum

        * gengtype-parser.c: updated 'token_names[]'
        (direct_declarator): support for parsing limited operators
        support for parsing constructors with no parameters
        support for parsing enums

        * gengtype.c: added 'type_p enums'  to maintain list of enums
        (resolve_typedef): added support for stucture types and enums
        added 'new_enum()'


 extern type_p create_array (type_p t, const char *len);
@@ -458,6 +466,7 @@ enum
     STATIC,
     UNION,
     STRUCT,
+    CLASS,
     ENUM,
     VEC_TOKEN,
     ELLIPSIS,
@@ -471,6 +480,8 @@ enum
     STRING,
     CHAR,
     ARRAY,
+    OPERATOR_KEYWORD,
+    OPERATOR,

     /* print_token assumes that any token >= FIRST_TOKEN_WITH_VALUE may have
        a meaningful value to be printed.  */

Comments

Laurynas Biveinis Aug. 30, 2012, 4:59 a.m. UTC | #1
Hi -

2012/8/30 Aaron Gray <aaronngray.lists@gmail.com>:
> First of two patches for class'ized cp/parser.c|h gives limited
> support for gengtype to parse C++ classes and enums as first class
> citizens.

Please sync with Diego to avoid duplicate work and/or conflicting designs.

Thanks,
Diego Novillo Sept. 11, 2012, 8:41 p.m. UTC | #2
On 2012-08-29 20:31 , Aaron Gray wrote:

> 2012-08-30 Aaron Gray <aaronngray.lists@gmail.com>
>
>          * gengtype-lex.l: Support for FILE
>          Support for C++ single line Comments
>          Support for classes
>          Support for enums
>          ignore 'static'
>          ignore 'inline'
>          ignore 'public:'
>          ignore 'protected:'
>          ignore 'private:'
>          ignore 'friend'
>          support for 'operator' token
>          support for 'new'
>          support for 'delete'
>          added support for '+' as a token for summations in enum bodies
>
>          * gengtype.h: added 'TYPE_ENUM' to 'enum typekind'
>          added enum TYPE_ENUM to 'struct type' union

Write entries like these as:

	* gengtype.h (enum type_kind): Add TYPE_ENUM.
	(struct type): Add TYPE_ENUM.

>          added OPERATOR_KEYWORD and OPERATOR keywords to Token Code enum

Likewise.

>
>          * gengtype-parser.c: updated 'token_names[]'
>          (direct_declarator): support for parsing limited operators
>          support for parsing constructors with no parameters
>          support for parsing enums
>
>          * gengtype.c: added 'type_p enums'  to maintain list of enums
>          (resolve_typedef): added support for stucture types and enums
>          added 'new_enum()'
>
>
> diff --git a/gcc/gengtype-lex.l b/gcc/gengtype-lex.l
> index 5788a6a..af9696a 100644
> --- a/gcc/gengtype-lex.l
> +++ b/gcc/gengtype-lex.l
> @@ -53,11 +53,11 @@ update_lineno (const char *l, size_t len)
>   ID	[[:alpha:]_][[:alnum:]_]*
>   WS	[[:space:]]+
>   HWS	[ \t\r\v\f]*
> -IWORD	short|long|(un)?signed|char|int|HOST_WIDE_INT|HOST_WIDEST_INT|bool|size_t|BOOL_BITFIELD|CPPCHAR_SIGNED_T|ino_t|dev_t|HARD_REG_SET
> +IWORD	short|long|(un)?signed|char|int|HOST_WIDE_INT|HOST_WIDEST_INT|bool|size_t|BOOL_BITFIELD|CPPCHAR_SIGNED_T|ino_t|dev_t|HARD_REG_SET|FILE
>   ITYPE	{IWORD}({WS}{IWORD})*
>   EOID	[^[:alnum:]_]
>
> -%x in_struct in_struct_comment in_comment
> +%x in_struct in_struct_comment in_comment in_line_comment
> in_line_struct_comment
>   %option warn noyywrap nounput nodefault perf-report
>   %option 8bit never-interactive
>   %%
> @@ -83,6 +83,14 @@ EOID	[^[:alnum:]_]
>     BEGIN(in_struct);
>     return UNION;
>   }
> +^{HWS}class/{EOID} {
> +  BEGIN(in_struct);
> +  return STRUCT;
> +}
> +^{HWS}enum/{EOID} {
> +  BEGIN(in_struct);
> +  return ENUM;
> +}
>   ^{HWS}extern/{EOID} {
>     BEGIN(in_struct);
>     return EXTERN;
> @@ -101,10 +109,20 @@ EOID	[^[:alnum:]_]
>   \\\n				{ lexer_line.line++; }
>
>   "const"/{EOID}			/* don't care */
> +"static"/{EOID}			/* don't care */
> +"inline"/{EOID}			/* don't care */
> +"public:"			/* don't care */
> +"private:"			/* don't care */
> +"protected:"			/* don't care */
> +"operator"/{EOID}               { return OPERATOR_KEYWORD; }
> +"new"/{EOID}                    { *yylval = XDUPVAR (const char,
> yytext+1, yyleng-2, yyleng-1); return OPERATOR; }
> +"delete"/{EOID}                 { *yylval = XDUPVAR (const char,
> yytext+1, yyleng-2, yyleng-1); return OPERATOR; }
> +"friend"/{EOID}
>   "GTY"/{EOID}			{ return GTY_TOKEN; }
>   "VEC"/{EOID}			{ return VEC_TOKEN; }
>   "union"/{EOID}			{ return UNION; }
>   "struct"/{EOID}			{ return STRUCT; }
> +"class"/{EOID}			{ return CLASS; }

Why not just return STRUCT here?

> @@ -3,7 +3,7 @@
>
>      This file is part of GCC.
>
> -   GCC is free software; you can redistribute it and/or modify it under
> +   /GCC is free software; you can redistribute it and/or modify it under

This seems out of place.


> @@ -778,6 +791,7 @@ type (options_p *optsp, bool nested)
>         return resolve_typedef (s, &lexer_line);
>
>       case STRUCT:
> +    case CLASS:

I think that as far as gengtype is concerned, 'struct' and 'class' 
should be exactly the same thing.  So, all the handling for 'CLASS' you 
added should not be needed.


> +/* enum definition: type() does all the work.  */
> +static void
> +parse_enum (void)
> +{
> +  options_p dummy;
> +  type (&dummy, false);
> +  /* There may be junk after the type: notably, we cannot currently
> +     distinguish 'struct foo *function(prototype);' from 'struct foo;'
> +     ...  we could call declarator(), but it's a waste of time at
> +     present.  Instead, just eat whatever token is currently lookahead
> +     and go back to lexical skipping mode. */
> +  advance ();
> +}
> +

I'm not quite sure what is this trying to do.

> @@ -601,16 +602,93 @@ type_p
>   resolve_typedef (const char *s, struct fileloc *pos)
>   {
>     pair_p p;
> +  type_p t;
> +  type_p e;
> +
>     for (p = typedefs; p != NULL; p = p->next)
>       if (strcmp (p->name, s) == 0)
>         return p->type;
>
> +  for (t = structures; t != NULL; t = t->next)
> +    {
> +      switch ( t->kind)
> +        {
> +          case TYPE_NONE:
> +	    if (do_debug)
> +              fprintf(stderr, "TYPE_NONE:\n");
> +            break;
> +          case TYPE_SCALAR:
> +            if (do_debug)
> +              fprintf(stderr, "TYPE_SCALAR:\n");
> +            break;
> +          case TYPE_STRING:
> +            if (do_debug)
> +              fprintf(stderr, "TYPE_STRING:\n");
> +          break;
> +          case TYPE_STRUCT:
> +            if (do_debug)
> +              fprintf(stderr, "TYPE_STRUCT: '%s'\n", t->u.s.tag);
> +            goto structure;
> +          case TYPE_UNION:
> +            if (do_debug)
> +              fprintf(stderr, "TYPE_UNION: '%s'\n", t->u.s.tag);
> +            goto structure;
> +          case TYPE_LANG_STRUCT:
> +            if (do_debug)
> +              fprintf(stderr, "TYPE_LANG_STRUCT: '%s'\n", t->u.s.tag);
> +        structure:
> +            if (strcmp (t->u.s.tag, s) == 0)
> +              return t;
> +            break;
> +          case TYPE_POINTER:
> +            if (do_debug)
> +              fprintf(stderr, "TYPE_POINTER:\n");
> +            break;
> +          case TYPE_ARRAY:
> +            if (do_debug)
> +              fprintf(stderr, "TYPE_ARRAY:\n");
> +            break;
> +          case TYPE_PARAM_STRUCT:
> +            if (do_debug)
> +              fprintf(stderr, "TYPE_PARAM_STRUCT:\n");
> +            break;
> +          default:
> +            if (do_debug)
> +              fprintf(stderr, "default:\n");
> +            break;
> +        }
> +    };
> +

Yikes.  What are you trying to do here?

> @@ -148,9 +149,10 @@ enum typekind {
>                              param1_is, param2_is,... use_param1,
>                              use_param_2,... use_params) GTY
>                              options.  */
> -  TYPE_USER_STRUCT	/* User defined type.  Walkers and markers for
> +  TYPE_USER_STRUCT,	/* User defined type.  Walkers and markers for
>   			   this type are assumed to be provided by the
>   			   user.  */
> +  TYPE_ENUM		/* Type for enums. */

What are enums used for?  Do they affect gengtype's operation in any way?

>   };
>
>   /* Discriminating kind for options.  */
> @@ -309,6 +311,11 @@ struct type {
>         struct fileloc line;      /* The source location.  */
>       } param_struct;
>
> +    /* when TYPE_ENUM */
> +
> +    struct {
> +      const char *tag;          /* the aggragate tag, if any.  */

s/aggragate/aggregate/



Diego.
Gabriel Dos Reis Sept. 11, 2012, 10:45 p.m. UTC | #3
On Tue, Sep 11, 2012 at 3:41 PM, Diego Novillo <dnovillo@google.com> wrote:

>> @@ -778,6 +791,7 @@ type (options_p *optsp, bool nested)
>>         return resolve_typedef (s, &lexer_line);
>>
>>       case STRUCT:
>> +    case CLASS:
>
>
> I think that as far as gengtype is concerned, 'struct' and 'class' should be
> exactly the same thing.  So, all the handling for 'CLASS' you added should
> not be needed.


100% agreed.

-- Gaby
Gabriel Dos Reis Sept. 12, 2012, 10:01 p.m. UTC | #4
On Wed, Sep 12, 2012 at 4:54 PM, Aaron Gray <aaronngray.lists@gmail.com> wrote:
> On 11 September 2012 23:45, Gabriel Dos Reis
> <gdr@integrable-solutions.net> wrote:
>> On Tue, Sep 11, 2012 at 3:41 PM, Diego Novillo <dnovillo@google.com> wrote:
>>
>>>> @@ -778,6 +791,7 @@ type (options_p *optsp, bool nested)
>>>>         return resolve_typedef (s, &lexer_line);
>>>>
>>>>       case STRUCT:
>>>> +    case CLASS:
>>>
>>>
>>> I think that as far as gengtype is concerned, 'struct' and 'class' should be
>>> exactly the same thing.  So, all the handling for 'CLASS' you added should
>>> not be needed.
>>
>>
>> 100% agreed.
>
> The reason I included a CLASS type distinct from STRUCT was for
> reporting debugging information when I get to that stage.

In general, patches are easier to assess when they are self-contained
(e.g. each change is justified by the purpose of the patch.)   My recommendation
would be for your patches to focus on one topic at a time.

-- Gaby
Diego Novillo Oct. 2, 2012, 1:43 p.m. UTC | #5
Aaron,

I'm currently fixing other issues with gengtype and I needed this
patch on top of them.  I will be rolling both patches into a single
one and commit them today/tomorrow.  If you were working on further
fixes to this, please give me a chance to commit this one first.


Thanks.  Diego.
diff mbox

Patch

diff --git a/gcc/gengtype-lex.l b/gcc/gengtype-lex.l
index 5788a6a..af9696a 100644
--- a/gcc/gengtype-lex.l
+++ b/gcc/gengtype-lex.l
@@ -53,11 +53,11 @@  update_lineno (const char *l, size_t len)
 ID	[[:alpha:]_][[:alnum:]_]*
 WS	[[:space:]]+
 HWS	[ \t\r\v\f]*
-IWORD	short|long|(un)?signed|char|int|HOST_WIDE_INT|HOST_WIDEST_INT|bool|size_t|BOOL_BITFIELD|CPPCHAR_SIGNED_T|ino_t|dev_t|HARD_REG_SET
+IWORD	short|long|(un)?signed|char|int|HOST_WIDE_INT|HOST_WIDEST_INT|bool|size_t|BOOL_BITFIELD|CPPCHAR_SIGNED_T|ino_t|dev_t|HARD_REG_SET|FILE
 ITYPE	{IWORD}({WS}{IWORD})*
 EOID	[^[:alnum:]_]

-%x in_struct in_struct_comment in_comment
+%x in_struct in_struct_comment in_comment in_line_comment
in_line_struct_comment
 %option warn noyywrap nounput nodefault perf-report
 %option 8bit never-interactive
 %%
@@ -83,6 +83,14 @@  EOID	[^[:alnum:]_]
   BEGIN(in_struct);
   return UNION;
 }
+^{HWS}class/{EOID} {
+  BEGIN(in_struct);
+  return STRUCT;
+}
+^{HWS}enum/{EOID} {
+  BEGIN(in_struct);
+  return ENUM;
+}
 ^{HWS}extern/{EOID} {
   BEGIN(in_struct);
   return EXTERN;
@@ -101,10 +109,20 @@  EOID	[^[:alnum:]_]
 \\\n				{ lexer_line.line++; }

 "const"/{EOID}			/* don't care */
+"static"/{EOID}			/* don't care */
+"inline"/{EOID}			/* don't care */
+"public:"			/* don't care */
+"private:"			/* don't care */
+"protected:"			/* don't care */
+"operator"/{EOID}               { return OPERATOR_KEYWORD; }
+"new"/{EOID}                    { *yylval = XDUPVAR (const char,
yytext+1, yyleng-2, yyleng-1); return OPERATOR; }
+"delete"/{EOID}                 { *yylval = XDUPVAR (const char,
yytext+1, yyleng-2, yyleng-1); return OPERATOR; }
+"friend"/{EOID}
 "GTY"/{EOID}			{ return GTY_TOKEN; }
 "VEC"/{EOID}			{ return VEC_TOKEN; }
 "union"/{EOID}			{ return UNION; }
 "struct"/{EOID}			{ return STRUCT; }
+"class"/{EOID}			{ return CLASS; }
 "enum"/{EOID}			{ return ENUM; }
 "ptr_alias"/{EOID}	  	{ return PTR_ALIAS; }
 "nested_ptr"/{EOID}		{ return NESTED_PTR; }
@@ -148,7 +166,7 @@  EOID	[^[:alnum:]_]
 }

 "..."				{ return ELLIPSIS; }
-[(){},*:<>;=%|-]		{ return yytext[0]; }
+[(){},*:<>;=%|\-\+]		{ return yytext[0]; }

    /* ignore pp-directives */
 ^{HWS}"#"{HWS}[a-z_]+[^\n]*\n   {lexer_line.line++;}
@@ -159,6 +177,7 @@  EOID	[^[:alnum:]_]
 }

 "/*"			{ BEGIN(in_comment); }
+"//"			{ BEGIN(in_line_comment); }
 \n			{ lexer_line.line++; }
 {ID}			|
 "'"("\\".|[^\\])"'"	|
@@ -172,8 +191,17 @@  EOID	[^[:alnum:]_]
 [^*\n]		/* do nothing */
 "*"/[^/]	/* do nothing */
 }
+
+<in_line_comment,in_line_struct_comment>{
+[^*\n]{16}	|
+[^*\n]		/* do nothing */
+"*"/[^/]	/* do nothing */
+}
+
 <in_comment>"*/"	{ BEGIN(INITIAL); }
 <in_struct_comment>"*/"	{ BEGIN(in_struct); }
+<in_line_comment>\n	        { lexer_line.line++; BEGIN(INITIAL); }
+<in_line_struct_comment>\n	{ lexer_line.line++; BEGIN(in_struct); }

 ["/]    		|
 <in_struct_comment,in_comment>"*"	{
diff --git a/gcc/gengtype-parse.c b/gcc/gengtype-parse.c
index 03ee781..663db56 100644
--- a/gcc/gengtype-parse.c
+++ b/gcc/gengtype-parse.c
@@ -3,7 +3,7 @@ 

    This file is part of GCC.

-   GCC is free software; you can redistribute it and/or modify it under
+   /GCC is free software; you can redistribute it and/or modify it under
    the terms of the GNU General Public License as published by the Free
    Software Foundation; either version 3, or (at your option) any later
    version.
@@ -75,6 +75,7 @@  static const char *const token_names[] = {
   "static",
   "union",
   "struct",
+  "class",
   "enum",
   "VEC",
   "...",
@@ -608,10 +609,22 @@  direct_declarator (type_p ty, const char
**namep, options_p *optsp)

     case '(':
       advance ();
+
+      if (token() == ')')
+	{
+	  advance();
+	  return create_scalar_type ("constructor");
+	}
+
       ty = inner_declarator (ty, namep, optsp);
       require (')');
       break;

+    case OPERATOR_KEYWORD:
+      advance();
+      *namep = require (OPERATOR);
+      break;
+
     default:
       parse_error ("expected '(', 'GTY', or an identifier, have %s",
 		   print_cur_token ());
@@ -778,6 +791,7 @@  type (options_p *optsp, bool nested)
       return resolve_typedef (s, &lexer_line);

     case STRUCT:
+    case CLASS:
     case UNION:
       {
 	options_p opts = 0;
@@ -923,6 +937,20 @@  struct_or_union (void)
   advance ();
 }

+/* enum definition: type() does all the work.  */
+static void
+parse_enum (void)
+{
+  options_p dummy;
+  type (&dummy, false);
+  /* There may be junk after the type: notably, we cannot currently
+     distinguish 'struct foo *function(prototype);' from 'struct foo;'
+     ...  we could call declarator(), but it's a waste of time at
+     present.  Instead, just eat whatever token is currently lookahead
+     and go back to lexical skipping mode. */
+  advance ();
+}
+
 /* GC root declaration:
    (extern|static) gtymarker? type ID array_declarators_opt (';'|'=')
    If the gtymarker is not present, we ignore the rest of the declaration.  */
@@ -974,10 +1002,15 @@  parse_file (const char *fname)
 	  break;

 	case STRUCT:
+	case CLASS:
 	case UNION:
 	  struct_or_union ();
 	  break;

+	case ENUM:
+	  parse_enum ();
+	  break;
+
 	case TYPEDEF:
 	  typedef_decl ();
 	  break;
diff --git a/gcc/gengtype.c b/gcc/gengtype.c
index 2ae4372..2cd07fe 100644
--- a/gcc/gengtype.c
+++ b/gcc/gengtype.c
@@ -497,10 +497,11 @@  struct type scalar_char = {

 /* Lists of various things.  */

-pair_p typedefs;
-type_p structures;
-type_p param_structs;
-pair_p variables;
+pair_p typedefs = NULL;
+type_p structures = NULL;
+type_p enums = NULL;
+type_p param_structs = NULL;
+pair_p variables = NULL;

 static type_p find_param_structure (type_p t, type_p param[NUM_PARAM]);
 static type_p adjust_field_tree_exp (type_p t, options_p opt);
@@ -601,16 +602,93 @@  type_p
 resolve_typedef (const char *s, struct fileloc *pos)
 {
   pair_p p;
+  type_p t;
+  type_p e;
+
   for (p = typedefs; p != NULL; p = p->next)
     if (strcmp (p->name, s) == 0)
       return p->type;

+  for (t = structures; t != NULL; t = t->next)
+    {
+      switch ( t->kind)
+        {
+          case TYPE_NONE:
+	    if (do_debug)
+              fprintf(stderr, "TYPE_NONE:\n");
+            break;
+          case TYPE_SCALAR:
+            if (do_debug)
+              fprintf(stderr, "TYPE_SCALAR:\n");
+            break;
+          case TYPE_STRING:
+            if (do_debug)
+              fprintf(stderr, "TYPE_STRING:\n");
+          break;
+          case TYPE_STRUCT:
+            if (do_debug)
+              fprintf(stderr, "TYPE_STRUCT: '%s'\n", t->u.s.tag);
+            goto structure;
+          case TYPE_UNION:
+            if (do_debug)
+              fprintf(stderr, "TYPE_UNION: '%s'\n", t->u.s.tag);
+            goto structure;
+          case TYPE_LANG_STRUCT:
+            if (do_debug)
+              fprintf(stderr, "TYPE_LANG_STRUCT: '%s'\n", t->u.s.tag);
+        structure:
+            if (strcmp (t->u.s.tag, s) == 0)
+              return t;
+            break;
+          case TYPE_POINTER:
+            if (do_debug)
+              fprintf(stderr, "TYPE_POINTER:\n");
+            break;
+          case TYPE_ARRAY:
+            if (do_debug)
+              fprintf(stderr, "TYPE_ARRAY:\n");
+            break;
+          case TYPE_PARAM_STRUCT:
+            if (do_debug)
+              fprintf(stderr, "TYPE_PARAM_STRUCT:\n");
+            break;
+          default:
+            if (do_debug)
+              fprintf(stderr, "default:\n");
+            break;
+        }
+    };
+
+  for (e = enums; e != NULL; e = e->next)
+    if (strcmp (e->u.e.tag, s) == 0)
+      return e;
+
   /* If we did not find a typedef registered, assume this is a name
      for a user-defined type which will need to provide its own
      marking functions.  */
   return create_user_defined_type (s, pos);
 }

+type_p
+new_enum (const char *name)
+{
+  type_p ei;
+  type_p e;
+
+  for (ei = enums; ei != NULL; ei = ei->next)
+    if (strcmp (name, ei->u.e.tag) == 0)
+      return ei;
+
+  e = XCNEW (struct type);
+
+  e->u.e.tag = name;
+
+  e->next = enums;
+  enums = e;
+
+  return e;
+}
+
 /* Create and return a new structure with tag NAME at POS with fields
    FIELDS and options O.  The KIND of structure must be one of
    TYPE_STRUCT, TYPE_UNION or TYPE_USER_STRUCT.  */
@@ -2450,6 +2528,7 @@  output_mangled_typename (outf_p of, const_type_p t)
 	}
 	break;
       case TYPE_ARRAY:
+      case TYPE_ENUM:
 	gcc_unreachable ();
       }
 }
@@ -3137,6 +3216,7 @@  write_types_process_field (type_p f, const
struct walk_type_data *d)
       break;

     case TYPE_ARRAY:
+    case TYPE_ENUM:
       gcc_unreachable ();
     }
 }
diff --git a/gcc/gengtype.h b/gcc/gengtype.h
index 4a178ec..3d43c75 100644
--- a/gcc/gengtype.h
+++ b/gcc/gengtype.h
@@ -125,6 +125,7 @@  extern struct fileloc lexer_line;
    gengtype.c & in gengtype-state.c files.  */
 extern pair_p typedefs;
 extern type_p structures;
+extern type_p enums;
 extern type_p param_structs;
 extern pair_p variables;

@@ -148,9 +149,10 @@  enum typekind {
                            param1_is, param2_is,... use_param1,
                            use_param_2,... use_params) GTY
                            options.  */
-  TYPE_USER_STRUCT	/* User defined type.  Walkers and markers for
+  TYPE_USER_STRUCT,	/* User defined type.  Walkers and markers for
 			   this type are assumed to be provided by the
 			   user.  */
+  TYPE_ENUM		/* Type for enums. */
 };

 /* Discriminating kind for options.  */
@@ -309,6 +311,11 @@  struct type {
       struct fileloc line;      /* The source location.  */
     } param_struct;

+    /* when TYPE_ENUM */
+
+    struct {
+      const char *tag;          /* the aggragate tag, if any.  */
+    } e;
   } u;
 };

@@ -425,6 +432,7 @@  extern type_p new_structure (const char *name,
enum typekind kind,
 			     struct fileloc *pos, pair_p fields,
 			     options_p o);
 extern type_p find_structure (const char *s, enum typekind kind);
+extern type_p new_enum (const char *name);
 extern type_p create_scalar_type (const char *name);
 extern type_p create_pointer (type_p t);