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