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