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->{FILE},
30 "LINE" => $_[0]->YYData->{LINE}
33 include: 'include' commalist ';' {{
36 "FILE" => $_[0]->YYData->{FILE},
37 "LINE" => $_[0]->YYData->{LINE}
40 importlib: 'importlib' commalist ';' {{
41 "TYPE" => "IMPORTLIB",
43 "FILE" => $_[0]->YYData->{FILE},
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->{FILE},
60 "LINE" => $_[0]->YYData->{LINE},
66 | interface_names 'interface' identifier ';' { push(@{$_[1]}, $_[2]); $_[1] }
69 interface: property_list 'interface' identifier '{' definitions '}' optional_semicolon
71 "TYPE" => "INTERFACE",
72 "PROPERTIES" => $_[1],
75 "FILE" => $_[0]->YYData->{FILE},
76 "LINE" => $_[0]->YYData->{LINE},
81 definition { [ $_[1] ] }
82 | definitions definition { push(@{$_[1]}, $_[2]); $_[1] }
86 definition: function | const | typedef | declare | typedecl
89 const: 'const' identifier pointers identifier '=' anytext ';'
96 "FILE" => $_[0]->YYData->{FILE},
97 "LINE" => $_[0]->YYData->{LINE},
99 | 'const' identifier pointers identifier array_len '=' anytext ';'
105 "ARRAY_LEN" => $_[5],
107 "FILE" => $_[0]->YYData->{FILE},
108 "LINE" => $_[0]->YYData->{LINE},
113 function: property_list type identifier '(' element_list2 ')' ';'
115 "TYPE" => "FUNCTION",
117 "RETURN_TYPE" => $_[2],
118 "PROPERTIES" => $_[1],
120 "FILE" => $_[0]->YYData->{FILE},
121 "LINE" => $_[0]->YYData->{LINE},
125 declare: 'declare' property_list decl_type identifier';'
128 "PROPERTIES" => $_[2],
131 "FILE" => $_[0]->YYData->{FILE},
132 "LINE" => $_[0]->YYData->{LINE},
136 decl_type: decl_enum | decl_bitmap | decl_union
145 decl_bitmap: 'bitmap'
157 typedef: property_list 'typedef' type identifier array_len ';'
160 "PROPERTIES" => $_[1],
163 "ARRAY_LEN" => $_[5],
164 "FILE" => $_[0]->YYData->{FILE},
165 "LINE" => $_[0]->YYData->{LINE},
169 usertype: struct | union | enum | bitmap;
171 typedecl: usertype ';' { $_[1] };
173 sign: 'signed' | 'unsigned';
176 sign identifier { ($_[1]?$_[1]:"signed") ." $_[2]" }
180 type: usertype | existingtype | void { "void" } ;
182 enum_body: '{' enum_elements '}' { $_[2] };
183 opt_enum_body: | enum_body;
184 enum: property_list 'enum' optional_identifier opt_enum_body
187 "PROPERTIES" => $_[1],
194 enum_element { [ $_[1] ] }
195 | enum_elements ',' enum_element { push(@{$_[1]}, $_[3]); $_[1] }
198 enum_element: identifier
199 | identifier '=' anytext { "$_[1]$_[2]$_[3]" }
202 bitmap_body: '{' opt_bitmap_elements '}' { $_[2] };
203 opt_bitmap_body: | bitmap_body;
204 bitmap: property_list 'bitmap' optional_identifier opt_bitmap_body
207 "PROPERTIES" => $_[1],
214 bitmap_element { [ $_[1] ] }
215 | bitmap_elements ',' bitmap_element { push(@{$_[1]}, $_[3]); $_[1] }
218 opt_bitmap_elements: | bitmap_elements;
220 bitmap_element: identifier '=' anytext { "$_[1] ( $_[3] )" }
223 struct_body: '{' element_list1 '}' { $_[2] };
224 opt_struct_body: | struct_body;
226 struct: property_list 'struct' optional_identifier opt_struct_body
229 "PROPERTIES" => $_[1],
235 empty_element: property_list ';'
239 "PROPERTIES" => $_[1],
242 "FILE" => $_[0]->YYData->{FILE},
243 "LINE" => $_[0]->YYData->{LINE},
247 base_or_empty: base_element ';' | empty_element;
249 optional_base_element:
250 property_list base_or_empty { $_[2]->{PROPERTIES} = FlattenHash([$_[1],$_[2]->{PROPERTIES}]); $_[2] }
255 | union_elements optional_base_element { push(@{$_[1]}, $_[2]); $_[1] }
258 union_body: '{' union_elements '}' { $_[2] };
259 opt_union_body: | union_body;
261 union: property_list 'union' optional_identifier opt_union_body
264 "PROPERTIES" => $_[1],
270 base_element: property_list type pointers identifier array_len
274 "PROPERTIES" => $_[1],
276 "ARRAY_LEN" => $_[5],
277 "FILE" => $_[0]->YYData->{FILE},
278 "LINE" => $_[0]->YYData->{LINE},
286 | pointers '*' { $_[1]+1 }
291 | element_list1 base_element ';' { push(@{$_[1]}, $_[2]); $_[1] }
297 | base_element { [ $_[1] ] }
298 | element_list2 ',' base_element { push(@{$_[1]}, $_[3]); $_[1] }
303 | '[' ']' array_len { push(@{$_[3]}, "*"); $_[3] }
304 | '[' anytext ']' array_len { push(@{$_[4]}, "$_[2]"); $_[4] }
310 | property_list '[' properties ']' { FlattenHash([$_[1],$_[3]]); }
313 properties: property { $_[1] }
314 | properties ',' property { FlattenHash([$_[1], $_[3]]); }
317 property: identifier {{ "$_[1]" => "1" }}
318 | identifier '(' listtext ')' {{ "$_[1]" => "$_[3]" }}
323 | listtext ',' anytext { "$_[1] $_[3]" }
328 | commalisttext ',' anytext { "$_[1],$_[3]" }
333 | identifier | constant | text
334 | anytext '-' anytext { "$_[1]$_[2]$_[3]" }
335 | anytext '.' anytext { "$_[1]$_[2]$_[3]" }
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 '(' commalisttext ')' anytext { "$_[1]$_[2]$_[3]$_[4]$_[5]" }
348 | anytext '{' commalisttext '}' anytext { "$_[1]$_[2]$_[3]$_[4]$_[5]" }
351 identifier: IDENTIFIER
362 text: TEXT { "\"$_[1]\"" }
371 #####################################
375 use Parse::Pidl qw(error);
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}) {
405 # this removes any undefined elements from the array
406 @{$v} = grep { defined $_ } @{$v};
407 } elsif (ref($v) eq "HASH") {
408 foreach my $x (keys %{$v}) {
410 if (!defined $v->{$x}) { delete($v->{$x}); next; }
417 if (exists $_[0]->YYData->{ERRMSG}) {
418 error($_[0]->YYData, $_[0]->YYData->{ERRMSG});
419 delete $_[0]->YYData->{ERRMSG};
422 my $last_token = $_[0]->YYData->{LAST_TOKEN};
424 error($_[0]->YYData, "Syntax error near '$last_token'");
431 $parser->YYData->{INPUT} or return('',undef);
434 $parser->YYData->{INPUT} =~ s/^[ \t]*//;
436 for ($parser->YYData->{INPUT}) {
438 if (s/^\# (\d+) \"(.*?)\"( \d+|)//) {
439 $parser->YYData->{LINE} = $1-1;
440 $parser->YYData->{FILE} = $2;
443 if (s/^\#line (\d+) \"(.*?)\"( \d+|)//) {
444 $parser->YYData->{LINE} = $1-1;
445 $parser->YYData->{FILE} = $2;
453 $parser->YYData->{LINE}++;
456 if (s/^\"(.*?)\"//) {
457 $parser->YYData->{LAST_TOKEN} = $1;
460 if (s/^(\d+)(\W|$)/$2/) {
461 $parser->YYData->{LAST_TOKEN} = $1;
462 return('CONSTANT',$1);
465 $parser->YYData->{LAST_TOKEN} = $1;
467 /^(coclass|interface|const|typedef|declare|union
468 |struct|enum|bitmap|void|unsigned|signed|import|include
472 return('IDENTIFIER',$1);
475 $parser->YYData->{LAST_TOKEN} = $1;
483 my ($data,$filename) = @_;
485 my $self = new Parse::Pidl::IDL;
487 $self->YYData->{FILE} = $filename;
488 $self->YYData->{INPUT} = $data;
489 $self->YYData->{LINE} = 0;
490 $self->YYData->{LAST_TOKEN} = "NONE";
492 my $idl = $self->YYParse( yylex => \&_Lexer, yyerror => \&_Error );
494 return CleanData($idl);
499 my ($filename,$incdirs) = @_;
501 my $saved_delim = $/;
504 if (! defined $cpp) {
507 my $includes = join('',map { " -I$_" } @$incdirs);
508 my $data = `$cpp -D__PIDL__$includes -xc $filename`;
511 return parse_string($data, $filename);