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},
197 usertype ';' { $_[1] }
207 sign identifier { ($_[1]?$_[1]:"signed") ." $_[2]" }
221 '{' enum_elements '}' { $_[2] }
231 property_list 'enum' optional_identifier opt_enum_body
234 "PROPERTIES" => $_[1],
237 "FILE" => $_[0]->YYData->{FILE},
238 "LINE" => $_[0]->YYData->{LINE},
243 enum_element { [ $_[1] ] }
245 enum_elements ',' enum_element { push(@{$_[1]}, $_[3]); $_[1] }
251 identifier '=' anytext { "$_[1]$_[2]$_[3]" }
255 '{' opt_bitmap_elements '}' { $_[2] }
265 property_list 'bitmap' optional_identifier opt_bitmap_body
268 "PROPERTIES" => $_[1],
271 "FILE" => $_[0]->YYData->{FILE},
272 "LINE" => $_[0]->YYData->{LINE},
277 bitmap_element { [ $_[1] ] }
279 bitmap_elements ',' bitmap_element { push(@{$_[1]}, $_[3]); $_[1] }
289 identifier '=' anytext { "$_[1] ( $_[3] )" }
293 '{' element_list1 '}' { $_[2] }
303 property_list 'struct' optional_identifier opt_struct_body
306 "PROPERTIES" => $_[1],
309 "FILE" => $_[0]->YYData->{FILE},
310 "LINE" => $_[0]->YYData->{LINE},
319 "PROPERTIES" => $_[1],
322 "FILE" => $_[0]->YYData->{FILE},
323 "LINE" => $_[0]->YYData->{LINE},
332 optional_base_element:
333 property_list base_or_empty { $_[2]->{PROPERTIES} = FlattenHash([$_[1],$_[2]->{PROPERTIES}]); $_[2] }
339 union_elements optional_base_element { push(@{$_[1]}, $_[2]); $_[1] }
343 '{' union_elements '}' { $_[2] }
353 property_list 'union' optional_identifier opt_union_body
356 "PROPERTIES" => $_[1],
359 "FILE" => $_[0]->YYData->{FILE},
360 "LINE" => $_[0]->YYData->{LINE},
365 property_list type pointers identifier array_len
369 "PROPERTIES" => $_[1],
371 "ARRAY_LEN" => $_[5],
372 "FILE" => $_[0]->YYData->{FILE},
373 "LINE" => $_[0]->YYData->{LINE},
381 pointers '*' { $_[1]+1 }
385 property_list 'pipe' type
388 "PROPERTIES" => $_[1],
390 "FILE" => $_[0]->YYData->{FILE},
391 "LINE" => $_[0]->YYData->{LINE},
399 element_list1 base_element ';' { push(@{$_[1]}, $_[2]); $_[1] }
413 optional_const base_element { [ $_[2] ] }
415 element_list2 ',' optional_const base_element { push(@{$_[1]}, $_[4]); $_[1] }
421 '[' ']' array_len { push(@{$_[3]}, "*"); $_[3] }
423 '[' anytext ']' array_len { push(@{$_[4]}, "$_[2]"); $_[4] }
429 property_list '[' properties ']' { FlattenHash([$_[1],$_[3]]); }
435 properties ',' property { FlattenHash([$_[1], $_[3]]); }
439 identifier {{ "$_[1]" => "1" }}
441 identifier '(' commalisttext ')' {{ "$_[1]" => "$_[3]" }}
447 commalisttext ',' anytext { "$_[1],$_[3]" }
460 anytext '-' anytext { "$_[1]$_[2]$_[3]" }
462 anytext '.' anytext { "$_[1]$_[2]$_[3]" }
464 anytext '*' anytext { "$_[1]$_[2]$_[3]" }
466 anytext '>' anytext { "$_[1]$_[2]$_[3]" }
468 anytext '<' anytext { "$_[1]$_[2]$_[3]" }
470 anytext '|' anytext { "$_[1]$_[2]$_[3]" }
472 anytext '&' anytext { "$_[1]$_[2]$_[3]" }
474 anytext '/' anytext { "$_[1]$_[2]$_[3]" }
476 anytext '?' anytext { "$_[1]$_[2]$_[3]" }
478 anytext ':' anytext { "$_[1]$_[2]$_[3]" }
480 anytext '=' anytext { "$_[1]$_[2]$_[3]" }
482 anytext '+' anytext { "$_[1]$_[2]$_[3]" }
484 anytext '~' anytext { "$_[1]$_[2]$_[3]" }
486 anytext '(' commalisttext ')' anytext { "$_[1]$_[2]$_[3]$_[4]$_[5]" }
488 anytext '{' commalisttext '}' anytext { "$_[1]$_[2]$_[3]$_[4]$_[5]" }
516 #####################################
520 use Parse::Pidl qw(error);
522 #####################################################################
523 # flatten an array of hashes into a single hash
529 for my $k (keys %{$d}) {
536 #####################################################################
537 # traverse a perl data structure removing any empty arrays or
538 # hashes and any hash elements that map to undef
544 return undef if (not defined($v));
546 if (ref($v) eq "ARRAY") {
547 foreach my $i (0 .. $#{$v}) {
550 # this removes any undefined elements from the array
551 @{$v} = grep { defined $_ } @{$v};
552 } elsif (ref($v) eq "HASH") {
553 foreach my $x (keys %{$v}) {
555 if (!defined $v->{$x}) {
566 if (exists $_[0]->YYData->{ERRMSG}) {
567 error($_[0]->YYData, $_[0]->YYData->{ERRMSG});
568 delete $_[0]->YYData->{ERRMSG};
572 my $last_token = $_[0]->YYData->{LAST_TOKEN};
574 error($_[0]->YYData, "Syntax error near '$last_token'");
581 $parser->YYData->{INPUT} or return('',undef);
584 $parser->YYData->{INPUT} =~ s/^[ \t]*//;
586 for ($parser->YYData->{INPUT}) {
588 if (s/^\# (\d+) \"(.*?)\"( \d+|)//) {
589 $parser->YYData->{LINE} = $1-1;
590 $parser->YYData->{FILE} = $2;
593 if (s/^\#line (\d+) \"(.*?)\"( \d+|)//) {
594 $parser->YYData->{LINE} = $1-1;
595 $parser->YYData->{FILE} = $2;
603 $parser->YYData->{LINE}++;
606 if (s/^\"(.*?)\"//) {
607 $parser->YYData->{LAST_TOKEN} = $1;
610 if (s/^(\d+)(\W|$)/$2/) {
611 $parser->YYData->{LAST_TOKEN} = $1;
612 return('CONSTANT',$1);
615 $parser->YYData->{LAST_TOKEN} = $1;
617 /^(coclass|interface|import|importlib
618 |include|cpp_quote|typedef
619 |union|struct|enum|bitmap|pipe
620 |void|const|unsigned|signed)$/x) {
623 return('IDENTIFIER',$1);
626 $parser->YYData->{LAST_TOKEN} = $1;
634 my ($data,$filename) = @_;
636 my $self = new Parse::Pidl::IDL;
638 $self->YYData->{FILE} = $filename;
639 $self->YYData->{INPUT} = $data;
640 $self->YYData->{LINE} = 0;
641 $self->YYData->{LAST_TOKEN} = "NONE";
643 my $idl = $self->YYParse( yylex => \&_Lexer, yyerror => \&_Error );
645 return CleanData($idl);
650 my ($filename,$incdirs) = @_;
652 my $saved_delim = $/;
655 if (! defined $cpp) {
658 my $includes = join('',map { " -I$_" } @$incdirs);
659 my $data = `$cpp -D__PIDL__$includes -xc $filename`;
662 return parse_string($data, $filename);