]> git.buserror.net Git - polintos/scott/priv.git/blob - idlcomp/cdlparse.y
License change.
[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                 $$.ident->retain();
348                 
349                 cur_strlist->pop_back();
350                 
351                 if (!cur_strlist->empty())
352                         $$.ns = add_nspace(cur_strlist, true);
353                 else {
354                         $$.ns = cur_nspace;
355                         nspace_stack.push_front(cur_nspace);
356                 }
357                 
358                 cur_strlist = NULL;
359                 
360                 if (!$$.ns)
361                         do_yyerror();
362         }
363 ;
364
365 class:
366         TOK_CLASS qualified_decl {
367                 cur_class = new Class($2.ident);
368                 $2.ns->add_user(cur_class);
369         } ':' qualified_idlist {
370                 if ($5->empty()) {
371                         yyerrorf("A class must implement at least one interface.");
372                         throw UserError();
373                 }
374         
375                 for (IDList::const_iterator i = $5->begin(); i != $5->end(); ++i) {
376                         StrList *strl = *i;
377                         Symbol *sym = lookup_sym(toplevel, strl, toplevel);
378                         Interface *iface = dynamic_cast<Interface *>(sym);
379
380                         if (!iface) {
381                                 yyerrorfl(cur_input_file, strl->back()->line,
382                                           "\"%s\" is not an interface.", 
383                                           strl->flatten()->c_str());
384
385                                 throw UserError();
386                         }
387                         
388                         cur_class->add_iface(iface);
389                 }
390         } class_body {
391                 pop_nspace();
392                 cur_class->finalize();
393                 cur_class = NULL;
394         }
395 ;
396
397 class_body:
398         ';'
399 |       '{' multi_class_body '}'
400 ;
401
402 multi_class_body:
403         one_class_body
404 |       multi_class_body one_class_body
405 ;
406
407 one_class_body:
408         TOK_METHOD qualified_ident {
409                 // FIXME: use the set of supported interfaces as a search path
410                 Symbol *sym = lookup_sym(toplevel, $2, toplevel);
411                 cur_method = dynamic_cast<Method *>(sym);
412                 
413                 if (!cur_method) {
414                         yyerrorfl(cur_input_file, $2->back()->line,
415                                   "\"%s\" is not a method.", 
416                                   $2->flatten()->c_str());
417                                 throw UserError();
418                 }
419         } method_body {
420                 cur_method = NULL;
421         }
422 ;
423
424 method_body:
425         one_method_body
426 |       '{' multi_method_body '}'
427 ;
428
429 multi_method_body:
430         one_method_body
431 |       multi_method_body one_method_body
432 ;
433
434 one_method_body:
435         TOK_NAME qualified_ident ';' {
436                 Class::MethodInfo *mi = cur_class->add_method(cur_method);
437                 mi->implname = $2;
438         }
439 |       TOK_COPY ids ';' {
440                 Class::MethodInfo *mi = cur_class->add_method(cur_method);
441                 
442                 for (StrList::const_iterator i = $2->begin(); i != $2->end(); ++i) {
443                         const String *str = *i;
444                         Symbol *sym;
445                         
446                         try {
447                                 sym = cur_method->lookup(str);
448                         }
449                         catch (SymbolNotFound) {
450                                 yyerrorfl(cur_input_file, str->line,
451                                           "\"%s\" is not a parameter of \"%s\".",
452                                           str->c_str(),
453                                           cur_method->get_fq_name()->flatten()->c_str());
454
455                                 throw UserError();
456                         }
457                         
458                         Param *p = dynamic_cast<Param *>(sym);
459                         assert(p);
460                         
461                         Class::ParamInfo *pi = mi->add_param(p);
462                         pi->copy = true;
463                         mi->copy_params = true;
464                 }
465         }
466 ;
467
468 %%
469
470 static Con dummy_con;
471
472 void setup_cdlparse()
473 {
474         yylval_con = &dummy_con;
475         yylval_string = &cdl_lval.string;
476 }
477
478 list<ClassRef> classes;
479