]> git.buserror.net Git - polintos/scott/priv.git/blob - idlcomp/idlparse.y
minor doc updates
[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 param_list_nonempty:
425         param
426 |       param_list_nonempty ',' param
427 ;
428
429 param_list:
430         /* empty */
431 |       param_list_nonempty
432
433 method:
434         ident '(' {
435                 $<meth>$ = Method::declare($1, cur_nspace);
436                 
437                 nspace_stack.push_front(cur_nspace);
438                 cur_nspace = $<meth>$;
439         } param_list ')' maybe_strlist {
440                 for (StrList::iterator i = $6->begin(); i != $6->end(); ++i) {
441                         const String *attr = *i;
442
443                         switch (attr->token) {
444                                 case TOK_ASYNC:
445                                         $<meth>3->set_async();
446                                         break;
447                                 
448                                 default:
449                                         yyerrorfl(attr->file, attr->line,
450                                                   "Invalid attribute \"%s\".", (*i)->c_str());
451                         }
452                 }
453                 pop_nspace();
454         }
455 ;
456
457 iface_body:
458         /* empty */
459 |       method ';' iface_body
460 |       enum ';' iface_body {}
461 |       bitfield ';' iface_body {}
462 |       struct ';' iface_body {}
463 |       iface ';' iface_body {}
464 |       typedef_or_alias ';' iface_body
465 |       const_datum ';' iface_body
466 |       guid ';' iface_body {
467                 Interface *iface = dynamic_cast<Interface *>(*cur_nspace);
468                 assert(iface);
469                 
470                 iface->set_guid($1);
471         }
472 |       using ';' iface_body
473 ;
474
475 guid:
476         TOK_GUID ':' TOK_STR {
477                 parse_guid($3->c_str(), (char *)$$);
478         }
479 ;
480         
481
482 inherit_ifaces:
483         /* empty */ {
484                 $$ = new IDList;
485         }
486 |       ':' qualified_idlist {
487                 $$ = $2;
488         }
489 ;
490
491 iface:
492         TOK_IFACE qualified_decl inherit_ifaces {
493                 $<iface>$ = Interface::declare($2.ident, $2.ns, $3);
494
495                 nspace_stack.push_front(cur_nspace);
496                 cur_nspace = $<iface>$;
497         } '{' iface_body '}' {
498                 pop_nspace();
499                 pop_nspace();
500                 $$ = $<iface>4;
501         }
502 ;
503
504 maybe_namespace:
505                 /* empty */
506         |       TOK_NAMESPACE
507 ;
508
509 using_list_entry:
510         maybe_namespace qualified_ident {
511                 const String *end = $2->back();
512                 bool ns = false;
513                 
514                 if (end->token == '*') {
515                         ns = true;
516                         $2->pop_back();
517                 }
518                 
519                 if (ns) {
520                         cur_nspace->add_search($2);
521                 } else {
522                         Alias::declare(end, cur_nspace, $2, true);
523                 }
524         }
525 ;
526
527 using_list:
528                 using_list_entry
529         |       using_list_entry ',' using_list
530 ;
531
532 using:  TOK_USING using_list
533 ;
534
535 ids_body:
536         ident {
537                 cur_strlist->push_back($1);
538         }
539 |       ids_body ',' ident {
540                 cur_strlist->push_back($3);
541         }
542 ;
543
544 ids:
545         ids_body {
546                 $$ = cur_strlist;
547                 cur_strlist = new StrList;
548         }
549 ;
550
551 maybe_ids:
552         /* empty */ {
553                 $$ = NULL;
554         }
555 |       ids {
556                 $$ = $1;
557         }
558 ;
559
560 coninit:
561         ident '=' const {
562                 cur_conlist->push_back(ConInit($1, $3));
563         }
564 ;
565
566 /* ideqs is ids with a constant initializer for each element. */
567
568 ideqs_body:
569         coninit
570 |       ids_body ',' coninit
571 ;
572
573 ideqs:
574         ideqs_body {
575                 $$ = cur_conlist;
576                 cur_conlist = new ConList;
577         }
578 ;
579
580 ident:
581         TOK_IDENT
582 |       TOK_ASYNC    {
583                 $$ = new String("async", cur_input_file, curline, TOK_ASYNC);
584         }
585 |       TOK_INOUT    {
586                 $$ = new String("inout", cur_input_file, curline, TOK_INOUT);
587         }
588 |       TOK_OUT      {
589                 $$ = new String("out", cur_input_file, curline, TOK_OUT);
590         }
591 |       TOK_SHARED   {
592                 $$ = new String("shared", cur_input_file, curline, TOK_SHARED);
593         }
594 |       TOK_PUSH     {
595                 $$ = new String("push", cur_input_file, curline, TOK_PUSH);
596         }
597 |       TOK_SHORT    {
598                 $$ = new String("short", cur_input_file, curline, TOK_SHORT);
599         }
600 |       TOK_INT      {
601                 $$ = new String("int", cur_input_file, curline, TOK_INT);
602         }
603 |       TOK_LONG     {
604                 $$ = new String("long", cur_input_file, curline, TOK_LONG);
605         }
606 |       TOK_USHORT   {
607                 $$ = new String("ushort", cur_input_file, curline, TOK_USHORT);
608         }
609 |       TOK_UINT     {
610                 $$ = new String("uint", cur_input_file, curline, TOK_UINT);
611         }
612 |       TOK_ULONG    {
613                 $$ = new String("ulong", cur_input_file, curline, TOK_ULONG);
614         }
615 |       TOK_CHAR     {
616                 $$ = new String("char", cur_input_file, curline, TOK_CHAR);
617         }
618 |       TOK_OCTET    {
619                 $$ = new String("octet", cur_input_file, curline, TOK_OCTET);
620         }
621 |       TOK_FSHORT   {
622                 $$ = new String("fshort", cur_input_file, curline, TOK_FSHORT);
623         }
624 |       TOK_FLONG    {
625                 $$ = new String("flong", cur_input_file, curline, TOK_FLONG);
626         }
627 |       TOK_BOOL     {
628                 $$ = new String("bool", cur_input_file, curline, TOK_BOOL);
629         }
630 |       TOK_METHOD   {
631                 $$ = new String("method", cur_input_file, curline, TOK_METHOD);
632         }
633 |       TOK_NAME     {
634                 $$ = new String("name", cur_input_file, curline, TOK_NAME);
635         }
636 |       TOK_COPY     {
637                 $$ = new String("copy", cur_input_file, curline, TOK_COPY);
638         }
639 |       TOK_CLASS    {
640                 $$ = new String("class", cur_input_file, curline, TOK_CLASS);
641         }
642 |       TOK_GUID     {
643                 $$ = new String("guid", cur_input_file, curline, TOK_GUID);
644         }
645 |       TOK_STATIC   {
646                 $$ = new String("static", cur_input_file, curline, TOK_STATIC);
647         }
648 |       TOK_VIRTUAL  {
649                 $$ = new String("virtual", cur_input_file, curline, TOK_VIRTUAL);
650         }
651 |       TOK_INLINE {
652                 $$ = new String("inline", cur_input_file, curline, TOK_INLINE);
653         }
654 |       TOK_IMMUTABLE {
655                 $$ = new String("immutable", cur_input_file, curline, TOK_IMMUTABLE);
656         }
657 ;
658
659 strlist_body:
660         ident {
661                 cur_strlist->push_back($1);
662         }
663 |       strlist_body ident {
664                 cur_strlist->push_back($2);
665         }
666 ;
667
668 end_strlist: {
669                 $$ = cur_strlist;
670                 cur_strlist = new StrList;
671         }
672 ;
673
674 strlist:
675         strlist_body end_strlist {
676                 $$ = $2;
677         }
678 ;
679
680 maybe_strlist:
681         end_strlist 
682 |       strlist
683 ;
684
685 qualified_ident_raw:
686         ident {
687                 cur_strlist->push_back($1);
688         }
689 |       qualified_ident_raw '.' ident {
690                 cur_strlist->push_back($3);
691         }
692 ;
693
694 maybe_dot_star:
695         /* empty */ {
696                 $$ = false;
697         }
698 |       '.' '*' {
699                 $$ = true;
700         }
701 ;
702
703 qualified_ident_nodbldot:
704         qualified_ident_raw maybe_dot_star {
705                 if ($2)
706                         cur_strlist->push_back(new String("*", cur_input_file, 
707                                                           curline, '*'));
708                 
709                 $$ = cur_strlist;
710                 cur_strlist = new StrList;
711         }
712 ;
713
714 qualified_ident:
715         TOK_2DOT {
716                 cur_strlist->push_front(new String("", cur_input_file, 
717                                                    curline, TOK_IDENT));
718         } qualified_ident_nodbldot {
719                 $$ = $3;
720         }
721 |       qualified_ident_nodbldot
722 ;
723
724 qualified_decl:
725         qualified_ident_raw {
726                 $$.ident = cur_strlist->back();
727                 cur_strlist->pop_back();
728                 
729                 if (!cur_strlist->empty())
730                         $$.ns = add_nspace(cur_strlist, true);
731                 else {
732                         $$.ns = cur_nspace;
733                         nspace_stack.push_front(cur_nspace);
734                 }
735                 
736                 cur_strlist = new StrList;
737                 
738                 if (!$$.ns)
739                         do_yyerror();
740         }
741 ;
742
743 anon_decl: {
744                 char buf[32];
745                 snprintf(buf, 32, "_anon_%u", cur_nspace->anon++);
746                 
747                 $$.ns = cur_nspace;
748                 $$.ident = new String(buf, cur_input_file, curline, TOK_ANON);
749                 nspace_stack.push_front(cur_nspace);
750         }
751 ;
752
753 maybe_qualified_decl:
754         anon_decl
755 |       qualified_decl
756 ;
757
758 qualified_ids:
759         qualified_ident {
760                 cur_idlist->push_back($1);
761         } 
762 |       qualified_ids ',' qualified_ident {
763                 cur_idlist->push_back($3);
764         }
765 ;
766
767 qualified_idlist:
768         qualified_ids {
769                 $$ = cur_idlist;
770                 cur_idlist = new IDList;
771         }
772 ;
773
774 enum:
775         TOK_ENUM maybe_qualified_decl size '{' {
776                 int bits = 32;
777                 
778                 if ($3.type == TOK_UCON)
779                         bits = $3.con.ucon;
780
781                 $<en>$ = Enum::declare($2.ident, $2.ns, bits);
782
783                 nspace_stack.push_front(cur_nspace);
784                 cur_nspace = $<en>$;
785         } enuments '}' {
786                 pop_nspace();
787                 pop_nspace();
788                 $$ = $<en>5;
789         }
790 ;
791
792 more_enuments:
793         /* empty */
794 |       ',' enuments
795 ;
796
797 enuments:
798         /* empty */
799 |       ident {
800                 Enum *en = dynamic_cast<Enum *>(*cur_nspace);
801                 assert(en);
802
803                 CompiledBasicType bt = { bits: en->def.bits };
804                 
805                 // GCC can't handle complex labelled initializers as of 3.3;
806                 // plus, the syntax gets kind of ugly.
807                 
808                 bt.flags.field.Unsigned = 1;
809                 
810                 Con con;
811                 con.type = TOK_UCON;
812                 con.con.ucon = en->next_val++;
813                 
814                 Datum::declare($1, en, bt, NULL, &con);
815         } more_enuments
816 ;
817
818 bitfield:
819         TOK_BITFIELD maybe_qualified_decl size '{' {
820                 int bits = 32;
821                 
822                 if ($3.type == TOK_UCON)
823                         bits = $3.con.ucon;
824         
825                 $<bf>$ = BitField::declare($2.ident, $2.ns, bits);
826
827                 nspace_stack.push_front(cur_nspace);
828                 cur_nspace = $<bf>$;
829         } maybe_bfelems '}' {
830                 pop_nspace();
831                 pop_nspace();
832                 $$ = $<bf>5;
833         }
834 ;
835
836 size:
837         /* empty */ {
838                 $$.type = TOK_NONE;
839         }
840 |       ':' const {
841                 $$ = $2;
842                 
843                 if ($$.type == TOK_DCON) {
844                         // FIXME: support symbolic sizes
845                         yyerrorf("Symbolic sizes are currently unsupported.\n");
846                         $$.type = TOK_INVALID;
847                 } else if (!(($$.type == TOK_UCON && $$.con.ucon > 0) ||
848                              ($$.type == TOK_ICON && $$.con.icon > 0)))
849                 {
850                         yyerrorf("Sizes must be positive integers.");
851                         
852                         $$.type = TOK_INVALID;
853                         $$.con.ucon = 0;
854                 } else {
855                         // Promote signed to unsigned.
856                         $$.type = TOK_UCON;
857                 }
858         }
859 ;
860
861 bfelems:
862         bfelem {
863                 $$ = new SymList;
864                 $$->push_back($1);
865         }
866 |       bfelems ',' bfelem {
867                 $1->push_back($3);
868         }
869 ;
870
871 maybe_comma:
872                 /* empty */
873         |       ','
874 ;
875
876 maybe_bfelems:
877                 /* empty */ {
878                         $$ = new SymList;
879                 }
880         |       bfelems maybe_comma
881 ;
882
883 bftype:
884         ident {
885                 CompiledBasicType bt = {};
886                 bt.flags.field.Unsigned = 1;
887                 bt.bits = dynamic_cast<BitField *>(*cur_nspace)->def.bits;
888
889                 $$ = Datum::declare($1, cur_nspace, bt, NULL);
890         }
891 |       basictype ident {
892                 $$ = Datum::declare($2, cur_nspace, $1, NULL);
893         }
894 |       enum ident {
895                 StrList *strl = $1->get_fq_name();
896                 strl->push_front(new String(""));
897                 $$ = Datum::declare($2, cur_nspace, strl, NULL);
898         }
899 |       bitfield ident {
900                 StrList *strl = $1->get_fq_name();
901                 strl->push_front(new String(""));
902                 $$ = Datum::declare($2, cur_nspace, strl, NULL);
903         }
904 ;
905  
906 bfelem: bftype size {
907                 $$ = $1;
908
909                 if ($2.type == TOK_UCON)
910                         $$->def.ucon = $2.con.ucon;
911                 else
912                         $$->def.icon = -1;
913         }
914 ;
915
916 basictype:
917         qualified_ident {
918                 $$ = $1;
919         }
920 ;
921
922 type:
923         basictype {
924                 $$.type = $1;
925                 $$.array = NULL;
926         }
927 |       basictype '[' arraybounds ']' { 
928                 $$.type = $1;
929                 $$.array = $3;
930         }
931 ;
932
933 maybeconst:
934         /* empty */ {
935                 $$.type = TOK_NONE;
936         }
937 |       const {
938                 $$ = $1;
939         }
940 ;
941
942 const:
943         constnominus     {  $$ = $1; }
944 |       '-' constnominus {
945         
946                 switch($2.type) {
947                         case TOK_UCON:
948                                 yyerrorf("The constant %" PRIu64 " is too large to be negated.",
949                                          $2.con.ucon);
950                                 do_yyerror();
951                                 break;
952                                 
953                         case TOK_ICON:  
954                                 $$.con.icon = -$2.con.icon;
955                                 break;
956                                 
957                         case TOK_FCON:
958                                 $$.con.fcon = -$2.con.fcon;
959                 }
960                 
961                 $$.type = $2.type;
962         }
963 |       TOK_FALSE {
964                 $$.type = TOK_BOOL;
965                 $$.con.ucon = 0;
966         }
967 |       TOK_TRUE {
968                 $$.type = TOK_BOOL;
969                 $$.con.ucon = 1;
970         }
971 ;
972
973 constnominus:   
974         TOK_ICON     { $$ = $1; }
975 |       TOK_UCON     { $$ = $1; }
976 |       TOK_FCON     { $$ = $1; }
977 |       TOK_INVALID  { $$ = $1; }
978 |       qualified_ident {
979                 assert($1);
980                 $$.type = TOK_DCON;
981                 $$.con.dcon = $1;
982         }
983 ;
984
985 arraybounds:
986         /* empty */ {
987                 $$ = new Array(cur_nspace);
988                 $$->set_unbounded();
989         }
990 |       const {
991                 $$ = new Array(cur_nspace);
992                 $$->set_bound($1, 0);
993                 $$->set_bound($1, 1);
994         }
995 |       maybeconst TOK_3DOT maybeconst {
996                 $$ = new Array(cur_nspace);
997                 $$->set_bound($1, 0);
998                 $$->set_bound($3, 1);
999         }
1000 ;
1001
1002 typedef_or_alias_keyword:
1003         TOK_TYPEDEF {
1004                 $$ = true;
1005         }
1006 |       TOK_ALIAS {
1007                 $$ = false;
1008         }
1009 ;
1010
1011 typedef_or_alias:
1012         typedef_or_alias_keyword basictype ids {
1013                 Type *t = lookup_type($2, NULL, true);
1014                 BasicType *bt = dynamic_cast<BasicType *>(t);
1015                 
1016                 if (bt) {
1017                         // It's a basic type, so a symbolic typedef won't work.
1018                         declare_basictypes(cur_nspace, $3, bt, $1);
1019                 } else {
1020                         declare_aliases(cur_nspace, $3, $2, $1);
1021                 }
1022         }
1023 ;
1024
1025 %%
1026
1027 void setup_idlparse()
1028 {
1029         yylval_con = &idl_lval.con;
1030         yylval_string = &idl_lval.string;
1031
1032         // These are kept in an initialized state so as to avoid the need
1033         // for some early actions, thus eliminating some conflicts that
1034         // would otherwise have caused things like "guid" to need to be
1035         // reserved words.
1036
1037         cur_strlist = new StrList;
1038         cur_conlist = new ConList;
1039         cur_idlist = new IDList;
1040 }