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