2 /* idlparse.y -- parser for the IDL compiler
4 * Written by Scott Wood <scott@buserror.net>
16 #define do_yyerror() do { \
17 fprintf(stderr, "YYERROR at %d\n", __LINE__); \
21 #define do_yyerror() YYERROR
24 static StrListRef nspace_name;
25 static StrListRef cur_strlist;
26 static ConListRef cur_conlist;
27 static IDListRef cur_idlist;
31 // The lifetime of any of these pointers is one instance
32 // of the one_input rule.
38 struct Decl { // Used for namespace-qualified type declarations
39 NameSpace *ns; // Namespace portion -- all but last field
40 const String *ident; // New identifier portion -- last field
78 // The token list must be exactly the same as in idlparse.y, so that
79 // the same lexer can be used.
81 %token <string> TOK_IDENT
89 %token <con> TOK_INVALID
109 %token <string> TOK_STR
128 // These are not real tokens, but are used as special values in places that
129 // normally accept tokens.
134 %type <strl> basictype
137 %type <con> maybeconst
138 %type <array> arraybounds
139 %type <con> constnominus
142 %type <syml> maybe_bfelems
143 %type <strl> maybe_ids
148 %type <strl> maybe_strlist
149 %type <strl> end_strlist
152 %type <strl> qualified_ident
153 %type <strl> qualified_ident_nodbldot
154 %type <decl> qualified_decl
155 %type <decl> maybe_qualified_decl
156 %type <decl> anon_decl
157 %type <idl> qualified_idlist
158 %type <boolean> maybe_dot_star
159 %type <strl> inherit_struct
164 %type <idl> inherit_ifaces
165 %type <boolean> typedef_or_alias_keyword
167 %type <struct_decl_attr> struct_decl_and_attr
168 %type <ids_attr> ids_attr
184 | typedef_or_alias ';' {}
194 NameSpace *ret = add_nspace(nspace_name, false);
201 NameSpace *ret = add_nspace(nspace_name, true);
210 NameSpace *ret = add_nspace(nspace_name, true);
221 TOK_NAMESPACE qualified_ident {
227 TOK_CONST type ideqs {
230 for (ConList::iterator i = cl->begin(); i != cl->end(); ++i)
231 Datum::declare((*i).str, cur_nspace, $2.type, $2.array, &(*i).con);
240 | ids maybe_strlist {
248 | type ids maybe_strlist ';' {
249 declare_data(cur_nspace, $2, $1.type, $1.array, $3);
251 | enum maybe_ids ';' {
252 if (!$2 && $1->name->token == TOK_ANON)
253 yyerrorfl($1->name->file, $1->name->line,
254 "An anonymous type must declare a datum.");
257 StrList *strl = $1->get_fq_name();
258 strl->push_front(new String(""));
259 declare_data(cur_nspace, $2, strl, NULL, NULL);
262 | bitfield maybe_ids ';' {
263 if (!$2 && $1->name->token == TOK_ANON)
264 yyerrorfl($1->name->file, $1->name->line,
265 "An anonymous type must declare a datum.");
268 StrList *strl = $1->get_fq_name();
269 strl->push_front(new String(""));
270 declare_data(cur_nspace, $2, strl, NULL, NULL);
273 | struct ids_attr ';' {
274 if (!$2.ids && $1->name->token == TOK_ANON)
275 yyerrorfl($1->name->file, $1->name->line,
276 "An anonymous type must declare a datum.");
279 StrList *strl = $1->get_fq_name();
280 strl->push_front(new String(""));
281 declare_data(cur_nspace, $2.ids, strl, NULL, $2.attr);
284 | typedef_or_alias ';'
287 Struct *str = dynamic_cast<Struct *>(*cur_nspace);
296 | struct_elem struct_body
303 | ':' qualified_ident {
308 struct_decl_and_attr:
310 // Anonymous structs have no attributes.
312 $$.attr = new StrList;
314 | qualified_decl maybe_strlist {
321 TOK_STRUCT struct_decl_and_attr inherit_struct '{' {
322 $<str>$ = Struct::declare($2.decl.ident, $2.decl.ns, $3);
324 for (StrList::iterator i = $2.attr->begin(); i != $2.attr->end(); ++i) {
325 const String *attr = *i;
327 switch (attr->token) {
329 $<str>$->set_virtual();
333 $<str>$->set_inline();
337 yyerrorfl(attr->file, attr->line, "Invalid attribute \"%s\"",
342 nspace_stack.push_front(cur_nspace);
343 cur_nspace = $<str>$;
347 // One for the struct's namespace, and one for the
348 // namespace it was declared in.
357 const String *name = $2->front();
360 CompiledParam::Flags flags = {};
365 for (StrList::iterator i = $2->begin(); i != $2->end(); ++i) {
366 const String *attr = *i;
368 switch (attr->token) {
371 yyerrorf("Only one direction attribute may be given.");
381 yyerrorf("Only one direction attribute may be given.");
390 flags.field.Shared = 1;
394 flags.field.Push = 1;
398 flags.field.Inline = 1;
402 flags.field.Immutable = 1;
406 yyerrorfl(attr->file, attr->line,
407 "Invalid attribute \"%s\"", (*i)->c_str());
411 Param::declare(name, cur_nspace, $1.type, flags, $1.array);
427 $<meth>$ = Method::declare($1, cur_nspace);
429 nspace_stack.push_front(cur_nspace);
430 cur_nspace = $<meth>$;
431 } param_list ')' maybe_strlist {
432 for (StrList::iterator i = $6->begin(); i != $6->end(); ++i) {
433 const String *attr = *i;
435 switch (attr->token) {
437 $<meth>3->set_async();
441 yyerrorfl(attr->file, attr->line,
442 "Invalid attribute \"%s\".", (*i)->c_str());
451 | method ';' iface_body
452 | enum ';' iface_body {}
453 | bitfield ';' iface_body {}
454 | struct ';' iface_body {}
455 | iface ';' iface_body {}
456 | typedef_or_alias ';' iface_body
457 | const_datum ';' iface_body
458 | guid ';' iface_body {
459 Interface *iface = dynamic_cast<Interface *>(*cur_nspace);
464 | using ';' iface_body
468 TOK_GUID ':' TOK_STR {
469 parse_guid($3->c_str(), (char *)$$);
478 | ':' qualified_idlist {
484 TOK_IFACE qualified_decl inherit_ifaces {
485 $<iface>$ = Interface::declare($2.ident, $2.ns, $3);
487 nspace_stack.push_front(cur_nspace);
488 cur_nspace = $<iface>$;
489 } '{' iface_body '}' {
502 maybe_namespace qualified_ident {
503 const String *end = $2->back();
506 if (end->token == '*') {
512 cur_nspace->add_search($2);
514 Alias::declare(end, cur_nspace, $2, true);
521 | using_list_entry ',' using_list
524 using: TOK_USING using_list
529 cur_strlist->push_back($1);
531 | ids_body ',' ident {
532 cur_strlist->push_back($3);
539 cur_strlist = new StrList;
554 cur_conlist->push_back(ConInit($1, $3));
558 /* ideqs is ids with a constant initializer for each element. */
562 | ids_body ',' coninit
568 cur_conlist = new ConList;
575 $$ = new String("async", cur_input_file, curline, TOK_ASYNC);
578 $$ = new String("inout", cur_input_file, curline, TOK_INOUT);
581 $$ = new String("out", cur_input_file, curline, TOK_OUT);
584 $$ = new String("shared", cur_input_file, curline, TOK_SHARED);
587 $$ = new String("push", cur_input_file, curline, TOK_PUSH);
590 $$ = new String("short", cur_input_file, curline, TOK_SHORT);
593 $$ = new String("int", cur_input_file, curline, TOK_INT);
596 $$ = new String("long", cur_input_file, curline, TOK_LONG);
599 $$ = new String("ushort", cur_input_file, curline, TOK_USHORT);
602 $$ = new String("uint", cur_input_file, curline, TOK_UINT);
605 $$ = new String("ulong", cur_input_file, curline, TOK_ULONG);
608 $$ = new String("char", cur_input_file, curline, TOK_CHAR);
611 $$ = new String("octet", cur_input_file, curline, TOK_OCTET);
614 $$ = new String("fshort", cur_input_file, curline, TOK_FSHORT);
617 $$ = new String("flong", cur_input_file, curline, TOK_FLONG);
620 $$ = new String("bool", cur_input_file, curline, TOK_BOOL);
623 $$ = new String("method", cur_input_file, curline, TOK_METHOD);
626 $$ = new String("name", cur_input_file, curline, TOK_NAME);
629 $$ = new String("copy", cur_input_file, curline, TOK_COPY);
632 $$ = new String("class", cur_input_file, curline, TOK_CLASS);
635 $$ = new String("guid", cur_input_file, curline, TOK_GUID);
638 $$ = new String("static", cur_input_file, curline, TOK_STATIC);
641 $$ = new String("virtual", cur_input_file, curline, TOK_VIRTUAL);
644 $$ = new String("inline", cur_input_file, curline, TOK_INLINE);
647 $$ = new String("immutable", cur_input_file, curline, TOK_IMMUTABLE);
653 cur_strlist->push_back($1);
655 | strlist_body ident {
656 cur_strlist->push_back($2);
662 cur_strlist = new StrList;
667 strlist_body end_strlist {
679 cur_strlist->push_back($1);
681 | qualified_ident_raw '.' ident {
682 cur_strlist->push_back($3);
695 qualified_ident_nodbldot:
696 qualified_ident_raw maybe_dot_star {
698 cur_strlist->push_back(new String("*", cur_input_file,
702 cur_strlist = new StrList;
708 cur_strlist->push_front(new String("", cur_input_file,
709 curline, TOK_IDENT));
710 } qualified_ident_nodbldot {
713 | qualified_ident_nodbldot
717 qualified_ident_raw {
718 $$.ident = cur_strlist->back();
721 cur_strlist->pop_back();
723 if (!cur_strlist->empty())
724 $$.ns = add_nspace(cur_strlist, true);
727 nspace_stack.push_front(cur_nspace);
730 cur_strlist = new StrList;
739 snprintf(buf, 32, "_anon_%u", cur_nspace->anon++);
742 $$.ident = new String(buf, cur_input_file, curline, TOK_ANON);
743 nspace_stack.push_front(cur_nspace);
747 maybe_qualified_decl:
754 cur_idlist->push_back($1);
756 | qualified_ids ',' qualified_ident {
757 cur_idlist->push_back($3);
764 cur_idlist = new IDList;
769 TOK_ENUM maybe_qualified_decl size '{' {
772 if ($3.type == TOK_UCON)
775 $<en>$ = Enum::declare($2.ident, $2.ns, bits);
777 nspace_stack.push_front(cur_nspace);
794 Enum *en = dynamic_cast<Enum *>(*cur_nspace);
797 CompiledBasicType bt = { bits: en->def.bits };
799 // GCC can't handle complex labelled initializers as of 3.3;
800 // plus, the syntax gets kind of ugly.
802 bt.flags.field.Unsigned = 1;
806 con.con.ucon = en->next_val++;
808 Datum::declare($1, en, bt, NULL, &con);
813 TOK_BITFIELD maybe_qualified_decl size '{' {
816 if ($3.type == TOK_UCON)
819 $<bf>$ = BitField::declare($2.ident, $2.ns, bits);
821 nspace_stack.push_front(cur_nspace);
823 } maybe_bfelems '}' {
837 if ($$.type == TOK_DCON) {
838 // FIXME: support symbolic sizes
839 yyerrorf("Symbolic sizes are currently unsupported.\n");
840 $$.type = TOK_INVALID;
841 } else if (!(($$.type == TOK_UCON && $$.con.ucon > 0) ||
842 ($$.type == TOK_ICON && $$.con.icon > 0)))
844 yyerrorf("Sizes must be positive integers.");
846 $$.type = TOK_INVALID;
849 // Promote signed to unsigned.
860 | bfelems ',' bfelem {
874 | bfelems maybe_comma
879 CompiledBasicType bt = {};
880 bt.flags.field.Unsigned = 1;
881 bt.bits = dynamic_cast<BitField *>(*cur_nspace)->def.bits;
883 $$ = Datum::declare($1, cur_nspace, bt, NULL);
886 $$ = Datum::declare($2, cur_nspace, $1, NULL);
889 StrList *strl = $1->get_fq_name();
890 strl->push_front(new String(""));
891 $$ = Datum::declare($2, cur_nspace, strl, NULL);
894 StrList *strl = $1->get_fq_name();
895 strl->push_front(new String(""));
896 $$ = Datum::declare($2, cur_nspace, strl, NULL);
900 bfelem: bftype size {
903 if ($2.type == TOK_UCON)
904 $$->def.ucon = $2.con.ucon;
921 | basictype '[' arraybounds ']' {
937 constnominus { $$ = $1; }
942 yyerrorf("The constant %" PRIu64 " is too large to be negated.",
948 $$.con.icon = -$2.con.icon;
952 $$.con.fcon = -$2.con.fcon;
968 TOK_ICON { $$ = $1; }
969 | TOK_UCON { $$ = $1; }
970 | TOK_FCON { $$ = $1; }
971 | TOK_INVALID { $$ = $1; }
981 $$ = new Array(cur_nspace);
985 $$ = new Array(cur_nspace);
986 $$->set_bound($1, 0);
987 $$->set_bound($1, 1);
989 | maybeconst TOK_3DOT maybeconst {
990 $$ = new Array(cur_nspace);
991 $$->set_bound($1, 0);
992 $$->set_bound($3, 1);
996 typedef_or_alias_keyword:
1006 typedef_or_alias_keyword basictype ids {
1007 Type *t = lookup_type($2, NULL, true);
1008 BasicType *bt = dynamic_cast<BasicType *>(t);
1011 // It's a basic type, so a symbolic typedef won't work.
1012 declare_basictypes(cur_nspace, $3, bt, $1);
1014 declare_aliases(cur_nspace, $3, $2, $1);
1021 void setup_idlparse()
1023 yylval_con = &idl_lval.con;
1024 yylval_string = &idl_lval.string;
1026 // These are kept in an initialized state so as to avoid the need
1027 // for some early actions, thus eliminating some conflicts that
1028 // would otherwise have caused things like "guid" to need to be
1031 cur_strlist = new StrList;
1032 cur_conlist = new ConList;
1033 cur_idlist = new IDList;