r7161: - Add support for "aliases" for pidls scalar types and add a few aliases.
[samba.git] / source4 / build / pidl / idl.yp
index f780c9966222ef35e83c62f25d6b76448c047c32..b556b064b42d495daf468cfd6b915daf340fd754 100644 (file)
@@ -5,39 +5,52 @@
 
 
 
+# the precedence actually doesn't matter at all for this grammer, but
+# by providing a precedence we reduce the number of conflicts
+# enormously
+%left   '-' '+' '&' '|' '*' '>' '.' '/' '(' ')' '[' ',' ';'
+
+
 ################
 # grammer
 %%
-idl: idl_interface 
-     | idl idl_interface { util::FlattenArray([$_[1],$_[2]]) }
+idl: 
+       #empty  { {} }
+       | idl interface { push(@{$_[1]}, $_[2]); $_[1] }
+       | idl coclass { push(@{$_[1]}, $_[2]); $_[1] }
 ;
 
-idl_interface: module_header interface { [ $_[1], $_[2] ] }
-;
-
-module_header: '[' module_params ']'
-          {{ 
-              "TYPE" => "MODULEHEADER", 
-              "PROPERTIES" => util::FlattenHash($_[2])
+coclass: property_list 'coclass' identifier '{' interface_names '}' optional_semicolon
+          {$_[3] => {
+               "TYPE" => "COCLASS", 
+              "PROPERTIES" => $_[1],
+              "NAME" => $_[3],
+              "DATA" => $_[5],
+                  "FILE" => $_[0]->YYData->{INPUT_FILENAME},
+                  "LINE" => $_[0]->YYData->{LINE},
           }}
 ;
 
-module_params: 
-    #empty
-    | module_param                    { [ $_[1] ] }            
-    | module_params ',' module_param  { push(@{$_[1]}, $_[3]); $_[1] }
+interface_names:
+       #empty { {} }
+       | interface_names 'interface' identifier ';' { push(@{$_[1]}, $_[2]); $_[1] }
 ;
 
-module_param: identifier '(' listtext ')'
-{ { "$_[1]" => "$_[3]" } }
+interface: property_list 'interface' identifier base_interface '{' definitions '}' optional_semicolon
+          {$_[3] => {
+               "TYPE" => "INTERFACE", 
+              "PROPERTIES" => $_[1],
+              "NAME" => $_[3],
+              "BASE" => $_[4],
+              "DATA" => $_[6],
+                  "FILE" => $_[0]->YYData->{INPUT_FILENAME},
+                  "LINE" => $_[0]->YYData->{LINE},
+          }}
 ;
 
-interface: 'interface' identifier '{' definitions '}'
-          {{
-                       "TYPE" => "INTERFACE", 
-                      "NAME" => $_[2],
-                      "DATA" => $_[4]
-          }}
+base_interface:
+       #empty
+       | ':' identifier { $_[2] }
 ;
 
 definitions: 
@@ -46,7 +59,7 @@ definitions:
 ;    
 
 
-definition: function | const | typedef
+definition: function | const | typedef | declare
 ;
 
 const: 'const' identifier identifier '=' anytext ';' 
@@ -54,7 +67,19 @@ const: 'const' identifier identifier '=' anytext ';'
                      "TYPE"  => "CONST", 
                     "DTYPE"  => $_[2],
                     "NAME"  => $_[3],
-                    "VALUE" => $_[5]
+                    "VALUE" => $_[5],
+                    "FILE" => $_[0]->YYData->{INPUT_FILENAME},
+                    "LINE" => $_[0]->YYData->{LINE},
+        }}
+       | 'const' identifier identifier array_len '=' anytext ';' 
+        {{
+                     "TYPE"  => "CONST", 
+                    "DTYPE"  => $_[2],
+                    "NAME"  => $_[3],
+                    "ARRAY_LEN" => $_[4],
+                    "VALUE" => $_[6],
+                    "FILE" => $_[0]->YYData->{INPUT_FILENAME},
+                    "LINE" => $_[0]->YYData->{LINE},
         }}
 ;
 
