Merge branch 'master' of ssh://git.samba.org/data/git/samba
[ira/wip.git] / pidl / idl.yp
index d557590494edcfff808d5b22c9920813fc281bf4..dc8e293f765046eca4b3bb89e22b7a1b8e9999b7 100644 (file)
 %%
 idl: 
        #empty  { {} }
-       | idl interface { push(@{$_[1]}, $_[2]); $_[1] }
-       | idl coclass { push(@{$_[1]}, $_[2]); $_[1] }
-       | idl import { push(@{$_[1]}, $_[2]); $_[1] }
-       | idl include { push(@{$_[1]}, $_[2]); $_[1] }
-       | idl importlib { push(@{$_[1]}, $_[2]); $_[1] }
-       | idl cpp_quote { push(@{$_[1]}, $_[2]); $_[1] }
-;
-
-import: 'import' commalist ';' {{
-                       "TYPE" => "IMPORT", 
-                       "PATHS" => $_[2],
-                  "FILE" => $_[0]->YYData->{FILE},
-                  "LINE" => $_[0]->YYData->{LINE}
-               }}
-;
-include: 'include' commalist ';' {{ 
-                       "TYPE" => "INCLUDE", 
-                       "PATHS" => $_[2],
-                  "FILE" => $_[0]->YYData->{FILE},
-                  "LINE" => $_[0]->YYData->{LINE}
-               }}
-;
-importlib: 'importlib' commalist ';' {{ 
-                       "TYPE" => "IMPORTLIB", 
-                       "PATHS" => $_[2],
-                  "FILE" => $_[0]->YYData->{FILE},
-                  "LINE" => $_[0]->YYData->{LINE}
-               }}
-;
-
-commalist: 
-      text { [ $_[1] ] }
-    | commalist ',' text { push(@{$_[1]}, $_[3]); $_[1] }
-;
-
-coclass: property_list 'coclass' identifier '{' interface_names '}' optional_semicolon
-          {{
-               "TYPE" => "COCLASS", 
-              "PROPERTIES" => $_[1],
-              "NAME" => $_[3],
-              "DATA" => $_[5],
-                  "FILE" => $_[0]->YYData->{FILE},
-                  "LINE" => $_[0]->YYData->{LINE},
-          }}
+       |
+       idl interface { push(@{$_[1]}, $_[2]); $_[1] }
+       |
+       idl coclass   { push(@{$_[1]}, $_[2]); $_[1] }
+       |
+       idl import    { push(@{$_[1]}, $_[2]); $_[1] }
+       |
+       idl include   { push(@{$_[1]}, $_[2]); $_[1] }
+       |
+       idl importlib { push(@{$_[1]}, $_[2]); $_[1] }
+       |
+       idl cpp_quote { push(@{$_[1]}, $_[2]); $_[1] }
+;
+
+import:
+       'import' commalist ';'
+       {{
+               "TYPE" => "IMPORT",
+               "PATHS" => $_[2],
+               "FILE" => $_[0]->YYData->{FILE},
+               "LINE" => $_[0]->YYData->{LINE},
+       }}
+;
+
+include:
+       'include' commalist ';'
+       {{
+               "TYPE" => "INCLUDE",
+               "PATHS" => $_[2],
+               "FILE" => $_[0]->YYData->{FILE},
+               "LINE" => $_[0]->YYData->{LINE},
+       }}
+;
+
+importlib:
+       'importlib' commalist ';'
+       {{
+               "TYPE" => "IMPORTLIB",
+               "PATHS" => $_[2],
+               "FILE" => $_[0]->YYData->{FILE},
+               "LINE" => $_[0]->YYData->{LINE},
+       }}
+;
+
+commalist:
+       text { [ $_[1] ] }
+       |
+       commalist ',' text { push(@{$_[1]}, $_[3]); $_[1] }
+;
+
+coclass:
+       property_list 'coclass' identifier '{' interface_names '}' optional_semicolon
+       {{
+               "TYPE" => "COCLASS",
+               "PROPERTIES" => $_[1],
+               "NAME" => $_[3],
+               "DATA" => $_[5],
+               "FILE" => $_[0]->YYData->{FILE},
+               "LINE" => $_[0]->YYData->{LINE},
+       }}
 ;
 
 interface_names:
        #empty { {} }
