]> git.buserror.net Git - polintos/scott/priv.git/blob - idlcomp/idlparse.y
e15c7dd6f68794c58d734e6a91299ce2f6c60109
[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                 $$.ident->retain();
729                 
730                 cur_strlist->pop_back();
731                 
732                 if (!cur_strlist->empty())
733                         $$.ns = add_nspace(cur_strlist, true);
734                 else {
735                         $$.ns = cur_nspace;
736                         nspace_stack.push_front(cur_nspace);
737                 }
738                 
739                 cur_strlist = new StrList;
740                 
741                 if (!$$.ns)
742                         do_yyerror();
743         }
744 ;
745
746 anon_decl: {
747                 char buf[32];
748                 snprintf(buf, 32, "_anon_%u", cur_nspace->anon++);
749                 
750                 $$.ns = cur_nspace;
751                 $$.ident = new String(buf, cur_input_file, curline, TOK_ANON);
752                 nspace_stack.push_front(cur_nspace);
753         }
754 ;
755
756 maybe_qualified_decl:
757         anon_decl
758 |       qualified_decl
759 ;
760
761 qualified_ids:
762         qualified_ident {
763                 cur_idlist->push_back($1);
764         } 
765 |       qualified_ids ',' qualified_ident {
766                 cur_idlist->push_back($3);
767         }
768 ;
769
770 qualified_idlist:
771         qualified_ids {
772                 $$ = cur_idlist;
773                 cur_idlist = new IDList;
774         }
775 ;
776
777 enum:
778         TOK_ENUM maybe_qualified_decl size '{' {
779                 int bits = 32;
780                 
781                 if ($3.type == TOK_UCON)
782                         bits = $3.con.ucon;
783
784                 $<en>$ = Enum::declare($2.ident, $2.ns, bits);
785
786                 nspace_stack.push_front(cur_nspace);
787                 cur_nspace = $<en>$;
788         } enuments '}' {
789                 pop_nspace();
790                 pop_nspace();
791                 $$ = $<en>5;
792         }
793 ;
794
795 more_enuments:
796         /* empty */
797 |       ',' enuments
798 ;
799
800 enuments:
801         /* empty */
802 |       ident {
803                 Enum *en = dynamic_cast<Enum *>(*cur_nspace);
804                 assert(en);
805
806                 CompiledBasicType bt = { bits: en->def.bits };
807                 
808                 // GCC can't handle complex labelled initializers as of 3.3;
809                 // plus, the syntax gets kind of ugly.
810                 
811                 bt.flags.field.Unsigned = 1;
812                 
813                 Con con;
814                 con.type = TOK_UCON;
815                 con.con.ucon = en->next_val++;
816                 
817                 Datum::declare($1, en, bt, NULL, &con);
818         } more_enuments
819 ;
820
821 bitfield:
822         TOK_BITFIELD maybe_qualified_decl size '{' {
823                 int bits = 32;
824                 
825                 if ($3.type == TOK_UCON)
826                         bits = $3.con.ucon;
827         
828                 $<bf>$ = BitField::declare($2.ident, $2.ns, bits);
829
830                 nspace_stack.push_front(cur_nspace);
831                 cur_nspace = $<bf>$;
832         } maybe_bfelems '}' {
833                 pop_nspace();
834                 pop_nspace();
835                 $$ = $<bf>5;
836         }
837 ;
838
839 size:
840         /* empty */ {
841                 $$.type = TOK_NONE;
842         }
843 |       ':' const {
844                 $$ = $2;
845                 
846                 if ($$.type == TOK_DCON) {
847                         // FIXME: support symbolic sizes
848                         yyerrorf("Symbolic sizes are currently unsupported.\n");
849                         $$.type = TOK_INVALID;
850                 } else if (!(($$.type == TOK_UCON && $$.con.ucon > 0) ||
851                              ($$.type == TOK_ICON && $$.con.icon > 0)))
852                 {
853                         yyerrorf("Sizes must be positive integers.");
854                         
855                         $$.type = TOK_INVALID;
856                         $$.con.ucon = 0;
857                 } else {
858                         // Promote signed to unsigned.
859                         $$.type = TOK_UCON;
860                 }
861         }
862 ;
863
864 bfelems:
865         bfelem {
866                 $$ = new SymList;
867                 $$->push_back($1);
868         }
869 |       bfelems ',' bfelem {
870                 $1->push_back($3);
871         }
872 ;
873
874 maybe_comma:
875                 /* empty */
876         |       ','
877 ;
878
879 maybe_bfelems:
880                 /* empty */ {
881                         $$ = new SymList;
882                 }
883         |       bfelems maybe_comma
884 ;
885
886 bftype:
887         ident {
888                 CompiledBasicType bt = {};
889                 bt.flags.field.Unsigned = 1;
890                 bt.bits = dynamic_cast<BitField *>(*cur_nspace)->def.bits;
891
892                 $$ = Datum::declare($1, cur_nspace, bt, NULL);
893         }
894 |       basictype ident {
895                 $$ = Datum::declare($2, cur_nspace, $1, NULL);
896         }
897 |       enum ident {
898                 StrList *strl = $1->get_fq_name();
899                 strl->push_front(new String(""));
900                 $$ = Datum::declare($2, cur_nspace, strl, NULL);
901         }
902 |       bitfield ident {
903                 StrList *strl = $1->get_fq_name();
904                 strl->push_front(new String(""));
905                 $$ = Datum::declare($2, cur_nspace, strl, NULL);
906         }
907 ;
908  
909 bfelem: bftype size {
910                 $$ = $1;
911
912                 if ($2.type == TOK_UCON)
913                         $$->def.ucon = $2.con.ucon;
914                 else
915                         $$->def.icon = -1;
916         }
917 ;
918
919 basictype:
920         qualified_ident {
921                 $$ = $1;
922         }
923 ;
924
925 type:
926         basictype {
927                 $$.type = $1;
928                 $$.array = NULL;
929         }
930 |       basictype '[' arraybounds ']' { 
931                 $$.type = $1;
932                 $$.array = $3;
933         }
934 ;
935
936 maybeconst:
937         /* empty */ {
938                 $$.type = TOK_NONE;
939         }
940 |       const {
941                 $$ = $1;
942         }
943 ;
944
945 const:
946         constnominus     {  $$ = $1; }
947 |       '-' constnominus {
948         
949                 switch($2.type) {
950                         case TOK_UCON:
951                                 yyerrorf("The constant %" PRIu64 " is too large to be negated.",
952                                          $2.con.ucon);
953                                 do_yyerror();
954                                 break;
955                                 
956                         case TOK_ICON:  
957                                 $$.con.icon = -$2.con.icon;
958                                 break;
959                                 
960                         case TOK_FCON:
961                                 $$.con.fcon = -$2.con.fcon;
962                 }
963                 
964                 $$.type = $2.type;
965         }
966 |       TOK_FALSE {
967                 $$.type = TOK_BOOL;
968                 $$.con.ucon = 0;
969         }
970 |       TOK_TRUE {
971                 $$.type = TOK_BOOL;
972                 $$.con.ucon = 1;
973         }
974 ;
975
976 constnominus:   
977         TOK_ICON     { $$ = $1; }
978 |       TOK_UCON     { $$ = $1; }
979 |       TOK_FCON     { $$ = $1; }
980 |       TOK_INVALID  { $$ = $1; }
981 |       qualified_ident {
982                 assert($1);
983                 $$.type = TOK_DCON;
984                 $$.con.dcon = $1;
985         }
986 ;
987
988 arraybounds:
989         /* empty */ {
990                 $$ = new Array(cur_nspace);
991                 $$->set_unbounded();
992         }
993 |       const {
994                 $$ = new Array(cur_nspace);
995                 $$->set_bound($1, 0);
996                 $$->set_bound($1, 1);
997         }
998 |       maybeconst TOK_3DOT maybeconst {
999                 $$ = new Array(cur_nspace);
1000                 $$->set_bound($1, 0);
1001                 $$->set_bound($3, 1);
1002         }
1003 ;
1004
1005 typedef_or_alias_keyword:
1006         TOK_TYPEDEF {
1007                 $$ = true;
1008         }
1009 |       TOK_ALIAS {
1010                 $$ = false;
1011         }
1012 ;
1013
1014 typedef_or_alias:
1015         typedef_or_alias_keyword basictype ids {
1016                 Type *t = lookup_type($2, NULL, true);
1017                 BasicType *bt = dynamic_cast<BasicType *>(t);
1018                 
1019                 if (bt) {
1020                         // It's a basic type, so a symbolic typedef won't work.
1021                         declare_basictypes(cur_nspace, $3, bt, $1);
1022                 } else {
1023                         declare_aliases(cur_nspace, $3, $2, $1);
1024                 }
1025         }
1026 ;
1027
1028 %%
1029
1030 void setup_idlparse()
1031 {
1032         yylval_con = &idl_lval.con;
1033         yylval_string = &idl_lval.string;
1034
1035         // These are kept in an initialized state so as to avoid the need
1036         // for some early actions, thus eliminating some conflicts that
1037         // would otherwise have caused things like "guid" to need to be
1038         // reserved words.
1039
1040         cur_strlist = new StrList;
1041         cur_conlist = new ConList;
1042         cur_idlist = new IDList;
1043 }