@@ -65,27 +90,58 @@ function: property_list type identifier '(' element_list2 ')' ';'
                "NAME" => $_[3],
                "RETURN_TYPE" => $_[2],
                "PROPERTIES" => $_[1],
-               "DATA" => $_[5]
-        }}
+               "ELEMENTS" => $_[5],
+               "FILE" => $_[0]->YYData->{INPUT_FILENAME},
+               "LINE" => $_[0]->YYData->{LINE},
+         }}
 ;
 
-typedef: 'typedef' type identifier array_len ';' 
+declare: 'declare' property_list decl_type identifier';' 
         {{
-                     "TYPE" => "TYPEDEF", 
-                    "NAME" => $_[3],
-                    "DATA" => $_[2],
-                    "ARRAY_LEN" => $_[4]
+                    "TYPE" => "DECLARE", 
+                     "PROPERTIES" => $_[2],
+                    "NAME" => $_[4],
+                    "DATA" => $_[3],
+                    "FILE" => $_[0]->YYData->{INPUT_FILENAME},
+                    "LINE" => $_[0]->YYData->{LINE},
         }}
 ;
 
-type:   struct | union | enum | identifier 
+decl_type: decl_enum | decl_bitmap
+;
+
+decl_enum: 'enum' 
+        {{
+                     "TYPE" => "ENUM"
+        }}
+;
+
+decl_bitmap: 'bitmap' 
+        {{
+                     "TYPE" => "BITMAP"
+        }}
+;
+
+typedef: 'typedef' property_list type identifier array_len ';' 
+        {{
+                    "TYPE" => "TYPEDEF", 
+                     "PROPERTIES" => $_[2],
+                    "NAME" => $_[4],
+                    "DATA" => $_[3],
+                    "ARRAY_LEN" => $_[5],
+                    "FILE" => $_[0]->YYData->{INPUT_FILENAME},
+                    "LINE" => $_[0]->YYData->{LINE},
+        }}
+;
+
+type:   struct | union | enum | bitmap | identifier 
        | void { "void" }
 ;
 
 
 enum: 'enum' '{' enum_elements '}' 
         {{
-                     "TYPE" => "ENUM", 
+             "TYPE" => "ENUM", 
                     "ELEMENTS" => $_[3]
         }}
 ;
@@ -99,50 +155,56 @@ enum_element: identifier
              | identifier '=' anytext { "$_[1]$_[2]$_[3]" }
 ;
 
-struct: property_list 'struct' '{' element_list1 '}' 
+bitmap: 'bitmap' '{' bitmap_elements '}' 
+        {{
+                     "TYPE" => "BITMAP", 
+                    "ELEMENTS" => $_[3]
+        }}
+;
+
+bitmap_elements: 
+      bitmap_element                    { [ $_[1] ] }            
+    | bitmap_elements ',' bitmap_element  { push(@{$_[1]}, $_[3]); $_[1] }
+;
+
+bitmap_element: identifier '=' anytext { "$_[1] ( $_[3] )" }
+;
+
+struct: 'struct' '{' element_list1 '}' 
         {{
                      "TYPE" => "STRUCT", 
-                    "PROPERTIES" => $_[1],
-                    "ELEMENTS" => $_[4]
+                    "ELEMENTS" => $_[3]
         }}
 ;
 
