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