-       | interface_names 'interface' identifier ';' { push(@{$_[1]}, $_[2]); $_[1] }
+       |
+       interface_names 'interface' identifier ';' { push(@{$_[1]}, $_[2]); $_[1] }
 ;
 
-interface: property_list 'interface' identifier base_interface '{' definitions '}' optional_semicolon
-          {{
-               "TYPE" => "INTERFACE", 
-              "PROPERTIES" => $_[1],
-              "NAME" => $_[3],
-                  "BASE" => $_[4],
-              "DATA" => $_[6],
-                  "FILE" => $_[0]->YYData->{FILE},
-                  "LINE" => $_[0]->YYData->{LINE},
-          }}
+interface:
+       property_list 'interface' identifier base_interface '{' definitions '}' optional_semicolon
+       {{
+               "TYPE" => "INTERFACE",
+               "PROPERTIES" => $_[1],
+               "NAME" => $_[3],
+               "BASE" => $_[4],
+               "DATA" => $_[6],
+               "FILE" => $_[0]->YYData->{FILE},
+               "LINE" => $_[0]->YYData->{LINE},
+       }}
 ;
 
 base_interface:
-    #empty
-    | ':' identifier { $_[2] }
+       #empty
+       |
+       ':' identifier { $_[2] }
 ;
 
 
-cpp_quote: 'cpp_quote' '(' text ')'
+cpp_quote:
+       'cpp_quote' '(' text ')'
        {{
                 "TYPE" => "CPP_QUOTE",
+                "DATA" => $_[3],
                 "FILE" => $_[0]->YYData->{FILE},
                 "LINE" => $_[0]->YYData->{LINE},
-                "DATA" => $_[3]
        }}
 ;
 
-definitions: 
-      definition              { [ $_[1] ] }    
-    | definitions definition  { push(@{$_[1]}, $_[2]); $_[1] }
-;    
-
-
-definition: function | const | typedef | typedecl
+definitions:
+       definition              { [ $_[1] ] }
+       |
+       definitions definition  { push(@{$_[1]}, $_[2]); $_[1] }
 ;
 
-const: 'const' identifier pointers identifier '=' anytext ';' 
-        {{
-                     "TYPE"  => "CONST", 
-                    "DTYPE"  => $_[2],
-                        "POINTERS" => $_[3],
-                    "NAME"  => $_[4],
-                    "VALUE" => $_[6],
-                    "FILE" => $_[0]->YYData->{FILE},
-                    "LINE" => $_[0]->YYData->{LINE},
-        }}
-       | 'const' identifier pointers identifier array_len '=' anytext ';' 
-        {{
-                     "TYPE"  => "CONST", 
-                    "DTYPE"  => $_[2],
-                        "POINTERS" => $_[3],
-                    "NAME"  => $_[4],
-                    "ARRAY_LEN" => $_[5],
-                    "VALUE" => $_[7],
-                    "FILE" => $_[0]->YYData->{FILE},
-                    "LINE" => $_[0]->YYData->{LINE},
-        }}
+definition:
+       function
+       |
+       const
+       |
+       typedef
+       |
+       typedecl
 ;
 
+const:
+       'const' identifier pointers identifier '=' anytext ';'
+       {{
+               "TYPE"  => "CONST",
+               "DTYPE"  => $_[2],
+               "POINTERS" => $_[3],
+               "NAME"  => $_[4],
+               "VALUE" => $_[6],
+               "FILE" => $_[0]->YYData->{FILE},
+               "LINE" => $_[0]->YYData->{LINE},
+       }}
+       |
+       'const' identifier pointers identifier array_len '=' anytext ';'
+       {{
+               "TYPE"  => "CONST",
+               "DTYPE"  => $_[2],
+               "POINTERS" => $_[3],
+               "NAME"  => $_[4],
+               "ARRAY_LEN" => $_[5],
+               "VALUE" => $_[7],
+               "FILE" => $_[0]->YYData->{FILE},
+               "LINE" => $_[0]->YYData->{LINE},
+       }}
+;
 
