4 // This software is copyright (c) 2006 Scott Wood <scott@buserror.net>.
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:
13 // The above copyright notice and this permission notice shall be
14 // included in all copies or substantial portions of the Software.
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
33 #define do_yyerror() do { \
34 fprintf(stderr, "YYERROR at %d\n", __LINE__); \
38 #define do_yyerror() YYERROR
41 static StrListRef nspace_name;
42 static StrListRef cur_strlist;
43 static ConListRef cur_conlist;
44 static IDListRef cur_idlist;
48 // The lifetime of any of these pointers is one instance
49 // of the one_input rule.
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
95 // The token list must be exactly the same as in idlparse.y, so that
96 // the same lexer can be used.
98 %token <string> TOK_IDENT
103 %token <con> TOK_ICON
104 %token <con> TOK_FCON
105 %token <con> TOK_UCON
106 %token <con> TOK_INVALID
126 %token <string> TOK_STR
145 // These are not real tokens, but are used as special values in places that
146 // normally accept tokens.
151 %type <strl> basictype
154 %type <con> maybeconst
155 %type <array> arraybounds
156 %type <con> constnominus
159 %type <syml> maybe_bfelems
160 %type <strl> maybe_ids
165 %type <strl> maybe_strlist
166 %type <strl> end_strlist
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
181 %type <idl> inherit_ifaces
182 %type <boolean> typedef_or_alias_keyword
184 %type <struct_decl_attr> struct_decl_and_attr
185 %type <ids_attr> ids_attr
201 | typedef_or_alias ';' {}
211 NameSpace *ret = add_nspace(nspace_name, false);
218 NameSpace *ret = add_nspace(nspace_name, true);
227 NameSpace *ret = add_nspace(nspace_name, true);
238 TOK_NAMESPACE qualified_ident {
244 TOK_CONST type ideqs {
247 for (ConList::iterator i = cl->begin(); i != cl->end(); ++i)
248 Datum::declare((*i).str, cur_nspace, $2.type, $2.array, &(*i).con);
257 | ids maybe_strlist {
265 | type ids maybe_strlist ';' {
266 declare_data(cur_nspace, $2, $1.type, $1.array, $3);
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.");
274 StrList *strl = $1->get_fq_name();
275 strl->push_front(new String(""));
276 declare_data(cur_nspace, $2, strl, NULL, NULL);
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.");
285 StrList *strl = $1->get_fq_name();
286 strl->push_front(new String(""));
287 declare_data(cur_nspace, $2, strl, NULL, NULL);
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.");
296 StrList *strl = $1->get_fq_name();
297 strl->push_front(new String(""));
298 declare_data(cur_nspace, $2.ids, strl, NULL, $2.attr);
301 | typedef_or_alias ';'
304 Struct *str = dynamic_cast<Struct *>(*cur_nspace);
313 | struct_elem struct_body
320 | ':' qualified_ident {
325 struct_decl_and_attr:
327 // Anonymous structs have no attributes.
329 $$.attr = new StrList;
331 | qualified_decl maybe_strlist {
338 TOK_STRUCT struct_decl_and_attr inherit_struct '{' {
339 $<str>$ = Struct::declare($2.decl.ident, $2.decl.ns, $3);
341 for (StrList::iterator i = $2.attr->begin(); i != $2.attr->end(); ++i) {
342 const String *attr = *i;
344 switch (attr->token) {
346 $<str>$->set_virtual();
350 $<str>$->set_inline();
354 yyerrorfl(attr->file, attr->line, "Invalid attribute \"%s\"",
359 nspace_stack.push_front(cur_nspace);
360 cur_nspace = $<str>$;
364 // One for the struct's namespace, and one for the
365 // namespace it was declared in.
374 const String *name = $2->front();
377 CompiledParam::Flags flags = {};
382 for (StrList::iterator i = $2->begin(); i != $2->end(); ++i) {
383 const String *attr = *i;
385 switch (attr->token) {
388 yyerrorf("Only one direction attribute may be given.");
398 yyerrorf("Only one direction attribute may be given.");
407 flags.field.Shared = 1;
411 flags.field.Push = 1;
415 flags.field.Inline = 1;
419 flags.field.Immutable = 1;
423 yyerrorfl(attr->file, attr->line,
424 "Invalid attribute \"%s\"", (*i)->c_str());
428 Param::declare(name, cur_nspace, $1.type, flags, $1.array);
444 $<meth>$ = Method::declare($1, cur_nspace);
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;
452 switch (attr->token) {
454 $<meth>3->set_async();
458 yyerrorfl(attr->file, attr->line,
459 "Invalid attribute \"%s\".", (*i)->c_str());
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);
481 | using ';' iface_body
485 TOK_GUID ':' TOK_STR {
486 parse_guid($3->c_str(), (char *)$$);
495 | ':' qualified_idlist {
501 TOK_IFACE qualified_decl inherit_ifaces {
502 $<iface>$ = Interface::declare($2.ident, $2.ns, $3);
504 nspace_stack.push_front(cur_nspace);
505 cur_nspace = $<iface>$;
506 } '{' iface_body '}' {
519 maybe_namespace qualified_ident {
520 const String *end = $2->back();
523 if (end->token == '*') {
529 cur_nspace->add_search($2);
531 Alias::declare(end, cur_nspace, $2, true);
538 | using_list_entry ',' using_list
541 using: TOK_USING using_list
546 cur_strlist->push_back($1);
548 | ids_body ',' ident {
549 cur_strlist->push_back($3);
556 cur_strlist = new StrList;
571 cur_conlist->push_back(ConInit($1, $3));
575 /* ideqs is ids with a constant initializer for each element. */
579 | ids_body ',' coninit
585 cur_conlist = new ConList;
592 $$ = new String("async", cur_input_file, curline, TOK_ASYNC);
595 $$ = new String("inout", cur_input_file, curline, TOK_INOUT);
598 $$ = new String("out", cur_input_file, curline, TOK_OUT);
601 $$ = new String("shared", cur_input_file, curline, TOK_SHARED);
604 $$ = new String("push", cur_input_file, curline, TOK_PUSH);
607 $$ = new String("short", cur_input_file, curline, TOK_SHORT);
610 $$ = new String("int", cur_input_file, curline, TOK_INT);
613 $$ = new String("long", cur_input_file, curline, TOK_LONG);
616 $$ = new String("ushort", cur_input_file, curline, TOK_USHORT);
619 $$ = new String("uint", cur_input_file, curline, TOK_UINT);
622 $$ = new String("ulong", cur_input_file, curline, TOK_ULONG);
625 $$ = new String("char", cur_input_file, curline, TOK_CHAR);
628 $$ = new String("octet", cur_input_file, curline, TOK_OCTET);
631 $$ = new String("fshort", cur_input_file, curline, TOK_FSHORT);
634 $$ = new String("flong", cur_input_file, curline, TOK_FLONG);
637 $$ = new String("bool", cur_input_file, curline, TOK_BOOL);
640 $$ = new String("method", cur_input_file, curline, TOK_METHOD);
643 $$ = new String("name", cur_input_file, curline, TOK_NAME);
646 $$ = new String("copy", cur_input_file, curline, TOK_COPY);
649 $$ = new String("class", cur_input_file, curline, TOK_CLASS);
652 $$ = new String("guid", cur_input_file, curline, TOK_GUID);
655 $$ = new String("static", cur_input_file, curline, TOK_STATIC);
658 $$ = new String("virtual", cur_input_file, curline, TOK_VIRTUAL);
661 $$ = new String("inline", cur_input_file, curline, TOK_INLINE);
664 $$ = new String("immutable", cur_input_file, curline, TOK_IMMUTABLE);
670 cur_strlist->push_back($1);
672 | strlist_body ident {
673 cur_strlist->push_back($2);
679 cur_strlist = new StrList;
684 strlist_body end_strlist {
696 cur_strlist->push_back($1);
698 | qualified_ident_raw '.' ident {
699 cur_strlist->push_back($3);
712 qualified_ident_nodbldot:
713 qualified_ident_raw maybe_dot_star {
715 cur_strlist->push_back(new String("*", cur_input_file,
719 cur_strlist = new StrList;
725 cur_strlist->push_front(new String("", cur_input_file,
726 curline, TOK_IDENT));
727 } qualified_ident_nodbldot {
730 | qualified_ident_nodbldot
734 qualified_ident_raw {
735 $$.ident = cur_strlist->back();
738 cur_strlist->pop_back();
740 if (!cur_strlist->empty())
741 $$.ns = add_nspace(cur_strlist, true);
744 nspace_stack.push_front(cur_nspace);
747 cur_strlist = new StrList;
756 snprintf(buf, 32, "_anon_%u", cur_nspace->anon++);
759 $$.ident = new String(buf, cur_input_file, curline, TOK_ANON);
760 nspace_stack.push_front(cur_nspace);
764 maybe_qualified_decl:
771 cur_idlist->push_back($1);
773 | qualified_ids ',' qualified_ident {
774 cur_idlist->push_back($3);
781 cur_idlist = new IDList;
786 TOK_ENUM maybe_qualified_decl size '{' {
789 if ($3.type == TOK_UCON)
792 $<en>$ = Enum::declare($2.ident, $2.ns, bits);
794 nspace_stack.push_front(cur_nspace);
811 Enum *en = dynamic_cast<Enum *>(*cur_nspace);
814 CompiledBasicType bt = { bits: en->def.bits };
816 // GCC can't handle complex labelled initializers as of 3.3;
817 // plus, the syntax gets kind of ugly.
819 bt.flags.field.Unsigned = 1;
823 con.con.ucon = en->next_val++;
825 Datum::declare($1, en, bt, NULL, &con);
830 TOK_BITFIELD maybe_qualified_decl size '{' {
833 if ($3.type == TOK_UCON)
836 $<bf>$ = BitField::declare($2.ident, $2.ns, bits);
838 nspace_stack.push_front(cur_nspace);
840 } maybe_bfelems '}' {
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)))
861 yyerrorf("Sizes must be positive integers.");
863 $$.type = TOK_INVALID;
866 // Promote signed to unsigned.
877 | bfelems ',' bfelem {
891 | bfelems maybe_comma
896 CompiledBasicType bt = {};
897 bt.flags.field.Unsigned = 1;
898 bt.bits = dynamic_cast<BitField *>(*cur_nspace)->def.bits;
900 $$ = Datum::declare($1, cur_nspace, bt, NULL);
903 $$ = Datum::declare($2, cur_nspace, $1, NULL);
906 StrList *strl = $1->get_fq_name();
907 strl->push_front(new String(""));
908 $$ = Datum::declare($2, cur_nspace, strl, NULL);
911 StrList *strl = $1->get_fq_name();
912 strl->push_front(new String(""));
913 $$ = Datum::declare($2, cur_nspace, strl, NULL);
917 bfelem: bftype size {
920 if ($2.type == TOK_UCON)
921 $$->def.ucon = $2.con.ucon;
938 | basictype '[' arraybounds ']' {
954 constnominus { $$ = $1; }
959 yyerrorf("The constant %" PRIu64 " is too large to be negated.",
965 $$.con.icon = -$2.con.icon;
969 $$.con.fcon = -$2.con.fcon;
985 TOK_ICON { $$ = $1; }
986 | TOK_UCON { $$ = $1; }
987 | TOK_FCON { $$ = $1; }
988 | TOK_INVALID { $$ = $1; }
998 $$ = new Array(cur_nspace);
1002 $$ = new Array(cur_nspace);
1003 $$->set_bound($1, 0);
1004 $$->set_bound($1, 1);
1006 | maybeconst TOK_3DOT maybeconst {
1007 $$ = new Array(cur_nspace);
1008 $$->set_bound($1, 0);
1009 $$->set_bound($3, 1);
1013 typedef_or_alias_keyword:
1023 typedef_or_alias_keyword basictype ids {
1024 Type *t = lookup_type($2, NULL, true);
1025 BasicType *bt = dynamic_cast<BasicType *>(t);
1028 // It's a basic type, so a symbolic typedef won't work.
1029 declare_basictypes(cur_nspace, $3, bt, $1);
1031 declare_aliases(cur_nspace, $3, $2, $1);
1038 void setup_idlparse()
1040 yylval_con = &idl_lval.con;
1041 yylval_string = &idl_lval.string;
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
1048 cur_strlist = new StrList;
1049 cur_conlist = new ConList;
1050 cur_idlist = new IDList;