-union: property_list 'union' '{' union_elements '}' 
-        {{
-               "TYPE" => "UNION",
-               "PROPERTIES" => $_[1],
-               "DATA" => $_[4]
+empty_element: property_list ';'
+       {{
+                "NAME" => "",
+                "TYPE" => "EMPTY",
+                "PROPERTIES" => $_[1],
+                "POINTERS" => 0,
+                "ARRAY_LEN" => [],
+                "FILE" => $_[0]->YYData->{INPUT_FILENAME},
+                "LINE" => $_[0]->YYData->{LINE},
         }}
 ;
 
+base_or_empty: base_element ';' | empty_element;
+
+optional_base_element:
+       property_list base_or_empty { $_[2]->{PROPERTIES} = util::FlattenHash([$_[1],$_[2]->{PROPERTIES}]); $_[2] }
+;
+
 union_elements: 
-      union_element                    { [ $_[1] ] }            
-    | union_elements union_element  { push(@{$_[1]}, $_[2]); $_[1] }
+    #empty
+    | union_elements optional_base_element { push(@{$_[1]}, $_[2]); $_[1] }
 ;
 
-union_element: 
-         '[' 'case' '(' anytext ')' ']' base_element ';'
-        {{
-               "TYPE" => "UNION_ELEMENT",
-               "CASE" => $_[4],
-               "DATA" => $_[7]
-        }}
-         | '[' 'case' '(' anytext ')' ']' ';'
-        {{
-               "TYPE" => "EMPTY",
-               "CASE" => $_[4],
-        }}
-         | '[' 'default' ']' base_element ';'
-        {{
-               "TYPE" => "UNION_ELEMENT",
-               "CASE" => "default",
-               "DATA" => $_[4]
-        }}
-         | '[' 'default' ']' ';'
-        {{
-               "TYPE" => "EMPTY",
-               "CASE" => "default",
-        }}
+union: 'union' '{' union_elements '}' 
+        {{
+                     "TYPE" => "UNION", 
+                    "ELEMENTS" => $_[3]
+        }}
 ;
 
 base_element: property_list type pointers identifier array_len
@@ -151,7 +213,9 @@ base_element: property_list type pointers identifier array_len
                           "TYPE" => $_[2],
                           "PROPERTIES" => $_[1],
                           "POINTERS" => $_[3],
-                          "ARRAY_LEN" => $_[5]
+                          "ARRAY_LEN" => $_[5],
+                      "FILE" => $_[0]->YYData->{INPUT_FILENAME},
+                      "LINE" => $_[0]->YYData->{LINE},
               }}
 ;
 
@@ -162,41 +226,36 @@ pointers:
     | pointers '*'  { $_[1]+1 }
 ;
 
-
-
 element_list1: 
     #empty
-    | base_element ';'               { [ $_[1] ] }
     | element_list1 base_element ';' { push(@{$_[1]}, $_[2]); $_[1] }
 ;
 
 element_list2: 
     #empty
-    | 'void'
-    | base_element                   { [ $_[1] ] }
+    | 'void' 
+    | base_element { [ $_[1] ] }
     | element_list2 ',' base_element { push(@{$_[1]}, $_[3]); $_[1] }
 ;
 
 array_len: 
-    #empty 
-    | '[' ']'            { "*" }
-    | '[' '*' ']'        { "*" }
-    | '[' anytext ']'    { "$_[2]" }
+    #empty                        { [] }
+    | '[' ']' array_len           { push(@{$_[3]}, "*"); $_[3] }
+    | '[' anytext ']' array_len   { push(@{$_[4]}, "$_[2]"); $_[4] }
 ;
 
 
 property_list: 
-    #empty 
-    | '[' properties ']' { $_[2] }
-    | property_list '[' properties ']' { util::FlattenArray([$_[1],$_[3]]); }
+    #empty
+    | property_list '[' properties ']' { util::FlattenHash([$_[1],$_[3]]); }
 ;
 
-properties: property          { [ $_[1] ] }
-    | properties ',' property { push(@{$_[1]}, $_[3]); $_[1] }
+properties: property          { $_[1] }
+    | properties ',' property { util::FlattenHash([$_[1], $_[3]]); }
 ;
 
-property: identifier
-          | identifier '(' anytext ')' {{ "$_[1]" => "$_[3]" }}
+property: identifier                   {{ "$_[1]" => "1"     }}
+          | identifier '(' listtext ')' {{ "$_[1]" => "$_[3]" }}
 ;
 
 listtext:
@@ -204,6 +263,11 @@ listtext:
     | listtext ',' anytext { "$_[1] $_[3]" }
 ;
 
+commalisttext:
+    anytext 
+    | commalisttext ',' anytext { "$_[1],$_[3]" }
+;
+
 anytext:  #empty
     { "" }
     | identifier | constant | text