-function: property_list type identifier '(' element_list2 ')' ';' 
-        {{
+function:
+       property_list type identifier '(' element_list2 ')' ';'
+       {{
                "TYPE" => "FUNCTION",
                "NAME" => $_[3],
                "RETURN_TYPE" => $_[2],
@@ -136,220 +165,351 @@ function: property_list type identifier '(' element_list2 ')' ';'
                "ELEMENTS" => $_[5],
                "FILE" => $_[0]->YYData->{FILE},
                "LINE" => $_[0]->YYData->{LINE},
-         }}
-;
-
-typedef: property_list 'typedef' type identifier array_len ';' 
-        {{
-                    "TYPE" => "TYPEDEF", 
-                     "PROPERTIES" => $_[1],
-                    "NAME" => $_[4],
-                    "DATA" => $_[3],
-                    "ARRAY_LEN" => $_[5],
-                    "FILE" => $_[0]->YYData->{FILE},
-                    "LINE" => $_[0]->YYData->{LINE},
+       }}
+;
+
+typedef:
+       property_list 'typedef' type identifier array_len ';'
+       {{
+               "TYPE" => "TYPEDEF",
+               "PROPERTIES" => $_[1],
+               "NAME" => $_[4],
+               "DATA" => $_[3],
+               "ARRAY_LEN" => $_[5],
+               "FILE" => $_[0]->YYData->{FILE},
+               "LINE" => $_[0]->YYData->{LINE},
         }}
 ;
 
-usertype: struct | union | enum | bitmap;
+usertype:
+       struct
+       |
+       union
+       |
+       enum
+       |
+       bitmap
+       |
+       pipe
+;
 
-typedecl: usertype ';' { $_[1] };
+typedecl:
+       usertype ';' { $_[1] }
+;
 
-sign: 'signed' | 'unsigned';
+sign:
+       'signed'
+       |
+       'unsigned'
+;
 
-existingtype: 
+existingtype:
        sign identifier { ($_[1]?$_[1]:"signed") ." $_[2]" }
-       | identifier 
+       |
+       identifier
 ;
 
-type: usertype | existingtype | void { "void" } ;
+type:
+       usertype
+       |
+       existingtype
+       |
+       void { "void" }
+;
 
-enum_body: '{' enum_elements '}' { $_[2] };
-opt_enum_body: | enum_body;
-enum: property_list 'enum' optional_identifier opt_enum_body
-        {{
-             "TYPE" => "ENUM", 
-                        "PROPERTIES" => $_[1],
-                        "NAME" => $_[3],
-                    "ELEMENTS" => $_[4]
-        }}
+enum_body:
+       '{' enum_elements '}' { $_[2] }
+;
+
+opt_enum_body:
+       #empty
+       |
+       enum_body
+;
+
+enum:
+       property_list 'enum' optional_identifier opt_enum_body
+       {{
+               "TYPE" => "ENUM",
+               "PROPERTIES" => $_[1],
+               "NAME" => $_[3],
+               "ELEMENTS" => $_[4],
+               "FILE" => $_[0]->YYData->{FILE},
+               "LINE" => $_[0]->YYData->{LINE},
+       }}
 ;
 
-enum_elements: 
-      enum_element                    { [ $_[1] ] }            
-    | enum_elements ',' enum_element  { push(@{$_[1]}, $_[3]); $_[1] }
+enum_elements:
+       enum_element                    { [ $_[1] ] }
+       |
+       enum_elements ',' enum_element  { push(@{$_[1]}, $_[3]); $_[1] }
 ;
 
-enum_element: identifier 
-             | identifier '=' anytext { "$_[1]$_[2]$_[3]" }
+enum_element:
+       identifier
+       |
+       identifier '=' anytext { "$_[1]$_[2]$_[3]" }
 ;
 
-bitmap_body: '{' opt_bitmap_elements '}' { $_[2] };
-opt_bitmap_body: | bitmap_body;
-bitmap: property_list 'bitmap' optional_identifier opt_bitmap_body
-        {{
-             "TYPE" => "BITMAP", 
-                    "PROPERTIES" => $_[1],
-                        "NAME" => $_[3],
-                    "ELEMENTS" => $_[4]
-        }}
+bitmap_body:
+       '{' opt_bitmap_elements '}' { $_[2] }
+;
+
+opt_bitmap_body:
+       #empty
+       |
+       bitmap_body
 ;
 
-bitmap_elements: 
-      bitmap_element                    { [ $_[1] ] }            
-    | bitmap_elements ',' bitmap_element  { push(@{$_[1]}, $_[3]); $_[1] }
+bitmap:
+       property_list 'bitmap' optional_identifier opt_bitmap_body
+       {{
+               "TYPE" => "BITMAP",
+               "PROPERTIES" => $_[1],
+               "NAME" => $_[3],
+               "ELEMENTS" => $_[4],
+               "FILE" => $_[0]->YYData->{FILE},
+               "LINE" => $_[0]->YYData->{LINE},
+       }}
 ;
 
-opt_bitmap_elements: | bitmap_elements;
+bitmap_elements:
+       bitmap_element                      { [ $_[1] ] }
+       |
+       bitmap_elements ',' bitmap_element  { push(@{$_[1]}, $_[3]); $_[1] }
+;
 
-bitmap_element: identifier '=' anytext { "$_[1] ( $_[3] )" }
+opt_bitmap_elements:
+       #empty
+       |
+       bitmap_elements
 ;
 
-struct_body: '{' element_list1 '}' { $_[2] };
-opt_struct_body: | struct_body;
+bitmap_element:
+       identifier '=' anytext { "$_[1] ( $_[3] )" }
+;
 
-struct: property_list 'struct' optional_identifier opt_struct_body
-        {{
-             "TYPE" => "STRUCT", 
-                        "PROPERTIES" => $_[1],
-                        "NAME" => $_[3],
-                    "ELEMENTS" => $_[4]
-        }}
+struct_body:
+       '{' element_list1 '}' { $_[2] }
 ;
 
-empty_element: property_list ';'
+opt_struct_body:
+       #empty
+       |
+       struct_body
+;
+
+struct:
+       property_list 'struct' optional_identifier opt_struct_body
        {{
-                "NAME" => "",
-                "TYPE" => "EMPTY",
-                "PROPERTIES" => $_[1],
-                "POINTERS" => 0,
-                "ARRAY_LEN" => [],
-                "FILE" => $_[0]->YYData->{FILE},
-                "LINE" => $_[0]->YYData->{LINE},
-        }}
+               "TYPE" => "STRUCT",
+               "PROPERTIES" => $_[1],
+               "NAME" => $_[3],
+               "ELEMENTS" => $_[4],
+               "FILE" => $_[0]->YYData->{FILE},
+               "LINE" => $_[0]->YYData->{LINE},
+       }}
 ;
 
