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);
436 $<meth>$ = Method::declare($1, cur_nspace);
438 nspace_stack.push_front(cur_nspace);
439 cur_nspace = $<meth>$;
440 } param_list ')' maybe_strlist {
441 for (StrList::iterator i = $6->begin(); i != $6->end(); ++i) {
442 const String *attr = *i;
444 switch (attr->token) {
446 $<meth>3->set_async();
450 yyerrorfl(attr->file, attr->line,
451 "Invalid attribute \"%s\".", (*i)->c_str());
460 | method ';' iface_body
461 | enum ';' iface_body {}
462 | bitfield ';' iface_body {}
463 | struct ';' iface_body {}
464 | iface ';' iface_body {}
465 | typedef_or_alias ';' iface_body
466 | const_datum ';' iface_body
467 | guid ';' iface_body {
468 Interface *iface = dynamic_cast<Interface *>(*cur_nspace);
473 | using ';' iface_body
477 TOK_GUID ':' TOK_STR {
478 parse_guid($3->c_str(), (char *)$$);
487 | ':' qualified_idlist {
493 TOK_IFACE qualified_decl inherit_ifaces {
494 $<iface>$ = Interface::declare($2.ident, $2.ns, $3);
496 nspace_stack.push_front(cur_nspace);
497 cur_nspace = $<iface>$;
498 } '{' iface_body '}' {
511 maybe_namespace qualified_ident {
512 const String *end = $2->back();
515 if (end->token == '*') {
521 cur_nspace->add_search($2);
523 Alias::declare(end, cur_nspace, $2, true);
530 | using_list_entry ',' using_list
533 using: TOK_USING using_list
538 cur_strlist->push_back($1);
540 | ids_body ',' ident {
541 cur_strlist->push_back($3);
548 cur_strlist = new StrList;
563 cur_conlist->push_back(ConInit($1, $3));
567 /* ideqs is ids with a constant initializer for each element. */
571 | ids_body ',' coninit
577 cur_conlist = new ConList;
584 $$ = new String("async", cur_input_file, curline, TOK_ASYNC);
587 $$ = new String("inout", cur_input_file, curline, TOK_INOUT);
590 $$ = new String("out", cur_input_file, curline, TOK_OUT);
593 $$ = new String("shared", cur_input_file, curline, TOK_SHARED);
596 $$ = new String("push", cur_input_file, curline, TOK_PUSH);
599 $$ = new String("short", cur_input_file, curline, TOK_SHORT);
602 $$ = new String("int", cur_input_file, curline, TOK_INT);
605 $$ = new String("long", cur_input_file, curline, TOK_LONG);
608 $$ = new String("ushort", cur_input_file, curline, TOK_USHORT);
611 $$ = new String("uint", cur_input_file, curline, TOK_UINT);
614 $$ = new String("ulong", cur_input_file, curline, TOK_ULONG);
617 $$ = new String("char", cur_input_file, curline, TOK_CHAR);
620 $$ = new String("octet", cur_input_file, curline, TOK_OCTET);
623 $$ = new String("fshort", cur_input_file, curline, TOK_FSHORT);
626 $$ = new String("flong", cur_input_file, curline, TOK_FLONG);
629 $$ = new String("bool", cur_input_file, curline, TOK_BOOL);
632 $$ = new String("method", cur_input_file, curline, TOK_METHOD);
635 $$ = new String("name", cur_input_file, curline, TOK_NAME);
638 $$ = new String("copy", cur_input_file, curline, TOK_COPY);
641 $$ = new String("class", cur_input_file, curline, TOK_CLASS);
644 $$ = new String("guid", cur_input_file, curline, TOK_GUID);
647 $$ = new String("static", cur_input_file, curline, TOK_STATIC);
650 $$ = new String("virtual", cur_input_file, curline, TOK_VIRTUAL);
653 $$ = new String("inline", cur_input_file, curline, TOK_INLINE);
656 $$ = new String("immutable", cur_input_file, curline, TOK_IMMUTABLE);
662 cur_strlist->push_back($1);
664 | strlist_body ident {
665 cur_strlist->push_back($2);
671 cur_strlist = new StrList;
676 strlist_body end_strlist {
688 cur_strlist->push_back($1);
690 | qualified_ident_raw '.' ident {
691 cur_strlist->push_back($3);
704 qualified_ident_nodbldot:
705 qualified_ident_raw maybe_dot_star {
707 cur_strlist->push_back(new String("*", cur_input_file,
711 cur_strlist = new StrList;
717 cur_strlist->push_front(new String("", cur_input_file,
718 curline, TOK_IDENT));
719 } qualified_ident_nodbldot {
722 | qualified_ident_nodbldot
726 qualified_ident_raw {
727 $$.ident = cur_strlist->back();
728 cur_strlist->pop_back();
730 if (!cur_strlist->empty())
731 $$.ns = add_nspace(cur_strlist, true);
734 nspace_stack.push_front(cur_nspace);
737 cur_strlist = new StrList;
746 snprintf(buf, 32, "_anon_%u", cur_nspace->anon++);
749 $$.ident = new String(buf, cur_input_file, curline, TOK_ANON);
750 nspace_stack.push_front(cur_nspace);
754 maybe_qualified_decl:
761 cur_idlist->push_back($1);
763 | qualified_ids ',' qualified_ident {
764 cur_idlist->push_back($3);
771 cur_idlist = new IDList;
776 TOK_ENUM maybe_qualified_decl size '{' {
779 if ($3.type == TOK_UCON)
782 $<en>$ = Enum::declare($2.ident, $2.ns, bits);
784 nspace_stack.push_front(cur_nspace);
801 Enum *en = dynamic_cast<Enum *>(*cur_nspace);
804 CompiledBasicType bt = { bits: en->def.bits };
806 // GCC can't handle complex labelled initializers as of 3.3;
807 // plus, the syntax gets kind of ugly.
809 bt.flags.field.Unsigned = 1;
813 con.con.ucon = en->next_val++;
815 Datum::declare($1, en, bt, NULL, &con);
820 TOK_BITFIELD maybe_qualified_decl size '{' {
823 if ($3.type == TOK_UCON)
826 $<bf>$ = BitField::declare($2.ident, $2.ns, bits);
828 nspace_stack.push_front(cur_nspace);
830 } maybe_bfelems '}' {
844 if ($$.type == TOK_DCON) {
845 // FIXME: support symbolic sizes
846 yyerrorf("Symbolic sizes are currently unsupported.\n");
847 $$.type = TOK_INVALID;
848 } else if (!(($$.type == TOK_UCON && $$.con.ucon > 0) ||
849 ($$.type == TOK_ICON && $$.con.icon > 0)))
851 yyerrorf("Sizes must be positive integers.");
853 $$.type = TOK_INVALID;
856 // Promote signed to unsigned.
867 | bfelems ',' bfelem {
881 | bfelems maybe_comma
886 CompiledBasicType bt = {};
887 bt.flags.field.Unsigned = 1;
888 bt.bits = dynamic_cast<BitField *>(*cur_nspace)->def.bits;
890 $$ = Datum::declare($1, cur_nspace, bt, NULL);
893 $$ = Datum::declare($2, cur_nspace, $1, NULL);
896 StrList *strl = $1->get_fq_name();
897 strl->push_front(new String(""));
898 $$ = Datum::declare($2, cur_nspace, strl, NULL);
901 StrList *strl = $1->get_fq_name();
902 strl->push_front(new String(""));
903 $$ = Datum::declare($2, cur_nspace, strl, NULL);
907 bfelem: bftype size {
910 if ($2.type == TOK_UCON)
911 $$->def.ucon = $2.con.ucon;
928 | basictype '[' arraybounds ']' {
944 constnominus { $$ = $1; }
949 yyerrorf("The constant %" PRIu64 " is too large to be negated.",
955 $$.con.icon = -$2.con.icon;
959 $$.con.fcon = -$2.con.fcon;
975 TOK_ICON { $$ = $1; }
976 | TOK_UCON { $$ = $1; }
977 | TOK_FCON { $$ = $1; }
978 | TOK_INVALID { $$ = $1; }
988 $$ = new Array(cur_nspace);
992 $$ = new Array(cur_nspace);
993 $$->set_bound($1, 0);
994 $$->set_bound($1, 1);
996 | maybeconst TOK_3DOT maybeconst {
997 $$ = new Array(cur_nspace);
998 $$->set_bound($1, 0);
999 $$->set_bound($3, 1);
1003 typedef_or_alias_keyword:
1013 typedef_or_alias_keyword basictype ids {
1014 Type *t = lookup_type($2, NULL, true);
1015 BasicType *bt = dynamic_cast<BasicType *>(t);
1018 // It's a basic type, so a symbolic typedef won't work.
1019 declare_basictypes(cur_nspace, $3, bt, $1);
1021 declare_aliases(cur_nspace, $3, $2, $1);
1028 void setup_idlparse()
1030 yylval_con = &idl_lval.con;
1031 yylval_string = &idl_lval.string;
1033 // These are kept in an initialized state so as to avoid the need
1034 // for some early actions, thus eliminating some conflicts that
1035 // would otherwise have caused things like "guid" to need to be
1038 cur_strlist = new StrList;
1039 cur_conlist = new ConList;
1040 cur_idlist = new IDList;