@@ -211,11 +275,14 @@ anytext:  #empty
     | 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 ')' anytext  { "$_[1]$_[2]$_[3]$_[4]$_[5]" }
+    | anytext '~' anytext  { "$_[1]$_[2]$_[3]" }
+    | anytext '(' commalisttext ')' anytext  { "$_[1]$_[2]$_[3]$_[4]$_[5]" }
+    | anytext '{' commalisttext '}' anytext  { "$_[1]$_[2]$_[3]$_[4]$_[5]" }
 ;
 
 identifier: IDENTIFIER
@@ -227,15 +294,20 @@ constant: CONSTANT
 text: TEXT { "\"$_[1]\"" }
 ;
 
+optional_semicolon: 
+       #empty
+       | ';'
+;
+
 
 #####################################
 # start code
 %%
 
-use util;
+use pidl::util;
 
 sub _Error {
-        if (exists $_[0]->YYData->{ERRMSG}) {
+    if (exists $_[0]->YYData->{ERRMSG}) {
                print $_[0]->YYData->{ERRMSG};
                delete $_[0]->YYData->{ERRMSG};
                return;
@@ -244,10 +316,11 @@ sub _Error {
        my $last_token = $_[0]->YYData->{LAST_TOKEN};
        my $file = $_[0]->YYData->{INPUT_FILENAME};
        
-       print "Syntax error at $file:$line near '$last_token'\n";
+       print "$file:$line: Syntax error near '$last_token'\n";
 }
 
-sub _Lexer {
+sub _Lexer($)
+{
        my($parser)=shift;
 
         $parser->YYData->{INPUT}
@@ -257,10 +330,20 @@ again:
        $parser->YYData->{INPUT} =~ s/^[ \t]*//;
 
        for ($parser->YYData->{INPUT}) {
-               if (s/^\# (\d+) \"(.*?)\"( \d+|)//) {
-                       $parser->YYData->{LINE} = $1;
-                       $parser->YYData->{INPUT_FILENAME} = $2;
-                       goto again;
+               if (/^\#/) {
+                       if (s/^\# (\d+) \"(.*?)\"( \d+|)//) {
+                               $parser->YYData->{LINE} = $1-1;
+                               $parser->YYData->{INPUT_FILENAME} = $2;
+                               goto again;
+                       }
+                       if (s/^\#line (\d+) \"(.*?)\"( \d+|)//) {
+                               $parser->YYData->{LINE} = $1-1;
+                               $parser->YYData->{INPUT_FILENAME} = $2;
+                               goto again;
+                       }
+                       if (s/^(\#.*)$//m) {
+                               goto again;
+                       }
                }
                if (s/^(\n)//) {
                        $parser->YYData->{LINE}++;
@@ -277,8 +360,8 @@ again:
                if (s/^([\w_]+)//) {
                        $parser->YYData->{LAST_TOKEN} = $1;
                        if ($1 =~ 
-                           /^(interface|const|typedef|union
-                             |struct|enum|void|case|default)$/x) {
+                           /^(coclass|interface|const|typedef|declare|union
+                             |struct|enum|bitmap|void)$/x) {
                                return $1;
                        }
                        return('IDENTIFIER',$1);
@@ -297,11 +380,18 @@ sub parse_idl($$)
 
        my $saved_delim = $/;
        undef $/;
-       my $data = `cpp $filename`;
+       my $cpp = $ENV{CPP};
+       if (! defined $cpp) {
+               $cpp = "cpp"
+       }
+       my $data = `$cpp -D__PIDL__ -xc $filename`;
        $/ = $saved_delim;
 
-        $self->YYData->{INPUT} = $data;
-        $self->YYData->{LINE} = 0;
-        $self->YYData->{LAST_TOKEN} = "NONE";
-       return $self->YYParse( yylex => \&_Lexer, yyerror => \&_Error );
+    $self->YYData->{INPUT} = $data;
+    $self->YYData->{LINE} = 0;
+    $self->YYData->{LAST_TOKEN} = "NONE";
+
+       my $idl = $self->YYParse( yylex => \&_Lexer, yyerror => \&_Error );
+
+       return util::CleanData($idl);
 }