r7161: - Add support for "aliases" for pidls scalar types and add a few aliases.
[samba.git] / source / build / pidl / idl.yp
1 ########################
2 # IDL Parse::Yapp parser
3 # Copyright (C) Andrew Tridgell <tridge@samba.org>
4 # released under the GNU GPL version 2 or later
5
6
7
8 # the precedence actually doesn't matter at all for this grammer, but
9 # by providing a precedence we reduce the number of conflicts
10 # enormously
11 %left   '-' '+' '&' '|' '*' '>' '.' '/' '(' ')' '[' ',' ';'
12
13
14 ################
15 # grammer
16 %%
17 idl: 
18         #empty  { {} }
19         | idl interface { push(@{$_[1]}, $_[2]); $_[1] }
20         | idl coclass { push(@{$_[1]}, $_[2]); $_[1] }
21 ;
22
23 coclass: property_list 'coclass' identifier '{' interface_names '}' optional_semicolon
24           {$_[3] => {
25                "TYPE" => "COCLASS", 
26                "PROPERTIES" => $_[1],
27                "NAME" => $_[3],
28                "DATA" => $_[5],
29                    "FILE" => $_[0]->YYData->{INPUT_FILENAME},
30                    "LINE" => $_[0]->YYData->{LINE},
31           }}
32 ;
33
34 interface_names:
35         #empty { {} }
36         | interface_names 'interface' identifier ';' { push(@{$_[1]}, $_[2]); $_[1] }
37 ;
38
39 interface: property_list 'interface' identifier base_interface '{' definitions '}' optional_semicolon
40           {$_[3] => {
41                "TYPE" => "INTERFACE", 
42                "PROPERTIES" => $_[1],
43                "NAME" => $_[3],
44                "BASE" => $_[4],
45                "DATA" => $_[6],
46                    "FILE" => $_[0]->YYData->{INPUT_FILENAME},
47                    "LINE" => $_[0]->YYData->{LINE},
48           }}
49 ;
50
51 base_interface:
52         #empty
53         | ':' identifier { $_[2] }
54 ;
55
56 definitions: 
57       definition              { [ $_[1] ] }    
58     | definitions definition  { push(@{$_[1]}, $_[2]); $_[1] }
59 ;    
60
61
62 definition: function | const | typedef | declare
63 ;
64
65 const: 'const' identifier identifier '=' anytext ';' 
66         {{
67                      "TYPE"  => "CONST", 
68                      "DTYPE"  => $_[2],
69                      "NAME"  => $_[3],
70                      "VALUE" => $_[5],
71                      "FILE" => $_[0]->YYData->{INPUT_FILENAME},
72                      "LINE" => $_[0]->YYData->{LINE},
73         }}
74         | 'const' identifier identifier array_len '=' anytext ';' 
75         {{
76                      "TYPE"  => "CONST", 
77                      "DTYPE"  => $_[2],
78                      "NAME"  => $_[3],
79                      "ARRAY_LEN" => $_[4],
80                      "VALUE" => $_[6],
81                      "FILE" => $_[0]->YYData->{INPUT_FILENAME},
82                      "LINE" => $_[0]->YYData->{LINE},
83         }}
84 ;
85
86
87 function: property_list type identifier '(' element_list2 ')' ';' 
88          {{
89                 "TYPE" => "FUNCTION",
90                 "NAME" => $_[3],
91                 "RETURN_TYPE" => $_[2],
92                 "PROPERTIES" => $_[1],
93                 "ELEMENTS" => $_[5],
94                 "FILE" => $_[0]->YYData->{INPUT_FILENAME},
95                 "LINE" => $_[0]->YYData->{LINE},
96           }}
97 ;
98
99 declare: 'declare' property_list decl_type identifier';' 
100         {{
101                      "TYPE" => "DECLARE", 
102                      "PROPERTIES" => $_[2],
103                      "NAME" => $_[4],
104                      "DATA" => $_[3],
105                      "FILE" => $_[0]->YYData->{INPUT_FILENAME},
106                      "LINE" => $_[0]->YYData->{LINE},
107         }}
108 ;
109
110 decl_type: decl_enum | decl_bitmap
111 ;
112
113 decl_enum: 'enum' 
114         {{
115                      "TYPE" => "ENUM"
116         }}
117 ;
118
119 decl_bitmap: 'bitmap' 
120         {{
121                      "TYPE" => "BITMAP"
122         }}
123 ;
124
125 typedef: 'typedef' property_list type identifier array_len ';' 
126         {{
127                      "TYPE" => "TYPEDEF", 
128                      "PROPERTIES" => $_[2],
129                      "NAME" => $_[4],
130                      "DATA" => $_[3],
131                      "ARRAY_LEN" => $_[5],
132                      "FILE" => $_[0]->YYData->{INPUT_FILENAME},
133                      "LINE" => $_[0]->YYData->{LINE},
134         }}
135 ;
136
137 type:   struct | union | enum | bitmap | identifier 
138         | void { "void" }
139 ;
140
141
142 enum: 'enum' '{' enum_elements '}' 
143         {{
144              "TYPE" => "ENUM", 
145                      "ELEMENTS" => $_[3]
146         }}
147 ;
148
149 enum_elements: 
150       enum_element                    { [ $_[1] ] }            
151     | enum_elements ',' enum_element  { push(@{$_[1]}, $_[3]); $_[1] }
152 ;
153
154 enum_element: identifier 
155               | identifier '=' anytext { "$_[1]$_[2]$_[3]" }
156 ;
157
158 bitmap: 'bitmap' '{' bitmap_elements '}' 
159         {{
160                      "TYPE" => "BITMAP", 
161                      "ELEMENTS" => $_[3]
162         }}
163 ;
164
165 bitmap_elements: 
166       bitmap_element                    { [ $_[1] ] }            
167     | bitmap_elements ',' bitmap_element  { push(@{$_[1]}, $_[3]); $_[1] }
168 ;
169
170 bitmap_element: identifier '=' anytext { "$_[1] ( $_[3] )" }
171 ;
172
173 struct: 'struct' '{' element_list1 '}' 
174         {{
175                      "TYPE" => "STRUCT", 
176                      "ELEMENTS" => $_[3]
177         }}
178 ;
179
180 empty_element: property_list ';'
181         {{
182                  "NAME" => "",
183                  "TYPE" => "EMPTY",
184                  "PROPERTIES" => $_[1],
185                  "POINTERS" => 0,
186                  "ARRAY_LEN" => [],
187                  "FILE" => $_[0]->YYData->{INPUT_FILENAME},
188                  "LINE" => $_[0]->YYData->{LINE},
189          }}
190 ;
191
192 base_or_empty: base_element ';' | empty_element;
193
194 optional_base_element:
195         property_list base_or_empty { $_[2]->{PROPERTIES} = util::FlattenHash([$_[1],$_[2]->{PROPERTIES}]); $_[2] }
196 ;
197
198 union_elements: 
199     #empty
200     | union_elements optional_base_element { push(@{$_[1]}, $_[2]); $_[1] }
201 ;
202
203 union: 'union' '{' union_elements '}' 
204         {{
205                      "TYPE" => "UNION", 
206                      "ELEMENTS" => $_[3]
207         }}
208 ;
209
210 base_element: property_list type pointers identifier array_len
211               {{
212                            "NAME" => $_[4],
213                            "TYPE" => $_[2],
214                            "PROPERTIES" => $_[1],
215                            "POINTERS" => $_[3],
216                            "ARRAY_LEN" => $_[5],
217                        "FILE" => $_[0]->YYData->{INPUT_FILENAME},
218                        "LINE" => $_[0]->YYData->{LINE},
219               }}
220 ;
221
222
223 pointers: 
224   #empty            
225    { 0 }
226     | pointers '*'  { $_[1]+1 }
227 ;
228
229 element_list1: 
230     #empty
231     | element_list1 base_element ';' { push(@{$_[1]}, $_[2]); $_[1] }
232 ;
233
234 element_list2: 
235     #empty
236     | 'void' 
237     | base_element { [ $_[1] ] }
238     | element_list2 ',' base_element { push(@{$_[1]}, $_[3]); $_[1] }
239 ;
240
241 array_len: 
242     #empty                        { [] }
243     | '[' ']' array_len           { push(@{$_[3]}, "*"); $_[3] }
244     | '[' anytext ']' array_len   { push(@{$_[4]}, "$_[2]"); $_[4] }
245 ;
246
247
248 property_list: 
249     #empty
250     | property_list '[' properties ']' { util::FlattenHash([$_[1],$_[3]]); }
251 ;
252
253 properties: property          { $_[1] }
254     | properties ',' property { util::FlattenHash([$_[1], $_[3]]); }
255 ;
256
257 property: identifier                   {{ "$_[1]" => "1"     }}
258           | identifier '(' listtext ')' {{ "$_[1]" => "$_[3]" }}
259 ;
260
261 listtext:
262     anytext 
263     | listtext ',' anytext { "$_[1] $_[3]" }
264 ;
265
266 commalisttext:
267     anytext 
268     | commalisttext ',' anytext { "$_[1],$_[3]" }
269 ;
270
271 anytext:  #empty
272     { "" }
273     | identifier | constant | text
274     | anytext '-' anytext  { "$_[1]$_[2]$_[3]" }
275     | anytext '.' anytext  { "$_[1]$_[2]$_[3]" }
276     | anytext '*' anytext  { "$_[1]$_[2]$_[3]" }
277     | anytext '>' anytext  { "$_[1]$_[2]$_[3]" }
278     | anytext '<' anytext  { "$_[1]$_[2]$_[3]" }
279     | anytext '|' anytext  { "$_[1]$_[2]$_[3]" }
280     | anytext '&' anytext  { "$_[1]$_[2]$_[3]" }
281     | anytext '/' anytext  { "$_[1]$_[2]$_[3]" }
282     | anytext '+' anytext  { "$_[1]$_[2]$_[3]" }
283     | anytext '~' anytext  { "$_[1]$_[2]$_[3]" }
284     | anytext '(' commalisttext ')' anytext  { "$_[1]$_[2]$_[3]$_[4]$_[5]" }
285     | anytext '{' commalisttext '}' anytext  { "$_[1]$_[2]$_[3]$_[4]$_[5]" }
286 ;
287
288 identifier: IDENTIFIER
289 ;
290
291 constant: CONSTANT
292 ;
293
294 text: TEXT { "\"$_[1]\"" }
295 ;
296
297 optional_semicolon: 
298         #empty
299         | ';'
300 ;
301
302
303 #####################################
304 # start code
305 %%
306
307 use pidl::util;
308
309 sub _Error {
310     if (exists $_[0]->YYData->{ERRMSG}) {
311                 print $_[0]->YYData->{ERRMSG};
312                 delete $_[0]->YYData->{ERRMSG};
313                 return;
314         };
315         my $line = $_[0]->YYData->{LINE};
316         my $last_token = $_[0]->YYData->{LAST_TOKEN};
317         my $file = $_[0]->YYData->{INPUT_FILENAME};
318         
319         print "$file:$line: Syntax error near '$last_token'\n";
320 }
321
322 sub _Lexer($)
323 {
324         my($parser)=shift;
325
326         $parser->YYData->{INPUT}
327         or  return('',undef);
328
329 again:
330         $parser->YYData->{INPUT} =~ s/^[ \t]*//;
331
332         for ($parser->YYData->{INPUT}) {
333                 if (/^\#/) {
334                         if (s/^\# (\d+) \"(.*?)\"( \d+|)//) {
335                                 $parser->YYData->{LINE} = $1-1;
336                                 $parser->YYData->{INPUT_FILENAME} = $2;
337                                 goto again;
338                         }
339                         if (s/^\#line (\d+) \"(.*?)\"( \d+|)//) {
340                                 $parser->YYData->{LINE} = $1-1;
341                                 $parser->YYData->{INPUT_FILENAME} = $2;
342                                 goto again;
343                         }
344                         if (s/^(\#.*)$//m) {
345                                 goto again;
346                         }
347                 }
348                 if (s/^(\n)//) {
349                         $parser->YYData->{LINE}++;
350                         goto again;
351                 }
352                 if (s/^\"(.*?)\"//) {
353                         $parser->YYData->{LAST_TOKEN} = $1;
354                         return('TEXT',$1); 
355                 }
356                 if (s/^(\d+)(\W|$)/$2/) {
357                         $parser->YYData->{LAST_TOKEN} = $1;
358                         return('CONSTANT',$1); 
359                 }
360                 if (s/^([\w_]+)//) {
361                         $parser->YYData->{LAST_TOKEN} = $1;
362                         if ($1 =~ 
363                             /^(coclass|interface|const|typedef|declare|union
364                               |struct|enum|bitmap|void)$/x) {
365                                 return $1;
366                         }
367                         return('IDENTIFIER',$1);
368                 }
369                 if (s/^(.)//s) {
370                         $parser->YYData->{LAST_TOKEN} = $1;
371                         return($1,$1);
372                 }
373         }
374 }
375
376 sub parse_idl($$)
377 {
378         my $self = shift;
379         my $filename = shift;
380
381         my $saved_delim = $/;
382         undef $/;
383         my $cpp = $ENV{CPP};
384         if (! defined $cpp) {
385                 $cpp = "cpp"
386         }
387         my $data = `$cpp -D__PIDL__ -xc $filename`;
388         $/ = $saved_delim;
389
390     $self->YYData->{INPUT} = $data;
391     $self->YYData->{LINE} = 0;
392     $self->YYData->{LAST_TOKEN} = "NONE";
393
394         my $idl = $self->YYParse( yylex => \&_Lexer, yyerror => \&_Error );
395
396         return util::CleanData($idl);
397 }