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],
393 "PROPERTIES" => $_[1],
397 "PROPERTIES" => $_[1],
400 "TYPE" => "uint3264",
401 "FILE" => $_[0]->YYData->{FILE},
402 "LINE" => $_[0]->YYData->{LINE},
405 "PROPERTIES" => $_[1],
407 "ARRAY_LEN" => [ "count" ],
409 "FILE" => $_[0]->YYData->{FILE},
410 "LINE" => $_[0]->YYData->{LINE},
412 "FILE" => $_[0]->YYData->{FILE},
413 "LINE" => $_[0]->YYData->{LINE},
415 "FILE" => $_[0]->YYData->{FILE},
416 "LINE" => $_[0]->YYData->{LINE},
424 element_list1 base_element ';' { push(@{$_[1]}, $_[2]); $_[1] }
438 optional_const base_element { [ $_[2] ] }
440 element_list2 ',' optional_const base_element { push(@{$_[1]}, $_[4]); $_[1] }
446 '[' ']' array_len { push(@{$_[3]}, "*"); $_[3] }
448 '[' anytext ']' array_len { push(@{$_[4]}, "$_[2]"); $_[4] }
454 property_list '[' properties ']' { FlattenHash([$_[1],$_[3]]); }
460 properties ',' property { FlattenHash([$_[1], $_[3]]); }
464 identifier {{ "$_[1]" => "1" }}
466 identifier '(' commalisttext ')' {{ "$_[1]" => "$_[3]" }}
472 commalisttext ',' anytext { "$_[1],$_[3]" }
485 anytext '-' anytext { "$_[1]$_[2]$_[3]" }
487 anytext '.' anytext { "$_[1]$_[2]$_[3]" }
489 anytext '*' anytext { "$_[1]$_[2]$_[3]" }
491 anytext '>' anytext { "$_[1]$_[2]$_[3]" }
493 anytext '<' anytext { "$_[1]$_[2]$_[3]" }
495 anytext '|' anytext { "$_[1]$_[2]$_[3]" }
497 anytext '&' anytext { "$_[1]$_[2]$_[3]" }
499 anytext '/' anytext { "$_[1]$_[2]$_[3]" }
501 anytext '?' anytext { "$_[1]$_[2]$_[3]" }
503 anytext ':' anytext { "$_[1]$_[2]$_[3]" }
505 anytext '=' anytext { "$_[1]$_[2]$_[3]" }
507 anytext '+' anytext { "$_[1]$_[2]$_[3]" }
509 anytext '~' anytext { "$_[1]$_[2]$_[3]" }
511 anytext '(' commalisttext ')' anytext { "$_[1]$_[2]$_[3]$_[4]$_[5]" }
513 anytext '{' commalisttext '}' anytext { "$_[1]$_[2]$_[3]$_[4]$_[5]" }
541 #####################################
545 use Parse::Pidl qw(error);
547 #####################################################################
548 # flatten an array of hashes into a single hash
554 for my $k (keys %{$d}) {
561 #####################################################################
562 # traverse a perl data structure removing any empty arrays or
563 # hashes and any hash elements that map to undef
569 return undef if (not defined($v));
571 if (ref($v) eq "ARRAY") {
572 foreach my $i (0 .. $#{$v}) {
575 # this removes any undefined elements from the array
576 @{$v} = grep { defined $_ } @{$v};
577 } elsif (ref($v) eq "HASH") {
578 foreach my $x (keys %{$v}) {
580 if (!defined $v->{$x}) {
591 if (exists $_[0]->YYData->{ERRMSG}) {
592 error($_[0]->YYData, $_[0]->YYData->{ERRMSG});
593 delete $_[0]->YYData->{ERRMSG};
597 my $last_token = $_[0]->YYData->{LAST_TOKEN};
599 error($_[0]->YYData, "Syntax error near '$last_token'");
606 $parser->YYData->{INPUT} or return('',undef);
609 $parser->YYData->{INPUT} =~ s/^[ \t]*//;
611 for ($parser->YYData->{INPUT}) {
613 # Linemarker format is described at
614 # http://gcc.gnu.org/onlinedocs/cpp/Preprocessor-Output.html
615 if (s/^\# (\d+) \"(.*?)\"(( \d+){1,4}|)//) {
616 $parser->YYData->{LINE} = $1-1;
617 $parser->YYData->{FILE} = $2;
620 if (s/^\#line (\d+) \"(.*?)\"( \d+|)//) {
621 $parser->YYData->{LINE} = $1-1;
622 $parser->YYData->{FILE} = $2;
630 $parser->YYData->{LINE}++;
633 if (s/^\"(.*?)\"//) {
634 $parser->YYData->{LAST_TOKEN} = $1;
637 if (s/^(\d+)(\W|$)/$2/) {
638 $parser->YYData->{LAST_TOKEN} = $1;
639 return('CONSTANT',$1);
642 $parser->YYData->{LAST_TOKEN} = $1;
644 /^(coclass|interface|import|importlib
645 |include|cpp_quote|typedef
646 |union|struct|enum|bitmap|pipe
647 |void|const|unsigned|signed)$/x) {
650 return('IDENTIFIER',$1);
653 $parser->YYData->{LAST_TOKEN} = $1;
661 my ($data,$filename) = @_;
663 my $self = new Parse::Pidl::IDL;
665 $self->YYData->{FILE} = $filename;
666 $self->YYData->{INPUT} = $data;
667 $self->YYData->{LINE} = 0;
668 $self->YYData->{LAST_TOKEN} = "NONE";
670 my $idl = $self->YYParse( yylex => \&_Lexer, yyerror => \&_Error );
672 return CleanData($idl);
677 my ($filename,$incdirs) = @_;
679 my $saved_delim = $/;
683 if (! defined $cpp) {
684 if (defined $ENV{CC}) {
691 my $includes = join('',map { " -I$_" } @$incdirs);
692 my $data = `$cpp $options -D__PIDL__$includes -xc "$filename"`;
695 return parse_string($data, $filename);