torture: complete dfs referral tests
[Samba/gebeck_regimport.git] / pidl / idl.yp
blobb3d5ed16ac0657c1d5994531aeed720629528400
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
10 # enormously
11 %left   '-' '+' '&' '|' '*' '>' '.' '/' '(' ')' '[' ',' ';'
14 ################
15 # grammar
17 idl: 
18         #empty  { {} }
19         |
20         idl interface { push(@{$_[1]}, $_[2]); $_[1] }
21         |
22         idl coclass   { push(@{$_[1]}, $_[2]); $_[1] }
23         |
24         idl import    { push(@{$_[1]}, $_[2]); $_[1] }
25         |
26         idl include   { push(@{$_[1]}, $_[2]); $_[1] }
27         |
28         idl importlib { push(@{$_[1]}, $_[2]); $_[1] }
29         |
30         idl cpp_quote { push(@{$_[1]}, $_[2]); $_[1] }
33 import:
34         'import' commalist ';'
35         {{
36                 "TYPE" => "IMPORT",
37                 "PATHS" => $_[2],
38                 "FILE" => $_[0]->YYData->{FILE},
39                 "LINE" => $_[0]->YYData->{LINE},
40         }}
43 include:
44         'include' commalist ';'
45         {{
46                 "TYPE" => "INCLUDE",
47                 "PATHS" => $_[2],
48                 "FILE" => $_[0]->YYData->{FILE},
49                 "LINE" => $_[0]->YYData->{LINE},
50         }}
53 importlib:
54         'importlib' commalist ';'
55         {{
56                 "TYPE" => "IMPORTLIB",
57                 "PATHS" => $_[2],
58                 "FILE" => $_[0]->YYData->{FILE},
59                 "LINE" => $_[0]->YYData->{LINE},
60         }}
63 commalist:
64         text { [ $_[1] ] }
65         |
66         commalist ',' text { push(@{$_[1]}, $_[3]); $_[1] }
69 coclass:
70         property_list 'coclass' identifier '{' interface_names '}' optional_semicolon
71         {{
72                 "TYPE" => "COCLASS",
73                 "PROPERTIES" => $_[1],
74                 "NAME" => $_[3],
75                 "DATA" => $_[5],
76                 "FILE" => $_[0]->YYData->{FILE},
77                 "LINE" => $_[0]->YYData->{LINE},
78         }}
81 interface_names:
82         #empty { {} }
83         |
84         interface_names 'interface' identifier ';' { push(@{$_[1]}, $_[2]); $_[1] }
87 interface:
88         property_list 'interface' identifier base_interface '{' definitions '}' optional_semicolon
89         {{
90                 "TYPE" => "INTERFACE",
91                 "PROPERTIES" => $_[1],
92                 "NAME" => $_[3],
93                 "BASE" => $_[4],
94                 "DATA" => $_[6],
95                 "FILE" => $_[0]->YYData->{FILE},
96                 "LINE" => $_[0]->YYData->{LINE},
97         }}
100 base_interface:
101         #empty
102         |
103         ':' identifier { $_[2] }
107 cpp_quote:
108         'cpp_quote' '(' text ')'
109         {{
110                  "TYPE" => "CPP_QUOTE",
111                  "DATA" => $_[3],
112                  "FILE" => $_[0]->YYData->{FILE},
113                  "LINE" => $_[0]->YYData->{LINE},
114         }}
117 definitions:
118         definition              { [ $_[1] ] }
119         |
120         definitions definition  { push(@{$_[1]}, $_[2]); $_[1] }
123 definition:
124         function
125         |
126         const
127         |
128         typedef
129         |
130         typedecl
133 const:
134         'const' identifier pointers identifier '=' anytext ';'
135         {{
136                 "TYPE"  => "CONST",
137                 "DTYPE"  => $_[2],
138                 "POINTERS" => $_[3],
139                 "NAME"  => $_[4],
140                 "VALUE" => $_[6],
141                 "FILE" => $_[0]->YYData->{FILE},
142                 "LINE" => $_[0]->YYData->{LINE},
143         }}
144         |
145         'const' identifier pointers identifier array_len '=' anytext ';'
146         {{
147                 "TYPE"  => "CONST",
148                 "DTYPE"  => $_[2],
149                 "POINTERS" => $_[3],
150                 "NAME"  => $_[4],
151                 "ARRAY_LEN" => $_[5],
152                 "VALUE" => $_[7],
153                 "FILE" => $_[0]->YYData->{FILE},
154                 "LINE" => $_[0]->YYData->{LINE},
155         }}
158 function:
159         property_list type identifier '(' element_list2 ')' ';'
160         {{
161                 "TYPE" => "FUNCTION",
162                 "NAME" => $_[3],
163                 "RETURN_TYPE" => $_[2],
164                 "PROPERTIES" => $_[1],
165                 "ELEMENTS" => $_[5],
166                 "FILE" => $_[0]->YYData->{FILE},
167                 "LINE" => $_[0]->YYData->{LINE},
168         }}
171 typedef:
172         property_list 'typedef' type pointers identifier array_len ';'
173         {{
174                 "TYPE" => "TYPEDEF",
175                 "PROPERTIES" => $_[1],
176                 "NAME" => $_[5],
177                 "DATA" => $_[3],
178                 "POINTERS" => $_[4],
179                 "ARRAY_LEN" => $_[6],
180                 "FILE" => $_[0]->YYData->{FILE},
181                 "LINE" => $_[0]->YYData->{LINE},
182         }}
185 usertype:
186         struct
187         |
188         union
189         |
190         enum
191         |
192         bitmap
193         |
194         pipe
197 typedecl:
198         usertype ';' { $_[1] }
201 sign:
202         'signed'
203         |
204         'unsigned'
207 existingtype:
208         sign identifier { ($_[1]?$_[1]:"signed") ." $_[2]" }
209         |
210         identifier
213 type:
214         usertype
215         |
216         existingtype
217         |
218         void { "void" }
221 enum_body:
222         '{' enum_elements '}' { $_[2] }
225 opt_enum_body:
226         #empty
227         |
228         enum_body
231 enum:
232         property_list 'enum' optional_identifier opt_enum_body
233         {{
234                 "TYPE" => "ENUM",
235                 "PROPERTIES" => $_[1],
236                 "NAME" => $_[3],
237                 "ELEMENTS" => $_[4],
238                 "FILE" => $_[0]->YYData->{FILE},
239                 "LINE" => $_[0]->YYData->{LINE},
240         }}
243 enum_elements:
244         enum_element                    { [ $_[1] ] }
245         |
246         enum_elements ',' enum_element  { push(@{$_[1]}, $_[3]); $_[1] }
249 enum_element:
250         identifier
251         |
252         identifier '=' anytext { "$_[1]$_[2]$_[3]" }
255 bitmap_body:
256         '{' opt_bitmap_elements '}' { $_[2] }
259 opt_bitmap_body:
260         #empty
261         |
262         bitmap_body
265 bitmap:
266         property_list 'bitmap' optional_identifier opt_bitmap_body
267         {{
268                 "TYPE" => "BITMAP",
269                 "PROPERTIES" => $_[1],
270                 "NAME" => $_[3],
271                 "ELEMENTS" => $_[4],
272                 "FILE" => $_[0]->YYData->{FILE},
273                 "LINE" => $_[0]->YYData->{LINE},
274         }}
277 bitmap_elements:
278         bitmap_element                      { [ $_[1] ] }
279         |
280         bitmap_elements ',' bitmap_element  { push(@{$_[1]}, $_[3]); $_[1] }
283 opt_bitmap_elements:
284         #empty
285         |
286         bitmap_elements
289 bitmap_element:
290         identifier '=' anytext { "$_[1] ( $_[3] )" }
293 struct_body:
294         '{' element_list1 '}' { $_[2] }
297 opt_struct_body:
298         #empty
299         |
300         struct_body
303 struct:
304         property_list 'struct' optional_identifier opt_struct_body
305         {{
306                 "TYPE" => "STRUCT",
307                 "PROPERTIES" => $_[1],
308                 "NAME" => $_[3],
309                 "ELEMENTS" => $_[4],
310                 "FILE" => $_[0]->YYData->{FILE},
311                 "LINE" => $_[0]->YYData->{LINE},
312         }}
315 empty_element:
316         property_list ';'
317         {{
318                 "NAME" => "",
319                 "TYPE" => "EMPTY",
320                 "PROPERTIES" => $_[1],
321                 "POINTERS" => 0,
322                 "ARRAY_LEN" => [],
323                 "FILE" => $_[0]->YYData->{FILE},
324                 "LINE" => $_[0]->YYData->{LINE},
325         }}
328 base_or_empty:
329         base_element ';'
330         |
331         empty_element;
333 optional_base_element:
334         property_list base_or_empty { $_[2]->{PROPERTIES} = FlattenHash([$_[1],$_[2]->{PROPERTIES}]); $_[2] }
337 union_elements:
338         #empty
339         |
340         union_elements optional_base_element { push(@{$_[1]}, $_[2]); $_[1] }
343 union_body:
344         '{' union_elements '}' { $_[2] }
347 opt_union_body:
348         #empty
349         |
350         union_body
353 union:
354         property_list 'union' optional_identifier opt_union_body
355         {{
356                 "TYPE" => "UNION",
357                 "PROPERTIES" => $_[1],
358                 "NAME" => $_[3],
359                 "ELEMENTS" => $_[4],
360                 "FILE" => $_[0]->YYData->{FILE},
361                 "LINE" => $_[0]->YYData->{LINE},
362         }}
365 base_element:
366         property_list type pointers identifier array_len
367         {{
368                 "NAME" => $_[4],
369                 "TYPE" => $_[2],
370                 "PROPERTIES" => $_[1],
371                 "POINTERS" => $_[3],
372                 "ARRAY_LEN" => $_[5],
373                 "FILE" => $_[0]->YYData->{FILE},
374                 "LINE" => $_[0]->YYData->{LINE},
375         }}
378 pointers:
379         #empty
380         { 0 }
381         |
382         pointers '*'  { $_[1]+1 }
385 pipe:
386         property_list 'pipe' type
387         {{
388                 "TYPE" => "PIPE",
389                 "PROPERTIES" => $_[1],
390                 "DATA" => $_[3],
391                 "FILE" => $_[0]->YYData->{FILE},
392                 "LINE" => $_[0]->YYData->{LINE},
393         }}
396 element_list1:
397         #empty
398         { [] }
399         |
400         element_list1 base_element ';' { push(@{$_[1]}, $_[2]); $_[1] }
403 optional_const:
404         #empty
405         |
406         'const'
409 element_list2:
410         #empty
411         |
412         'void'
413         |
414         optional_const base_element { [ $_[2] ] }
415         |
416         element_list2 ',' optional_const base_element { push(@{$_[1]}, $_[4]); $_[1] }
419 array_len:
420         #empty { [] }
421         |
422         '[' ']' array_len           { push(@{$_[3]}, "*"); $_[3] }
423         |
424         '[' anytext ']' array_len   { push(@{$_[4]}, "$_[2]"); $_[4] }
427 property_list:
428         #empty
429         |
430         property_list '[' properties ']' { FlattenHash([$_[1],$_[3]]); }
433 properties:
434         property                { $_[1] }
435         |
436         properties ',' property { FlattenHash([$_[1], $_[3]]); }
439 property:
440         identifier                       {{ "$_[1]" => "1"     }}
441         |
442         identifier '(' commalisttext ')' {{ "$_[1]" => "$_[3]" }}
445 commalisttext:
446         anytext
447         |
448         commalisttext ',' anytext { "$_[1],$_[3]" }
451 anytext:
452         #empty
453         { "" }
454         |
455         identifier
456         |
457         constant
458         |
459         text
460         |
461         anytext '-' anytext  { "$_[1]$_[2]$_[3]" }
462         |
463         anytext '.' anytext  { "$_[1]$_[2]$_[3]" }
464         |
465         anytext '*' anytext  { "$_[1]$_[2]$_[3]" }
466         |
467         anytext '>' anytext  { "$_[1]$_[2]$_[3]" }
468         |
469         anytext '<' anytext  { "$_[1]$_[2]$_[3]" }
470         |
471         anytext '|' anytext  { "$_[1]$_[2]$_[3]" }
472         |
473         anytext '&' anytext  { "$_[1]$_[2]$_[3]" }
474         |
475         anytext '/' anytext  { "$_[1]$_[2]$_[3]" }
476         |
477         anytext '?' anytext  { "$_[1]$_[2]$_[3]" }
478         |
479         anytext ':' anytext  { "$_[1]$_[2]$_[3]" }
480         |
481         anytext '=' anytext  { "$_[1]$_[2]$_[3]" }
482         |
483         anytext '+' anytext  { "$_[1]$_[2]$_[3]" }
484         |
485         anytext '~' anytext  { "$_[1]$_[2]$_[3]" }
486         |
487         anytext '(' commalisttext ')' anytext  { "$_[1]$_[2]$_[3]$_[4]$_[5]" }
488         |
489         anytext '{' commalisttext '}' anytext  { "$_[1]$_[2]$_[3]$_[4]$_[5]" }
492 identifier:
493         IDENTIFIER
496 optional_identifier:
497         #empty { undef }
498         |
499         IDENTIFIER
502 constant:
503         CONSTANT
506 text:
507         TEXT { "\"$_[1]\"" }
510 optional_semicolon:
511         #empty
512         |
513         ';'
517 #####################################
518 # start code
521 use Parse::Pidl qw(error);
523 #####################################################################
524 # flatten an array of hashes into a single hash
525 sub FlattenHash($)
527         my $a = shift;
528         my %b;
529         for my $d (@{$a}) {
530                 for my $k (keys %{$d}) {
531                 $b{$k} = $d->{$k};
532                 }
533         }
534         return \%b;
537 #####################################################################
538 # traverse a perl data structure removing any empty arrays or
539 # hashes and any hash elements that map to undef
540 sub CleanData($)
542         sub CleanData($);
543         my($v) = shift;
545         return undef if (not defined($v));
547         if (ref($v) eq "ARRAY") {
548                 foreach my $i (0 .. $#{$v}) {
549                         CleanData($v->[$i]);
550                 }
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}) {
555                         CleanData($v->{$x});
556                         if (!defined $v->{$x}) {
557                                 delete($v->{$x});
558                                 next;
559                         }
560                 }
561         }
563         return $v;
566 sub _Error {
567         if (exists $_[0]->YYData->{ERRMSG}) {
568                 error($_[0]->YYData, $_[0]->YYData->{ERRMSG});
569                 delete $_[0]->YYData->{ERRMSG};
570                 return;
571         }
573         my $last_token = $_[0]->YYData->{LAST_TOKEN};
575         error($_[0]->YYData, "Syntax error near '$last_token'");
578 sub _Lexer($)
580         my($parser)=shift;
582         $parser->YYData->{INPUT} or return('',undef);
584 again:
585         $parser->YYData->{INPUT} =~ s/^[ \t]*//;
587         for ($parser->YYData->{INPUT}) {
588                 if (/^\#/) {
589                         if (s/^\# (\d+) \"(.*?)\"( \d+|)//) {
590                                 $parser->YYData->{LINE} = $1-1;
591                                 $parser->YYData->{FILE} = $2;
592                                 goto again;
593                         }
594                         if (s/^\#line (\d+) \"(.*?)\"( \d+|)//) {
595                                 $parser->YYData->{LINE} = $1-1;
596                                 $parser->YYData->{FILE} = $2;
597                                 goto again;
598                         }
599                         if (s/^(\#.*)$//m) {
600                                 goto again;
601                         }
602                 }
603                 if (s/^(\n)//) {
604                         $parser->YYData->{LINE}++;
605                         goto again;
606                 }
607                 if (s/^\"(.*?)\"//) {
608                         $parser->YYData->{LAST_TOKEN} = $1;
609                         return('TEXT',$1);
610                 }
611                 if (s/^(\d+)(\W|$)/$2/) {
612                         $parser->YYData->{LAST_TOKEN} = $1;
613                         return('CONSTANT',$1);
614                 }
615                 if (s/^([\w_]+)//) {
616                         $parser->YYData->{LAST_TOKEN} = $1;
617                         if ($1 =~
618                             /^(coclass|interface|import|importlib
619                               |include|cpp_quote|typedef
620                               |union|struct|enum|bitmap|pipe
621                               |void|const|unsigned|signed)$/x) {
622                                 return $1;
623                         }
624                         return('IDENTIFIER',$1);
625                 }
626                 if (s/^(.)//s) {
627                         $parser->YYData->{LAST_TOKEN} = $1;
628                         return($1,$1);
629                 }
630         }
633 sub parse_string
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);
649 sub parse_file($$)
651         my ($filename,$incdirs) = @_;
653         my $saved_delim = $/;
654         undef $/;
655         my $cpp = $ENV{CPP};
656         if (! defined $cpp) {
657                 $cpp = "cpp";
658         }
659         my $includes = join('',map { " -I$_" } @$incdirs);
660         my $data = `$cpp -D__PIDL__$includes -xc $filename`;
661         $/ = $saved_delim;
663         return parse_string($data, $filename);