-base_or_empty: base_element ';' | empty_element;
+empty_element:
+       property_list ';'
+       {{
+               "NAME" => "",
+               "TYPE" => "EMPTY",
+               "PROPERTIES" => $_[1],
+               "POINTERS" => 0,
+               "ARRAY_LEN" => [],
+               "FILE" => $_[0]->YYData->{FILE},
+               "LINE" => $_[0]->YYData->{LINE},
+       }}
+;
+
+base_or_empty:
+       base_element ';'
+       |
+       empty_element;
 
 optional_base_element:
        property_list base_or_empty { $_[2]->{PROPERTIES} = FlattenHash([$_[1],$_[2]->{PROPERTIES}]); $_[2] }
 ;
 
-union_elements: 
-    #empty
-    | union_elements optional_base_element { push(@{$_[1]}, $_[2]); $_[1] }
+union_elements:
+       #empty
+       |
+       union_elements optional_base_element { push(@{$_[1]}, $_[2]); $_[1] }
+;
+
+union_body:
+       '{' union_elements '}' { $_[2] }
 ;
 
-union_body: '{' union_elements '}' { $_[2] };
-opt_union_body: | union_body;
+opt_union_body:
+       #empty
+       |
+       union_body
+;
 
-union: property_list 'union' optional_identifier opt_union_body
-        {{
-             "TYPE" => "UNION", 
-                        "PROPERTIES" => $_[1],
-                    "NAME" => $_[3],
-                    "ELEMENTS" => $_[4]
-        }}
+union:
+       property_list 'union' optional_identifier opt_union_body
+       {{
+               "TYPE" => "UNION",
+               "PROPERTIES" => $_[1],
+               "NAME" => $_[3],
+               "ELEMENTS" => $_[4],
+               "FILE" => $_[0]->YYData->{FILE},
+               "LINE" => $_[0]->YYData->{LINE},
+       }}
 ;
 
