1 ########################
2 # IDL Parse::Yapp parser
3 # Copyright (C) Andrew Tridgell <tridge@samba.org>
4 # released under the GNU GPL version 2 or later
8 # the precedence actually doesn't matter at all for this grammar, but
9 # by providing a precedence we reduce the number of conflicts
11 %left '-' '+' '&' '|' '*' '>' '.' '/' '(' ')' '[' ',' ';'
19 | idl interface { push(@{$_[1]}, $_[2]); $_[1] }
20 | idl coclass { push(@{$_[1]}, $_[2]); $_[1] }
23 coclass: property_list 'coclass' identifier '{' interface_names '}' optional_semicolon
26 "PROPERTIES" => $_[1],
29 "FILE" => $_[0]->YYData->{INPUT_FILENAME},
30 "LINE" => $_[0]->YYData->{LINE},
36 | interface_names 'interface' identifier ';' { push(@{$_[1]}, $_[2]); $_[1] }
39 interface: property_list 'interface' identifier base_interface '{' definitions '}' optional_semicolon
41 "TYPE" => "INTERFACE",
42 "PROPERTIES" => $_[1],
46 "FILE" => $_[0]->YYData->{INPUT_FILENAME},
47 "LINE" => $_[0]->YYData->{LINE},
53 | ':' identifier { $_[2] }
57 definition { [ $_[1] ] }
58 | definitions definition { push(@{$_[1]}, $_[2]); $_[1] }
62 definition: function | const | typedef | declare | typedecl
65 const: 'const' identifier pointers identifier '=' anytext ';'
72 "FILE" => $_[0]->YYData->{INPUT_FILENAME},
73 "LINE" => $_[0]->YYData->{LINE},
75 | 'const' identifier pointers identifier array_len '=' anytext ';'
83 "FILE" => $_[0]->YYData->{INPUT_FILENAME},
84 "LINE" => $_[0]->YYData->{LINE},
89 function: property_list type identifier '(' element_list2 ')' ';'
93 "RETURN_TYPE" => $_[2],
94 "PROPERTIES" => $_[1],
96 "FILE" => $_[0]->YYData->{INPUT_FILENAME},
97 "LINE" => $_[0]->YYData->{LINE},
101 declare: 'declare' property_list decl_type identifier';'
104 "PROPERTIES" => $_[2],
107 "FILE" => $_[0]->YYData->{INPUT_FILENAME},
108 "LINE" => $_[0]->YYData->{LINE},
112 decl_type: decl_enum | decl_bitmap
121 decl_bitmap: 'bitmap'
127 typedef: 'typedef' property_list type identifier array_len ';'
130 "PROPERTIES" => $_[2],
133 "ARRAY_LEN" => $_[5],
134 "FILE" => $_[0]->YYData->{INPUT_FILENAME},
135 "LINE" => $_[0]->YYData->{LINE},
139 usertype: struct | union | enum | bitmap;
141 typedecl: usertype ';' { $_[1] };
143 sign: 'signed' | 'unsigned';
146 | sign identifier { "$_[1] $_[2]" }
150 type: usertype | existingtype | void { "void" } ;
152 enum_body: '{' enum_elements '}' { $_[2] };
153 opt_enum_body: | enum_body;
154 enum: 'enum' optional_identifier opt_enum_body
163 enum_element { [ $_[1] ] }
164 | enum_elements ',' enum_element { push(@{$_[1]}, $_[3]); $_[1] }
167 enum_element: identifier
168 | identifier '=' anytext { "$_[1]$_[2]$_[3]" }
171 bitmap_body: '{' bitmap_elements '}' { $_[2] };
172 opt_bitmap_body: | bitmap_body;
173 bitmap: 'bitmap' optional_identifier opt_bitmap_body
182 bitmap_element { [ $_[1] ] }
183 | bitmap_elements ',' bitmap_element { push(@{$_[1]}, $_[3]); $_[1] }
186 bitmap_element: identifier '=' anytext { "$_[1] ( $_[3] )" }
189 struct_body: '{' element_list1 '}' { $_[2] };
190 opt_struct_body: | struct_body;
192 struct: 'struct' optional_identifier opt_struct_body
200 empty_element: property_list ';'
204 "PROPERTIES" => $_[1],
207 "FILE" => $_[0]->YYData->{INPUT_FILENAME},
208 "LINE" => $_[0]->YYData->{LINE},
212 base_or_empty: base_element ';' | empty_element;
214 optional_base_element:
215 property_list base_or_empty { $_[2]->{PROPERTIES} = FlattenHash([$_[1],$_[2]->{PROPERTIES}]); $_[2] }
220 | union_elements optional_base_element { push(@{$_[1]}, $_[2]); $_[1] }
223 union_body: '{' union_elements '}' { $_[2] };
224 opt_union_body: | union_body;
226 union: 'union' optional_identifier opt_union_body
234 base_element: property_list type pointers identifier array_len
238 "PROPERTIES" => $_[1],
240 "ARRAY_LEN" => $_[5],
241 "FILE" => $_[0]->YYData->{INPUT_FILENAME},
242 "LINE" => $_[0]->YYData->{LINE},
250 | pointers '*' { $_[1]+1 }
255 | element_list1 base_element ';' { push(@{$_[1]}, $_[2]); $_[1] }
261 | base_element { [ $_[1] ] }
262 | element_list2 ',' base_element { push(@{$_[1]}, $_[3]); $_[1] }
267 | '[' ']' array_len { push(@{$_[3]}, "*"); $_[3] }
268 | '[' anytext ']' array_len { push(@{$_[4]}, "$_[2]"); $_[4] }
274 | property_list '[' properties ']' { FlattenHash([$_[1],$_[3]]); }
277 properties: property { $_[1] }
278 | properties ',' property { FlattenHash([$_[1], $_[3]]); }
281 property: identifier {{ "$_[1]" => "1" }}
282 | identifier '(' listtext ')' {{ "$_[1]" => "$_[3]" }}
287 | listtext ',' anytext { "$_[1] $_[3]" }
292 | commalisttext ',' anytext { "$_[1],$_[3]" }
297 | identifier | constant | text
298 | anytext '-' anytext { "$_[1]$_[2]$_[3]" }
299 | anytext '.' anytext { "$_[1]$_[2]$_[3]" }
300 | anytext '*' anytext { "$_[1]$_[2]$_[3]" }
301 | anytext '>' anytext { "$_[1]$_[2]$_[3]" }
302 | anytext '<' anytext { "$_[1]$_[2]$_[3]" }
303 | anytext '|' anytext { "$_[1]$_[2]$_[3]" }
304 | anytext '&' anytext { "$_[1]$_[2]$_[3]" }
305 | anytext '/' anytext { "$_[1]$_[2]$_[3]" }
306 | anytext '?' anytext { "$_[1]$_[2]$_[3]" }
307 | anytext ':' anytext { "$_[1]$_[2]$_[3]" }
308 | anytext '=' anytext { "$_[1]$_[2]$_[3]" }
309 | anytext '+' anytext { "$_[1]$_[2]$_[3]" }
310 | anytext '~' anytext { "$_[1]$_[2]$_[3]" }
311 | anytext '(' commalisttext ')' anytext { "$_[1]$_[2]$_[3]$_[4]$_[5]" }
312 | anytext '{' commalisttext '}' anytext { "$_[1]$_[2]$_[3]$_[4]$_[5]" }
315 identifier: IDENTIFIER
326 text: TEXT { "\"$_[1]\"" }
335 #####################################
339 #####################################################################
340 # flatten an array of hashes into a single hash
346 for my $k (keys %{$d}) {
355 #####################################################################
356 # traverse a perl data structure removing any empty arrays or
357 # hashes and any hash elements that map to undef
362 return undef if (not defined($v));
363 if (ref($v) eq "ARRAY") {
364 foreach my $i (0 .. $#{$v}) {
366 if (ref($v->[$i]) eq "ARRAY" && $#{$v->[$i]}==-1) {
371 # this removes any undefined elements from the array
372 @{$v} = grep { defined $_ } @{$v};
373 } elsif (ref($v) eq "HASH") {
374 foreach my $x (keys %{$v}) {
376 if (!defined $v->{$x}) { delete($v->{$x}); next; }
377 if (ref($v->{$x}) eq "ARRAY" && $#{$v->{$x}}==-1) { delete($v->{$x}); next; }
384 if (exists $_[0]->YYData->{ERRMSG}) {
385 print $_[0]->YYData->{ERRMSG};
386 delete $_[0]->YYData->{ERRMSG};
389 my $line = $_[0]->YYData->{LINE};
390 my $last_token = $_[0]->YYData->{LAST_TOKEN};
391 my $file = $_[0]->YYData->{INPUT_FILENAME};
393 print "$file:$line: Syntax error near '$last_token'\n";
400 $parser->YYData->{INPUT} or return('',undef);
403 $parser->YYData->{INPUT} =~ s/^[ \t]*//;
405 for ($parser->YYData->{INPUT}) {
407 if (s/^\# (\d+) \"(.*?)\"( \d+|)//) {
408 $parser->YYData->{LINE} = $1-1;
409 $parser->YYData->{INPUT_FILENAME} = $2;
412 if (s/^\#line (\d+) \"(.*?)\"( \d+|)//) {
413 $parser->YYData->{LINE} = $1-1;
414 $parser->YYData->{INPUT_FILENAME} = $2;
422 $parser->YYData->{LINE}++;
425 if (s/^\"(.*?)\"//) {
426 $parser->YYData->{LAST_TOKEN} = $1;
429 if (s/^(\d+)(\W|$)/$2/) {
430 $parser->YYData->{LAST_TOKEN} = $1;
431 return('CONSTANT',$1);
434 $parser->YYData->{LAST_TOKEN} = $1;
436 /^(coclass|interface|const|typedef|declare|union
437 |struct|enum|bitmap|void|unsigned|signed)$/x) {
440 return('IDENTIFIER',$1);
443 $parser->YYData->{LAST_TOKEN} = $1;
451 my ($data,$filename) = @_;
453 my $self = new Parse::Pidl::IDL;
455 $self->YYData->{INPUT_FILENAME} = $filename;
456 $self->YYData->{INPUT} = $data;
457 $self->YYData->{LINE} = 0;
458 $self->YYData->{LAST_TOKEN} = "NONE";
460 my $idl = $self->YYParse( yylex => \&_Lexer, yyerror => \&_Error );
462 return CleanData($idl);
469 my $saved_delim = $/;
472 if (! defined $cpp) {
475 my $data = `$cpp -D__PIDL__ -xc $filename`;
478 return parse_string($data, $filename);