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();
730 cur_strlist->pop_back();
732 if (!cur_strlist->empty())
733 $$.ns = add_nspace(cur_strlist, true);
736 nspace_stack.push_front(cur_nspace);
739 cur_strlist = new StrList;
748 snprintf(buf, 32, "_anon_%u", cur_nspace->anon++);
751 $$.ident = new String(buf, cur_input_file, curline, TOK_ANON);
752 nspace_stack.push_front(cur_nspace);
756 maybe_qualified_decl:
763 cur_idlist->push_back($1);
765 | qualified_ids ',' qualified_ident {
766 cur_idlist->push_back($3);
773 cur_idlist = new IDList;
778 TOK_ENUM maybe_qualified_decl size '{' {
781 if ($3.type == TOK_UCON)
784 $<en>$ = Enum::declare($2.ident, $2.ns, bits);
786 nspace_stack.push_front(cur_nspace);
803 Enum *en = dynamic_cast<Enum *>(*cur_nspace);
806 CompiledBasicType bt = { bits: en->def.bits };
808 // GCC can't handle complex labelled initializers as of 3.3;
809 // plus, the syntax gets kind of ugly.
811 bt.flags.field.Unsigned = 1;
815 con.con.ucon = en->next_val++;
817 Datum::declare($1, en, bt, NULL, &con);
822 TOK_BITFIELD maybe_qualified_decl size '{' {
825 if ($3.type == TOK_UCON)
828 $<bf>$ = BitField::declare($2.ident, $2.ns, bits);
830 nspace_stack.push_front(cur_nspace);
832 } maybe_bfelems '}' {
846 if ($$.type == TOK_DCON) {
847 // FIXME: support symbolic sizes
848 yyerrorf("Symbolic sizes are currently unsupported.\n");
849 $$.type = TOK_INVALID;
850 } else if (!(($$.type == TOK_UCON && $$.con.ucon > 0) ||
851 ($$.type == TOK_ICON && $$.con.icon > 0)))
853 yyerrorf("Sizes must be positive integers.");
855 $$.type = TOK_INVALID;
858 // Promote signed to unsigned.
869 | bfelems ',' bfelem {
883 | bfelems maybe_comma
888 CompiledBasicType bt = {};
889 bt.flags.field.Unsigned = 1;
890 bt.bits = dynamic_cast<BitField *>(*cur_nspace)->def.bits;
892 $$ = Datum::declare($1, cur_nspace, bt, NULL);
895 $$ = Datum::declare($2, cur_nspace, $1, NULL);
898 StrList *strl = $1->get_fq_name();
899 strl->push_front(new String(""));
900 $$ = Datum::declare($2, cur_nspace, strl, NULL);
903 StrList *strl = $1->get_fq_name();
904 strl->push_front(new String(""));
905 $$ = Datum::declare($2, cur_nspace, strl, NULL);
909 bfelem: bftype size {
912 if ($2.type == TOK_UCON)
913 $$->def.ucon = $2.con.ucon;
930 | basictype '[' arraybounds ']' {
946 constnominus { $$ = $1; }
951 yyerrorf("The constant %" PRIu64 " is too large to be negated.",
957 $$.con.icon = -$2.con.icon;
961 $$.con.fcon = -$2.con.fcon;
977 TOK_ICON { $$ = $1; }
978 | TOK_UCON { $$ = $1; }
979 | TOK_FCON { $$ = $1; }
980 | TOK_INVALID { $$ = $1; }
990 $$ = new Array(cur_nspace);
994 $$ = new Array(cur_nspace);
995 $$->set_bound($1, 0);
996 $$->set_bound($1, 1);
998 | maybeconst TOK_3DOT maybeconst {
999 $$ = new Array(cur_nspace);
1000 $$->set_bound($1, 0);
1001 $$->set_bound($3, 1);
1005 typedef_or_alias_keyword:
1015 typedef_or_alias_keyword basictype ids {
1016 Type *t = lookup_type($2, NULL, true);
1017 BasicType *bt = dynamic_cast<BasicType *>(t);
1020 // It's a basic type, so a symbolic typedef won't work.
1021 declare_basictypes(cur_nspace, $3, bt, $1);
1023 declare_aliases(cur_nspace, $3, $2, $1);
1030 void setup_idlparse()
1032 yylval_con = &idl_lval.con;
1033 yylval_string = &idl_lval.string;
1035 // These are kept in an initialized state so as to avoid the need
1036 // for some early actions, thus eliminating some conflicts that
1037 // would otherwise have caused things like "guid" to need to be
1040 cur_strlist = new StrList;
1041 cur_conlist = new ConList;
1042 cur_idlist = new IDList;