parser: remove unnecessary retains
[polintos/scott/priv.git] / idlcomp / cdlparse.y
1 %{
2 // CDL parser
3 //
4 // This software is copyright (c) 2006 Scott Wood <scott@buserror.net>.
5 // 
6 // This software is provided 'as-is', without any express or implied warranty.
7 // In no event will the authors or contributors be held liable for any damages
8 // arising from the use of this software.
9 // 
10 // Permission is hereby granted to everyone, free of charge, to use, copy,
11 // modify, prepare derivative works of, publish, distribute, perform,
12 // sublicense, and/or sell copies of the Software, provided that the above
13 // copyright notice and disclaimer of warranty be included in all copies or
14 // substantial portions of this software.
15
16 #include <stdlib.h>
17 #include <string.h>
18 #include <string>
19
20 #include <idlc.h>
21 #include <cdl.h>
22
23 #define YYDEBUG 1
24
25 #define do_yyerror() do { \
26         fprintf(stderr, "YYERROR at %d\n", __LINE__); \
27         throw UserError(); \
28 } while (0)
29
30 static StrListRef nspace_name;
31 static StrListRef cur_strlist;
32 static IDListRef cur_idlist;
33 static ClassRef cur_class;
34 static MethodRef cur_method;
35
36 %}
37 %union {
38         // The lifetime of any of these pointers is one instance
39         // of the one_input rule.
40         
41         String *string;
42         StrList *strl;
43         IDList *idl;
44         SymList *syml;
45         Symbol *sym;
46         Method *meth;
47         Class *cla;
48         bool boolean;
49
50         struct {                // Used for namespace-qualified type declarations
51                 NameSpace *ns;       // Namespace portion -- all but last field
52                 const String *ident; // New identifier portion -- last field
53         } decl;
54 }
55
56 // The token list must be exactly the same as in idlparse.y, so that
57 // the same lexer can be used.
58
59 %token <string> TOK_IDENT
60 %token TOK_IFACE
61 %token TOK_STRUCT
62 %token TOK_CHAR
63 %token TOK_OCTET
64 %token <con> TOK_ICON
65 %token <con> TOK_FCON
66 %token <con> TOK_UCON
67 %token <con> TOK_INVALID
68 %token TOK_BOOL
69 %token TOK_SHORT
70 %token TOK_INT
71 %token TOK_LONG
72 %token TOK_USHORT
73 %token TOK_UINT
74 %token TOK_ULONG
75 %token TOK_FSHORT
76 %token TOK_FLONG
77 %token TOK_CONST
78 %token TOK_BITFIELD
79 %token TOK_ENUM
80 %token TOK_NAMESPACE
81 %token TOK_USING
82 %token TOK_ASYNC
83 %token TOK_INOUT
84 %token TOK_OUT
85 %token TOK_3DOT
86 %token TOK_2DOT
87 %token <string> TOK_STR
88 %token TOK_SHARED
89 %token TOK_PUSH
90 %token TOK_TYPEDEF
91 %token TOK_ALIAS
92 %token TOK_VIRTUAL
93 %token TOK_GUID
94 %token TOK_INLINE
95 %token TOK_STATIC
96 %token TOK_IMMUTABLE
97 %token TOK_TRUE
98 %token TOK_FALSE
99
100 // CDL tokens
101 %token TOK_COPY
102 %token TOK_METHOD
103 %token TOK_CLASS
104 %token TOK_NAME
105
106 // These are not real tokens, but are used as special values in places that
107 // normally accept tokens.
108 %token TOK_NONE
109 %token TOK_ANON
110 %token TOK_DCON
111
112 %type <strl>       ids
113 %type <string>     ident
114 %type <strl>       qualified_ident
115 %type <idl>        qualified_idlist
116 %type <boolean>    maybe_dbldot
117 %type <decl>       qualified_decl
118
119 %%
120
121 input:
122         /* empty */
123 |       input one_input
124 ;
125
126 one_input:
127         one_input_real
128 ;
129
130 one_input_real:
131         class
132 |       namespace
133 ;
134
135 namespace_body:
136         ';' {
137                 NameSpace *ret = add_nspace(nspace_name, false);
138                 nspace_name = NULL;
139
140                 if (!ret)
141                         do_yyerror();
142         }
143 |       '{' {
144                 NameSpace *ret = add_nspace(nspace_name, true);
145                 nspace_name = NULL;
146
147                 if (!ret)
148                         do_yyerror();
149         } input '}' {
150                 pop_nspace();
151         }
152 |       {
153                 NameSpace *ret = add_nspace(nspace_name, true);
154                 nspace_name = NULL;
155
156                 if (!ret)
157                         do_yyerror();
158         } one_input {
159                 pop_nspace();
160         } 
161 ;
162
163 namespace:
164         TOK_NAMESPACE qualified_ident {
165                 nspace_name = $2;
166         } namespace_body
167 ;
168
169 ids_body:
170         ident {
171                 cur_strlist->push_back($1);
172         }
173 |       ids_body ',' ident {
174                 cur_strlist->push_back($3);
175         }
176 ;
177
178 ids:
179         {
180                 cur_strlist = new StrList;
181         } ids_body {
182                 $$ = cur_strlist;
183                 cur_strlist = NULL;
184         }
185 ;
186
187 ident:
188         TOK_IDENT
189 |       TOK_ASYNC    {
190                 $$ = new String("async", cur_input_file, curline, TOK_ASYNC);
191         }
192 |       TOK_INOUT    {
193                 $$ = new String("inout", cur_input_file, curline, TOK_INOUT);
194         }
195 |       TOK_OUT      {
196                 $$ = new String("out", cur_input_file, curline, TOK_OUT);
197         }
198 |       TOK_SHARED   {
199                 $$ = new String("shared", cur_input_file, curline, TOK_SHARED);
200         }
201 |       TOK_PUSH     {
202                 $$ = new String("push", cur_input_file, curline, TOK_PUSH);
203         }
204 |       TOK_SHORT    {
205                 $$ = new String("short", cur_input_file, curline, TOK_SHORT);
206         }
207 |       TOK_INT      {
208                 $$ = new String("int", cur_input_file, curline, TOK_INT);
209         }
210 |       TOK_LONG     {
211                 $$ = new String("long", cur_input_file, curline, TOK_LONG);
212         }
213 |       TOK_USHORT   {
214                 $$ = new String("ushort", cur_input_file, curline, TOK_USHORT);
215         }
216 |       TOK_UINT     {
217                 $$ = new String("uint", cur_input_file, curline, TOK_UINT);
218         }
219 |       TOK_ULONG    {
220                 $$ = new String("ulong", cur_input_file, curline, TOK_ULONG);
221         }
222 |       TOK_CHAR     {
223                 $$ = new String("char", cur_input_file, curline, TOK_CHAR);
224         }
225 |       TOK_OCTET    {
226                 $$ = new String("octet", cur_input_file, curline, TOK_OCTET);
227         }
228 |       TOK_FSHORT   {
229                 $$ = new String("fshort", cur_input_file, curline, TOK_FSHORT);
230         }
231 |       TOK_FLONG    {
232                 $$ = new String("flong", cur_input_file, curline, TOK_FLONG);
233         }
234 |       TOK_BOOL     {
235                 $$ = new String("bool", cur_input_file, curline, TOK_BOOL);
236         }
237 |       TOK_METHOD   {
238                 $$ = new String("method", cur_input_file, curline, TOK_METHOD);
239         }
240 |       TOK_NAME     {
241                 $$ = new String("name", cur_input_file, curline, TOK_NAME);
242         }
243 |       TOK_COPY     {
244                 $$ = new String("copy", cur_input_file, curline, TOK_COPY);
245         }
246 |       TOK_CLASS    {
247                 $$ = new String("class", cur_input_file, curline, TOK_CLASS);
248         }
249 |       TOK_GUID     {
250                 $$ = new String("guid", cur_input_file, curline, TOK_GUID);
251         }
252 |       TOK_STATIC   {
253                 $$ = new String("static", cur_input_file, curline, TOK_STATIC);
254         }
255 |       TOK_IFACE    {
256                 $$ = new String("interface", cur_input_file, curline, TOK_IFACE);
257         }
258 |       TOK_STRUCT   {
259                 $$ = new String("struct", cur_input_file, curline, TOK_STRUCT);
260         }
261 |       TOK_CONST    {
262                 $$ = new String("const", cur_input_file, curline, TOK_CONST);
263         }
264 |       TOK_BITFIELD {
265                 $$ = new String("bitfield", cur_input_file, curline, TOK_BITFIELD);
266         }
267 |       TOK_ENUM     {
268                 $$ = new String("enum", cur_input_file, curline, TOK_ENUM);
269         }
270 |       TOK_USING    {
271                 $$ = new String("using", cur_input_file, curline, TOK_USING);
272         }
273 |       TOK_TYPEDEF  {
274                 $$ = new String("typedef", cur_input_file, curline, TOK_TYPEDEF);
275         }
276 |       TOK_ALIAS    {
277                 $$ = new String("alias", cur_input_file, curline, TOK_ALIAS);
278         }
279 |       TOK_VIRTUAL  {
280                 $$ = new String("virtual", cur_input_file, curline, TOK_VIRTUAL);
281         }
282 |       TOK_INLINE {
283                 $$ = new String("inline", cur_input_file, curline, TOK_INLINE);
284         }
285 ;
286
287 qualified_ident_raw:
288         ident {
289                 cur_strlist->push_back($1);
290         }
291 |       qualified_ident_raw '.' ident {
292                 cur_strlist->push_back($3);
293         }
294 ;
295
296 maybe_dbldot:
297         /* empty */ {
298                 $$ = false;
299         }
300 |       TOK_2DOT {
301                 $$ = true;
302         }
303 ;
304
305 /* The mid-rule action is to keep curline correct, as well
306    as creating cur_strlist. */
307 qualified_ident:
308         maybe_dbldot {
309                 cur_strlist = new StrList;
310                 
311                 if ($1)
312                         cur_strlist->push_front(new String("", cur_input_file, 
313                                                            curline, TOK_IDENT));
314         } qualified_ident_raw {
315                 $$ = cur_strlist;
316                 cur_strlist = NULL;
317         }
318 ;
319
320 qualified_ids:
321         qualified_ident {
322                 cur_idlist->push_back($1);
323         } 
324 |       qualified_ids ',' qualified_ident {
325                 cur_idlist->push_back($3);
326         }
327 ;
328
329 qualified_idlist:
330         {
331                 cur_idlist = new IDList;
332         } qualified_ids {
333                 $$ = cur_idlist;
334                 cur_idlist = NULL;
335         }
336 ;
337
338 qualified_decl:
339         maybe_dbldot {
340                 if ($1)
341                         yyerrorf("Namespaces cannot be declared "
342                                  "with an absolute path.");
343         
344                 cur_strlist = new StrList;
345         } qualified_ident_raw {
346                 $$.ident = cur_strlist->back();
347                 cur_strlist->pop_back();
348                 
349                 if (!cur_strlist->empty())
350                         $$.ns = add_nspace(cur_strlist, true);
351                 else {
352                         $$.ns = cur_nspace;
353                         nspace_stack.push_front(cur_nspace);
354                 }
355                 
356                 cur_strlist = NULL;
357                 
358                 if (!$$.ns)
359                         do_yyerror();
360         }
361 ;
362
363 class:
364         TOK_CLASS qualified_decl {
365                 cur_class = new Class($2.ident);
366                 $2.ns->add_user(cur_class);
367         } ':' qualified_idlist {
368                 if ($5->empty()) {
369                         yyerrorf("A class must implement at least one interface.");
370                         throw UserError();
371                 }
372         
373                 for (IDList::const_iterator i = $5->begin(); i != $5->end(); ++i) {
374                         StrList *strl = *i;
375                         Symbol *sym = lookup_sym(toplevel, strl, toplevel);
376                         Interface *iface = dynamic_cast<Interface *>(sym);
377
378                         if (!iface) {
379                                 yyerrorfl(cur_input_file, strl->back()->line,
380                                           "\"%s\" is not an interface.", 
381                                           strl->flatten()->c_str());
382
383                                 throw UserError();
384                         }
385                         
386                         cur_class->add_iface(iface);
387                 }
388         } class_body {
389                 pop_nspace();
390                 cur_class->finalize();
391                 cur_class = NULL;
392         }
393 ;
394
395 class_body:
396         ';'
397 |       '{' multi_class_body '}'
398 ;
399
400 multi_class_body:
401         one_class_body
402 |       multi_class_body one_class_body
403 ;
404
405 one_class_body:
406         TOK_METHOD qualified_ident {
407                 // FIXME: use the set of supported interfaces as a search path
408                 Symbol *sym = lookup_sym(toplevel, $2, toplevel);
409                 cur_method = dynamic_cast<Method *>(sym);
410                 
411                 if (!cur_method) {
412                         yyerrorfl(cur_input_file, $2->back()->line,
413                                   "\"%s\" is not a method.", 
414                                   $2->flatten()->c_str());
415                                 throw UserError();
416                 }
417         } method_body {
418                 cur_method = NULL;
419         }
420 ;
421
422 method_body:
423         one_method_body
424 |       '{' multi_method_body '}'
425 ;
426
427 multi_method_body:
428         one_method_body
429 |       multi_method_body one_method_body
430 ;
431
432 one_method_body:
433         TOK_NAME qualified_ident ';' {
434                 Class::MethodInfo *mi = cur_class->add_method(cur_method);
435                 mi->implname = $2;
436         }
437 |       TOK_COPY ids ';' {
438                 Class::MethodInfo *mi = cur_class->add_method(cur_method);
439                 
440                 for (StrList::const_iterator i = $2->begin(); i != $2->end(); ++i) {
441                         const String *str = *i;
442                         Symbol *sym;
443                         
444                         try {
445                                 sym = cur_method->lookup(str);
446                         }
447                         catch (SymbolNotFound) {
448                                 yyerrorfl(cur_input_file, str->line,
449                                           "\"%s\" is not a parameter of \"%s\".",
450                                           str->c_str(),
451                                           cur_method->get_fq_name()->flatten()->c_str());
452
453                                 throw UserError();
454                         }
455                         
456                         Param *p = dynamic_cast<Param *>(sym);
457                         assert(p);
458                         
459                         Class::ParamInfo *pi = mi->add_param(p);
460                         pi->copy = true;
461                         mi->copy_params = true;
462                 }
463         }
464 ;
465
466 %%
467
468 static Con dummy_con;
469
470 void setup_cdlparse()
471 {
472         yylval_con = &dummy_con;
473         yylval_string = &cdl_lval.string;
474 }
475
476 list<ClassRef> classes;
477