4 // This software is copyright (c) 2006 Scott Wood <scott@buserror.net>.
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.
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.
25 #define do_yyerror() do { \
26 fprintf(stderr, "YYERROR at %d\n", __LINE__); \
30 #define do_yyerror() YYERROR
33 static StrListRef nspace_name;
34 static StrListRef cur_strlist;
35 static ConListRef cur_conlist;
36 static IDListRef cur_idlist;
40 // The lifetime of any of these pointers is one instance
41 // of the one_input rule.
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
87 // The token list must be exactly the same as in idlparse.y, so that
88 // the same lexer can be used.
90 %token <string> TOK_IDENT
98 %token <con> TOK_INVALID
118 %token <string> TOK_STR
137 // These are not real tokens, but are used as special values in places that
138 // normally accept tokens.
143 %type <strl> basictype
146 %type <con> maybeconst
147 %type <array> arraybounds
148 %type <con> constnominus
151 %type <syml> maybe_bfelems
152 %type <strl> maybe_ids
157 %type <strl> maybe_strlist
158 %type <strl> end_strlist
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
173 %type <idl> inherit_ifaces
174 %type <boolean> typedef_or_alias_keyword
176 %type <struct_decl_attr> struct_decl_and_attr
177 %type <ids_attr> ids_attr
193 | typedef_or_alias ';' {}
203 NameSpace *ret = add_nspace(nspace_name, false);
210 NameSpace *ret = add_nspace(nspace_name, true);
219 NameSpace *ret = add_nspace(nspace_name, true);
230 TOK_NAMESPACE qualified_ident {
236 TOK_CONST type ideqs {
239 for (ConList::iterator i = cl->begin(); i != cl->end(); ++i)
240 Datum::declare((*i).str, cur_nspace, $2.type, $2.array, &(*i).con);
249 | ids maybe_strlist {
257 | type ids maybe_strlist ';' {
258 declare_data(cur_nspace, $2, $1.type, $1.array, $3);
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.");
266 StrList *strl = $1->get_fq_name();
267 strl->push_front(new String(""));
268 declare_data(cur_nspace, $2, strl, NULL, NULL);
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.");
277 StrList *strl = $1->get_fq_name();
278 strl->push_front(new String(""));
279 declare_data(cur_nspace, $2, strl, NULL, NULL);
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.");
288 StrList *strl = $1->get_fq_name();
289 strl->push_front(new String(""));
290 declare_data(cur_nspace, $2.ids, strl, NULL, $2.attr);
293 | typedef_or_alias ';'
296 Struct *str = dynamic_cast<Struct *>(*cur_nspace);
305 | struct_elem struct_body
312 | ':' qualified_ident {
317 struct_decl_and_attr:
319 // Anonymous structs have no attributes.
321 $$.attr = new StrList;
323 | qualified_decl maybe_strlist {
330 TOK_STRUCT struct_decl_and_attr inherit_struct '{' {
331 $<str>$ = Struct::declare($2.decl.ident, $2.decl.ns, $3);
333 for (StrList::iterator i = $2.attr->begin(); i != $2.attr->end(); ++i) {
334 const String *attr = *i;
336 switch (attr->token) {
338 $<str>$->set_virtual();
342 $<str>$->set_inline();
346 yyerrorfl(attr->file, attr->line, "Invalid attribute \"%s\"",
351 nspace_stack.push_front(cur_nspace);
352 cur_nspace = $<str>$;
356 // One for the struct's namespace, and one for the
357 // namespace it was declared in.
366 const String *name = $2->front();
369 CompiledParam::Flags flags = {};
374 for (StrList::iterator i = $2->begin(); i != $2->end(); ++i) {
375 const String *attr = *i;
377 switch (attr->token) {
380 yyerrorf("Only one direction attribute may be given.");
390 yyerrorf("Only one direction attribute may be given.");
399 flags.field.Shared = 1;
403 flags.field.Push = 1;
407 flags.field.Inline = 1;
411 flags.field.Immutable = 1;
415 yyerrorfl(attr->file, attr->line,
416 "Invalid attribute \"%s\"", (*i)->c_str());
420 Param::declare(name, cur_nspace, $1.type, flags, $1.array);
426 | param_list_nonempty ',' param
431 | param_list_nonempty
435 $<meth>$ = Method::declare($1, cur_nspace);
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;
443 switch (attr->token) {
445 $<meth>3->set_async();
449 yyerrorfl(attr->file, attr->line,
450 "Invalid attribute \"%s\".", (*i)->c_str());
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);
472 | using ';' iface_body
476 TOK_GUID ':' TOK_STR {
477 parse_guid($3->c_str(), (char *)$$);
486 | ':' qualified_idlist {
492 TOK_IFACE qualified_decl inherit_ifaces {
493 $<iface>$ = Interface::declare($2.ident, $2.ns, $3);
495 nspace_stack.push_front(cur_nspace);
496 cur_nspace = $<iface>$;
497 } '{' iface_body '}' {
510 maybe_namespace qualified_ident {
511 const String *end = $2->back();
514 if (end->token == '*') {
520 cur_nspace->add_search($2);
522 Alias::declare(end, cur_nspace, $2, true);
529 | using_list_entry ',' using_list
532 using: TOK_USING using_list
537 cur_strlist->push_back($1);
539 | ids_body ',' ident {
540 cur_strlist->push_back($3);
547 cur_strlist = new StrList;
562 cur_conlist->push_back(ConInit($1, $3));
566 /* ideqs is ids with a constant initializer for each element. */
570 | ids_body ',' coninit
576 cur_conlist = new ConList;
583 $$ = new String("async", cur_input_file, curline, TOK_ASYNC);
586 $$ = new String("inout", cur_input_file, curline, TOK_INOUT);
589 $$ = new String("out", cur_input_file, curline, TOK_OUT);
592 $$ = new String("shared", cur_input_file, curline, TOK_SHARED);
595 $$ = new String("push", cur_input_file, curline, TOK_PUSH);
598 $$ = new String("short", cur_input_file, curline, TOK_SHORT);
601 $$ = new String("int", cur_input_file, curline, TOK_INT);
604 $$ = new String("long", cur_input_file, curline, TOK_LONG);
607 $$ = new String("ushort", cur_input_file, curline, TOK_USHORT);
610 $$ = new String("uint", cur_input_file, curline, TOK_UINT);
613 $$ = new String("ulong", cur_input_file, curline, TOK_ULONG);
616 $$ = new String("char", cur_input_file, curline, TOK_CHAR);
619 $$ = new String("octet", cur_input_file, curline, TOK_OCTET);
622 $$ = new String("fshort", cur_input_file, curline, TOK_FSHORT);
625 $$ = new String("flong", cur_input_file, curline, TOK_FLONG);
628 $$ = new String("bool", cur_input_file, curline, TOK_BOOL);
631 $$ = new String("method", cur_input_file, curline, TOK_METHOD);
634 $$ = new String("name", cur_input_file, curline, TOK_NAME);
637 $$ = new String("copy", cur_input_file, curline, TOK_COPY);
640 $$ = new String("class", cur_input_file, curline, TOK_CLASS);
643 $$ = new String("guid", cur_input_file, curline, TOK_GUID);
646 $$ = new String("static", cur_input_file, curline, TOK_STATIC);
649 $$ = new String("virtual", cur_input_file, curline, TOK_VIRTUAL);
652 $$ = new String("inline", cur_input_file, curline, TOK_INLINE);
655 $$ = new String("immutable", cur_input_file, curline, TOK_IMMUTABLE);
661 cur_strlist->push_back($1);
663 | strlist_body ident {
664 cur_strlist->push_back($2);
670 cur_strlist = new StrList;
675 strlist_body end_strlist {
687 cur_strlist->push_back($1);
689 | qualified_ident_raw '.' ident {
690 cur_strlist->push_back($3);
703 qualified_ident_nodbldot:
704 qualified_ident_raw maybe_dot_star {
706 cur_strlist->push_back(new String("*", cur_input_file,
710 cur_strlist = new StrList;
716 cur_strlist->push_front(new String("", cur_input_file,
717 curline, TOK_IDENT));
718 } qualified_ident_nodbldot {
721 | qualified_ident_nodbldot
725 qualified_ident_raw {
726 $$.ident = cur_strlist->back();
727 cur_strlist->pop_back();
729 if (!cur_strlist->empty())
730 $$.ns = add_nspace(cur_strlist, true);
733 nspace_stack.push_front(cur_nspace);
736 cur_strlist = new StrList;
745 snprintf(buf, 32, "_anon_%u", cur_nspace->anon++);
748 $$.ident = new String(buf, cur_input_file, curline, TOK_ANON);
749 nspace_stack.push_front(cur_nspace);
753 maybe_qualified_decl:
760 cur_idlist->push_back($1);
762 | qualified_ids ',' qualified_ident {
763 cur_idlist->push_back($3);
770 cur_idlist = new IDList;
775 TOK_ENUM maybe_qualified_decl size '{' {
778 if ($3.type == TOK_UCON)
781 $<en>$ = Enum::declare($2.ident, $2.ns, bits);
783 nspace_stack.push_front(cur_nspace);
800 Enum *en = dynamic_cast<Enum *>(*cur_nspace);
803 CompiledBasicType bt = { bits: en->def.bits };
805 // GCC can't handle complex labelled initializers as of 3.3;
806 // plus, the syntax gets kind of ugly.
808 bt.flags.field.Unsigned = 1;
812 con.con.ucon = en->next_val++;
814 Datum::declare($1, en, bt, NULL, &con);
819 TOK_BITFIELD maybe_qualified_decl size '{' {
822 if ($3.type == TOK_UCON)
825 $<bf>$ = BitField::declare($2.ident, $2.ns, bits);
827 nspace_stack.push_front(cur_nspace);
829 } maybe_bfelems '}' {
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)))
850 yyerrorf("Sizes must be positive integers.");
852 $$.type = TOK_INVALID;
855 // Promote signed to unsigned.
866 | bfelems ',' bfelem {
880 | bfelems maybe_comma
885 CompiledBasicType bt = {};
886 bt.flags.field.Unsigned = 1;
887 bt.bits = dynamic_cast<BitField *>(*cur_nspace)->def.bits;
889 $$ = Datum::declare($1, cur_nspace, bt, NULL);
892 $$ = Datum::declare($2, cur_nspace, $1, NULL);
895 StrList *strl = $1->get_fq_name();
896 strl->push_front(new String(""));
897 $$ = Datum::declare($2, cur_nspace, strl, NULL);
900 StrList *strl = $1->get_fq_name();
901 strl->push_front(new String(""));
902 $$ = Datum::declare($2, cur_nspace, strl, NULL);
906 bfelem: bftype size {
909 if ($2.type == TOK_UCON)
910 $$->def.ucon = $2.con.ucon;
927 | basictype '[' arraybounds ']' {
943 constnominus { $$ = $1; }
948 yyerrorf("The constant %" PRIu64 " is too large to be negated.",
954 $$.con.icon = -$2.con.icon;
958 $$.con.fcon = -$2.con.fcon;
974 TOK_ICON { $$ = $1; }
975 | TOK_UCON { $$ = $1; }
976 | TOK_FCON { $$ = $1; }
977 | TOK_INVALID { $$ = $1; }
987 $$ = new Array(cur_nspace);
991 $$ = new Array(cur_nspace);
992 $$->set_bound($1, 0);
993 $$->set_bound($1, 1);
995 | maybeconst TOK_3DOT maybeconst {
996 $$ = new Array(cur_nspace);
997 $$->set_bound($1, 0);
998 $$->set_bound($3, 1);
1002 typedef_or_alias_keyword:
1012 typedef_or_alias_keyword basictype ids {
1013 Type *t = lookup_type($2, NULL, true);
1014 BasicType *bt = dynamic_cast<BasicType *>(t);
1017 // It's a basic type, so a symbolic typedef won't work.
1018 declare_basictypes(cur_nspace, $3, bt, $1);
1020 declare_aliases(cur_nspace, $3, $2, $1);
1027 void setup_idlparse()
1029 yylval_con = &idl_lval.con;
1030 yylval_string = &idl_lval.string;
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
1037 cur_strlist = new StrList;
1038 cur_conlist = new ConList;
1039 cur_idlist = new IDList;