1 ########################
2 # IDL Parse::Yapp parser
3 # Copyright (C) Andrew Tridgell <tridge@samba.org>
4 # released under the GNU GPL version 3 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] }
24 | idl cpp_quote { push(@{$_[1]}, $_[2]); $_[1] }
27 import: 'import' commalist ';' {{
30 "FILE" => $_[0]->YYData->{FILE},
31 "LINE" => $_[0]->YYData->{LINE}
34 include: 'include' commalist ';' {{
37 "FILE" => $_[0]->YYData->{FILE},
38 "LINE" => $_[0]->YYData->{LINE}
41 importlib: 'importlib' commalist ';' {{
42 "TYPE" => "IMPORTLIB",
44 "FILE" => $_[0]->YYData->{FILE},
45 "LINE" => $_[0]->YYData->{LINE}
51 | commalist ',' text { push(@{$_[1]}, $_[3]); $_[1] }
54 coclass: property_list 'coclass' identifier '{' interface_names '}' optional_semicolon
57 "PROPERTIES" => $_[1],
60 "FILE" => $_[0]->YYData->{FILE},
61 "LINE" => $_[0]->YYData->{LINE},
67 | interface_names 'interface' identifier ';' { push(@{$_[1]}, $_[2]); $_[1] }
70 interface: property_list 'interface' identifier base_interface '{' definitions '}' optional_semicolon
72 "TYPE" => "INTERFACE",
73 "PROPERTIES" => $_[1],
77 "FILE" => $_[0]->YYData->{FILE},
78 "LINE" => $_[0]->YYData->{LINE},
84 | ':' identifier { $_[2] }
88 cpp_quote: 'cpp_quote' '(' text ')'
90 "TYPE" => "CPP_QUOTE",
91 "FILE" => $_[0]->YYData->{FILE},
92 "LINE" => $_[0]->YYData->{LINE},
98 definition { [ $_[1] ] }
99 | definitions definition { push(@{$_[1]}, $_[2]); $_[1] }
103 definition: function | const | typedef | typedecl
106 const: 'const' identifier pointers identifier '=' anytext ';'
113 "FILE" => $_[0]->YYData->{FILE},
114 "LINE" => $_[0]->YYData->{LINE},
116 | 'const' identifier pointers identifier array_len '=' anytext ';'
122 "ARRAY_LEN" => $_[5],
124 "FILE" => $_[0]->YYData->{FILE},
125 "LINE" => $_[0]->YYData->{LINE},
130 function: property_list type identifier '(' element_list2 ')' ';'
132 "TYPE" => "FUNCTION",
134 "RETURN_TYPE" => $_[2],
135 "PROPERTIES" => $_[1],
137 "FILE" => $_[0]->YYData->{FILE},
138 "LINE" => $_[0]->YYData->{LINE},
142 typedef: property_list 'typedef' type identifier array_len ';'
145 "PROPERTIES" => $_[1],
148 "ARRAY_LEN" => $_[5],
149 "FILE" => $_[0]->YYData->{FILE},
150 "LINE" => $_[0]->YYData->{LINE},
154 usertype: struct | union | enum | bitmap;
156 typedecl: usertype ';' { $_[1] };
158 sign: 'signed' | 'unsigned';
161 sign identifier { ($_[1]?$_[1]:"signed") ." $_[2]" }
165 type: usertype | existingtype | void { "void" } ;
167 enum_body: '{' enum_elements '}' { $_[2] };
168 opt_enum_body: | enum_body;
169 enum: property_list 'enum' optional_identifier opt_enum_body
172 "PROPERTIES" => $_[1],
179 enum_element { [ $_[1] ] }
180 | enum_elements ',' enum_element { push(@{$_[1]}, $_[3]); $_[1] }
183 enum_element: identifier
184 | identifier '=' anytext { "$_[1]$_[2]$_[3]" }
187 bitmap_body: '{' opt_bitmap_elements '}' { $_[2] };
188 opt_bitmap_body: | bitmap_body;
189 bitmap: property_list 'bitmap' optional_identifier opt_bitmap_body
192 "PROPERTIES" => $_[1],
199 bitmap_element { [ $_[1] ] }
200 | bitmap_elements ',' bitmap_element { push(@{$_[1]}, $_[3]); $_[1] }
203 opt_bitmap_elements: | bitmap_elements;
205 bitmap_element: identifier '=' anytext { "$_[1] ( $_[3] )" }
208 struct_body: '{' element_list1 '}' { $_[2] };
209 opt_struct_body: | struct_body;
211 struct: property_list 'struct' optional_identifier opt_struct_body
214 "PROPERTIES" => $_[1],
220 empty_element: property_list ';'
224 "PROPERTIES" => $_[1],
227 "FILE" => $_[0]->YYData->{FILE},
228 "LINE" => $_[0]->YYData->{LINE},
232 base_or_empty: base_element ';' | empty_element;
234 optional_base_element:
235 property_list base_or_empty { $_[2]->{PROPERTIES} = FlattenHash([$_[1],$_[2]->{PROPERTIES}]); $_[2] }
240 | union_elements optional_base_element { push(@{$_[1]}, $_[2]); $_[1] }
243 union_body: '{' union_elements '}' { $_[2] };
244 opt_union_body: | union_body;
246 union: property_list 'union' optional_identifier opt_union_body
249 "PROPERTIES" => $_[1],
255 base_element: property_list type pointers identifier array_len
259 "PROPERTIES" => $_[1],
261 "ARRAY_LEN" => $_[5],
262 "FILE" => $_[0]->YYData->{FILE},
263 "LINE" => $_[0]->YYData->{LINE},
271 | pointers '*' { $_[1]+1 }
276 | element_list1 base_element ';' { push(@{$_[1]}, $_[2]); $_[1] }
287 | optional_const base_element { [ $_[2] ] }
288 | element_list2 ',' optional_const base_element { push(@{$_[1]}, $_[4]); $_[1] }
293 | '[' ']' array_len { push(@{$_[3]}, "*"); $_[3] }
294 | '[' anytext ']' array_len { push(@{$_[4]}, "$_[2]"); $_[4] }
300 | property_list '[' properties ']' { FlattenHash([$_[1],$_[3]]); }
303 properties: property { $_[1] }
304 | properties ',' property { FlattenHash([$_[1], $_[3]]); }
307 property: identifier {{ "$_[1]" => "1" }}
308 | identifier '(' commalisttext ')' {{ "$_[1]" => "$_[3]" }}
313 | commalisttext ',' anytext { "$_[1],$_[3]" }
318 | identifier | constant | text
319 | anytext '-' anytext { "$_[1]$_[2]$_[3]" }
320 | anytext '.' anytext { "$_[1]$_[2]$_[3]" }
321 | anytext '*' anytext { "$_[1]$_[2]$_[3]" }
322 | anytext '>' anytext { "$_[1]$_[2]$_[3]" }
323 | anytext '<' anytext { "$_[1]$_[2]$_[3]" }
324 | anytext '|' anytext { "$_[1]$_[2]$_[3]" }
325 | anytext '&' anytext { "$_[1]$_[2]$_[3]" }
326 | anytext '/' anytext { "$_[1]$_[2]$_[3]" }
327 | anytext '?' anytext { "$_[1]$_[2]$_[3]" }
328 | anytext ':' anytext { "$_[1]$_[2]$_[3]" }
329 | anytext '=' anytext { "$_[1]$_[2]$_[3]" }
330 | anytext '+' anytext { "$_[1]$_[2]$_[3]" }
331 | anytext '~' anytext { "$_[1]$_[2]$_[3]" }
332 | anytext '(' commalisttext ')' anytext { "$_[1]$_[2]$_[3]$_[4]$_[5]" }
333 | anytext '{' commalisttext '}' anytext { "$_[1]$_[2]$_[3]$_[4]$_[5]" }
336 identifier: IDENTIFIER
347 text: TEXT { "\"$_[1]\"" }
356 #####################################
360 use Parse::Pidl qw(error);
362 #####################################################################
363 # flatten an array of hashes into a single hash
369 for my $k (keys %{$d}) {
378 #####################################################################
379 # traverse a perl data structure removing any empty arrays or
380 # hashes and any hash elements that map to undef
385 return undef if (not defined($v));
386 if (ref($v) eq "ARRAY") {
387 foreach my $i (0 .. $#{$v}) {
390 # this removes any undefined elements from the array
391 @{$v} = grep { defined $_ } @{$v};
392 } elsif (ref($v) eq "HASH") {
393 foreach my $x (keys %{$v}) {
395 if (!defined $v->{$x}) { delete($v->{$x}); next; }
402 if (exists $_[0]->YYData->{ERRMSG}) {
403 error($_[0]->YYData, $_[0]->YYData->{ERRMSG});
404 delete $_[0]->YYData->{ERRMSG};
407 my $last_token = $_[0]->YYData->{LAST_TOKEN};
409 error($_[0]->YYData, "Syntax error near '$last_token'");
416 $parser->YYData->{INPUT} or return('',undef);
419 $parser->YYData->{INPUT} =~ s/^[ \t]*//;
421 for ($parser->YYData->{INPUT}) {
423 if (s/^\# (\d+) \"(.*?)\"( \d+|)//) {
424 $parser->YYData->{LINE} = $1-1;
425 $parser->YYData->{FILE} = $2;
428 if (s/^\#line (\d+) \"(.*?)\"( \d+|)//) {
429 $parser->YYData->{LINE} = $1-1;
430 $parser->YYData->{FILE} = $2;
438 $parser->YYData->{LINE}++;
441 if (s/^\"(.*?)\"//) {
442 $parser->YYData->{LAST_TOKEN} = $1;
445 if (s/^(\d+)(\W|$)/$2/) {
446 $parser->YYData->{LAST_TOKEN} = $1;
447 return('CONSTANT',$1);
450 $parser->YYData->{LAST_TOKEN} = $1;
452 /^(coclass|interface|const|typedef|union|cpp_quote
453 |struct|enum|bitmap|void|unsigned|signed|import|include
457 return('IDENTIFIER',$1);
460 $parser->YYData->{LAST_TOKEN} = $1;
468 my ($data,$filename) = @_;
470 my $self = new Parse::Pidl::IDL;
472 $self->YYData->{FILE} = $filename;
473 $self->YYData->{INPUT} = $data;
474 $self->YYData->{LINE} = 0;
475 $self->YYData->{LAST_TOKEN} = "NONE";
477 my $idl = $self->YYParse( yylex => \&_Lexer, yyerror => \&_Error );
479 return CleanData($idl);
484 my ($filename,$incdirs) = @_;
486 my $saved_delim = $/;
489 if (! defined $cpp) {
492 my $includes = join('',map { " -I$_" } @$incdirs);
493 my $data = `$cpp -D__PIDL__$includes -xc $filename`;
496 return parse_string($data, $filename);