parser: remove unnecessary retains
[polintos/scott/priv.git] / idlcomp / idlparse.y
1 %{
2 // IDL 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 <util.h>
22 #define YYDEBUG 1
23
24 #if 1
25 #define do_yyerror() do { \
26         fprintf(stderr, "YYERROR at %d\n", __LINE__); \
27         throw UserError(); \
28 } while (0)
29 #else
30 #define do_yyerror() YYERROR
31 #endif
32
33 static StrListRef nspace_name;
34 static StrListRef cur_strlist;
35 static ConListRef cur_conlist;
36 static IDListRef cur_idlist;
37
38 %}
39 %union {
40         // The lifetime of any of these pointers is one instance
41         // of the one_input rule.
42         
43         String *string;
44         StrList *strl;
45         IDList *idl;
46
47         struct Decl {           // Used for namespace-qualified type declarations
48                 NameSpace *ns;       // Namespace portion -- all but last field
49                 const String *ident; // New identifier portion -- last field
50         } decl;
51         
52         SymList *syml;
53         Symbol *sym;
54         Enum *en;
55         Struct *str;
56         BitField *bf;
57         Interface *iface;
58         Method *meth;
59         Datum *datum;
60         bool boolean;
61         IFaceList *ifl;
62
63         Con con;
64         ConList *conl;
65         Array *array;
66
67         struct {
68                 StrList *type;
69                 Array *array;
70         } type;
71         
72         int val;
73
74         struct {
75                 Decl decl;
76                 StrList *attr;
77         } struct_decl_attr;
78
79         struct {
80                 StrList *ids;
81                 StrList *attr;
82         } ids_attr;
83
84         uint64_t guid[2];
85 }
86
87 // The token list must be exactly the same as in idlparse.y, so that
88 // the same lexer can be used.
89
90 %token <string> TOK_IDENT
91 %token TOK_IFACE
92 %token TOK_STRUCT
93 %token TOK_CHAR
94 %token TOK_OCTET
95 %token <con> TOK_ICON
96 %token <con> TOK_FCON
97 %token <con> TOK_UCON
98 %token <con> TOK_INVALID
99 %token TOK_BOOL
100 %token TOK_SHORT
101 %token TOK_INT
102 %token TOK_LONG
103 %token TOK_USHORT
104 %token TOK_UINT
105 %token TOK_ULONG
106 %token TOK_FSHORT
107 %token TOK_FLONG
108 %token TOK_CONST
109 %token TOK_BITFIELD
110 %token TOK_ENUM
111 %token TOK_NAMESPACE
112 %token TOK_USING
113 %token TOK_ASYNC
114 %token TOK_INOUT
115 %token TOK_OUT
116 %token TOK_3DOT
117 %token TOK_2DOT
118 %token <string> TOK_STR
119 %token TOK_SHARED
120 %token TOK_PUSH
121 %token TOK_TYPEDEF
122 %token TOK_ALIAS
123 %token TOK_VIRTUAL
124 %token TOK_GUID
125 %token TOK_INLINE
126 %token TOK_STATIC
127 %token TOK_IMMUTABLE
128 %token TOK_TRUE
129 %token TOK_FALSE
130
131 // CDL tokens
132 %token TOK_COPY
133 %token TOK_METHOD
134 %token TOK_CLASS
135 %token TOK_NAME
136
137 // These are not real tokens, but are used as special values in places that
138 // normally accept tokens.
139 %token TOK_NONE
140 %token TOK_ANON
141 %token TOK_DCON
142
143 %type <strl>       basictype
144 %type <type>       type
145 %type <con>        const
146 %type <con>        maybeconst
147 %type <array>      arraybounds
148 %type <con>        constnominus
149 %type <datum>      bfelem
150 %type <syml>       bfelems
151 %type <syml>       maybe_bfelems
152 %type <strl>       maybe_ids
153 %type <strl>       ids
154 %type <conl>       ideqs
155 %type <string>     ident
156 %type <strl>       strlist
157 %type <strl>       maybe_strlist
158 %type <strl>       end_strlist
159 %type <con>        size
160 %type <datum>      bftype
161 %type <strl>       qualified_ident
162 %type <strl>       qualified_ident_nodbldot
163 %type <decl>       qualified_decl
164 %type <decl>       maybe_qualified_decl
165 %type <decl>       anon_decl
166 %type <idl>        qualified_idlist
167 %type <boolean>    maybe_dot_star
168 %type <strl>       inherit_struct
169 %type <str>        struct
170 %type <bf>         bitfield
171 %type <en>         enum
172 %type <iface>      iface
173 %type <idl>        inherit_ifaces
174 %type <boolean>    typedef_or_alias_keyword
175 %type <guid>       guid
176 %type <struct_decl_attr> struct_decl_and_attr
177 %type <ids_attr>   ids_attr
178
179 %%
180
181 input:
182         /* empty */
183 |       input one_input
184 ;
185
186 one_input_real:
187         using ';'
188 |       namespace
189 |       enum ';' {}
190 |       bitfield ';' {}
191 |       struct ';' {}
192 |       iface ';' {}
193 |       typedef_or_alias ';' {}
194 |       const_datum ';' {}
195 ;
196
197 one_input:
198         one_input_real
199 ;
200
201 namespace_body:
202         ';' {
203                 NameSpace *ret = add_nspace(nspace_name, false);
204                 nspace_name = NULL;
205
206                 if (!ret)
207                         do_yyerror();
208         }
209 |       '{' {
210                 NameSpace *ret = add_nspace(nspace_name, true);
211                 nspace_name = NULL;
212
213                 if (!ret)
214                         do_yyerror();
215         } input '}' {
216                 pop_nspace();
217         }
218 |       {
219                 NameSpace *ret = add_nspace(nspace_name, true);
220                 nspace_name = NULL;
221
222                 if (!ret)
223                         do_yyerror();
224         } one_input {
225                 pop_nspace();
226         } 
227 ;
228
229 namespace:
230         TOK_NAMESPACE qualified_ident {
231                 nspace_name = $2;
232         } namespace_body
233 ;
234
235 const_datum:
236         TOK_CONST type ideqs {
237                 ConList *cl = $3;
238                 
239                 for (ConList::iterator i = cl->begin(); i != cl->end(); ++i)
240                         Datum::declare((*i).str, cur_nspace, $2.type, $2.array, &(*i).con);
241         }
242 ;
243
244 ids_attr:
245         /* empty */ {
246                 $$.ids = NULL;
247                 $$.attr = NULL;
248         }
249 |       ids maybe_strlist {
250                 $$.ids = $1;
251                 $$.attr = $2;
252         }
253 ;
254
255 struct_elem:
256         const_datum ';' 
257 |       type ids maybe_strlist ';' {
258                 declare_data(cur_nspace, $2, $1.type, $1.array, $3);
259         }
260 |       enum maybe_ids ';' {
261                 if (!$2 && $1->name->token == TOK_ANON)
262                         yyerrorfl($1->name->file, $1->name->line,
263                                   "An anonymous type must declare a datum.");
264
265                 if ($2) {
266                         StrList *strl = $1->get_fq_name();
267                         strl->push_front(new String(""));
268                         declare_data(cur_nspace, $2, strl, NULL, NULL);
269                 }
270         }
271 |       bitfield maybe_ids ';' {
272                 if (!$2 && $1->name->token == TOK_ANON)
273                         yyerrorfl($1->name->file, $1->name->line,
274                                   "An anonymous type must declare a datum.");
275
276                 if ($2) {
277                         StrList *strl = $1->get_fq_name();
278                         strl->push_front(new String(""));
279                         declare_data(cur_nspace, $2, strl, NULL, NULL);
280                 }
281         }
282 |       struct ids_attr ';' {
283                 if (!$2.ids && $1->name->token == TOK_ANON)
284                         yyerrorfl($1->name->file, $1->name->line,
285                                   "An anonymous type must declare a datum.");
286
287                 if ($2.ids) {
288                         StrList *strl = $1->get_fq_name();
289                         strl->push_front(new String(""));
290                         declare_data(cur_nspace, $2.ids, strl, NULL, $2.attr);
291                 }
292         }
293 |       typedef_or_alias ';'
294 |       using ';'
295 |       guid ';' {
296                 Struct *str = dynamic_cast<Struct *>(*cur_nspace);
297                 assert(str);
298                 
299                 str->set_guid($1);
300         }
301 ;
302
303 struct_body:
304         /* empty */
305 |       struct_elem struct_body
306 ;
307
308 inherit_struct:
309         /* empty */ {
310                 $$ = NULL;
311         }
312 |       ':' qualified_ident {
313                 $$ = $2;
314         }
315 ;
316
317 struct_decl_and_attr: 
318         anon_decl {
319                 // Anonymous structs have no attributes.
320                 $$.decl = $1;
321                 $$.attr = new StrList;
322         }
323 |       qualified_decl maybe_strlist {
324                 $$.decl = $1;
325                 $$.attr = $2;
326         }
327 ;
328
329 struct:
330         TOK_STRUCT struct_decl_and_attr inherit_struct '{' {
331                 $<str>$ = Struct::declare($2.decl.ident, $2.decl.ns, $3);
332                 
333                 for (StrList::iterator i = $2.attr->begin(); i != $2.attr->end(); ++i) {
334                         const String *attr = *i;
335
336                         switch (attr->token) {
337                                 case TOK_VIRTUAL:
338                                         $<str>$->set_virtual();
339                                         break;
340                                 
341                                 case TOK_INLINE:
342                                         $<str>$->set_inline();
343                                         break;
344                                 
345                                 default:
346                                         yyerrorfl(attr->file, attr->line, "Invalid attribute \"%s\"", 
347                                                   (*i)->c_str());
348                         }
349                 }
350
351                 nspace_stack.push_front(cur_nspace);
352                 cur_nspace = $<str>$;
353         }
354
355         struct_body '}' {
356                 // One for the struct's namespace, and one for the
357                 // namespace it was declared in.
358                 pop_nspace();
359                 pop_nspace();
360                 $$ = $<str>5;
361         }
362 ;
363
364 param:
365         type strlist {
366                 const String *name = $2->front();
367                 $2->pop_front();
368                 
369                 CompiledParam::Flags flags = {};
370                 int dirs = 0;
371                 
372                 flags.field.In = 1; 
373                 
374                 for (StrList::iterator i = $2->begin(); i != $2->end(); ++i) {
375                         const String *attr = *i;
376                         
377                         switch (attr->token) {
378                                 case TOK_OUT:
379                                         if (dirs++ > 0) {
380                                                 yyerrorf("Only one direction attribute may be given.");
381                                         } else {
382                                                 flags.field.In = 0;
383                                                 flags.field.Out = 1;
384                                         }
385                                         
386                                         break;
387                                 
388                                 case TOK_INOUT:
389                                         if (dirs++ > 0) {
390                                                 yyerrorf("Only one direction attribute may be given.");
391                                         } else {
392                                                 flags.field.In = 1;
393                                                 flags.field.Out = 1;
394                                         }
395                                         
396                                         break;
397                                 
398                                 case TOK_SHARED:
399                                         flags.field.Shared = 1;
400                                         break;
401                                 
402                                 case TOK_PUSH:
403                                         flags.field.Push = 1;
404                                         break;
405                                 
406                                 case TOK_INLINE:
407                                         flags.field.Inline = 1;
408                                         break;
409                                 
410                                 case TOK_IMMUTABLE:
411                                         flags.field.Immutable = 1;
412                                         break;
413                                         
414                                 default:
415                                         yyerrorfl(attr->file, attr->line, 
416                                                   "Invalid attribute \"%s\"", (*i)->c_str());
417                         }
418                 }
419
420                 Param::declare(name, cur_nspace, $1.type, flags, $1.array);
421         }                       
422 ;
423
424 more_params:
425         /* empty */
426 |       ',' param_list
427 ;
428
429 param_list:
430         /* empty */
431 |       param more_params
432 ;
433
434 method:
435         ident '(' {
436                 $<meth>$ = Method::declare($1, cur_nspace);
437                 
438                 nspace_stack.push_front(cur_nspace);
439                 cur_nspace = $<meth>$;
440         } param_list ')' maybe_strlist {
441                 for (StrList::iterator i = $6->begin(); i != $6->end(); ++i) {
442                         const String *attr = *i;
443
444                         switch (attr->token) {
445                                 case TOK_ASYNC:
446                                         $<meth>3->set_async();
447                                         break;
448                                 
449                                 default:
450                                         yyerrorfl(attr->file, attr->line,
451                                                   "Invalid attribute \"%s\".", (*i)->c_str());
452                         }
453                 }
454                 pop_nspace();
455         }
456 ;
457
458 iface_body:
459         /* empty */
460 |       method ';' iface_body
461 |       enum ';' iface_body {}
462 |       bitfield ';' iface_body {}
463 |       struct ';' iface_body {}
464 |       iface ';' iface_body {}
465 |       typedef_or_alias ';' iface_body
466 |       const_datum ';' iface_body
467 |       guid ';' iface_body {
468                 Interface *iface = dynamic_cast<Interface *>(*cur_nspace);
469                 assert(iface);
470                 
471                 iface->set_guid($1);
472         }
473 |       using ';' iface_body
474 ;
475
476 guid:
477         TOK_GUID ':' TOK_STR {
478                 parse_guid($3->c_str(), (char *)$$);
479         }
480 ;
481         
482
483 inherit_ifaces:
484         /* empty */ {
485                 $$ = new IDList;
486         }
487 |       ':' qualified_idlist {
488                 $$ = $2;
489         }
490 ;
491
492 iface:
493         TOK_IFACE qualified_decl inherit_ifaces {
494                 $<iface>$ = Interface::declare($2.ident, $2.ns, $3);
495
496                 nspace_stack.push_front(cur_nspace);
497                 cur_nspace = $<iface>$;
498         } '{' iface_body '}' {
499                 pop_nspace();
500                 pop_nspace();
501                 $$ = $<iface>4;
502         }
503 ;
504
505 maybe_namespace:
506                 /* empty */
507         |       TOK_NAMESPACE
508 ;
509
510 using_list_entry:
511         maybe_namespace qualified_ident {
512                 const String *end = $2->back();
513                 bool ns = false;
514                 
515                 if (end->token == '*') {
516                         ns = true;
517                         $2->pop_back();
518                 }
519                 
520                 if (ns) {
521                         cur_nspace->add_search($2);
522                 } else {
523                         Alias::declare(end, cur_nspace, $2, true);
524                 }
525         }
526 ;
527
528 using_list:
529                 using_list_entry
530         |       using_list_entry ',' using_list
531 ;
532
533 using:  TOK_USING using_list
534 ;
535
536 ids_body:
537         ident {
538                 cur_strlist->push_back($1);
539         }
540 |       ids_body ',' ident {
541                 cur_strlist->push_back($3);
542         }
543 ;
544
545 ids:
546         ids_body {
547                 $$ = cur_strlist;
548                 cur_strlist = new StrList;
549         }
550 ;
551
552 maybe_ids:
553         /* empty */ {
554                 $$ = NULL;
555         }
556 |       ids {
557                 $$ = $1;
558         }
559 ;
560
561 coninit:
562         ident '=' const {
563                 cur_conlist->push_back(ConInit($1, $3));
564         }
565 ;
566
567 /* ideqs is ids with a constant initializer for each element. */
568
569 ideqs_body:
570         coninit
571 |       ids_body ',' coninit
572 ;
573
574 ideqs:
575         ideqs_body {
576                 $$ = cur_conlist;
577                 cur_conlist = new ConList;
578         }
579 ;
580
581 ident:
582         TOK_IDENT
583 |       TOK_ASYNC    {
584                 $$ = new String("async", cur_input_file, curline, TOK_ASYNC);
585         }
586 |       TOK_INOUT    {
587                 $$ = new String("inout", cur_input_file, curline, TOK_INOUT);
588         }
589 |       TOK_OUT      {
590                 $$ = new String("out", cur_input_file, curline, TOK_OUT);
591         }
592 |       TOK_SHARED   {
593                 $$ = new String("shared", cur_input_file, curline, TOK_SHARED);
594         }
595 |       TOK_PUSH     {
596                 $$ = new String("push", cur_input_file, curline, TOK_PUSH);
597         }
598 |       TOK_SHORT    {
599                 $$ = new String("short", cur_input_file, curline, TOK_SHORT);
600         }
601 |       TOK_INT      {
602                 $$ = new String("int", cur_input_file, curline, TOK_INT);
603         }
604 |       TOK_LONG     {
605                 $$ = new String("long", cur_input_file, curline, TOK_LONG);
606         }
607 |       TOK_USHORT   {
608                 $$ = new String("ushort", cur_input_file, curline, TOK_USHORT);
609         }
610 |       TOK_UINT     {
611                 $$ = new String("uint", cur_input_file, curline, TOK_UINT);
612         }
613 |       TOK_ULONG    {
614                 $$ = new String("ulong", cur_input_file, curline, TOK_ULONG);
615         }
616 |       TOK_CHAR     {
617                 $$ = new String("char", cur_input_file, curline, TOK_CHAR);
618         }
619 |       TOK_OCTET    {
620                 $$ = new String("octet", cur_input_file, curline, TOK_OCTET);
621         }
622 |       TOK_FSHORT   {
623                 $$ = new String("fshort", cur_input_file, curline, TOK_FSHORT);
624         }
625 |       TOK_FLONG    {
626                 $$ = new String("flong", cur_input_file, curline, TOK_FLONG);
627         }
628 |       TOK_BOOL     {
629                 $$ = new String("bool", cur_input_file, curline, TOK_BOOL);
630         }
631 |       TOK_METHOD   {
632                 $$ = new String("method", cur_input_file, curline, TOK_METHOD);
633         }
634 |       TOK_NAME     {
635                 $$ = new String("name", cur_input_file, curline, TOK_NAME);
636         }
637 |       TOK_COPY     {
638                 $$ = new String("copy", cur_input_file, curline, TOK_COPY);
639         }
640 |       TOK_CLASS    {
641                 $$ = new String("class", cur_input_file, curline, TOK_CLASS);
642         }
643 |       TOK_GUID     {
644                 $$ = new String("guid", cur_input_file, curline, TOK_GUID);
645         }
646 |       TOK_STATIC   {
647                 $$ = new String("static", cur_input_file, curline, TOK_STATIC);
648         }
649 |       TOK_VIRTUAL  {
650                 $$ = new String("virtual", cur_input_file, curline, TOK_VIRTUAL);
651         }
652 |       TOK_INLINE {
653                 $$ = new String("inline", cur_input_file, curline, TOK_INLINE);
654         }
655 |       TOK_IMMUTABLE {
656                 $$ = new String("immutable", cur_input_file, curline, TOK_IMMUTABLE);
657         }
658 ;
659
660 strlist_body:
661         ident {
662                 cur_strlist->push_back($1);
663         }
664 |       strlist_body ident {
665                 cur_strlist->push_back($2);
666         }
667 ;
668
669 end_strlist: {
670                 $$ = cur_strlist;
671                 cur_strlist = new StrList;
672         }
673 ;
674
675 strlist:
676         strlist_body end_strlist {
677                 $$ = $2;
678         }
679 ;
680
681 maybe_strlist:
682         end_strlist 
683 |       strlist
684 ;
685
686 qualified_ident_raw:
687         ident {
688                 cur_strlist->push_back($1);
689         }
690 |       qualified_ident_raw '.' ident {
691                 cur_strlist->push_back($3);
692         }
693 ;
694
695 maybe_dot_star:
696         /* empty */ {
697                 $$ = false;
698         }
699 |       '.' '*' {
700                 $$ = true;
701         }
702 ;
703
704 qualified_ident_nodbldot:
705         qualified_ident_raw maybe_dot_star {
706                 if ($2)
707                         cur_strlist->push_back(new String("*", cur_input_file, 
708                                                           curline, '*'));
709                 
710                 $$ = cur_strlist;
711                 cur_strlist = new StrList;
712         }
713 ;
714
715 qualified_ident:
716         TOK_2DOT {
717                 cur_strlist->push_front(new String("", cur_input_file, 
718                                                    curline, TOK_IDENT));
719         } qualified_ident_nodbldot {
720                 $$ = $3;
721         }
722 |       qualified_ident_nodbldot
723 ;
724
725 qualified_decl:
726         qualified_ident_raw {
727                 $$.ident = cur_strlist->back();
728                 cur_strlist->pop_back();
729                 
730                 if (!cur_strlist->empty())
731                         $$.ns = add_nspace(cur_strlist, true);
732                 else {
733                         $$.ns = cur_nspace;
734                         nspace_stack.push_front(cur_nspace);
735                 }
736                 
737                 cur_strlist = new StrList;
738                 
739                 if (!$$.ns)
740                         do_yyerror();
741         }
742 ;
743
744 anon_decl: {
745                 char buf[32];
746                 snprintf(buf, 32, "_anon_%u", cur_nspace->anon++);
747                 
748                 $$.ns = cur_nspace;
749                 $$.ident = new String(buf, cur_input_file, curline, TOK_ANON);
750                 nspace_stack.push_front(cur_nspace);
751         }
752 ;
753
754 maybe_qualified_decl:
755         anon_decl
756 |       qualified_decl
757 ;
758
759 qualified_ids:
760         qualified_ident {
761                 cur_idlist->push_back($1);
762         } 
763 |       qualified_ids ',' qualified_ident {
764                 cur_idlist->push_back($3);
765         }
766 ;
767
768 qualified_idlist:
769         qualified_ids {
770                 $$ = cur_idlist;
771                 cur_idlist = new IDList;
772         }
773 ;
774
775 enum:
776         TOK_ENUM maybe_qualified_decl size '{' {
777                 int bits = 32;
778                 
779                 if ($3.type == TOK_UCON)
780                         bits = $3.con.ucon;
781
782                 $<en>$ = Enum::declare($2.ident, $2.ns, bits);
783
784                 nspace_stack.push_front(cur_nspace);
785                 cur_nspace = $<en>$;
786         } enuments '}' {
787                 pop_nspace();
788                 pop_nspace();
789                 $$ = $<en>5;
790         }
791 ;
792
793 more_enuments:
794         /* empty */
795 |       ',' enuments
796 ;
797
798 enuments:
799         /* empty */
800 |       ident {
801                 Enum *en = dynamic_cast<Enum *>(*cur_nspace);
802                 assert(en);
803
804                 CompiledBasicType bt = { bits: en->def.bits };
805                 
806                 // GCC can't handle complex labelled initializers as of 3.3;
807                 // plus, the syntax gets kind of ugly.
808                 
809                 bt.flags.field.Unsigned = 1;
810                 
811                 Con con;
812                 con.type = TOK_UCON;
813                 con.con.ucon = en->next_val++;
814                 
815                 Datum::declare($1, en, bt, NULL, &con);
816         } more_enuments
817 ;
818
819 bitfield:
820         TOK_BITFIELD maybe_qualified_decl size '{' {
821                 int bits = 32;
822                 
823                 if ($3.type == TOK_UCON)
824                         bits = $3.con.ucon;
825         
826                 $<bf>$ = BitField::declare($2.ident, $2.ns, bits);
827
828                 nspace_stack.push_front(cur_nspace);
829                 cur_nspace = $<bf>$;
830         } maybe_bfelems '}' {
831                 pop_nspace();
832                 pop_nspace();
833                 $$ = $<bf>5;
834         }
835 ;
836
837 size:
838         /* empty */ {
839                 $$.type = TOK_NONE;
840         }
841 |       ':' const {
842                 $$ = $2;
843                 
844                 if ($$.type == TOK_DCON) {
845                         // FIXME: support symbolic sizes
846                         yyerrorf("Symbolic sizes are currently unsupported.\n");
847                         $$.type = TOK_INVALID;
848                 } else if (!(($$.type == TOK_UCON && $$.con.ucon > 0) ||
849                              ($$.type == TOK_ICON && $$.con.icon > 0)))
850                 {
851                         yyerrorf("Sizes must be positive integers.");
852                         
853                         $$.type = TOK_INVALID;
854                         $$.con.ucon = 0;
855                 } else {
856                         // Promote signed to unsigned.
857                         $$.type = TOK_UCON;
858                 }
859         }
860 ;
861
862 bfelems:
863         bfelem {
864                 $$ = new SymList;
865                 $$->push_back($1);
866         }
867 |       bfelems ',' bfelem {
868                 $1->push_back($3);
869         }
870 ;
871
872 maybe_comma:
873                 /* empty */
874         |       ','
875 ;
876
877 maybe_bfelems:
878                 /* empty */ {
879                         $$ = new SymList;
880                 }
881         |       bfelems maybe_comma
882 ;
883
884 bftype:
885         ident {
886                 CompiledBasicType bt = {};
887                 bt.flags.field.Unsigned = 1;
888                 bt.bits = dynamic_cast<BitField *>(*cur_nspace)->def.bits;
889
890                 $$ = Datum::declare($1, cur_nspace, bt, NULL);
891         }
892 |       basictype ident {
893                 $$ = Datum::declare($2, cur_nspace, $1, NULL);
894         }
895 |       enum ident {
896                 StrList *strl = $1->get_fq_name();
897                 strl->push_front(new String(""));
898                 $$ = Datum::declare($2, cur_nspace, strl, NULL);
899         }
900 |       bitfield ident {
901                 StrList *strl = $1->get_fq_name();
902                 strl->push_front(new String(""));
903                 $$ = Datum::declare($2, cur_nspace, strl, NULL);
904         }
905 ;
906  
907 bfelem: bftype size {
908                 $$ = $1;
909
910                 if ($2.type == TOK_UCON)
911                         $$->def.ucon = $2.con.ucon;
912                 else
913                         $$->def.icon = -1;
914         }
915 ;
916
917 basictype:
918         qualified_ident {
919                 $$ = $1;
920         }
921 ;
922
923 type:
924         basictype {
925                 $$.type = $1;
926                 $$.array = NULL;
927         }
928 |       basictype '[' arraybounds ']' { 
929                 $$.type = $1;
930                 $$.array = $3;
931         }
932 ;
933
934 maybeconst:
935         /* empty */ {
936                 $$.type = TOK_NONE;
937         }
938 |       const {
939                 $$ = $1;
940         }
941 ;
942
943 const:
944         constnominus     {  $$ = $1; }
945 |       '-' constnominus {
946         
947                 switch($2.type) {
948                         case TOK_UCON:
949                                 yyerrorf("The constant %" PRIu64 " is too large to be negated.",
950                                          $2.con.ucon);
951                                 do_yyerror();
952                                 break;
953                                 
954                         case TOK_ICON:  
955                                 $$.con.icon = -$2.con.icon;
956                                 break;
957                                 
958                         case TOK_FCON:
959                                 $$.con.fcon = -$2.con.fcon;
960                 }
961                 
962                 $$.type = $2.type;
963         }
964 |       TOK_FALSE {
965                 $$.type = TOK_BOOL;
966                 $$.con.ucon = 0;
967         }
968 |       TOK_TRUE {
969                 $$.type = TOK_BOOL;
970                 $$.con.ucon = 1;
971         }
972 ;
973
974 constnominus:   
975         TOK_ICON     { $$ = $1; }
976 |       TOK_UCON     { $$ = $1; }
977 |       TOK_FCON     { $$ = $1; }
978 |       TOK_INVALID  { $$ = $1; }
979 |       qualified_ident {
980                 assert($1);
981                 $$.type = TOK_DCON;
982                 $$.con.dcon = $1;
983         }
984 ;
985
986 arraybounds:
987         /* empty */ {
988                 $$ = new Array(cur_nspace);
989                 $$->set_unbounded();
990         }
991 |       const {
992                 $$ = new Array(cur_nspace);
993                 $$->set_bound($1, 0);
994                 $$->set_bound($1, 1);
995         }
996 |       maybeconst TOK_3DOT maybeconst {
997                 $$ = new Array(cur_nspace);
998                 $$->set_bound($1, 0);
999                 $$->set_bound($3, 1);
1000         }
1001 ;
1002
1003 typedef_or_alias_keyword:
1004         TOK_TYPEDEF {
1005                 $$ = true;
1006         }
1007 |       TOK_ALIAS {
1008                 $$ = false;
1009         }
1010 ;
1011
1012 typedef_or_alias:
1013         typedef_or_alias_keyword basictype ids {
1014                 Type *t = lookup_type($2, NULL, true);
1015                 BasicType *bt = dynamic_cast<BasicType *>(t);
1016                 
1017                 if (bt) {
1018                         // It's a basic type, so a symbolic typedef won't work.
1019                         declare_basictypes(cur_nspace, $3, bt, $1);
1020                 } else {
1021                         declare_aliases(cur_nspace, $3, $2, $1);
1022                 }
1023         }
1024 ;
1025
1026 %%
1027
1028 void setup_idlparse()
1029 {
1030         yylval_con = &idl_lval.con;
1031         yylval_string = &idl_lval.string;
1032
1033         // These are kept in an initialized state so as to avoid the need
1034         // for some early actions, thus eliminating some conflicts that
1035         // would otherwise have caused things like "guid" to need to be
1036         // reserved words.
1037
1038         cur_strlist = new StrList;
1039         cur_conlist = new ConList;
1040         cur_idlist = new IDList;
1041 }