%{ /* cdlparse.y -- parser for the CDL compiler * * Written by Scott Wood */ #include #include #include #include #include #define YYDEBUG 1 #define do_yyerror() do { \ fprintf(stderr, "YYERROR at %d\n", __LINE__); \ throw UserError(); \ } while (0) static StrListRef nspace_name; static StrListRef cur_strlist; static IDListRef cur_idlist; static ClassRef cur_class; static MethodRef cur_method; %} %union { // The lifetime of any of these pointers is one instance // of the one_input rule. String *string; StrList *strl; IDList *idl; SymList *syml; Symbol *sym; Method *meth; Class *cla; bool boolean; struct { // Used for namespace-qualified type declarations NameSpace *ns; // Namespace portion -- all but last field const String *ident; // New identifier portion -- last field } decl; } // The token list must be exactly the same as in idlparse.y, so that // the same lexer can be used. %token TOK_IDENT %token TOK_IFACE %token TOK_STRUCT %token TOK_CHAR %token TOK_OCTET %token TOK_ICON %token TOK_FCON %token TOK_UCON %token TOK_INVALID %token TOK_BOOL %token TOK_SHORT %token TOK_INT %token TOK_LONG %token TOK_USHORT %token TOK_UINT %token TOK_ULONG %token TOK_FSHORT %token TOK_FLONG %token TOK_CONST %token TOK_BITFIELD %token TOK_ENUM %token TOK_NAMESPACE %token TOK_USING %token TOK_ASYNC %token TOK_INOUT %token TOK_OUT %token TOK_3DOT %token TOK_2DOT %token TOK_STR %token TOK_SHARED %token TOK_PUSH %token TOK_TYPEDEF %token TOK_ALIAS %token TOK_VIRTUAL %token TOK_GUID %token TOK_INLINE %token TOK_STATIC %token TOK_IMMUTABLE %token TOK_TRUE %token TOK_FALSE // CDL tokens %token TOK_COPY %token TOK_METHOD %token TOK_CLASS %token TOK_NAME // These are not real tokens, but are used as special values in places that // normally accept tokens. %token TOK_NONE %token TOK_ANON %token TOK_DCON %type ids %type ident %type qualified_ident %type qualified_idlist %type maybe_dbldot %type qualified_decl %% input: /* empty */ | input one_input ; one_input: one_input_real ; one_input_real: class | namespace ; namespace_body: ';' { NameSpace *ret = add_nspace(nspace_name, false); nspace_name = NULL; if (!ret) do_yyerror(); } | '{' { NameSpace *ret = add_nspace(nspace_name, true); nspace_name = NULL; if (!ret) do_yyerror(); } input '}' { pop_nspace(); } | { NameSpace *ret = add_nspace(nspace_name, true); nspace_name = NULL; if (!ret) do_yyerror(); } one_input { pop_nspace(); } ; namespace: TOK_NAMESPACE qualified_ident { nspace_name = $2; } namespace_body ; ids_body: ident { cur_strlist->push_back($1); } | ids_body ',' ident { cur_strlist->push_back($3); } ; ids: { cur_strlist = new StrList; } ids_body { $$ = cur_strlist; cur_strlist = NULL; } ; ident: TOK_IDENT | TOK_ASYNC { $$ = new String("async", cur_input_file, curline, TOK_ASYNC); } | TOK_INOUT { $$ = new String("inout", cur_input_file, curline, TOK_INOUT); } | TOK_OUT { $$ = new String("out", cur_input_file, curline, TOK_OUT); } | TOK_SHARED { $$ = new String("shared", cur_input_file, curline, TOK_SHARED); } | TOK_PUSH { $$ = new String("push", cur_input_file, curline, TOK_PUSH); } | TOK_SHORT { $$ = new String("short", cur_input_file, curline, TOK_SHORT); } | TOK_INT { $$ = new String("int", cur_input_file, curline, TOK_INT); } | TOK_LONG { $$ = new String("long", cur_input_file, curline, TOK_LONG); } | TOK_USHORT { $$ = new String("ushort", cur_input_file, curline, TOK_USHORT); } | TOK_UINT { $$ = new String("uint", cur_input_file, curline, TOK_UINT); } | TOK_ULONG { $$ = new String("ulong", cur_input_file, curline, TOK_ULONG); } | TOK_CHAR { $$ = new String("char", cur_input_file, curline, TOK_CHAR); } | TOK_OCTET { $$ = new String("octet", cur_input_file, curline, TOK_OCTET); } | TOK_FSHORT { $$ = new String("fshort", cur_input_file, curline, TOK_FSHORT); } | TOK_FLONG { $$ = new String("flong", cur_input_file, curline, TOK_FLONG); } | TOK_BOOL { $$ = new String("bool", cur_input_file, curline, TOK_BOOL); } | TOK_METHOD { $$ = new String("method", cur_input_file, curline, TOK_METHOD); } | TOK_NAME { $$ = new String("name", cur_input_file, curline, TOK_NAME); } | TOK_COPY { $$ = new String("copy", cur_input_file, curline, TOK_COPY); } | TOK_CLASS { $$ = new String("class", cur_input_file, curline, TOK_CLASS); } | TOK_GUID { $$ = new String("guid", cur_input_file, curline, TOK_GUID); } | TOK_STATIC { $$ = new String("static", cur_input_file, curline, TOK_STATIC); } | TOK_IFACE { $$ = new String("interface", cur_input_file, curline, TOK_IFACE); } | TOK_STRUCT { $$ = new String("struct", cur_input_file, curline, TOK_STRUCT); } | TOK_CONST { $$ = new String("const", cur_input_file, curline, TOK_CONST); } | TOK_BITFIELD { $$ = new String("bitfield", cur_input_file, curline, TOK_BITFIELD); } | TOK_ENUM { $$ = new String("enum", cur_input_file, curline, TOK_ENUM); } | TOK_USING { $$ = new String("using", cur_input_file, curline, TOK_USING); } | TOK_TYPEDEF { $$ = new String("typedef", cur_input_file, curline, TOK_TYPEDEF); } | TOK_ALIAS { $$ = new String("alias", cur_input_file, curline, TOK_ALIAS); } | TOK_VIRTUAL { $$ = new String("virtual", cur_input_file, curline, TOK_VIRTUAL); } | TOK_INLINE { $$ = new String("inline", cur_input_file, curline, TOK_INLINE); } ; qualified_ident_raw: ident { cur_strlist->push_back($1); } | qualified_ident_raw '.' ident { cur_strlist->push_back($3); } ; maybe_dbldot: /* empty */ { $$ = false; } | TOK_2DOT { $$ = true; } ; /* The mid-rule action is to keep curline correct, as well as creating cur_strlist. */ qualified_ident: maybe_dbldot { cur_strlist = new StrList; if ($1) cur_strlist->push_front(new String("", cur_input_file, curline, TOK_IDENT)); } qualified_ident_raw { $$ = cur_strlist; cur_strlist = NULL; } ; qualified_ids: qualified_ident { cur_idlist->push_back($1); } | qualified_ids ',' qualified_ident { cur_idlist->push_back($3); } ; qualified_idlist: { cur_idlist = new IDList; } qualified_ids { $$ = cur_idlist; cur_idlist = NULL; } ; qualified_decl: maybe_dbldot { if ($1) yyerrorf("Namespaces cannot be declared " "with an absolute path."); cur_strlist = new StrList; } qualified_ident_raw { $$.ident = cur_strlist->back(); $$.ident->retain(); cur_strlist->pop_back(); if (!cur_strlist->empty()) $$.ns = add_nspace(cur_strlist, true); else { $$.ns = cur_nspace; nspace_stack.push_front(cur_nspace); } cur_strlist = NULL; if (!$$.ns) do_yyerror(); } ; class: TOK_CLASS qualified_decl { cur_class = new Class($2.ident); $2.ns->add_user(cur_class); } ':' qualified_idlist { if ($5->empty()) { yyerrorf("A class must implement at least one interface."); throw UserError(); } for (IDList::const_iterator i = $5->begin(); i != $5->end(); ++i) { StrList *strl = *i; Symbol *sym = lookup_sym(toplevel, strl, toplevel); Interface *iface = dynamic_cast(sym); if (!iface) { yyerrorfl(cur_input_file, strl->back()->line, "\"%s\" is not an interface.", strl->flatten()->c_str()); throw UserError(); } cur_class->add_iface(iface); } } class_body { pop_nspace(); cur_class->finalize(); cur_class = NULL; } ; class_body: ';' | '{' multi_class_body '}' ; multi_class_body: one_class_body | multi_class_body one_class_body ; one_class_body: TOK_METHOD qualified_ident { // FIXME: use the set of supported interfaces as a search path Symbol *sym = lookup_sym(toplevel, $2, toplevel); cur_method = dynamic_cast(sym); if (!cur_method) { yyerrorfl(cur_input_file, $2->back()->line, "\"%s\" is not a method.", $2->flatten()->c_str()); throw UserError(); } } method_body { cur_method = NULL; } ; method_body: one_method_body | '{' multi_method_body '}' ; multi_method_body: one_method_body | multi_method_body one_method_body ; one_method_body: TOK_NAME qualified_ident ';' { Class::MethodInfo *mi = cur_class->add_method(cur_method); mi->implname = $2; } | TOK_COPY ids ';' { Class::MethodInfo *mi = cur_class->add_method(cur_method); for (StrList::const_iterator i = $2->begin(); i != $2->end(); ++i) { const String *str = *i; Symbol *sym; try { sym = cur_method->lookup(str); } catch (SymbolNotFound) { yyerrorfl(cur_input_file, str->line, "\"%s\" is not a parameter of \"%s\".", str->c_str(), cur_method->get_fq_name()->flatten()->c_str()); throw UserError(); } Param *p = dynamic_cast(sym); assert(p); Class::ParamInfo *pi = mi->add_param(p); pi->copy = true; mi->copy_params = true; } } ; %% static Con dummy_con; void setup_cdlparse() { yylval_con = &dummy_con; yylval_string = &cdl_lval.string; } list classes;