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] }
21 | idl import { push(@{$_[1]}, $_[2]); $_[1] }
22 | idl include { push(@{$_[1]}, $_[2]); $_[1] }
23 | idl importlib { push(@{$_[1]}, $_[2]); $_[1] }
26 import: 'import' commalist ';' {{
29 "FILE" => $_[0]->YYData->{INPUT_FILENAME},
30 "LINE" => $_[0]->YYData->{LINE}
33 include: 'include' commalist ';' {{
36 "FILE" => $_[0]->YYData->{INPUT_FILENAME},
37 "LINE" => $_[0]->YYData->{LINE}
40 importlib: 'importlib' commalist ';' {{
41 "TYPE" => "IMPORTLIB",
43 "FILE" => $_[0]->YYData->{INPUT_FILENAME},
44 "LINE" => $_[0]->YYData->{LINE}
50 | commalist ',' text { push(@{$_[1]}, $_[3]); $_[1] }
53 coclass: property_list 'coclass' identifier '{' interface_names '}' optional_semicolon
56 "PROPERTIES" => $_[1],
59 "FILE" => $_[0]->YYData->{INPUT_FILENAME},
60 "LINE" => $_[0]->YYData->{LINE},
66 | interface_names 'interface' identifier ';' { push(@{$_[1]}, $_[2]); $_[1] }
69 interface: property_list 'interface' identifier base_interface '{' definitions '}' optional_semicolon
71 "TYPE" => "INTERFACE",
72 "PROPERTIES" => $_[1],
76 "FILE" => $_[0]->YYData->{INPUT_FILENAME},
77 "LINE" => $_[0]->YYData->{LINE},
83 | ':' identifier { $_[2] }
87 definition { [ $_[1] ] }
88 | definitions definition { push(@{$_[1]}, $_[2]); $_[1] }
92 definition: function | const | typedef | declare | typedecl
95 const: 'const' identifier pointers identifier '=' anytext ';'
102 "FILE" => $_[0]->YYData->{INPUT_FILENAME},
103 "LINE" => $_[0]->YYData->{LINE},
105 | 'const' identifier pointers identifier array_len '=' anytext ';'
111 "ARRAY_LEN" => $_[5],
113 "FILE" => $_[0]->YYData->{INPUT_FILENAME},
114 "LINE" => $_[0]->YYData->{LINE},
119 function: property_list type identifier '(' element_list2 ')' ';'
121 "TYPE" => "FUNCTION",
123 "RETURN_TYPE" => $_[2],
124 "PROPERTIES" => $_[1],
126 "FILE" => $_[0]->YYData->{INPUT_FILENAME},
127 "LINE" => $_[0]->YYData->{LINE},
131 declare: 'declare' property_list decl_type identifier';'
134 "PROPERTIES" => $_[2],
137 "FILE" => $_[0]->YYData->{INPUT_FILENAME},
138 "LINE" => $_[0]->YYData->{LINE},
142 decl_type: decl_enum | decl_bitmap | decl_union
151 decl_bitmap: 'bitmap'
163 typedef: 'typedef' property_list type identifier array_len ';'
166 "PROPERTIES" => $_[2],
169 "ARRAY_LEN" => $_[5],
170 "FILE" => $_[0]->YYData->{INPUT_FILENAME},
171 "LINE" => $_[0]->YYData->{LINE},
175 usertype: struct | union | enum | bitmap;
177 typedecl: usertype ';' { $_[1] };
179 sign: 'signed' | 'unsigned';
182 | sign identifier { "$_[1] $_[2]" }
186 type: usertype | existingtype | void { "void" } ;
188 enum_body: '{' enum_elements '}' { $_[2] };
189 opt_enum_body: | enum_body;
190 enum: 'enum' optional_identifier opt_enum_body
199 enum_element { [ $_[1] ] }
200 | enum_elements ',' enum_element { push(@{$_[1]}, $_[3]); $_[1] }
203 enum_element: identifier
204 | identifier '=' anytext { "$_[1]$_[2]$_[3]" }
207 bitmap_body: '{' opt_bitmap_elements '}' { $_[2] };
208 opt_bitmap_body: | bitmap_body;
209 bitmap: 'bitmap' optional_identifier opt_bitmap_body
218 bitmap_element { [ $_[1] ] }
219 | bitmap_elements ',' bitmap_element { push(@{$_[1]}, $_[3]); $_[1] }
222 opt_bitmap_elements: | bitmap_elements;
224 bitmap_element: identifier '=' anytext { "$_[1] ( $_[3] )" }
227 struct_body: '{' element_list1 '}' { $_[2] };
228 opt_struct_body: | struct_body;
230 struct: 'struct' optional_identifier opt_struct_body
238 empty_element: property_list ';'
242 "PROPERTIES" => $_[1],
245 "FILE" => $_[0]->YYData->{INPUT_FILENAME},
246 "LINE" => $_[0]->YYData->{LINE},
250 base_or_empty: base_element ';' | empty_element;
252 optional_base_element:
253 property_list base_or_empty { $_[2]->{PROPERTIES} = FlattenHash([$_[1],$_[2]->{PROPERTIES}]); $_[2] }
258 | union_elements optional_base_element { push(@{$_[1]}, $_[2]); $_[1] }
261 union_body: '{' union_elements '}' { $_[2] };
262 opt_union_body: | union_body;
264 union: 'union' optional_identifier opt_union_body
272 base_element: property_list type pointers identifier array_len
276 "PROPERTIES" => $_[1],
278 "ARRAY_LEN" => $_[5],
279 "FILE" => $_[0]->YYData->{INPUT_FILENAME},
280 "LINE" => $_[0]->YYData->{LINE},
288 | pointers '*' { $_[1]+1 }
293 | element_list1 base_element ';' { push(@{$_[1]}, $_[2]); $_[1] }
299 | base_element { [ $_[1] ] }
300 | element_list2 ',' base_element { push(@{$_[1]}, $_[3]); $_[1] }
305 | '[' ']' array_len { push(@{$_[3]}, "*"); $_[3] }
306 | '[' anytext ']' array_len { push(@{$_[4]}, "$_[2]"); $_[4] }
312 | property_list '[' properties ']' { FlattenHash([$_[1],$_[3]]); }
315 properties: property { $_[1] }
316 | properties ',' property { FlattenHash([$_[1], $_[3]]); }
319 property: identifier {{ "$_[1]" => "1" }}
320 | identifier '(' listtext ')' {{ "$_[1]" => "$_[3]" }}
325 | listtext ',' anytext { "$_[1] $_[3]" }
330 | commalisttext ',' anytext { "$_[1],$_[3]" }
335 | identifier | constant | text
336 | anytext '-' anytext { "$_[1]$_[2]$_[3]" }
337 | anytext '.' anytext { "$_[1]$_[2]$_[3]" }
338 | anytext '*' anytext { "$_[1]$_[2]$_[3]" }
339 | anytext '>' anytext { "$_[1]$_[2]$_[3]" }
340 | anytext '<' anytext { "$_[1]$_[2]$_[3]" }
341 | anytext '|' anytext { "$_[1]$_[2]$_[3]" }
342 | anytext '&' anytext { "$_[1]$_[2]$_[3]" }
343 | anytext '/' anytext { "$_[1]$_[2]$_[3]" }
344 | anytext '?' anytext { "$_[1]$_[2]$_[3]" }
345 | anytext ':' anytext { "$_[1]$_[2]$_[3]" }
346 | anytext '=' anytext { "$_[1]$_[2]$_[3]" }
347 | anytext '+' anytext { "$_[1]$_[2]$_[3]" }
348 | anytext '~' anytext { "$_[1]$_[2]$_[3]" }
349 | anytext '(' commalisttext ')' anytext { "$_[1]$_[2]$_[3]$_[4]$_[5]" }
350 | anytext '{' commalisttext '}' anytext { "$_[1]$_[2]$_[3]$_[4]$_[5]" }
353 identifier: IDENTIFIER
364 text: TEXT { "\"$_[1]\"" }
373 #####################################
377 #####################################################################
378 # flatten an array of hashes into a single hash
384 for my $k (keys %{$d}) {
393 #####################################################################
394 # traverse a perl data structure removing any empty arrays or
395 # hashes and any hash elements that map to undef
400 return undef if (not defined($v));
401 if (ref($v) eq "ARRAY") {
402 foreach my $i (0 .. $#{$v}) {
404 if (ref($v->[$i]) eq "ARRAY" && $#{$v->[$i]}==-1) {
409 # this removes any undefined elements from the array
410 @{$v} = grep { defined $_ } @{$v};
411 } elsif (ref($v) eq "HASH") {
412 foreach my $x (keys %{$v}) {
414 if (!defined $v->{$x}) { delete($v->{$x}); next; }
415 if (ref($v->{$x}) eq "ARRAY" && $#{$v->{$x}}==-1) { delete($v->{$x}); next; }
422 if (exists $_[0]->YYData->{ERRMSG}) {
423 print $_[0]->YYData->{ERRMSG};
424 delete $_[0]->YYData->{ERRMSG};
427 my $line = $_[0]->YYData->{LINE};
428 my $last_token = $_[0]->YYData->{LAST_TOKEN};
429 my $file = $_[0]->YYData->{INPUT_FILENAME};
431 print "$file:$line: Syntax error near '$last_token'\n";
438 $parser->YYData->{INPUT} or return('',undef);
441 $parser->YYData->{INPUT} =~ s/^[ \t]*//;
443 for ($parser->YYData->{INPUT}) {
445 if (s/^\# (\d+) \"(.*?)\"( \d+|)//) {
446 $parser->YYData->{LINE} = $1-1;
447 $parser->YYData->{INPUT_FILENAME} = $2;
450 if (s/^\#line (\d+) \"(.*?)\"( \d+|)//) {
451 $parser->YYData->{LINE} = $1-1;
452 $parser->YYData->{INPUT_FILENAME} = $2;
460 $parser->YYData->{LINE}++;
463 if (s/^\"(.*?)\"//) {
464 $parser->YYData->{LAST_TOKEN} = $1;
467 if (s/^(\d+)(\W|$)/$2/) {
468 $parser->YYData->{LAST_TOKEN} = $1;
469 return('CONSTANT',$1);
472 $parser->YYData->{LAST_TOKEN} = $1;
474 /^(coclass|interface|const|typedef|declare|union
475 |struct|enum|bitmap|void|unsigned|signed|import|include
479 return('IDENTIFIER',$1);
482 $parser->YYData->{LAST_TOKEN} = $1;
490 my ($data,$filename) = @_;
492 my $self = new Parse::Pidl::IDL;
494 $self->YYData->{INPUT_FILENAME} = $filename;
495 $self->YYData->{INPUT} = $data;
496 $self->YYData->{LINE} = 0;
497 $self->YYData->{LAST_TOKEN} = "NONE";
499 my $idl = $self->YYParse( yylex => \&_Lexer, yyerror => \&_Error );
501 return CleanData($idl);
506 my ($filename,$incdirs) = @_;
508 my $saved_delim = $/;
511 if (! defined $cpp) {
514 my $includes = join('',map { " -I$_" } @$incdirs);
515 my $data = `$cpp -D__PIDL__$includes -xc $filename`;
518 return parse_string($data, $filename);