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 pointers identifier array_len ';'
175 "PROPERTIES" => $_[1],
179 "ARRAY_LEN" => $_[6],
180 "FILE" => $_[0]->YYData->{FILE},
181 "LINE" => $_[0]->YYData->{LINE},
198 usertype ';' { $_[1] }
208 sign identifier { ($_[1]?$_[1]:"signed") ." $_[2]" }
222 '{' enum_elements '}' { $_[2] }
232 property_list 'enum' optional_identifier opt_enum_body
235 "PROPERTIES" => $_[1],
238 "FILE" => $_[0]->YYData->{FILE},
239 "LINE" => $_[0]->YYData->{LINE},
244 enum_element { [ $_[1] ] }
246 enum_elements ',' enum_element { push(@{$_[1]}, $_[3]); $_[1] }
252 identifier '=' anytext { "$_[1]$_[2]$_[3]" }
256 '{' opt_bitmap_elements '}' { $_[2] }
266 property_list 'bitmap' optional_identifier opt_bitmap_body
269 "PROPERTIES" => $_[1],
272 "FILE" => $_[0]->YYData->{FILE},
273 "LINE" => $_[0]->YYData->{LINE},
278 bitmap_element { [ $_[1] ] }
280 bitmap_elements ',' bitmap_element { push(@{$_[1]}, $_[3]); $_[1] }
290 identifier '=' anytext { "$_[1] ( $_[3] )" }
294 '{' element_list1 '}' { $_[2] }
304 property_list 'struct' optional_identifier opt_struct_body
307 "PROPERTIES" => $_[1],
310 "FILE" => $_[0]->YYData->{FILE},
311 "LINE" => $_[0]->YYData->{LINE},
320 "PROPERTIES" => $_[1],
323 "FILE" => $_[0]->YYData->{FILE},
324 "LINE" => $_[0]->YYData->{LINE},
333 optional_base_element:
334 property_list base_or_empty { $_[2]->{PROPERTIES} = FlattenHash([$_[1],$_[2]->{PROPERTIES}]); $_[2] }
340 union_elements optional_base_element { push(@{$_[1]}, $_[2]); $_[1] }
344 '{' union_elements '}' { $_[2] }
354 property_list 'union' optional_identifier opt_union_body
357 "PROPERTIES" => $_[1],
360 "FILE" => $_[0]->YYData->{FILE},
361 "LINE" => $_[0]->YYData->{LINE},
366 property_list type pointers identifier array_len
370 "PROPERTIES" => $_[1],
372 "ARRAY_LEN" => $_[5],
373 "FILE" => $_[0]->YYData->{FILE},
374 "LINE" => $_[0]->YYData->{LINE},
382 pointers '*' { $_[1]+1 }
386 property_list 'pipe' type
389 "PROPERTIES" => $_[1],
391 "FILE" => $_[0]->YYData->{FILE},
392 "LINE" => $_[0]->YYData->{LINE},
400 element_list1 base_element ';' { push(@{$_[1]}, $_[2]); $_[1] }
414 optional_const base_element { [ $_[2] ] }
416 element_list2 ',' optional_const base_element { push(@{$_[1]}, $_[4]); $_[1] }
422 '[' ']' array_len { push(@{$_[3]}, "*"); $_[3] }
424 '[' anytext ']' array_len { push(@{$_[4]}, "$_[2]"); $_[4] }
430 property_list '[' properties ']' { FlattenHash([$_[1],$_[3]]); }
436 properties ',' property { FlattenHash([$_[1], $_[3]]); }
440 identifier {{ "$_[1]" => "1" }}
442 identifier '(' commalisttext ')' {{ "$_[1]" => "$_[3]" }}
448 commalisttext ',' anytext { "$_[1],$_[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 '&' anytext { "$_[1]$_[2]$_[3]" }
475 anytext '/' anytext { "$_[1]$_[2]$_[3]" }
477 anytext '?' anytext { "$_[1]$_[2]$_[3]" }
479 anytext ':' anytext { "$_[1]$_[2]$_[3]" }
481 anytext '=' anytext { "$_[1]$_[2]$_[3]" }
483 anytext '+' anytext { "$_[1]$_[2]$_[3]" }
485 anytext '~' anytext { "$_[1]$_[2]$_[3]" }
487 anytext '(' commalisttext ')' anytext { "$_[1]$_[2]$_[3]$_[4]$_[5]" }
489 anytext '{' commalisttext '}' anytext { "$_[1]$_[2]$_[3]$_[4]$_[5]" }
517 #####################################
521 use Parse::Pidl qw(error);
523 #####################################################################
524 # flatten an array of hashes into a single hash
530 for my $k (keys %{$d}) {
537 #####################################################################
538 # traverse a perl data structure removing any empty arrays or
539 # hashes and any hash elements that map to undef
545 return undef if (not defined($v));
547 if (ref($v) eq "ARRAY") {
548 foreach my $i (0 .. $#{$v}) {
551 # this removes any undefined elements from the array
552 @{$v} = grep { defined $_ } @{$v};
553 } elsif (ref($v) eq "HASH") {
554 foreach my $x (keys %{$v}) {
556 if (!defined $v->{$x}) {
567 if (exists $_[0]->YYData->{ERRMSG}) {
568 error($_[0]->YYData, $_[0]->YYData->{ERRMSG});
569 delete $_[0]->YYData->{ERRMSG};
573 my $last_token = $_[0]->YYData->{LAST_TOKEN};
575 error($_[0]->YYData, "Syntax error near '$last_token'");
582 $parser->YYData->{INPUT} or return('',undef);
585 $parser->YYData->{INPUT} =~ s/^[ \t]*//;
587 for ($parser->YYData->{INPUT}) {
589 if (s/^\# (\d+) \"(.*?)\"( \d+|)//) {
590 $parser->YYData->{LINE} = $1-1;
591 $parser->YYData->{FILE} = $2;
594 if (s/^\#line (\d+) \"(.*?)\"( \d+|)//) {
595 $parser->YYData->{LINE} = $1-1;
596 $parser->YYData->{FILE} = $2;
604 $parser->YYData->{LINE}++;
607 if (s/^\"(.*?)\"//) {
608 $parser->YYData->{LAST_TOKEN} = $1;
611 if (s/^(\d+)(\W|$)/$2/) {
612 $parser->YYData->{LAST_TOKEN} = $1;
613 return('CONSTANT',$1);
616 $parser->YYData->{LAST_TOKEN} = $1;
618 /^(coclass|interface|import|importlib
619 |include|cpp_quote|typedef
620 |union|struct|enum|bitmap|pipe
621 |void|const|unsigned|signed)$/x) {
624 return('IDENTIFIER',$1);
627 $parser->YYData->{LAST_TOKEN} = $1;
635 my ($data,$filename) = @_;
637 my $self = new Parse::Pidl::IDL;
639 $self->YYData->{FILE} = $filename;
640 $self->YYData->{INPUT} = $data;
641 $self->YYData->{LINE} = 0;
642 $self->YYData->{LAST_TOKEN} = "NONE";
644 my $idl = $self->YYParse( yylex => \&_Lexer, yyerror => \&_Error );
646 return CleanData($idl);
651 my ($filename,$incdirs) = @_;
653 my $saved_delim = $/;
656 if (! defined $cpp) {
659 my $includes = join('',map { " -I$_" } @$incdirs);
660 my $data = `$cpp -D__PIDL__$includes -xc $filename`;
663 return parse_string($data, $filename);