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 '{' definitions '}' optional_semicolon
72 "TYPE" => "INTERFACE",
73 "PROPERTIES" => $_[1],
76 "FILE" => $_[0]->YYData->{FILE},
77 "LINE" => $_[0]->YYData->{LINE},
81 cpp_quote: 'cpp_quote' '(' text ')'
83 "TYPE" => "CPP_QUOTE",
84 "FILE" => $_[0]->YYData->{FILE},
85 "LINE" => $_[0]->YYData->{LINE},
91 definition { [ $_[1] ] }
92 | definitions definition { push(@{$_[1]}, $_[2]); $_[1] }
96 definition: function | const | typedef | typedecl
99 const: 'const' identifier pointers identifier '=' anytext ';'
106 "FILE" => $_[0]->YYData->{FILE},
107 "LINE" => $_[0]->YYData->{LINE},
109 | 'const' identifier pointers identifier array_len '=' anytext ';'
115 "ARRAY_LEN" => $_[5],
117 "FILE" => $_[0]->YYData->{FILE},
118 "LINE" => $_[0]->YYData->{LINE},
123 function: property_list type identifier '(' element_list2 ')' ';'
125 "TYPE" => "FUNCTION",
127 "RETURN_TYPE" => $_[2],
128 "PROPERTIES" => $_[1],
130 "FILE" => $_[0]->YYData->{FILE},
131 "LINE" => $_[0]->YYData->{LINE},
135 typedef: property_list 'typedef' type identifier array_len ';'
138 "PROPERTIES" => $_[1],
141 "ARRAY_LEN" => $_[5],
142 "FILE" => $_[0]->YYData->{FILE},
143 "LINE" => $_[0]->YYData->{LINE},
147 usertype: struct | union | enum | bitmap;
149 typedecl: usertype ';' { $_[1] };
151 sign: 'signed' | 'unsigned';
154 sign identifier { ($_[1]?$_[1]:"signed") ." $_[2]" }
158 type: usertype | existingtype | void { "void" } ;
160 enum_body: '{' enum_elements '}' { $_[2] };
161 opt_enum_body: | enum_body;
162 enum: property_list 'enum' optional_identifier opt_enum_body
165 "PROPERTIES" => $_[1],
172 enum_element { [ $_[1] ] }
173 | enum_elements ',' enum_element { push(@{$_[1]}, $_[3]); $_[1] }
176 enum_element: identifier
177 | identifier '=' anytext { "$_[1]$_[2]$_[3]" }
180 bitmap_body: '{' opt_bitmap_elements '}' { $_[2] };
181 opt_bitmap_body: | bitmap_body;
182 bitmap: property_list 'bitmap' optional_identifier opt_bitmap_body
185 "PROPERTIES" => $_[1],
192 bitmap_element { [ $_[1] ] }
193 | bitmap_elements ',' bitmap_element { push(@{$_[1]}, $_[3]); $_[1] }
196 opt_bitmap_elements: | bitmap_elements;
198 bitmap_element: identifier '=' anytext { "$_[1] ( $_[3] )" }
201 struct_body: '{' element_list1 '}' { $_[2] };
202 opt_struct_body: | struct_body;
204 struct: property_list 'struct' optional_identifier opt_struct_body
207 "PROPERTIES" => $_[1],
213 empty_element: property_list ';'
217 "PROPERTIES" => $_[1],
220 "FILE" => $_[0]->YYData->{FILE},
221 "LINE" => $_[0]->YYData->{LINE},
225 base_or_empty: base_element ';' | empty_element;
227 optional_base_element:
228 property_list base_or_empty { $_[2]->{PROPERTIES} = FlattenHash([$_[1],$_[2]->{PROPERTIES}]); $_[2] }
233 | union_elements optional_base_element { push(@{$_[1]}, $_[2]); $_[1] }
236 union_body: '{' union_elements '}' { $_[2] };
237 opt_union_body: | union_body;
239 union: property_list 'union' optional_identifier opt_union_body
242 "PROPERTIES" => $_[1],
248 base_element: property_list type pointers identifier array_len
252 "PROPERTIES" => $_[1],
254 "ARRAY_LEN" => $_[5],
255 "FILE" => $_[0]->YYData->{FILE},
256 "LINE" => $_[0]->YYData->{LINE},
264 | pointers '*' { $_[1]+1 }
269 | element_list1 base_element ';' { push(@{$_[1]}, $_[2]); $_[1] }
275 | base_element { [ $_[1] ] }
276 | element_list2 ',' base_element { push(@{$_[1]}, $_[3]); $_[1] }
281 | '[' ']' array_len { push(@{$_[3]}, "*"); $_[3] }
282 | '[' anytext ']' array_len { push(@{$_[4]}, "$_[2]"); $_[4] }
288 | property_list '[' properties ']' { FlattenHash([$_[1],$_[3]]); }
291 properties: property { $_[1] }
292 | properties ',' property { FlattenHash([$_[1], $_[3]]); }
295 property: identifier {{ "$_[1]" => "1" }}
296 | identifier '(' commalisttext ')' {{ "$_[1]" => "$_[3]" }}
301 | commalisttext ',' anytext { "$_[1],$_[3]" }
306 | identifier | constant | text
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 '<' anytext { "$_[1]$_[2]$_[3]" }
312 | anytext '|' anytext { "$_[1]$_[2]$_[3]" }
313 | anytext '&' anytext { "$_[1]$_[2]$_[3]" }
314 | anytext '/' anytext { "$_[1]$_[2]$_[3]" }
315 | anytext '?' anytext { "$_[1]$_[2]$_[3]" }
316 | anytext ':' anytext { "$_[1]$_[2]$_[3]" }
317 | anytext '=' anytext { "$_[1]$_[2]$_[3]" }
318 | anytext '+' anytext { "$_[1]$_[2]$_[3]" }
319 | anytext '~' anytext { "$_[1]$_[2]$_[3]" }
320 | anytext '(' commalisttext ')' anytext { "$_[1]$_[2]$_[3]$_[4]$_[5]" }
321 | anytext '{' commalisttext '}' anytext { "$_[1]$_[2]$_[3]$_[4]$_[5]" }
324 identifier: IDENTIFIER
335 text: TEXT { "\"$_[1]\"" }
344 #####################################
348 use Parse::Pidl qw(error);
350 #####################################################################
351 # flatten an array of hashes into a single hash
357 for my $k (keys %{$d}) {
366 #####################################################################
367 # traverse a perl data structure removing any empty arrays or
368 # hashes and any hash elements that map to undef
373 return undef if (not defined($v));
374 if (ref($v) eq "ARRAY") {
375 foreach my $i (0 .. $#{$v}) {
378 # this removes any undefined elements from the array
379 @{$v} = grep { defined $_ } @{$v};
380 } elsif (ref($v) eq "HASH") {
381 foreach my $x (keys %{$v}) {
383 if (!defined $v->{$x}) { delete($v->{$x}); next; }
390 if (exists $_[0]->YYData->{ERRMSG}) {
391 error($_[0]->YYData, $_[0]->YYData->{ERRMSG});
392 delete $_[0]->YYData->{ERRMSG};
395 my $last_token = $_[0]->YYData->{LAST_TOKEN};
397 error($_[0]->YYData, "Syntax error near '$last_token'");
404 $parser->YYData->{INPUT} or return('',undef);
407 $parser->YYData->{INPUT} =~ s/^[ \t]*//;
409 for ($parser->YYData->{INPUT}) {
411 if (s/^\# (\d+) \"(.*?)\"( \d+|)//) {
412 $parser->YYData->{LINE} = $1-1;
413 $parser->YYData->{FILE} = $2;
416 if (s/^\#line (\d+) \"(.*?)\"( \d+|)//) {
417 $parser->YYData->{LINE} = $1-1;
418 $parser->YYData->{FILE} = $2;
426 $parser->YYData->{LINE}++;
429 if (s/^\"(.*?)\"//) {
430 $parser->YYData->{LAST_TOKEN} = $1;
433 if (s/^(\d+)(\W|$)/$2/) {
434 $parser->YYData->{LAST_TOKEN} = $1;
435 return('CONSTANT',$1);
438 $parser->YYData->{LAST_TOKEN} = $1;
440 /^(coclass|interface|const|typedef|union|cpp_quote
441 |struct|enum|bitmap|void|unsigned|signed|import|include
445 return('IDENTIFIER',$1);
448 $parser->YYData->{LAST_TOKEN} = $1;
456 my ($data,$filename) = @_;
458 my $self = new Parse::Pidl::IDL;
460 $self->YYData->{FILE} = $filename;
461 $self->YYData->{INPUT} = $data;
462 $self->YYData->{LINE} = 0;
463 $self->YYData->{LAST_TOKEN} = "NONE";
465 my $idl = $self->YYParse( yylex => \&_Lexer, yyerror => \&_Error );
467 return CleanData($idl);
472 my ($filename,$incdirs) = @_;
474 my $saved_delim = $/;
477 if (! defined $cpp) {
480 my $includes = join('',map { " -I$_" } @$incdirs);
481 my $data = `$cpp -D__PIDL__$includes -xc $filename`;
484 return parse_string($data, $filename);