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 '-' '+' '&' '|' '*' '>' '.' '/' '(' ')' '[' ',' ';'
20 idl interface { push(@{$_[1]}, $_[2]); $_[1] }
22 idl coclass { push(@{$_[1]}, $_[2]); $_[1] }
24 idl import { push(@{$_[1]}, $_[2]); $_[1] }
26 idl include { push(@{$_[1]}, $_[2]); $_[1] }
28 idl importlib { push(@{$_[1]}, $_[2]); $_[1] }
30 idl cpp_quote { push(@{$_[1]}, $_[2]); $_[1] }
34 'import' commalist ';'
38 "FILE" => $_[0]->YYData->{FILE},
39 "LINE" => $_[0]->YYData->{LINE},
44 'include' commalist ';'
48 "FILE" => $_[0]->YYData->{FILE},
49 "LINE" => $_[0]->YYData->{LINE},
54 'importlib' commalist ';'
56 "TYPE" => "IMPORTLIB",
58 "FILE" => $_[0]->YYData->{FILE},
59 "LINE" => $_[0]->YYData->{LINE},
66 commalist ',' text { push(@{$_[1]}, $_[3]); $_[1] }
70 property_list 'coclass' identifier '{' interface_names '}' optional_semicolon
73 "PROPERTIES" => $_[1],
76 "FILE" => $_[0]->YYData->{FILE},
77 "LINE" => $_[0]->YYData->{LINE},
84 interface_names 'interface' identifier ';' { push(@{$_[1]}, $_[2]); $_[1] }
88 property_list 'interface' identifier base_interface '{' definitions '}' optional_semicolon
90 "TYPE" => "INTERFACE",
91 "PROPERTIES" => $_[1],
95 "FILE" => $_[0]->YYData->{FILE},
96 "LINE" => $_[0]->YYData->{LINE},
103 ':' identifier { $_[2] }
108 'cpp_quote' '(' text ')'
110 "TYPE" => "CPP_QUOTE",
112 "FILE" => $_[0]->YYData->{FILE},
113 "LINE" => $_[0]->YYData->{LINE},
118 definition { [ $_[1] ] }
120 definitions definition { push(@{$_[1]}, $_[2]); $_[1] }
134 'const' identifier pointers identifier '=' anytext ';'
141 "FILE" => $_[0]->YYData->{FILE},
142 "LINE" => $_[0]->YYData->{LINE},
145 'const' identifier pointers identifier array_len '=' anytext ';'
151 "ARRAY_LEN" => $_[5],
153 "FILE" => $_[0]->YYData->{FILE},
154 "LINE" => $_[0]->YYData->{LINE},
159 property_list type identifier '(' element_list2 ')' ';'
161 "TYPE" => "FUNCTION",
163 "RETURN_TYPE" => $_[2],
164 "PROPERTIES" => $_[1],
166 "FILE" => $_[0]->YYData->{FILE},
167 "LINE" => $_[0]->YYData->{LINE},
172 property_list 'typedef' type identifier array_len ';'
175 "PROPERTIES" => $_[1],
178 "ARRAY_LEN" => $_[5],
179 "FILE" => $_[0]->YYData->{FILE},
180 "LINE" => $_[0]->YYData->{LINE},
195 usertype ';' { $_[1] }
205 sign identifier { ($_[1]?$_[1]:"signed") ." $_[2]" }
219 '{' enum_elements '}' { $_[2] }
229 property_list 'enum' optional_identifier opt_enum_body
232 "PROPERTIES" => $_[1],
235 "FILE" => $_[0]->YYData->{FILE},
236 "LINE" => $_[0]->YYData->{LINE},
241 enum_element { [ $_[1] ] }
243 enum_elements ',' enum_element { push(@{$_[1]}, $_[3]); $_[1] }
249 identifier '=' anytext { "$_[1]$_[2]$_[3]" }
253 '{' opt_bitmap_elements '}' { $_[2] }
263 property_list 'bitmap' optional_identifier opt_bitmap_body
266 "PROPERTIES" => $_[1],
269 "FILE" => $_[0]->YYData->{FILE},
270 "LINE" => $_[0]->YYData->{LINE},
275 bitmap_element { [ $_[1] ] }
277 bitmap_elements ',' bitmap_element { push(@{$_[1]}, $_[3]); $_[1] }
287 identifier '=' anytext { "$_[1] ( $_[3] )" }
291 '{' element_list1 '}' { $_[2] }
301 property_list 'struct' optional_identifier opt_struct_body
304 "PROPERTIES" => $_[1],
307 "FILE" => $_[0]->YYData->{FILE},
308 "LINE" => $_[0]->YYData->{LINE},
317 "PROPERTIES" => $_[1],
320 "FILE" => $_[0]->YYData->{FILE},
321 "LINE" => $_[0]->YYData->{LINE},
330 optional_base_element:
331 property_list base_or_empty { $_[2]->{PROPERTIES} = FlattenHash([$_[1],$_[2]->{PROPERTIES}]); $_[2] }
337 union_elements optional_base_element { push(@{$_[1]}, $_[2]); $_[1] }
341 '{' union_elements '}' { $_[2] }
351 property_list 'union' optional_identifier opt_union_body
354 "PROPERTIES" => $_[1],
357 "FILE" => $_[0]->YYData->{FILE},
358 "LINE" => $_[0]->YYData->{LINE},
363 property_list type pointers identifier array_len
367 "PROPERTIES" => $_[1],
369 "ARRAY_LEN" => $_[5],
370 "FILE" => $_[0]->YYData->{FILE},
371 "LINE" => $_[0]->YYData->{LINE},
379 pointers '*' { $_[1]+1 }
386 element_list1 base_element ';' { push(@{$_[1]}, $_[2]); $_[1] }
400 optional_const base_element { [ $_[2] ] }
402 element_list2 ',' optional_const base_element { push(@{$_[1]}, $_[4]); $_[1] }
408 '[' ']' array_len { push(@{$_[3]}, "*"); $_[3] }
410 '[' anytext ']' array_len { push(@{$_[4]}, "$_[2]"); $_[4] }
416 property_list '[' properties ']' { FlattenHash([$_[1],$_[3]]); }
422 properties ',' property { FlattenHash([$_[1], $_[3]]); }
426 identifier {{ "$_[1]" => "1" }}
428 identifier '(' commalisttext ')' {{ "$_[1]" => "$_[3]" }}
434 commalisttext ',' anytext { "$_[1],$_[3]" }
447 anytext '-' anytext { "$_[1]$_[2]$_[3]" }
449 anytext '.' anytext { "$_[1]$_[2]$_[3]" }
451 anytext '*' anytext { "$_[1]$_[2]$_[3]" }
453 anytext '>' anytext { "$_[1]$_[2]$_[3]" }
455 anytext '<' anytext { "$_[1]$_[2]$_[3]" }
457 anytext '|' anytext { "$_[1]$_[2]$_[3]" }
459 anytext '&' anytext { "$_[1]$_[2]$_[3]" }
461 anytext '/' anytext { "$_[1]$_[2]$_[3]" }
463 anytext '?' anytext { "$_[1]$_[2]$_[3]" }
465 anytext ':' anytext { "$_[1]$_[2]$_[3]" }
467 anytext '=' anytext { "$_[1]$_[2]$_[3]" }
469 anytext '+' anytext { "$_[1]$_[2]$_[3]" }
471 anytext '~' anytext { "$_[1]$_[2]$_[3]" }
473 anytext '(' commalisttext ')' anytext { "$_[1]$_[2]$_[3]$_[4]$_[5]" }
475 anytext '{' commalisttext '}' anytext { "$_[1]$_[2]$_[3]$_[4]$_[5]" }
503 #####################################
507 use Parse::Pidl qw(error);
509 #####################################################################
510 # flatten an array of hashes into a single hash
516 for my $k (keys %{$d}) {
523 #####################################################################
524 # traverse a perl data structure removing any empty arrays or
525 # hashes and any hash elements that map to undef
531 return undef if (not defined($v));
533 if (ref($v) eq "ARRAY") {
534 foreach my $i (0 .. $#{$v}) {
537 # this removes any undefined elements from the array
538 @{$v} = grep { defined $_ } @{$v};
539 } elsif (ref($v) eq "HASH") {
540 foreach my $x (keys %{$v}) {
542 if (!defined $v->{$x}) {
553 if (exists $_[0]->YYData->{ERRMSG}) {
554 error($_[0]->YYData, $_[0]->YYData->{ERRMSG});
555 delete $_[0]->YYData->{ERRMSG};
559 my $last_token = $_[0]->YYData->{LAST_TOKEN};
561 error($_[0]->YYData, "Syntax error near '$last_token'");
568 $parser->YYData->{INPUT} or return('',undef);
571 $parser->YYData->{INPUT} =~ s/^[ \t]*//;
573 for ($parser->YYData->{INPUT}) {
575 if (s/^\# (\d+) \"(.*?)\"( \d+|)//) {
576 $parser->YYData->{LINE} = $1-1;
577 $parser->YYData->{FILE} = $2;
580 if (s/^\#line (\d+) \"(.*?)\"( \d+|)//) {
581 $parser->YYData->{LINE} = $1-1;
582 $parser->YYData->{FILE} = $2;
590 $parser->YYData->{LINE}++;
593 if (s/^\"(.*?)\"//) {
594 $parser->YYData->{LAST_TOKEN} = $1;
597 if (s/^(\d+)(\W|$)/$2/) {
598 $parser->YYData->{LAST_TOKEN} = $1;
599 return('CONSTANT',$1);
602 $parser->YYData->{LAST_TOKEN} = $1;
604 /^(coclass|interface|import|importlib
605 |include|cpp_quote|typedef
606 |union|struct|enum|bitmap
607 |void|const|unsigned|signed)$/x) {
610 return('IDENTIFIER',$1);
613 $parser->YYData->{LAST_TOKEN} = $1;
621 my ($data,$filename) = @_;
623 my $self = new Parse::Pidl::IDL;
625 $self->YYData->{FILE} = $filename;
626 $self->YYData->{INPUT} = $data;
627 $self->YYData->{LINE} = 0;
628 $self->YYData->{LAST_TOKEN} = "NONE";
630 my $idl = $self->YYParse( yylex => \&_Lexer, yyerror => \&_Error );
632 return CleanData($idl);
637 my ($filename,$incdirs) = @_;
639 my $saved_delim = $/;
642 if (! defined $cpp) {
645 my $includes = join('',map { " -I$_" } @$incdirs);
646 my $data = `$cpp -D__PIDL__$includes -xc $filename`;
649 return parse_string($data, $filename);