-base_element: property_list type pointers identifier array_len
-             {{
-                          "NAME" => $_[4],
-                          "TYPE" => $_[2],
-                          "PROPERTIES" => $_[1],
-                          "POINTERS" => $_[3],
-                          "ARRAY_LEN" => $_[5],
-                      "FILE" => $_[0]->YYData->{FILE},
-                      "LINE" => $_[0]->YYData->{LINE},
-              }}
+base_element:
+       property_list type pointers identifier array_len
+       {{
+               "NAME" => $_[4],
+               "TYPE" => $_[2],
+               "PROPERTIES" => $_[1],
+               "POINTERS" => $_[3],
+               "ARRAY_LEN" => $_[5],
+               "FILE" => $_[0]->YYData->{FILE},
+               "LINE" => $_[0]->YYData->{LINE},
+       }}
 ;
 
+pointers:
+       #empty
+       { 0 }
+       |
+       pointers '*'  { $_[1]+1 }
+;
 
-pointers: 
-  #empty            
-   { 0 }
-    | pointers '*'  { $_[1]+1 }
+pipe:
+       property_list 'pipe' type
+       {{
+               "TYPE" => "PIPE",
+               "PROPERTIES" => $_[1],
+               "DATA" => $_[3],
+               "FILE" => $_[0]->YYData->{FILE},
+               "LINE" => $_[0]->YYData->{LINE},
+       }}
 ;
 
-element_list1: 
+element_list1:
+       #empty
        { [] }
-    | element_list1 base_element ';' { push(@{$_[1]}, $_[2]); $_[1] }
+       |
+       element_list1 base_element ';' { push(@{$_[1]}, $_[2]); $_[1] }
 ;
 
-optional_const: 
+optional_const:
        #empty
-       | 'const'
+       |
+       'const'
 ;
 
-element_list2: 
-    #empty
-    | 'void' 
-    | optional_const base_element { [ $_[2] ] }
-    | element_list2 ',' optional_const base_element { push(@{$_[1]}, $_[4]); $_[1] }
+element_list2:
+       #empty
+       |
+       'void'
+       |
+       optional_const base_element { [ $_[2] ] }
+       |
+       element_list2 ',' optional_const base_element { push(@{$_[1]}, $_[4]); $_[1] }
 ;
 
-array_len: 
-    #empty                        { [] }
-    | '[' ']' array_len           { push(@{$_[3]}, "*"); $_[3] }
-    | '[' anytext ']' array_len   { push(@{$_[4]}, "$_[2]"); $_[4] }
+array_len:
+       #empty { [] }
+       |
+       '[' ']' array_len           { push(@{$_[3]}, "*"); $_[3] }
+       |
+       '[' anytext ']' array_len   { push(@{$_[4]}, "$_[2]"); $_[4] }
 ;
 
-
-property_list: 
-    #empty
-    | property_list '[' properties ']' { FlattenHash([$_[1],$_[3]]); }
+property_list:
+       #empty
+       |
+       property_list '[' properties ']' { FlattenHash([$_[1],$_[3]]); }
 ;
 
-properties: property          { $_[1] }
-    | properties ',' property { FlattenHash([$_[1], $_[3]]); }
+properties:
+       property                { $_[1] }
+       |
+       properties ',' property { FlattenHash([$_[1], $_[3]]); }
 ;
 
-property: identifier                   {{ "$_[1]" => "1"     }}
-          | identifier '(' commalisttext ')' {{ "$_[1]" => "$_[3]" }}
+property:
+       identifier                       {{ "$_[1]" => "1"     }}
+       |
+       identifier '(' commalisttext ')' {{ "$_[1]" => "$_[3]" }}
 ;
 
 commalisttext:
-    anytext 
-    | commalisttext ',' anytext { "$_[1],$_[3]" }
-;
-
-anytext:  #empty
-    { "" }
-    | identifier | constant | text
-    | anytext '-' anytext  { "$_[1]$_[2]$_[3]" }
-    | anytext '.' anytext  { "$_[1]$_[2]$_[3]" }
-    | anytext '*' anytext  { "$_[1]$_[2]$_[3]" }
-    | anytext '>' anytext  { "$_[1]$_[2]$_[3]" }
-    | anytext '<' anytext  { "$_[1]$_[2]$_[3]" }
-    | anytext '|' anytext  { "$_[1]$_[2]$_[3]" }
-    | anytext '&' anytext  { "$_[1]$_[2]$_[3]" }
-    | anytext '/' anytext  { "$_[1]$_[2]$_[3]" }
-    | anytext '?' anytext  { "$_[1]$_[2]$_[3]" }
-    | anytext ':' anytext  { "$_[1]$_[2]$_[3]" }
-    | anytext '=' anytext  { "$_[1]$_[2]$_[3]" }
-    | anytext '+' anytext  { "$_[1]$_[2]$_[3]" }
-    | anytext '~' anytext  { "$_[1]$_[2]$_[3]" }
-    | anytext '(' commalisttext ')' anytext  { "$_[1]$_[2]$_[3]$_[4]$_[5]" }
-    | anytext '{' commalisttext '}' anytext  { "$_[1]$_[2]$_[3]$_[4]$_[5]" }
-;
-
-identifier: IDENTIFIER
-;
-
-optional_identifier: 
+       anytext
+       |
+       commalisttext ',' anytext { "$_[1],$_[3]" }
+;
+
+anytext:
+       #empty
+       { "" }
+       |
+       identifier
+       |
+       constant
+       |
+       text
+       |
+       anytext '-' anytext  { "$_[1]$_[2]$_[3]" }
+       |
+       anytext '.' anytext  { "$_[1]$_[2]$_[3]" }
+       |
+       anytext '*' anytext  { "$_[1]$_[2]$_[3]" }
+       |
+       anytext '>' anytext  { "$_[1]$_[2]$_[3]" }
+       |
+       anytext '<' anytext  { "$_[1]$_[2]$_[3]" }
+       |
+       anytext '|' anytext  { "$_[1]$_[2]$_[3]" }
+       |
+       anytext '&' anytext  { "$_[1]$_[2]$_[3]" }
+       |
+       anytext '/' anytext  { "$_[1]$_[2]$_[3]" }
+       |
+       anytext '?' anytext  { "$_[1]$_[2]$_[3]" }
+       |
+       anytext ':' anytext  { "$_[1]$_[2]$_[3]" }
+       |
+       anytext '=' anytext  { "$_[1]$_[2]$_[3]" }
+       |
+       anytext '+' anytext  { "$_[1]$_[2]$_[3]" }
+       |
+       anytext '~' anytext  { "$_[1]$_[2]$_[3]" }
+       |
+       anytext '(' commalisttext ')' anytext  { "$_[1]$_[2]$_[3]$_[4]$_[5]" }
+       |
+       anytext '{' commalisttext '}' anytext  { "$_[1]$_[2]$_[3]$_[4]$_[5]" }
+;
+
+identifier:
+       IDENTIFIER
+;
+
+optional_identifier:
+       #empty { undef }
+       |
        IDENTIFIER
-   | #empty { undef }
 ;
 
-constant: CONSTANT
+constant:
+       CONSTANT
 ;
 
-text: TEXT { "\"$_[1]\"" }
+text:
+       TEXT { "\"$_[1]\"" }
 ;
 
-optional_semicolon: 
+optional_semicolon:
        #empty
-       | ';'
+       |
+       ';'
 ;
 
 
@@ -361,51 +521,56 @@ use Parse::Pidl qw(error);
 
 #####################################################################
 # flatten an array of hashes into a single hash
-sub FlattenHash($) 
-{ 
-    my $a = shift;
-    my %b;
-    for my $d (@{$a}) {
-       for my $k (keys %{$d}) {
-           $b{$k} = $d->{$k};
+sub FlattenHash($)
+{
+       my $a = shift;
+       my %b;
+       for my $d (@{$a}) {
+               for my $k (keys %{$d}) {
+               $b{$k} = $d->{$k};
+               }
        }
-    }
-    return \%b;
+       return \%b;
 }
 
-
-
 #####################################################################
 # traverse a perl data structure removing any empty arrays or
 # hashes and any hash elements that map to undef
 sub CleanData($)
 {
-    sub CleanData($);
-    my($v) = shift;
+       sub CleanData($);
+       my($v) = shift;
+
        return undef if (not defined($v));
-    if (ref($v) eq "ARRAY") {
-       foreach my $i (0 .. $#{$v}) {
-           CleanData($v->[$i]);
-       }
-       # this removes any undefined elements from the array
-       @{$v} = grep { defined $_ } @{$v};
-    } elsif (ref($v) eq "HASH") {
-       foreach my $x (keys %{$v}) {
-           CleanData($v->{$x});
-           if (!defined $v->{$x}) { delete($v->{$x}); next; }
+
+       if (ref($v) eq "ARRAY") {
+               foreach my $i (0 .. $#{$v}) {
+                       CleanData($v->[$i]);
+               }
+               # this removes any undefined elements from the array
+               @{$v} = grep { defined $_ } @{$v};
+       } elsif (ref($v) eq "HASH") {
+               foreach my $x (keys %{$v}) {
+                       CleanData($v->{$x});
+                       if (!defined $v->{$x}) {
+                               delete($v->{$x});
+                               next;
+                       }
+               }
        }
-    }
+
        return $v;
 }
 
 sub _Error {
-    if (exists $_[0]->YYData->{ERRMSG}) {
+       if (exists $_[0]->YYData->{ERRMSG}) {
                error($_[0]->YYData, $_[0]->YYData->{ERRMSG});
                delete $_[0]->YYData->{ERRMSG};
                return;
        }
+
        my $last_token = $_[0]->YYData->{LAST_TOKEN};
-       
+
        error($_[0]->YYData, "Syntax error near '$last_token'");
 }
 
@@ -413,7 +578,7 @@ sub _Lexer($)
 {
        my($parser)=shift;
 
-    $parser->YYData->{INPUT} or return('',undef);
+       $parser->YYData->{INPUT} or return('',undef);
 
 again:
        $parser->YYData->{INPUT} =~ s/^[ \t]*//;
@@ -440,18 +605,19 @@ again:
                }
                if (s/^\"(.*?)\"//) {
                        $parser->YYData->{LAST_TOKEN} = $1;
-                       return('TEXT',$1); 
+                       return('TEXT',$1);
                }
                if (s/^(\d+)(\W|$)/$2/) {
                        $parser->YYData->{LAST_TOKEN} = $1;
-                       return('CONSTANT',$1); 
+                       return('CONSTANT',$1);
                }
                if (s/^([\w_]+)//) {
                        $parser->YYData->{LAST_TOKEN} = $1;
-                       if ($1 =~ 
-                           /^(coclass|interface|const|typedef|union|cpp_quote
-                             |struct|enum|bitmap|void|unsigned|signed|import|include
-                                 |importlib)$/x) {
+                       if ($1 =~
+                           /^(coclass|interface|import|importlib
+                             |include|cpp_quote|typedef
+                             |union|struct|enum|bitmap|pipe
+                             |void|const|unsigned|signed)$/x) {
                                return $1;
                        }
                        return('IDENTIFIER',$1);
@@ -469,10 +635,10 @@ sub parse_string
 
        my $self = new Parse::Pidl::IDL;
 
-    $self->YYData->{FILE} = $filename;
-    $self->YYData->{INPUT} = $data;
-    $self->YYData->{LINE} = 0;
-    $self->YYData->{LAST_TOKEN} = "NONE";
+       $self->YYData->{FILE} = $filename;
+       $self->YYData->{INPUT} = $data;
+       $self->YYData->{LINE} = 0;
+       $self->YYData->{LAST_TOKEN} = "NONE";
 
        my $idl = $self->YYParse( yylex => \&_Lexer, yyerror => \&_Error );