/* ----------------------------------------------------------------------------- * This file is part of SWIG, which is licensed as a whole under version 3 * (or any later version) of the GNU General Public License. Some additional * terms also apply to certain portions of SWIG. The full details of the SWIG * license and copyrights can be found in the LICENSE and COPYRIGHT files * included with the SWIG source code as distributed by the SWIG developers * and at http://www.swig.org/legal.html. * * parser.y * * YACC parser for SWIG. The grammar is a somewhat broken subset of C/C++. * This file is a bit of a mess and probably needs to be rewritten at * some point. Beware. * ----------------------------------------------------------------------------- */ %{ #define yylex yylex char cvsroot_parser_y[] = "$Id: parser.y 12666 2011-05-14 00:13:43Z wsfulton $"; #include "swig.h" #include "cparse.h" #include "preprocessor.h" #include /* We do this for portability */ #undef alloca #define alloca malloc /* ----------------------------------------------------------------------------- * Externals * ----------------------------------------------------------------------------- */ int yyparse(); /* NEW Variables */ static Node *top = 0; /* Top of the generated parse tree */ static int unnamed = 0; /* Unnamed datatype counter */ static Hash *extendhash = 0; /* Hash table of added methods */ static Hash *classes = 0; /* Hash table of classes */ static Symtab *prev_symtab = 0; static Node *current_class = 0; String *ModuleName = 0; static Node *module_node = 0; static String *Classprefix = 0; static String *Namespaceprefix = 0; static int inclass = 0; static int nested_template = 0; /* template class/function definition within a class */ static char *last_cpptype = 0; static int inherit_list = 0; static Parm *template_parameters = 0; static int extendmode = 0; static int compact_default_args = 0; static int template_reduce = 0; static int cparse_externc = 0; static int max_class_levels = 0; static int class_level = 0; static Node **class_decl = NULL; /* ----------------------------------------------------------------------------- * Assist Functions * ----------------------------------------------------------------------------- */ /* Called by the parser (yyparse) when an error is found.*/ static void yyerror (const char *e) { (void)e; } static Node *new_node(const_String_or_char_ptr tag) { Node *n = NewHash(); set_nodeType(n,tag); Setfile(n,cparse_file); Setline(n,cparse_line); return n; } /* Copies a node. Does not copy tree links or symbol table data (except for sym:name) */ static Node *copy_node(Node *n) { Node *nn; Iterator k; nn = NewHash(); Setfile(nn,Getfile(n)); Setline(nn,Getline(n)); for (k = First(n); k.key; k = Next(k)) { String *ci; String *key = k.key; char *ckey = Char(key); if ((strcmp(ckey,"nextSibling") == 0) || (strcmp(ckey,"previousSibling") == 0) || (strcmp(ckey,"parentNode") == 0) || (strcmp(ckey,"lastChild") == 0)) { continue; } if (Strncmp(key,"csym:",5) == 0) continue; /* We do copy sym:name. For templates */ if ((strcmp(ckey,"sym:name") == 0) || (strcmp(ckey,"sym:weak") == 0) || (strcmp(ckey,"sym:typename") == 0)) { String *ci = Copy(k.item); Setattr(nn,key, ci); Delete(ci); continue; } if (strcmp(ckey,"sym:symtab") == 0) { Setattr(nn,"sym:needs_symtab", "1"); } /* We don't copy any other symbol table attributes */ if (strncmp(ckey,"sym:",4) == 0) { continue; } /* If children. We copy them recursively using this function */ if (strcmp(ckey,"firstChild") == 0) { /* Copy children */ Node *cn = k.item; while (cn) { Node *copy = copy_node(cn); appendChild(nn,copy); Delete(copy); cn = nextSibling(cn); } continue; } /* We don't copy the symbol table. But we drop an attribute requires_symtab so that functions know it needs to be built */ if (strcmp(ckey,"symtab") == 0) { /* Node defined a symbol table. */ Setattr(nn,"requires_symtab","1"); continue; } /* Can't copy nodes */ if (strcmp(ckey,"node") == 0) { continue; } if ((strcmp(ckey,"parms") == 0) || (strcmp(ckey,"pattern") == 0) || (strcmp(ckey,"throws") == 0) || (strcmp(ckey,"kwargs") == 0)) { ParmList *pl = CopyParmList(k.item); Setattr(nn,key,pl); Delete(pl); continue; } /* Looks okay. Just copy the data using Copy */ ci = Copy(k.item); Setattr(nn, key, ci); Delete(ci); } return nn; } /* ----------------------------------------------------------------------------- * Variables * ----------------------------------------------------------------------------- */ static char *typemap_lang = 0; /* Current language setting */ static int cplus_mode = 0; static String *class_rename = 0; /* C++ modes */ #define CPLUS_PUBLIC 1 #define CPLUS_PRIVATE 2 #define CPLUS_PROTECTED 3 /* include types */ static int import_mode = 0; void SWIG_typemap_lang(const char *tm_lang) { typemap_lang = Swig_copy_string(tm_lang); } void SWIG_cparse_set_compact_default_args(int defargs) { compact_default_args = defargs; } int SWIG_cparse_template_reduce(int treduce) { template_reduce = treduce; return treduce; } /* ----------------------------------------------------------------------------- * Assist functions * ----------------------------------------------------------------------------- */ static int promote_type(int t) { if (t <= T_UCHAR || t == T_CHAR) return T_INT; return t; } /* Perform type-promotion for binary operators */ static int promote(int t1, int t2) { t1 = promote_type(t1); t2 = promote_type(t2); return t1 > t2 ? t1 : t2; } static String *yyrename = 0; /* Forward renaming operator */ static String *resolve_node_scope(String *cname); Hash *Swig_cparse_features(void) { static Hash *features_hash = 0; if (!features_hash) features_hash = NewHash(); return features_hash; } static String *feature_identifier_fix(String *s) { String *tp = SwigType_istemplate_templateprefix(s); if (tp) { String *ts, *ta, *tq; ts = SwigType_templatesuffix(s); ta = SwigType_templateargs(s); tq = Swig_symbol_type_qualify(ta,0); Append(tp,tq); Append(tp,ts); Delete(ts); Delete(ta); Delete(tq); return tp; } else { return NewString(s); } } /* Generate the symbol table name for an object */ /* This is a bit of a mess. Need to clean up */ static String *add_oldname = 0; static String *make_name(Node *n, String *name,SwigType *decl) { int destructor = name && (*(Char(name)) == '~'); if (yyrename) { String *s = NewString(yyrename); Delete(yyrename); yyrename = 0; if (destructor && (*(Char(s)) != '~')) { Insert(s,0,"~"); } return s; } if (!name) return 0; return Swig_name_make(n,Namespaceprefix,name,decl,add_oldname); } /* Generate an unnamed identifier */ static String *make_unnamed() { unnamed++; return NewStringf("$unnamed%d$",unnamed); } /* Return if the node is a friend declaration */ static int is_friend(Node *n) { return Cmp(Getattr(n,"storage"),"friend") == 0; } static int is_operator(String *name) { return Strncmp(name,"operator ", 9) == 0; } /* Add declaration list to symbol table */ static int add_only_one = 0; static void add_symbols(Node *n) { String *decl; String *wrn = 0; if (nested_template) { if (!(n && Equal(nodeType(n), "template"))) { return; } /* continue if template function, but not template class, declared within a class */ } if (inclass && n) { cparse_normalize_void(n); } while (n) { String *symname = 0; /* for friends, we need to pop the scope once */ String *old_prefix = 0; Symtab *old_scope = 0; int isfriend = inclass && is_friend(n); int iscdecl = Cmp(nodeType(n),"cdecl") == 0; int only_csymbol = 0; if (extendmode) { Setattr(n,"isextension","1"); } if (inclass) { String *name = Getattr(n, "name"); if (isfriend) { /* for friends, we need to add the scopename if needed */ String *prefix = name ? Swig_scopename_prefix(name) : 0; old_prefix = Namespaceprefix; old_scope = Swig_symbol_popscope(); Namespaceprefix = Swig_symbol_qualifiedscopename(0); if (!prefix) { if (name && !is_operator(name) && Namespaceprefix) { String *nname = NewStringf("%s::%s", Namespaceprefix, name); Setattr(n,"name",nname); Delete(nname); } } else { Symtab *st = Swig_symbol_getscope(prefix); String *ns = st ? Getattr(st,"name") : prefix; String *base = Swig_scopename_last(name); String *nname = NewStringf("%s::%s", ns, base); Setattr(n,"name",nname); Delete(nname); Delete(base); Delete(prefix); } Namespaceprefix = 0; } else { /* for member functions, we need to remove the redundant class scope if provided, as in struct Foo { int Foo::method(int a); }; */ String *prefix = name ? Swig_scopename_prefix(name) : 0; if (prefix) { if (Classprefix && (Equal(prefix,Classprefix))) { String *base = Swig_scopename_last(name); Setattr(n,"name",base); Delete(base); } Delete(prefix); } /* if (!Getattr(n,"parentNode") && class_level) set_parentNode(n,class_decl[class_level - 1]); */ Setattr(n,"ismember","1"); } } if (!isfriend && inclass) { if ((cplus_mode != CPLUS_PUBLIC)) { only_csymbol = 1; if (cplus_mode == CPLUS_PROTECTED) { Setattr(n,"access", "protected"); only_csymbol = !Swig_need_protected(n); } else { Setattr(n,"access", "private"); /* private are needed only when they are pure virtuals - why? */ if ((Cmp(Getattr(n,"storage"),"virtual") == 0) && (Cmp(Getattr(n,"value"),"0") == 0)) { only_csymbol = 0; } } } else { Setattr(n,"access", "public"); } } if (Getattr(n,"sym:name")) { n = nextSibling(n); continue; } decl = Getattr(n,"decl"); if (!SwigType_isfunction(decl)) { String *name = Getattr(n,"name"); String *makename = Getattr(n,"parser:makename"); if (iscdecl) { String *storage = Getattr(n, "storage"); if (Cmp(storage,"typedef") == 0) { Setattr(n,"kind","typedef"); } else { SwigType *type = Getattr(n,"type"); String *value = Getattr(n,"value"); Setattr(n,"kind","variable"); if (value && Len(value)) { Setattr(n,"hasvalue","1"); } if (type) { SwigType *ty; SwigType *tmp = 0; if (decl) { ty = tmp = Copy(type); SwigType_push(ty,decl); } else { ty = type; } if (!SwigType_ismutable(ty)) { SetFlag(n,"hasconsttype"); SetFlag(n,"feature:immutable"); } if (tmp) Delete(tmp); } if (!type) { Printf(stderr,"notype name %s\n", name); } } } Swig_features_get(Swig_cparse_features(), Namespaceprefix, name, 0, n); if (makename) { symname = make_name(n, makename,0); Delattr(n,"parser:makename"); /* temporary information, don't leave it hanging around */ } else { makename = name; symname = make_name(n, makename,0); } if (!symname) { symname = Copy(Getattr(n,"unnamed")); } if (symname) { wrn = Swig_name_warning(n, Namespaceprefix, symname,0); } } else { String *name = Getattr(n,"name"); SwigType *fdecl = Copy(decl); SwigType *fun = SwigType_pop_function(fdecl); if (iscdecl) { Setattr(n,"kind","function"); } Swig_features_get(Swig_cparse_features(),Namespaceprefix,name,fun,n); symname = make_name(n, name,fun); wrn = Swig_name_warning(n, Namespaceprefix,symname,fun); Delete(fdecl); Delete(fun); } if (!symname) { n = nextSibling(n); continue; } if (only_csymbol || GetFlag(n,"feature:ignore")) { /* Only add to C symbol table and continue */ Swig_symbol_add(0, n); } else if (strncmp(Char(symname),"$ignore",7) == 0) { char *c = Char(symname)+7; SetFlag(n,"feature:ignore"); if (strlen(c)) { SWIG_WARN_NODE_BEGIN(n); Swig_warning(0,Getfile(n), Getline(n), "%s\n",c+1); SWIG_WARN_NODE_END(n); } Swig_symbol_add(0, n); } else { Node *c; if ((wrn) && (Len(wrn))) { String *metaname = symname; if (!Getmeta(metaname,"already_warned")) { SWIG_WARN_NODE_BEGIN(n); Swig_warning(0,Getfile(n),Getline(n), "%s\n", wrn); SWIG_WARN_NODE_END(n); Setmeta(metaname,"already_warned","1"); } } c = Swig_symbol_add(symname,n); if (c != n) { /* symbol conflict attempting to add in the new symbol */ if (Getattr(n,"sym:weak")) { Setattr(n,"sym:name",symname); } else { String *e = NewStringEmpty(); String *en = NewStringEmpty(); String *ec = NewStringEmpty(); int redefined = Swig_need_redefined_warn(n,c,inclass); if (redefined) { Printf(en,"Identifier '%s' redefined (ignored)",symname); Printf(ec,"previous definition of '%s'",symname); } else { Printf(en,"Redundant redeclaration of '%s'",symname); Printf(ec,"previous declaration of '%s'",symname); } if (Cmp(symname,Getattr(n,"name"))) { Printf(en," (Renamed from '%s')", SwigType_namestr(Getattr(n,"name"))); } Printf(en,","); if (Cmp(symname,Getattr(c,"name"))) { Printf(ec," (Renamed from '%s')", SwigType_namestr(Getattr(c,"name"))); } Printf(ec,"."); SWIG_WARN_NODE_BEGIN(n); if (redefined) { Swig_warning(WARN_PARSE_REDEFINED,Getfile(n),Getline(n),"%s\n",en); Swig_warning(WARN_PARSE_REDEFINED,Getfile(c),Getline(c),"%s\n",ec); } else if (!is_friend(n) && !is_friend(c)) { Swig_warning(WARN_PARSE_REDUNDANT,Getfile(n),Getline(n),"%s\n",en); Swig_warning(WARN_PARSE_REDUNDANT,Getfile(c),Getline(c),"%s\n",ec); } SWIG_WARN_NODE_END(n); Printf(e,"%s:%d:%s\n%s:%d:%s\n",Getfile(n),Getline(n),en, Getfile(c),Getline(c),ec); Setattr(n,"error",e); Delete(e); Delete(en); Delete(ec); } } } /* restore the class scope if needed */ if (isfriend) { Swig_symbol_setscope(old_scope); if (old_prefix) { Delete(Namespaceprefix); Namespaceprefix = old_prefix; } } Delete(symname); if (add_only_one) return; n = nextSibling(n); } } /* add symbols a parse tree node copy */ static void add_symbols_copy(Node *n) { String *name; int emode = 0; while (n) { char *cnodeType = Char(nodeType(n)); if (strcmp(cnodeType,"access") == 0) { String *kind = Getattr(n,"kind"); if (Strcmp(kind,"public") == 0) { cplus_mode = CPLUS_PUBLIC; } else if (Strcmp(kind,"private") == 0) { cplus_mode = CPLUS_PRIVATE; } else if (Strcmp(kind,"protected") == 0) { cplus_mode = CPLUS_PROTECTED; } n = nextSibling(n); continue; } add_oldname = Getattr(n,"sym:name"); if ((add_oldname) || (Getattr(n,"sym:needs_symtab"))) { int old_inclass = -1; Node *old_current_class = 0; if (add_oldname) { DohIncref(add_oldname); /* Disable this, it prevents %rename to work with templates */ /* If already renamed, we used that name */ /* if (Strcmp(add_oldname, Getattr(n,"name")) != 0) { Delete(yyrename); yyrename = Copy(add_oldname); } */ } Delattr(n,"sym:needs_symtab"); Delattr(n,"sym:name"); add_only_one = 1; add_symbols(n); if (Getattr(n,"partialargs")) { Swig_symbol_cadd(Getattr(n,"partialargs"),n); } add_only_one = 0; name = Getattr(n,"name"); if (Getattr(n,"requires_symtab")) { Swig_symbol_newscope(); Swig_symbol_setscopename(name); Delete(Namespaceprefix); Namespaceprefix = Swig_symbol_qualifiedscopename(0); } if (strcmp(cnodeType,"class") == 0) { old_inclass = inclass; inclass = 1; old_current_class = current_class; current_class = n; if (Strcmp(Getattr(n,"kind"),"class") == 0) { cplus_mode = CPLUS_PRIVATE; } else { cplus_mode = CPLUS_PUBLIC; } } if (strcmp(cnodeType,"extend") == 0) { emode = cplus_mode; cplus_mode = CPLUS_PUBLIC; } add_symbols_copy(firstChild(n)); if (strcmp(cnodeType,"extend") == 0) { cplus_mode = emode; } if (Getattr(n,"requires_symtab")) { Setattr(n,"symtab", Swig_symbol_popscope()); Delattr(n,"requires_symtab"); Delete(Namespaceprefix); Namespaceprefix = Swig_symbol_qualifiedscopename(0); } if (add_oldname) { Delete(add_oldname); add_oldname = 0; } if (strcmp(cnodeType,"class") == 0) { inclass = old_inclass; current_class = old_current_class; } } else { if (strcmp(cnodeType,"extend") == 0) { emode = cplus_mode; cplus_mode = CPLUS_PUBLIC; } add_symbols_copy(firstChild(n)); if (strcmp(cnodeType,"extend") == 0) { cplus_mode = emode; } } n = nextSibling(n); } } /* Extension merge. This function is used to handle the %extend directive when it appears before a class definition. To handle this, the %extend actually needs to take precedence. Therefore, we will selectively nuke symbols from the current symbol table, replacing them with the added methods */ static void merge_extensions(Node *cls, Node *am) { Node *n; Node *csym; n = firstChild(am); while (n) { String *symname; if (Strcmp(nodeType(n),"constructor") == 0) { symname = Getattr(n,"sym:name"); if (symname) { if (Strcmp(symname,Getattr(n,"name")) == 0) { /* If the name and the sym:name of a constructor are the same, then it hasn't been renamed. However---the name of the class itself might have been renamed so we need to do a consistency check here */ if (Getattr(cls,"sym:name")) { Setattr(n,"sym:name", Getattr(cls,"sym:name")); } } } } symname = Getattr(n,"sym:name"); DohIncref(symname); if ((symname) && (!Getattr(n,"error"))) { /* Remove node from its symbol table */ Swig_symbol_remove(n); csym = Swig_symbol_add(symname,n); if (csym != n) { /* Conflict with previous definition. Nuke previous definition */ String *e = NewStringEmpty(); String *en = NewStringEmpty(); String *ec = NewStringEmpty(); Printf(ec,"Identifier '%s' redefined by %%extend (ignored),",symname); Printf(en,"%%extend definition of '%s'.",symname); SWIG_WARN_NODE_BEGIN(n); Swig_warning(WARN_PARSE_REDEFINED,Getfile(csym),Getline(csym),"%s\n",ec); Swig_warning(WARN_PARSE_REDEFINED,Getfile(n),Getline(n),"%s\n",en); SWIG_WARN_NODE_END(n); Printf(e,"%s:%d:%s\n%s:%d:%s\n",Getfile(csym),Getline(csym),ec, Getfile(n),Getline(n),en); Setattr(csym,"error",e); Delete(e); Delete(en); Delete(ec); Swig_symbol_remove(csym); /* Remove class definition */ Swig_symbol_add(symname,n); /* Insert extend definition */ } } n = nextSibling(n); } } static void append_previous_extension(Node *cls, Node *am) { Node *n, *ne; Node *pe = 0; Node *ae = 0; if (!am) return; n = firstChild(am); while (n) { ne = nextSibling(n); set_nextSibling(n,0); /* typemaps and fragments need to be prepended */ if (((Cmp(nodeType(n),"typemap") == 0) || (Cmp(nodeType(n),"fragment") == 0))) { if (!pe) pe = new_node("extend"); appendChild(pe, n); } else { if (!ae) ae = new_node("extend"); appendChild(ae, n); } n = ne; } if (pe) prependChild(cls,pe); if (ae) appendChild(cls,ae); } /* Check for unused %extend. Special case, don't report unused extensions for templates */ static void check_extensions() { Iterator ki; if (!extendhash) return; for (ki = First(extendhash); ki.key; ki = Next(ki)) { if (!Strchr(ki.key,'<')) { SWIG_WARN_NODE_BEGIN(ki.item); Swig_warning(WARN_PARSE_EXTEND_UNDEF,Getfile(ki.item), Getline(ki.item), "%%extend defined for an undeclared class %s.\n", ki.key); SWIG_WARN_NODE_END(ki.item); } } } /* Check a set of declarations to see if any are pure-abstract */ static List *pure_abstract(Node *n) { List *abs = 0; while (n) { if (Cmp(nodeType(n),"cdecl") == 0) { String *decl = Getattr(n,"decl"); if (SwigType_isfunction(decl)) { String *init = Getattr(n,"value"); if (Cmp(init,"0") == 0) { if (!abs) { abs = NewList(); } Append(abs,n); Setattr(n,"abstract","1"); } } } else if (Cmp(nodeType(n),"destructor") == 0) { if (Cmp(Getattr(n,"value"),"0") == 0) { if (!abs) { abs = NewList(); } Append(abs,n); Setattr(n,"abstract","1"); } } n = nextSibling(n); } return abs; } /* Make a classname */ static String *make_class_name(String *name) { String *nname = 0; String *prefix; if (Namespaceprefix) { nname= NewStringf("%s::%s", Namespaceprefix, name); } else { nname = NewString(name); } prefix = SwigType_istemplate_templateprefix(nname); if (prefix) { String *args, *qargs; args = SwigType_templateargs(nname); qargs = Swig_symbol_type_qualify(args,0); Append(prefix,qargs); Delete(nname); Delete(args); Delete(qargs); nname = prefix; } return nname; } static List *make_inherit_list(String *clsname, List *names) { int i, ilen; String *derived; List *bases = NewList(); if (Namespaceprefix) derived = NewStringf("%s::%s", Namespaceprefix,clsname); else derived = NewString(clsname); ilen = Len(names); for (i = 0; i < ilen; i++) { Node *s; String *base; String *n = Getitem(names,i); /* Try to figure out where this symbol is */ s = Swig_symbol_clookup(n,0); if (s) { while (s && (Strcmp(nodeType(s),"class") != 0)) { /* Not a class. Could be a typedef though. */ String *storage = Getattr(s,"storage"); if (storage && (Strcmp(storage,"typedef") == 0)) { String *nn = Getattr(s,"type"); s = Swig_symbol_clookup(nn,Getattr(s,"sym:symtab")); } else { break; } } if (s && ((Strcmp(nodeType(s),"class") == 0) || (Strcmp(nodeType(s),"template") == 0))) { String *q = Swig_symbol_qualified(s); Append(bases,s); if (q) { base = NewStringf("%s::%s", q, Getattr(s,"name")); Delete(q); } else { base = NewString(Getattr(s,"name")); } } else { base = NewString(n); } } else { base = NewString(n); } if (base) { Swig_name_inherit(base,derived); Delete(base); } } return bases; } /* If the class name is qualified. We need to create or lookup namespace entries */ static Symtab *set_scope_to_global() { Symtab *symtab = Swig_symbol_global_scope(); Swig_symbol_setscope(symtab); return symtab; } /* Remove the block braces, { and }, if the 'noblock' attribute is set. * Node *kw can be either a Hash or Parmlist. */ static String *remove_block(Node *kw, const String *inputcode) { String *modified_code = 0; while (kw) { String *name = Getattr(kw,"name"); if (name && (Cmp(name,"noblock") == 0)) { char *cstr = Char(inputcode); size_t len = Len(inputcode); if (len && cstr[0] == '{') { --len; ++cstr; if (len && cstr[len - 1] == '}') { --len; } /* we now remove the extra spaces */ while (len && isspace((int)cstr[0])) { --len; ++cstr; } while (len && isspace((int)cstr[len - 1])) { --len; } modified_code = NewStringWithSize(cstr, len); break; } } kw = nextSibling(kw); } return modified_code; } static Node *nscope = 0; static Node *nscope_inner = 0; /* Remove the scope prefix from cname and return the base name without the prefix. * The scopes specified in the prefix are found, or created in the current namespace. * So ultimately the scope is changed to that required for the base name. * For example AA::BB::CC as input returns CC and creates the namespace AA then inner * namespace BB in the current scope. If no scope separator (::) in the input, then nothing happens! */ static String *resolve_node_scope(String *cname) { Symtab *gscope = 0; nscope = 0; nscope_inner = 0; if (Swig_scopename_check(cname)) { Node *ns; String *prefix = Swig_scopename_prefix(cname); String *base = Swig_scopename_last(cname); if (prefix && (Strncmp(prefix,"::",2) == 0)) { /* Use the global scope */ String *nprefix = NewString(Char(prefix)+2); Delete(prefix); prefix= nprefix; gscope = set_scope_to_global(); } if (!prefix || (Len(prefix) == 0)) { /* Use the global scope, but we need to add a 'global' namespace. */ if (!gscope) gscope = set_scope_to_global(); /* note that this namespace is not the "unnamed" one, and we don't use Setattr(nscope,"name", ""), because the unnamed namespace is private */ nscope = new_node("namespace"); Setattr(nscope,"symtab", gscope);; nscope_inner = nscope; return base; } /* Try to locate the scope */ ns = Swig_symbol_clookup(prefix,0); if (!ns) { Swig_error(cparse_file,cparse_line,"Undefined scope '%s'\n", prefix); } else { Symtab *nstab = Getattr(ns,"symtab"); if (!nstab) { Swig_error(cparse_file,cparse_line, "'%s' is not defined as a valid scope.\n", prefix); ns = 0; } else { /* Check if the node scope is the current scope */ String *tname = Swig_symbol_qualifiedscopename(0); String *nname = Swig_symbol_qualifiedscopename(nstab); if (tname && (Strcmp(tname,nname) == 0)) { ns = 0; cname = base; } Delete(tname); Delete(nname); } if (ns) { /* we will try to create a new node using the namespaces we can find in the scope name */ List *scopes; String *sname; Iterator si; String *name = NewString(prefix); scopes = NewList(); while (name) { String *base = Swig_scopename_last(name); String *tprefix = Swig_scopename_prefix(name); Insert(scopes,0,base); Delete(base); Delete(name); name = tprefix; } for (si = First(scopes); si.item; si = Next(si)) { Node *ns1,*ns2; sname = si.item; ns1 = Swig_symbol_clookup(sname,0); assert(ns1); if (Strcmp(nodeType(ns1),"namespace") == 0) { if (Getattr(ns1,"alias")) { ns1 = Getattr(ns1,"namespace"); } } else { /* now this last part is a class */ si = Next(si); ns1 = Swig_symbol_clookup(sname,0); /* or a nested class tree, which is unrolled here */ for (; si.item; si = Next(si)) { if (si.item) { Printf(sname,"::%s",si.item); } } /* we get the 'inner' class */ nscope_inner = Swig_symbol_clookup(sname,0); /* set the scope to the inner class */ Swig_symbol_setscope(Getattr(nscope_inner,"symtab")); /* save the last namespace prefix */ Delete(Namespaceprefix); Namespaceprefix = Swig_symbol_qualifiedscopename(0); /* and return the node name, including the inner class prefix */ break; } /* here we just populate the namespace tree as usual */ ns2 = new_node("namespace"); Setattr(ns2,"name",sname); Setattr(ns2,"symtab", Getattr(ns1,"symtab")); add_symbols(ns2); Swig_symbol_setscope(Getattr(ns1,"symtab")); Delete(Namespaceprefix); Namespaceprefix = Swig_symbol_qualifiedscopename(0); if (nscope_inner) { if (Getattr(nscope_inner,"symtab") != Getattr(ns2,"symtab")) { appendChild(nscope_inner,ns2); Delete(ns2); } } nscope_inner = ns2; if (!nscope) nscope = ns2; } cname = base; Delete(scopes); } } Delete(prefix); } return cname; } /* Structures for handling code fragments built for nested classes */ typedef struct Nested { String *code; /* Associated code fragment */ int line; /* line number where it starts */ const char *name; /* Name associated with this nested class */ const char *kind; /* Kind of class */ int unnamed; /* unnamed class */ SwigType *type; /* Datatype associated with the name */ struct Nested *next; /* Next code fragment in list */ } Nested; /* Some internal variables for saving nested class information */ static Nested *nested_list = 0; /* Add a function to the nested list */ static void add_nested(Nested *n) { if (!nested_list) { nested_list = n; } else { Nested *n1 = nested_list; while (n1->next) n1 = n1->next; n1->next = n; } } /* ----------------------------------------------------------------------------- * nested_new_struct() * * Nested struct handling for C code only creates a global struct from the nested struct. * * Nested structure. This is a sick "hack". If we encounter * a nested structure, we're going to grab the text of its definition and * feed it back into the scanner. In the meantime, we need to grab * variable declaration information and generate the associated wrapper * code later. Yikes! * * This really only works in a limited sense. Since we use the * code attached to the nested class to generate both C code * it can't have any SWIG directives in it. It also needs to be parsable * by SWIG or this whole thing is going to puke. * ----------------------------------------------------------------------------- */ static void nested_new_struct(const char *kind, String *struct_code, Node *cpp_opt_declarators) { String *name; String *decl; /* Create a new global struct declaration which is just a copy of the nested struct */ Nested *nested = (Nested *) malloc(sizeof(Nested)); Nested *n = nested; name = Getattr(cpp_opt_declarators, "name"); decl = Getattr(cpp_opt_declarators, "decl"); n->code = NewStringEmpty(); Printv(n->code, "typedef ", kind, " ", struct_code, " $classname_", name, ";\n", NIL); n->name = Swig_copy_string(Char(name)); n->line = cparse_start_line; n->type = NewStringEmpty(); n->kind = kind; n->unnamed = 0; SwigType_push(n->type, decl); n->next = 0; /* Repeat for any multiple instances of the nested struct */ { Node *p = cpp_opt_declarators; p = nextSibling(p); while (p) { Nested *nn = (Nested *) malloc(sizeof(Nested)); name = Getattr(p, "name"); decl = Getattr(p, "decl"); nn->code = NewStringEmpty(); Printv(nn->code, "typedef ", kind, " ", struct_code, " $classname_", name, ";\n", NIL); nn->name = Swig_copy_string(Char(name)); nn->line = cparse_start_line; nn->type = NewStringEmpty(); nn->kind = kind; nn->unnamed = 0; SwigType_push(nn->type, decl); nn->next = 0; n->next = nn; n = nn; p = nextSibling(p); } } add_nested(nested); } /* ----------------------------------------------------------------------------- * nested_forward_declaration() * * Nested struct handling for C++ code only. * * Treat the nested class/struct/union as a forward declaration until a proper * nested class solution is implemented. * ----------------------------------------------------------------------------- */ static Node *nested_forward_declaration(const char *storage, const char *kind, String *sname, const char *name, Node *cpp_opt_declarators) { Node *nn = 0; int warned = 0; if (sname) { /* Add forward declaration of the nested type */ Node *n = new_node("classforward"); Setfile(n, cparse_file); Setline(n, cparse_line); Setattr(n, "kind", kind); Setattr(n, "name", sname); Setattr(n, "storage", storage); Setattr(n, "sym:weak", "1"); add_symbols(n); nn = n; } /* Add any variable instances. Also add in any further typedefs of the nested type. Note that anonymous typedefs (eg typedef struct {...} a, b;) are treated as class forward declarations */ if (cpp_opt_declarators) { int storage_typedef = (storage && (strcmp(storage, "typedef") == 0)); int variable_of_anonymous_type = !sname && !storage_typedef; if (!variable_of_anonymous_type) { int anonymous_typedef = !sname && (storage && (strcmp(storage, "typedef") == 0)); Node *n = cpp_opt_declarators; SwigType *type = NewString(name); while (n) { Setattr(n, "type", type); Setattr(n, "storage", storage); if (anonymous_typedef) { Setattr(n, "nodeType", "classforward"); Setattr(n, "sym:weak", "1"); } n = nextSibling(n); } Delete(type); add_symbols(cpp_opt_declarators); if (nn) { set_nextSibling(nn, cpp_opt_declarators); } else { nn = cpp_opt_declarators; } } } if (nn && Equal(nodeType(nn), "classforward")) { Node *n = nn; if (GetFlag(n, "feature:nestedworkaround")) { Swig_symbol_remove(n); nn = 0; warned = 1; } else { SWIG_WARN_NODE_BEGIN(n); Swig_warning(WARN_PARSE_NAMED_NESTED_CLASS, cparse_file, cparse_line,"Nested %s not currently supported (%s ignored)\n", kind, sname ? sname : name); SWIG_WARN_NODE_END(n); warned = 1; } } if (!warned) Swig_warning(WARN_PARSE_UNNAMED_NESTED_CLASS, cparse_file, cparse_line, "Nested %s not currently supported (ignored).\n", kind); return nn; } /* Strips C-style and C++-style comments from string in-place. */ static void strip_comments(char *string) { int state = 0; /* * 0 - not in comment * 1 - in c-style comment * 2 - in c++-style comment * 3 - in string * 4 - after reading / not in comments * 5 - after reading * in c-style comments * 6 - after reading \ in strings */ char * c = string; while (*c) { switch (state) { case 0: if (*c == '\"') state = 3; else if (*c == '/') state = 4; break; case 1: if (*c == '*') state = 5; *c = ' '; break; case 2: if (*c == '\n') state = 0; else *c = ' '; break; case 3: if (*c == '\"') state = 0; else if (*c == '\\') state = 6; break; case 4: if (*c == '/') { *(c-1) = ' '; *c = ' '; state = 2; } else if (*c == '*') { *(c-1) = ' '; *c = ' '; state = 1; } else state = 0; break; case 5: if (*c == '/') state = 0; else state = 1; *c = ' '; break; case 6: state = 3; break; } ++c; } } /* Dump all of the nested class declarations to the inline processor * However. We need to do a few name replacements and other munging * first. This function must be called before closing a class! */ static Node *dump_nested(const char *parent) { Nested *n,*n1; Node *ret = 0; Node *last = 0; n = nested_list; if (!parent) { nested_list = 0; return 0; } while (n) { Node *retx; SwigType *nt; /* Token replace the name of the parent class */ Replace(n->code, "$classname", parent, DOH_REPLACE_ANY); /* Fix up the name of the datatype (for building typedefs and other stuff) */ Append(n->type,parent); Append(n->type,"_"); Append(n->type,n->name); /* Add the appropriate declaration to the C++ processor */ retx = new_node("cdecl"); Setattr(retx,"name",n->name); nt = Copy(n->type); Setattr(retx,"type",nt); Delete(nt); Setattr(retx,"nested",parent); if (n->unnamed) { Setattr(retx,"unnamed","1"); } add_symbols(retx); if (ret) { set_nextSibling(last, retx); Delete(retx); } else { ret = retx; } last = retx; /* Strip comments - further code may break in presence of comments. */ strip_comments(Char(n->code)); /* Make all SWIG created typedef structs/unions/classes unnamed else redefinition errors occur - nasty hack alert.*/ { const char* types_array[3] = {"struct", "union", "class"}; int i; for (i=0; i<3; i++) { char* code_ptr = Char(n->code); while (code_ptr) { /* Replace struct name (as in 'struct name {...}' ) with whitespace name will be between struct and opening brace */ code_ptr = strstr(code_ptr, types_array[i]); if (code_ptr) { char *open_bracket_pos; code_ptr += strlen(types_array[i]); open_bracket_pos = strchr(code_ptr, '{'); if (open_bracket_pos) { /* Make sure we don't have something like struct A a; */ char* semi_colon_pos = strchr(code_ptr, ';'); if (!(semi_colon_pos && (semi_colon_pos < open_bracket_pos))) while (code_ptr < open_bracket_pos) *code_ptr++ = ' '; } } } } } { /* Remove SWIG directive %constant which may be left in the SWIG created typedefs */ char* code_ptr = Char(n->code); while (code_ptr) { code_ptr = strstr(code_ptr, "%constant"); if (code_ptr) { char* directive_end_pos = strchr(code_ptr, ';'); if (directive_end_pos) { while (code_ptr <= directive_end_pos) *code_ptr++ = ' '; } } } } { Node *newnode = new_node("insert"); String *code = NewStringEmpty(); Wrapper_pretty_print(n->code, code); Setattr(newnode,"code", code); Delete(code); set_nextSibling(last, newnode); Delete(newnode); last = newnode; } /* Dump the code to the scanner */ start_inline(Char(Getattr(last, "code")),n->line); n1 = n->next; Delete(n->code); free(n); n = n1; } nested_list = 0; return ret; } Node *Swig_cparse(File *f) { scanner_file(f); top = 0; yyparse(); return top; } static void single_new_feature(const char *featurename, String *val, Hash *featureattribs, char *declaratorid, SwigType *type, ParmList *declaratorparms, String *qualifier) { String *fname; String *name; String *fixname; SwigType *t = Copy(type); /* Printf(stdout, "single_new_feature: [%s] [%s] [%s] [%s] [%s] [%s]\n", featurename, val, declaratorid, t, ParmList_str_defaultargs(declaratorparms), qualifier); */ fname = NewStringf("feature:%s",featurename); if (declaratorid) { fixname = feature_identifier_fix(declaratorid); } else { fixname = NewStringEmpty(); } if (Namespaceprefix) { name = NewStringf("%s::%s",Namespaceprefix, fixname); } else { name = fixname; } if (declaratorparms) Setmeta(val,"parms",declaratorparms); if (!Len(t)) t = 0; if (t) { if (qualifier) SwigType_push(t,qualifier); if (SwigType_isfunction(t)) { SwigType *decl = SwigType_pop_function(t); if (SwigType_ispointer(t)) { String *nname = NewStringf("*%s",name); Swig_feature_set(Swig_cparse_features(), nname, decl, fname, val, featureattribs); Delete(nname); } else { Swig_feature_set(Swig_cparse_features(), name, decl, fname, val, featureattribs); } Delete(decl); } else if (SwigType_ispointer(t)) { String *nname = NewStringf("*%s",name); Swig_feature_set(Swig_cparse_features(),nname,0,fname,val, featureattribs); Delete(nname); } } else { /* Global feature, that is, feature not associated with any particular symbol */ Swig_feature_set(Swig_cparse_features(),name,0,fname,val, featureattribs); } Delete(fname); Delete(name); } /* Add a new feature to the Hash. Additional features are added if the feature has a parameter list (declaratorparms) * and one or more of the parameters have a default argument. An extra feature is added for each defaulted parameter, * simulating the equivalent overloaded method. */ static void new_feature(const char *featurename, String *val, Hash *featureattribs, char *declaratorid, SwigType *type, ParmList *declaratorparms, String *qualifier) { ParmList *declparms = declaratorparms; /* remove the { and } braces if the noblock attribute is set */ String *newval = remove_block(featureattribs, val); val = newval ? newval : val; /* Add the feature */ single_new_feature(featurename, val, featureattribs, declaratorid, type, declaratorparms, qualifier); /* Add extra features if there are default parameters in the parameter list */ if (type) { while (declparms) { if (ParmList_has_defaultargs(declparms)) { /* Create a parameter list for the new feature by copying all but the last (defaulted) parameter */ ParmList* newparms = CopyParmListMax(declparms, ParmList_len(declparms)-1); /* Create new declaration - with the last parameter removed */ SwigType *newtype = Copy(type); Delete(SwigType_pop_function(newtype)); /* remove the old parameter list from newtype */ SwigType_add_function(newtype,newparms); single_new_feature(featurename, Copy(val), featureattribs, declaratorid, newtype, newparms, qualifier); declparms = newparms; } else { declparms = 0; } } } } /* check if a function declaration is a plain C object */ static int is_cfunction(Node *n) { if (!cparse_cplusplus || cparse_externc) return 1; if (Cmp(Getattr(n,"storage"),"externc") == 0) { return 1; } return 0; } /* If the Node is a function with parameters, check to see if any of the parameters * have default arguments. If so create a new function for each defaulted argument. * The additional functions form a linked list of nodes with the head being the original Node n. */ static void default_arguments(Node *n) { Node *function = n; if (function) { ParmList *varargs = Getattr(function,"feature:varargs"); if (varargs) { /* Handles the %varargs directive by looking for "feature:varargs" and * substituting ... with an alternative set of arguments. */ Parm *p = Getattr(function,"parms"); Parm *pp = 0; while (p) { SwigType *t = Getattr(p,"type"); if (Strcmp(t,"v(...)") == 0) { if (pp) { ParmList *cv = Copy(varargs); set_nextSibling(pp,cv); Delete(cv); } else { ParmList *cv = Copy(varargs); Setattr(function,"parms", cv); Delete(cv); } break; } pp = p; p = nextSibling(p); } } /* Do not add in functions if kwargs is being used or if user wants old default argument wrapping (one wrapped method per function irrespective of number of default arguments) */ if (compact_default_args || is_cfunction(function) || GetFlag(function,"feature:compactdefaultargs") || GetFlag(function,"feature:kwargs")) { ParmList *p = Getattr(function,"parms"); if (p) Setattr(p,"compactdefargs", "1"); /* mark parameters for special handling */ function = 0; /* don't add in extra methods */ } } while (function) { ParmList *parms = Getattr(function,"parms"); if (ParmList_has_defaultargs(parms)) { /* Create a parameter list for the new function by copying all but the last (defaulted) parameter */ ParmList* newparms = CopyParmListMax(parms,ParmList_len(parms)-1); /* Create new function and add to symbol table */ { SwigType *ntype = Copy(nodeType(function)); char *cntype = Char(ntype); Node *new_function = new_node(ntype); SwigType *decl = Copy(Getattr(function,"decl")); int constqualifier = SwigType_isconst(decl); String *ccode = Copy(Getattr(function,"code")); String *cstorage = Copy(Getattr(function,"storage")); String *cvalue = Copy(Getattr(function,"value")); SwigType *ctype = Copy(Getattr(function,"type")); String *cthrow = Copy(Getattr(function,"throw")); Delete(SwigType_pop_function(decl)); /* remove the old parameter list from decl */ SwigType_add_function(decl,newparms); if (constqualifier) SwigType_add_qualifier(decl,"const"); Setattr(new_function,"name", Getattr(function,"name")); Setattr(new_function,"code", ccode); Setattr(new_function,"decl", decl); Setattr(new_function,"parms", newparms); Setattr(new_function,"storage", cstorage); Setattr(new_function,"value", cvalue); Setattr(new_function,"type", ctype); Setattr(new_function,"throw", cthrow); Delete(ccode); Delete(cstorage); Delete(cvalue); Delete(ctype); Delete(cthrow); Delete(decl); { Node *throws = Getattr(function,"throws"); ParmList *pl = CopyParmList(throws); if (throws) Setattr(new_function,"throws",pl); Delete(pl); } /* copy specific attributes for global (or in a namespace) template functions - these are not templated class methods */ if (strcmp(cntype,"template") == 0) { Node *templatetype = Getattr(function,"templatetype"); Node *symtypename = Getattr(function,"sym:typename"); Parm *templateparms = Getattr(function,"templateparms"); if (templatetype) { Node *tmp = Copy(templatetype); Setattr(new_function,"templatetype",tmp); Delete(tmp); } if (symtypename) { Node *tmp = Copy(symtypename); Setattr(new_function,"sym:typename",tmp); Delete(tmp); } if (templateparms) { Parm *tmp = CopyParmList(templateparms); Setattr(new_function,"templateparms",tmp); Delete(tmp); } } else if (strcmp(cntype,"constructor") == 0) { /* only copied for constructors as this is not a user defined feature - it is hard coded in the parser */ if (GetFlag(function,"feature:new")) SetFlag(new_function,"feature:new"); } add_symbols(new_function); /* mark added functions as ones with overloaded parameters and point to the parsed method */ Setattr(new_function,"defaultargs", n); /* Point to the new function, extending the linked list */ set_nextSibling(function, new_function); Delete(new_function); function = new_function; Delete(ntype); } } else { function = 0; } } } /* ----------------------------------------------------------------------------- * tag_nodes() * * Used by the parser to mark subtypes with extra information. * ----------------------------------------------------------------------------- */ static void tag_nodes(Node *n, const_String_or_char_ptr attrname, DOH *value) { while (n) { Setattr(n, attrname, value); tag_nodes(firstChild(n), attrname, value); n = nextSibling(n); } } %} %union { char *id; List *bases; struct Define { String *val; String *rawval; int type; String *qualifier; String *bitfield; Parm *throws; String *throwf; } dtype; struct { char *type; String *filename; int line; } loc; struct { char *id; SwigType *type; String *defarg; ParmList *parms; short have_parms; ParmList *throws; String *throwf; } decl; Parm *tparms; struct { String *method; Hash *kwargs; } tmap; struct { String *type; String *us; } ptype; SwigType *type; String *str; Parm *p; ParmList *pl; int intvalue; Node *node; }; %token ID %token HBLOCK %token POUND %token STRING %token INCLUDE IMPORT INSERT %token CHARCONST %token NUM_INT NUM_FLOAT NUM_UNSIGNED NUM_LONG NUM_ULONG NUM_LONGLONG NUM_ULONGLONG NUM_BOOL %token TYPEDEF %token TYPE_INT TYPE_UNSIGNED TYPE_SHORT TYPE_LONG TYPE_FLOAT TYPE_DOUBLE TYPE_CHAR TYPE_WCHAR TYPE_VOID TYPE_SIGNED TYPE_BOOL TYPE_COMPLEX TYPE_TYPEDEF TYPE_RAW TYPE_NON_ISO_INT8 TYPE_NON_ISO_INT16 TYPE_NON_ISO_INT32 TYPE_NON_ISO_INT64 %token LPAREN RPAREN COMMA SEMI EXTERN INIT LBRACE RBRACE PERIOD %token CONST_QUAL VOLATILE REGISTER STRUCT UNION EQUAL SIZEOF MODULE LBRACKET RBRACKET %token ILLEGAL CONSTANT %token NAME RENAME NAMEWARN EXTEND PRAGMA FEATURE VARARGS %token ENUM %token CLASS TYPENAME PRIVATE PUBLIC PROTECTED COLON STATIC VIRTUAL FRIEND THROW CATCH EXPLICIT %token USING %token NAMESPACE %token NATIVE INLINE %token TYPEMAP EXCEPT ECHO APPLY CLEAR SWIGTEMPLATE FRAGMENT %token WARN %token LESSTHAN GREATERTHAN DELETE_KW %token LESSTHANOREQUALTO GREATERTHANOREQUALTO EQUALTO NOTEQUALTO %token QUESTIONMARK %token TYPES PARMS %token NONID DSTAR DCNOT %token TEMPLATE %token OPERATOR %token COPERATOR %token PARSETYPE PARSEPARM PARSEPARMS %left CAST %left QUESTIONMARK %left LOR %left LAND %left OR %left XOR %left AND %left EQUALTO NOTEQUALTO %left GREATERTHAN LESSTHAN GREATERTHANOREQUALTO LESSTHANOREQUALTO %left LSHIFT RSHIFT %left PLUS MINUS %left STAR SLASH MODULO %left UMINUS NOT LNOT %left DCOLON %type program interface declaration swig_directive ; /* SWIG directives */ %type extend_directive apply_directive clear_directive constant_directive ; %type echo_directive except_directive fragment_directive include_directive inline_directive ; %type insert_directive module_directive name_directive native_directive ; %type pragma_directive rename_directive feature_directive varargs_directive typemap_directive ; %type types_directive template_directive warn_directive ; /* C declarations */ %type c_declaration c_decl c_decl_tail c_enum_decl c_enum_forward_decl c_constructor_decl ; %type enumlist edecl; /* C++ declarations */ %type cpp_declaration cpp_class_decl cpp_forward_class_decl cpp_template_decl; %type cpp_members cpp_member; %type cpp_constructor_decl cpp_destructor_decl cpp_protection_decl cpp_conversion_operator; %type cpp_swig_directive cpp_temp_possible cpp_nested cpp_opt_declarators ; %type cpp_using_decl cpp_namespace_decl cpp_catch_decl ; %type kwargs options; /* Misc */ %type initializer cpp_const ; %type storage_class; %type parms ptail rawparms varargs_parms; %type templateparameters templateparameterstail; %type

parm valparm rawvalparms valparms valptail ; %type

typemap_parm tm_list tm_tail ; %type

templateparameter ; %type templcpptype cpptype access_specifier; %type base_specifier %type type rawtype type_right ; %type base_list inherit raw_inherit; %type definetype def_args etype; %type expr exprnum exprcompound valexpr; %type ename ; %type template_decl; %type type_qualifier ; %type type_qualifier_raw; %type idstring idstringopt; %type pragma_lang; %type pragma_arg; %type includetype; %type pointer primitive_type; %type declarator direct_declarator notso_direct_declarator parameter_declarator typemap_parameter_declarator; %type abstract_declarator direct_abstract_declarator ctor_end; %type typemap_type; %type idcolon idcolontail idcolonnt idcolontailnt idtemplate stringbrace stringbracesemi; %type string stringnum ; %type template_parms; %type cpp_end cpp_vend; %type rename_namewarn; %type type_specifier primitive_type_list ; %type fname stringtype; %type featattr; %% /* ====================================================================== * High-level Interface file * * An interface is just a sequence of declarations which may be SWIG directives * or normal C declarations. * ====================================================================== */ program : interface { if (!classes) classes = NewHash(); Setattr($1,"classes",classes); Setattr($1,"name",ModuleName); if ((!module_node) && ModuleName) { module_node = new_node("module"); Setattr(module_node,"name",ModuleName); } Setattr($1,"module",module_node); check_extensions(); top = $1; } | PARSETYPE parm SEMI { top = Copy(Getattr($2,"type")); Delete($2); } | PARSETYPE error { top = 0; } | PARSEPARM parm SEMI { top = $2; } | PARSEPARM error { top = 0; } | PARSEPARMS LPAREN parms RPAREN SEMI { top = $3; } | PARSEPARMS error SEMI { top = 0; } ; interface : interface declaration { /* add declaration to end of linked list (the declaration isn't always a single declaration, sometimes it is a linked list itself) */ appendChild($1,$2); $$ = $1; } | empty { $$ = new_node("top"); } ; declaration : swig_directive { $$ = $1; } | c_declaration { $$ = $1; } | cpp_declaration { $$ = $1; } | SEMI { $$ = 0; } | error { $$ = 0; Swig_error(cparse_file, cparse_line,"Syntax error in input(1).\n"); exit(1); } /* Out of class constructor/destructor declarations */ | c_constructor_decl { if ($$) { add_symbols($$); } $$ = $1; } /* Out of class conversion operator. For example: inline A::operator char *() const { ... }. This is nearly impossible to parse normally. We just let the first part generate a syntax error and then resynchronize on the COPERATOR token---discarding the rest of the definition. Ugh. */ | error COPERATOR { $$ = 0; skip_decl(); } ; /* ====================================================================== * SWIG DIRECTIVES * ====================================================================== */ swig_directive : extend_directive { $$ = $1; } | apply_directive { $$ = $1; } | clear_directive { $$ = $1; } | constant_directive { $$ = $1; } | echo_directive { $$ = $1; } | except_directive { $$ = $1; } | fragment_directive { $$ = $1; } | include_directive { $$ = $1; } | inline_directive { $$ = $1; } | insert_directive { $$ = $1; } | module_directive { $$ = $1; } | name_directive { $$ = $1; } | native_directive { $$ = $1; } | pragma_directive { $$ = $1; } | rename_directive { $$ = $1; } | feature_directive { $$ = $1; } | varargs_directive { $$ = $1; } | typemap_directive { $$ = $1; } | types_directive { $$ = $1; } | template_directive { $$ = $1; } | warn_directive { $$ = $1; } ; /* ------------------------------------------------------------ %extend classname { ... } ------------------------------------------------------------ */ extend_directive : EXTEND options idcolon LBRACE { Node *cls; String *clsname; cplus_mode = CPLUS_PUBLIC; if (!classes) classes = NewHash(); if (!extendhash) extendhash = NewHash(); clsname = make_class_name($3); cls = Getattr(classes,clsname); if (!cls) { /* No previous definition. Create a new scope */ Node *am = Getattr(extendhash,clsname); if (!am) { Swig_symbol_newscope(); Swig_symbol_setscopename($3); prev_symtab = 0; } else { prev_symtab = Swig_symbol_setscope(Getattr(am,"symtab")); } current_class = 0; } else { /* Previous class definition. Use its symbol table */ prev_symtab = Swig_symbol_setscope(Getattr(cls,"symtab")); current_class = cls; extendmode = 1; } Classprefix = NewString($3); Namespaceprefix= Swig_symbol_qualifiedscopename(0); Delete(clsname); } cpp_members RBRACE { String *clsname; extendmode = 0; $$ = new_node("extend"); Setattr($$,"symtab",Swig_symbol_popscope()); if (prev_symtab) { Swig_symbol_setscope(prev_symtab); } Namespaceprefix = Swig_symbol_qualifiedscopename(0); clsname = make_class_name($3); Setattr($$,"name",clsname); /* Mark members as extend */ tag_nodes($6,"feature:extend",(char*) "1"); if (current_class) { /* We add the extension to the previously defined class */ appendChild($$,$6); appendChild(current_class,$$); } else { /* We store the extensions in the extensions hash */ Node *am = Getattr(extendhash,clsname); if (am) { /* Append the members to the previous extend methods */ appendChild(am,$6); } else { appendChild($$,$6); Setattr(extendhash,clsname,$$); } } current_class = 0; Delete(Classprefix); Delete(clsname); Classprefix = 0; prev_symtab = 0; $$ = 0; } ; /* ------------------------------------------------------------ %apply ------------------------------------------------------------ */ apply_directive : APPLY typemap_parm LBRACE tm_list RBRACE { $$ = new_node("apply"); Setattr($$,"pattern",Getattr($2,"pattern")); appendChild($$,$4); }; /* ------------------------------------------------------------ %clear ------------------------------------------------------------ */ clear_directive : CLEAR tm_list SEMI { $$ = new_node("clear"); appendChild($$,$2); } ; /* ------------------------------------------------------------ %constant name = value; %constant type name = value; ------------------------------------------------------------ */ constant_directive : CONSTANT ID EQUAL definetype SEMI { if (($4.type != T_ERROR) && ($4.type != T_SYMBOL)) { SwigType *type = NewSwigType($4.type); $$ = new_node("constant"); Setattr($$,"name",$2); Setattr($$,"type",type); Setattr($$,"value",$4.val); if ($4.rawval) Setattr($$,"rawval", $4.rawval); Setattr($$,"storage","%constant"); SetFlag($$,"feature:immutable"); add_symbols($$); Delete(type); } else { if ($4.type == T_ERROR) { Swig_warning(WARN_PARSE_UNSUPPORTED_VALUE,cparse_file,cparse_line,"Unsupported constant value (ignored)\n"); } $$ = 0; } } | CONSTANT type declarator def_args SEMI { if (($4.type != T_ERROR) && ($4.type != T_SYMBOL)) { SwigType_push($2,$3.type); /* Sneaky callback function trick */ if (SwigType_isfunction($2)) { SwigType_add_pointer($2); } $$ = new_node("constant"); Setattr($$,"name",$3.id); Setattr($$,"type",$2); Setattr($$,"value",$4.val); if ($4.rawval) Setattr($$,"rawval", $4.rawval); Setattr($$,"storage","%constant"); SetFlag($$,"feature:immutable"); add_symbols($$); } else { if ($4.type == T_ERROR) { Swig_warning(WARN_PARSE_UNSUPPORTED_VALUE,cparse_file,cparse_line,"Unsupported constant value\n"); } $$ = 0; } } | CONSTANT error SEMI { Swig_warning(WARN_PARSE_BAD_VALUE,cparse_file,cparse_line,"Bad constant value (ignored).\n"); $$ = 0; } ; /* ------------------------------------------------------------ %echo "text" %echo %{ ... %} ------------------------------------------------------------ */ echo_directive : ECHO HBLOCK { char temp[64]; Replace($2,"$file",cparse_file, DOH_REPLACE_ANY); sprintf(temp,"%d", cparse_line); Replace($2,"$line",temp,DOH_REPLACE_ANY); Printf(stderr,"%s\n", $2); Delete($2); $$ = 0; } | ECHO string { char temp[64]; String *s = NewString($2); Replace(s,"$file",cparse_file, DOH_REPLACE_ANY); sprintf(temp,"%d", cparse_line); Replace(s,"$line",temp,DOH_REPLACE_ANY); Printf(stderr,"%s\n", s); Delete(s); $$ = 0; } ; /* ------------------------------------------------------------ %except(lang) { ... } %except { ... } %except(lang); %except; ------------------------------------------------------------ */ except_directive : EXCEPT LPAREN ID RPAREN LBRACE { skip_balanced('{','}'); $$ = 0; Swig_warning(WARN_DEPRECATED_EXCEPT,cparse_file, cparse_line, "%%except is deprecated. Use %%exception instead.\n"); } | EXCEPT LBRACE { skip_balanced('{','}'); $$ = 0; Swig_warning(WARN_DEPRECATED_EXCEPT,cparse_file, cparse_line, "%%except is deprecated. Use %%exception instead.\n"); } | EXCEPT LPAREN ID RPAREN SEMI { $$ = 0; Swig_warning(WARN_DEPRECATED_EXCEPT,cparse_file, cparse_line, "%%except is deprecated. Use %%exception instead.\n"); } | EXCEPT SEMI { $$ = 0; Swig_warning(WARN_DEPRECATED_EXCEPT,cparse_file, cparse_line, "%%except is deprecated. Use %%exception instead.\n"); } ; /* fragment keyword arguments */ stringtype : string LBRACE parm RBRACE { $$ = NewHash(); Setattr($$,"value",$1); Setattr($$,"type",Getattr($3,"type")); } ; fname : string { $$ = NewHash(); Setattr($$,"value",$1); } | stringtype { $$ = $1; } ; /* ------------------------------------------------------------ %fragment(name, section) %{ ... %} %fragment("name" {type}, "section") %{ ... %} %fragment("name", "section", fragment="fragment1", fragment="fragment2") %{ ... %} Also as above but using { ... } %fragment("name"); ------------------------------------------------------------ */ fragment_directive: FRAGMENT LPAREN fname COMMA kwargs RPAREN HBLOCK { Hash *p = $5; $$ = new_node("fragment"); Setattr($$,"value",Getattr($3,"value")); Setattr($$,"type",Getattr($3,"type")); Setattr($$,"section",Getattr(p,"name")); Setattr($$,"kwargs",nextSibling(p)); Setattr($$,"code",$7); } | FRAGMENT LPAREN fname COMMA kwargs RPAREN LBRACE { Hash *p = $5; String *code; skip_balanced('{','}'); $$ = new_node("fragment"); Setattr($$,"value",Getattr($3,"value")); Setattr($$,"type",Getattr($3,"type")); Setattr($$,"section",Getattr(p,"name")); Setattr($$,"kwargs",nextSibling(p)); Delitem(scanner_ccode,0); Delitem(scanner_ccode,DOH_END); code = Copy(scanner_ccode); Setattr($$,"code",code); Delete(code); } | FRAGMENT LPAREN fname RPAREN SEMI { $$ = new_node("fragment"); Setattr($$,"value",Getattr($3,"value")); Setattr($$,"type",Getattr($3,"type")); Setattr($$,"emitonly","1"); } ; /* ------------------------------------------------------------ %includefile(option1="xyz", ...) "filename" [ declarations ] %importfile(option1="xyz", ...) "filename" [ declarations ] ------------------------------------------------------------ */ include_directive: includetype options string LBRACKET { $1.filename = Copy(cparse_file); $1.line = cparse_line; scanner_set_location(NewString($3),1); if ($2) { String *maininput = Getattr($2, "maininput"); if (maininput) scanner_set_main_input_file(NewString(maininput)); } } interface RBRACKET { String *mname = 0; $$ = $6; scanner_set_location($1.filename,$1.line+1); if (strcmp($1.type,"include") == 0) set_nodeType($$,"include"); if (strcmp($1.type,"import") == 0) { mname = $2 ? Getattr($2,"module") : 0; set_nodeType($$,"import"); if (import_mode) --import_mode; } Setattr($$,"name",$3); /* Search for the module (if any) */ { Node *n = firstChild($$); while (n) { if (Strcmp(nodeType(n),"module") == 0) { if (mname) { Setattr(n,"name", mname); mname = 0; } Setattr($$,"module",Getattr(n,"name")); break; } n = nextSibling(n); } if (mname) { /* There is no module node in the import node, ie, you imported a .h file directly. We are forced then to create a new import node with a module node. */ Node *nint = new_node("import"); Node *mnode = new_node("module"); Setattr(mnode,"name", mname); appendChild(nint,mnode); Delete(mnode); appendChild(nint,firstChild($$)); $$ = nint; Setattr($$,"module",mname); } } Setattr($$,"options",$2); } ; includetype : INCLUDE { $$.type = (char *) "include"; } | IMPORT { $$.type = (char *) "import"; ++import_mode;} ; /* ------------------------------------------------------------ %inline %{ ... %} ------------------------------------------------------------ */ inline_directive : INLINE HBLOCK { String *cpps; if (Namespaceprefix) { Swig_error(cparse_file, cparse_start_line, "%%inline directive inside a namespace is disallowed.\n"); $$ = 0; } else { $$ = new_node("insert"); Setattr($$,"code",$2); /* Need to run through the preprocessor */ Seek($2,0,SEEK_SET); Setline($2,cparse_start_line); Setfile($2,cparse_file); cpps = Preprocessor_parse($2); start_inline(Char(cpps), cparse_start_line); Delete($2); Delete(cpps); } } | INLINE LBRACE { String *cpps; int start_line = cparse_line; skip_balanced('{','}'); if (Namespaceprefix) { Swig_error(cparse_file, cparse_start_line, "%%inline directive inside a namespace is disallowed.\n"); $$ = 0; } else { String *code; $$ = new_node("insert"); Delitem(scanner_ccode,0); Delitem(scanner_ccode,DOH_END); code = Copy(scanner_ccode); Setattr($$,"code", code); Delete(code); cpps=Copy(scanner_ccode); start_inline(Char(cpps), start_line); Delete(cpps); } } ; /* ------------------------------------------------------------ %{ ... %} %insert(section) "filename" %insert("section") "filename" %insert(section) %{ ... %} %insert("section") %{ ... %} ------------------------------------------------------------ */ insert_directive : HBLOCK { $$ = new_node("insert"); Setattr($$,"code",$1); } | INSERT LPAREN idstring RPAREN string { String *code = NewStringEmpty(); $$ = new_node("insert"); Setattr($$,"section",$3); Setattr($$,"code",code); if (Swig_insert_file($5,code) < 0) { Swig_error(cparse_file, cparse_line, "Couldn't find '%s'.\n", $5); $$ = 0; } } | INSERT LPAREN idstring RPAREN HBLOCK { $$ = new_node("insert"); Setattr($$,"section",$3); Setattr($$,"code",$5); } | INSERT LPAREN idstring RPAREN LBRACE { String *code; skip_balanced('{','}'); $$ = new_node("insert"); Setattr($$,"section",$3); Delitem(scanner_ccode,0); Delitem(scanner_ccode,DOH_END); code = Copy(scanner_ccode); Setattr($$,"code", code); Delete(code); } ; /* ------------------------------------------------------------ %module modname %module "modname" ------------------------------------------------------------ */ module_directive: MODULE options idstring { $$ = new_node("module"); if ($2) { Setattr($$,"options",$2); if (Getattr($2,"directors")) { Wrapper_director_mode_set(1); } if (Getattr($2,"dirprot")) { Wrapper_director_protected_mode_set(1); } if (Getattr($2,"allprotected")) { Wrapper_all_protected_mode_set(1); } if (Getattr($2,"templatereduce")) { template_reduce = 1; } if (Getattr($2,"notemplatereduce")) { template_reduce = 0; } } if (!ModuleName) ModuleName = NewString($3); if (!import_mode) { /* first module included, we apply global ModuleName, which can be modify by -module */ String *mname = Copy(ModuleName); Setattr($$,"name",mname); Delete(mname); } else { /* import mode, we just pass the idstring */ Setattr($$,"name",$3); } if (!module_node) module_node = $$; } ; /* ------------------------------------------------------------ %name(newname) declaration %name("newname") declaration ------------------------------------------------------------ */ name_directive : NAME LPAREN idstring RPAREN { Swig_warning(WARN_DEPRECATED_NAME,cparse_file,cparse_line, "%%name is deprecated. Use %%rename instead.\n"); Delete(yyrename); yyrename = NewString($3); $$ = 0; } | NAME LPAREN RPAREN { Swig_warning(WARN_DEPRECATED_NAME,cparse_file,cparse_line, "%%name is deprecated. Use %%rename instead.\n"); $$ = 0; Swig_error(cparse_file,cparse_line,"Missing argument to %%name directive.\n"); } ; /* ------------------------------------------------------------ %native(scriptname) name; %native(scriptname) type name (parms); ------------------------------------------------------------ */ native_directive : NATIVE LPAREN ID RPAREN storage_class ID SEMI { $$ = new_node("native"); Setattr($$,"name",$3); Setattr($$,"wrap:name",$6); add_symbols($$); } | NATIVE LPAREN ID RPAREN storage_class type declarator SEMI { if (!SwigType_isfunction($7.type)) { Swig_error(cparse_file,cparse_line,"%%native declaration '%s' is not a function.\n", $7.id); $$ = 0; } else { Delete(SwigType_pop_function($7.type)); /* Need check for function here */ SwigType_push($6,$7.type); $$ = new_node("native"); Setattr($$,"name",$3); Setattr($$,"wrap:name",$7.id); Setattr($$,"type",$6); Setattr($$,"parms",$7.parms); Setattr($$,"decl",$7.type); } add_symbols($$); } ; /* ------------------------------------------------------------ %pragma(lang) name=value %pragma(lang) name %pragma name = value %pragma name ------------------------------------------------------------ */ pragma_directive : PRAGMA pragma_lang ID EQUAL pragma_arg { $$ = new_node("pragma"); Setattr($$,"lang",$2); Setattr($$,"name",$3); Setattr($$,"value",$5); } | PRAGMA pragma_lang ID { $$ = new_node("pragma"); Setattr($$,"lang",$2); Setattr($$,"name",$3); } ; pragma_arg : string { $$ = NewString($1); } | HBLOCK { $$ = $1; } ; pragma_lang : LPAREN ID RPAREN { $$ = $2; } | empty { $$ = (char *) "swig"; } ; /* ------------------------------------------------------------ %rename identifier newname; %rename identifier "newname"; ------------------------------------------------------------ */ rename_directive : rename_namewarn declarator idstring SEMI { SwigType *t = $2.type; Hash *kws = NewHash(); String *fixname; fixname = feature_identifier_fix($2.id); Setattr(kws,"name",$3); if (!Len(t)) t = 0; /* Special declarator check */ if (t) { if (SwigType_isfunction(t)) { SwigType *decl = SwigType_pop_function(t); if (SwigType_ispointer(t)) { String *nname = NewStringf("*%s",fixname); if ($1) { Swig_name_rename_add(Namespaceprefix, nname,decl,kws,$2.parms); } else { Swig_name_namewarn_add(Namespaceprefix,nname,decl,kws); } Delete(nname); } else { if ($1) { Swig_name_rename_add(Namespaceprefix,(fixname),decl,kws,$2.parms); } else { Swig_name_namewarn_add(Namespaceprefix,(fixname),decl,kws); } } Delete(decl); } else if (SwigType_ispointer(t)) { String *nname = NewStringf("*%s",fixname); if ($1) { Swig_name_rename_add(Namespaceprefix,(nname),0,kws,$2.parms); } else { Swig_name_namewarn_add(Namespaceprefix,(nname),0,kws); } Delete(nname); } } else { if ($1) { Swig_name_rename_add(Namespaceprefix,(fixname),0,kws,$2.parms); } else { Swig_name_namewarn_add(Namespaceprefix,(fixname),0,kws); } } $$ = 0; scanner_clear_rename(); } | rename_namewarn LPAREN kwargs RPAREN declarator cpp_const SEMI { String *fixname; Hash *kws = $3; SwigType *t = $5.type; fixname = feature_identifier_fix($5.id); if (!Len(t)) t = 0; /* Special declarator check */ if (t) { if ($6.qualifier) SwigType_push(t,$6.qualifier); if (SwigType_isfunction(t)) { SwigType *decl = SwigType_pop_function(t); if (SwigType_ispointer(t)) { String *nname = NewStringf("*%s",fixname); if ($1) { Swig_name_rename_add(Namespaceprefix, nname,decl,kws,$5.parms); } else { Swig_name_namewarn_add(Namespaceprefix,nname,decl,kws); } Delete(nname); } else { if ($1) { Swig_name_rename_add(Namespaceprefix,(fixname),decl,kws,$5.parms); } else { Swig_name_namewarn_add(Namespaceprefix,(fixname),decl,kws); } } Delete(decl); } else if (SwigType_ispointer(t)) { String *nname = NewStringf("*%s",fixname); if ($1) { Swig_name_rename_add(Namespaceprefix,(nname),0,kws,$5.parms); } else { Swig_name_namewarn_add(Namespaceprefix,(nname),0,kws); } Delete(nname); } } else { if ($1) { Swig_name_rename_add(Namespaceprefix,(fixname),0,kws,$5.parms); } else { Swig_name_namewarn_add(Namespaceprefix,(fixname),0,kws); } } $$ = 0; scanner_clear_rename(); } | rename_namewarn LPAREN kwargs RPAREN string SEMI { if ($1) { Swig_name_rename_add(Namespaceprefix,$5,0,$3,0); } else { Swig_name_namewarn_add(Namespaceprefix,$5,0,$3); } $$ = 0; scanner_clear_rename(); } ; rename_namewarn : RENAME { $$ = 1; } | NAMEWARN { $$ = 0; }; /* ------------------------------------------------------------ Feature targeting a symbol name (non-global feature): %feature(featurename) name "val"; %feature(featurename, val) name; where "val" could instead be the other bracket types, that is, { val } or %{ val %} or indeed omitted whereupon it defaults to "1". Or, the global feature which does not target a symbol name: %feature(featurename) "val"; %feature(featurename, val); An empty val (empty string) clears the feature. Any number of feature attributes can optionally be added, for example a non-global feature with 2 attributes: %feature(featurename, attrib1="attribval1", attrib2="attribval2") name "val"; %feature(featurename, val, attrib1="attribval1", attrib2="attribval2") name; ------------------------------------------------------------ */ /* Non-global feature */ feature_directive : FEATURE LPAREN idstring RPAREN declarator cpp_const stringbracesemi { String *val = $7 ? NewString($7) : NewString("1"); new_feature($3, val, 0, $5.id, $5.type, $5.parms, $6.qualifier); $$ = 0; scanner_clear_rename(); } | FEATURE LPAREN idstring COMMA stringnum RPAREN declarator cpp_const SEMI { String *val = Len($5) ? NewString($5) : 0; new_feature($3, val, 0, $7.id, $7.type, $7.parms, $8.qualifier); $$ = 0; scanner_clear_rename(); } | FEATURE LPAREN idstring featattr RPAREN declarator cpp_const stringbracesemi { String *val = $8 ? NewString($8) : NewString("1"); new_feature($3, val, $4, $6.id, $6.type, $6.parms, $7.qualifier); $$ = 0; scanner_clear_rename(); } | FEATURE LPAREN idstring COMMA stringnum featattr RPAREN declarator cpp_const SEMI { String *val = Len($5) ? NewString($5) : 0; new_feature($3, val, $6, $8.id, $8.type, $8.parms, $9.qualifier); $$ = 0; scanner_clear_rename(); } /* Global feature */ | FEATURE LPAREN idstring RPAREN stringbracesemi { String *val = $5 ? NewString($5) : NewString("1"); new_feature($3, val, 0, 0, 0, 0, 0); $$ = 0; scanner_clear_rename(); } | FEATURE LPAREN idstring COMMA stringnum RPAREN SEMI { String *val = Len($5) ? NewString($5) : 0; new_feature($3, val, 0, 0, 0, 0, 0); $$ = 0; scanner_clear_rename(); } | FEATURE LPAREN idstring featattr RPAREN stringbracesemi { String *val = $6 ? NewString($6) : NewString("1"); new_feature($3, val, $4, 0, 0, 0, 0); $$ = 0; scanner_clear_rename(); } | FEATURE LPAREN idstring COMMA stringnum featattr RPAREN SEMI { String *val = Len($5) ? NewString($5) : 0; new_feature($3, val, $6, 0, 0, 0, 0); $$ = 0; scanner_clear_rename(); } ; stringbracesemi : stringbrace { $$ = $1; } | SEMI { $$ = 0; } | PARMS LPAREN parms RPAREN SEMI { $$ = $3; } ; featattr : COMMA idstring EQUAL stringnum { $$ = NewHash(); Setattr($$,"name",$2); Setattr($$,"value",$4); } | COMMA idstring EQUAL stringnum featattr { $$ = NewHash(); Setattr($$,"name",$2); Setattr($$,"value",$4); set_nextSibling($$,$5); } ; /* %varargs() directive. */ varargs_directive : VARARGS LPAREN varargs_parms RPAREN declarator cpp_const SEMI { Parm *val; String *name; SwigType *t; if (Namespaceprefix) name = NewStringf("%s::%s", Namespaceprefix, $5.id); else name = NewString($5.id); val = $3; if ($5.parms) { Setmeta(val,"parms",$5.parms); } t = $5.type; if (!Len(t)) t = 0; if (t) { if ($6.qualifier) SwigType_push(t,$6.qualifier); if (SwigType_isfunction(t)) { SwigType *decl = SwigType_pop_function(t); if (SwigType_ispointer(t)) { String *nname = NewStringf("*%s",name); Swig_feature_set(Swig_cparse_features(), nname, decl, "feature:varargs", val, 0); Delete(nname); } else { Swig_feature_set(Swig_cparse_features(), name, decl, "feature:varargs", val, 0); } Delete(decl); } else if (SwigType_ispointer(t)) { String *nname = NewStringf("*%s",name); Swig_feature_set(Swig_cparse_features(),nname,0,"feature:varargs",val, 0); Delete(nname); } } else { Swig_feature_set(Swig_cparse_features(),name,0,"feature:varargs",val, 0); } Delete(name); $$ = 0; }; varargs_parms : parms { $$ = $1; } | NUM_INT COMMA parm { int i; int n; Parm *p; n = atoi(Char($1.val)); if (n <= 0) { Swig_error(cparse_file, cparse_line,"Argument count in %%varargs must be positive.\n"); $$ = 0; } else { String *name = Getattr($3, "name"); $$ = Copy($3); if (name) Setattr($$, "name", NewStringf("%s%d", name, n)); for (i = 1; i < n; i++) { p = Copy($3); name = Getattr(p, "name"); if (name) Setattr(p, "name", NewStringf("%s%d", name, n-i)); set_nextSibling(p,$$); Delete($$); $$ = p; } } } ; /* ------------------------------------------------------------ %typemap(method) type { ... } %typemap(method) type "..." %typemap(method) type; - typemap deletion %typemap(method) type1,type2,... = type; - typemap copy %typemap type1,type2,... = type; - typemap copy ------------------------------------------------------------ */ typemap_directive : TYPEMAP LPAREN typemap_type RPAREN tm_list stringbrace { $$ = 0; if ($3.method) { String *code = 0; $$ = new_node("typemap"); Setattr($$,"method",$3.method); if ($3.kwargs) { ParmList *kw = $3.kwargs; code = remove_block(kw, $6); Setattr($$,"kwargs", $3.kwargs); } code = code ? code : NewString($6); Setattr($$,"code", code); Delete(code); appendChild($$,$5); } } | TYPEMAP LPAREN typemap_type RPAREN tm_list SEMI { $$ = 0; if ($3.method) { $$ = new_node("typemap"); Setattr($$,"method",$3.method); appendChild($$,$5); } } | TYPEMAP LPAREN typemap_type RPAREN tm_list EQUAL typemap_parm SEMI { $$ = 0; if ($3.method) { $$ = new_node("typemapcopy"); Setattr($$,"method",$3.method); Setattr($$,"pattern", Getattr($7,"pattern")); appendChild($$,$5); } } ; /* typemap method type (lang,method) or (method) */ typemap_type : kwargs { Hash *p; String *name; p = nextSibling($1); if (p && (!Getattr(p,"value"))) { /* this is the deprecated two argument typemap form */ Swig_warning(WARN_DEPRECATED_TYPEMAP_LANG,cparse_file, cparse_line, "Specifying the language name in %%typemap is deprecated - use #ifdef SWIG instead.\n"); /* two argument typemap form */ name = Getattr($1,"name"); if (!name || (Strcmp(name,typemap_lang))) { $$.method = 0; $$.kwargs = 0; } else { $$.method = Getattr(p,"name"); $$.kwargs = nextSibling(p); } } else { /* one-argument typemap-form */ $$.method = Getattr($1,"name"); $$.kwargs = p; } } ; tm_list : typemap_parm tm_tail { $$ = $1; set_nextSibling($$,$2); } ; tm_tail : COMMA typemap_parm tm_tail { $$ = $2; set_nextSibling($$,$3); } | empty { $$ = 0;} ; typemap_parm : type typemap_parameter_declarator { Parm *parm; SwigType_push($1,$2.type); $$ = new_node("typemapitem"); parm = NewParmWithoutFileLineInfo($1,$2.id); Setattr($$,"pattern",parm); Setattr($$,"parms", $2.parms); Delete(parm); /* $$ = NewParmWithoutFileLineInfo($1,$2.id); Setattr($$,"parms",$2.parms); */ } | LPAREN parms RPAREN { $$ = new_node("typemapitem"); Setattr($$,"pattern",$2); /* Setattr($$,"multitype",$2); */ } | LPAREN parms RPAREN LPAREN parms RPAREN { $$ = new_node("typemapitem"); Setattr($$,"pattern", $2); /* Setattr($$,"multitype",$2); */ Setattr($$,"parms",$5); } ; /* ------------------------------------------------------------ %types(parmlist); %types(parmlist) %{ ... %} ------------------------------------------------------------ */ types_directive : TYPES LPAREN parms RPAREN stringbracesemi { $$ = new_node("types"); Setattr($$,"parms",$3); if ($5) Setattr($$,"convcode",NewString($5)); } ; /* ------------------------------------------------------------ %template(name) tname; ------------------------------------------------------------ */ template_directive: SWIGTEMPLATE LPAREN idstringopt RPAREN idcolonnt LESSTHAN valparms GREATERTHAN SEMI { Parm *p, *tp; Node *n; Symtab *tscope = 0; int specialized = 0; $$ = 0; tscope = Swig_symbol_current(); /* Get the current scope */ /* If the class name is qualified, we need to create or lookup namespace entries */ if (!inclass) { $5 = resolve_node_scope($5); } /* We use the new namespace entry 'nscope' only to emit the template node. The template parameters are resolved in the current 'tscope'. This is closer to the C++ (typedef) behavior. */ n = Swig_cparse_template_locate($5,$7,tscope); /* Patch the argument types to respect namespaces */ p = $7; while (p) { SwigType *value = Getattr(p,"value"); if (!value) { SwigType *ty = Getattr(p,"type"); if (ty) { SwigType *rty = 0; int reduce = template_reduce; if (reduce || !SwigType_ispointer(ty)) { rty = Swig_symbol_typedef_reduce(ty,tscope); if (!reduce) reduce = SwigType_ispointer(rty); } ty = reduce ? Swig_symbol_type_qualify(rty,tscope) : Swig_symbol_type_qualify(ty,tscope); Setattr(p,"type",ty); Delete(ty); Delete(rty); } } else { value = Swig_symbol_type_qualify(value,tscope); Setattr(p,"value",value); Delete(value); } p = nextSibling(p); } /* Look for the template */ { Node *nn = n; Node *linklistend = 0; while (nn) { Node *templnode = 0; if (Strcmp(nodeType(nn),"template") == 0) { int nnisclass = (Strcmp(Getattr(nn,"templatetype"),"class") == 0); /* if not a templated class it is a templated function */ Parm *tparms = Getattr(nn,"templateparms"); if (!tparms) { specialized = 1; } if (nnisclass && !specialized && ((ParmList_len($7) > ParmList_len(tparms)))) { Swig_error(cparse_file, cparse_line, "Too many template parameters. Maximum of %d.\n", ParmList_len(tparms)); } else if (nnisclass && !specialized && ((ParmList_len($7) < ParmList_numrequired(tparms)))) { Swig_error(cparse_file, cparse_line, "Not enough template parameters specified. %d required.\n", ParmList_numrequired(tparms)); } else if (!nnisclass && ((ParmList_len($7) != ParmList_len(tparms)))) { /* must be an overloaded templated method - ignore it as it is overloaded with a different number of template parameters */ nn = Getattr(nn,"sym:nextSibling"); /* repeat for overloaded templated functions */ continue; } else { String *tname = Copy($5); int def_supplied = 0; /* Expand the template */ Node *templ = Swig_symbol_clookup($5,0); Parm *targs = templ ? Getattr(templ,"templateparms") : 0; ParmList *temparms; if (specialized) temparms = CopyParmList($7); else temparms = CopyParmList(tparms); /* Create typedef's and arguments */ p = $7; tp = temparms; if (!p && ParmList_len(p) != ParmList_len(temparms)) { /* we have no template parameters supplied in %template for a template that has default args*/ p = tp; def_supplied = 1; } while (p) { String *value = Getattr(p,"value"); if (def_supplied) { Setattr(p,"default","1"); } if (value) { Setattr(tp,"value",value); } else { SwigType *ty = Getattr(p,"type"); if (ty) { Setattr(tp,"type",ty); } Delattr(tp,"value"); } /* fix default arg values */ if (targs) { Parm *pi = temparms; Parm *ti = targs; String *tv = Getattr(tp,"value"); if (!tv) tv = Getattr(tp,"type"); while(pi != tp && ti && pi) { String *name = Getattr(ti,"name"); String *value = Getattr(pi,"value"); if (!value) value = Getattr(pi,"type"); Replaceid(tv, name, value); pi = nextSibling(pi); ti = nextSibling(ti); } } p = nextSibling(p); tp = nextSibling(tp); if (!p && tp) { p = tp; def_supplied = 1; } } templnode = copy_node(nn); /* We need to set the node name based on name used to instantiate */ Setattr(templnode,"name",tname); Delete(tname); if (!specialized) { Delattr(templnode,"sym:typename"); } else { Setattr(templnode,"sym:typename","1"); } if ($3 && !inclass) { /* Comment this out for 1.3.28. We need to re-enable it later but first we need to move %ignore from using %rename to use %feature(ignore). String *symname = Swig_name_make(templnode,0,$3,0,0); */ String *symname = $3; Swig_cparse_template_expand(templnode,symname,temparms,tscope); Setattr(templnode,"sym:name",symname); } else { static int cnt = 0; String *nname = NewStringf("__dummy_%d__", cnt++); Swig_cparse_template_expand(templnode,nname,temparms,tscope); Setattr(templnode,"sym:name",nname); Delete(nname); Setattr(templnode,"feature:onlychildren", "typemap,typemapitem,typemapcopy,typedef,types,fragment"); if ($3) { Swig_warning(WARN_PARSE_NESTED_TEMPLATE, cparse_file, cparse_line, "Named nested template instantiations not supported. Processing as if no name was given to %%template().\n"); } } Delattr(templnode,"templatetype"); Setattr(templnode,"template",nn); Setfile(templnode,cparse_file); Setline(templnode,cparse_line); Delete(temparms); add_symbols_copy(templnode); if (Strcmp(nodeType(templnode),"class") == 0) { /* Identify pure abstract methods */ Setattr(templnode,"abstract", pure_abstract(firstChild(templnode))); /* Set up inheritance in symbol table */ { Symtab *csyms; List *baselist = Getattr(templnode,"baselist"); csyms = Swig_symbol_current(); Swig_symbol_setscope(Getattr(templnode,"symtab")); if (baselist) { List *bases = make_inherit_list(Getattr(templnode,"name"),baselist); if (bases) { Iterator s; for (s = First(bases); s.item; s = Next(s)) { Symtab *st = Getattr(s.item,"symtab"); if (st) { Setfile(st,Getfile(s.item)); Setline(st,Getline(s.item)); Swig_symbol_inherit(st); } } Delete(bases); } } Swig_symbol_setscope(csyms); } /* Merge in %extend methods for this class */ /* !!! This may be broken. We may have to add the %extend methods at the beginning of the class */ if (extendhash) { String *stmp = 0; String *clsname; Node *am; if (Namespaceprefix) { clsname = stmp = NewStringf("%s::%s", Namespaceprefix, Getattr(templnode,"name")); } else { clsname = Getattr(templnode,"name"); } am = Getattr(extendhash,clsname); if (am) { Symtab *st = Swig_symbol_current(); Swig_symbol_setscope(Getattr(templnode,"symtab")); /* Printf(stdout,"%s: %s %x %x\n", Getattr(templnode,"name"), clsname, Swig_symbol_current(), Getattr(templnode,"symtab")); */ merge_extensions(templnode,am); Swig_symbol_setscope(st); append_previous_extension(templnode,am); Delattr(extendhash,clsname); } if (stmp) Delete(stmp); } /* Add to classes hash */ if (!classes) classes = NewHash(); { if (Namespaceprefix) { String *temp = NewStringf("%s::%s", Namespaceprefix, Getattr(templnode,"name")); Setattr(classes,temp,templnode); Delete(temp); } else { String *qs = Swig_symbol_qualifiedscopename(templnode); Setattr(classes, qs,templnode); Delete(qs); } } } } /* all the overloaded templated functions are added into a linked list */ if (nscope_inner) { /* non-global namespace */ if (templnode) { appendChild(nscope_inner,templnode); Delete(templnode); if (nscope) $$ = nscope; } } else { /* global namespace */ if (!linklistend) { $$ = templnode; } else { set_nextSibling(linklistend,templnode); Delete(templnode); } linklistend = templnode; } } nn = Getattr(nn,"sym:nextSibling"); /* repeat for overloaded templated functions. If a templated class there will never be a sibling. */ } } Swig_symbol_setscope(tscope); Delete(Namespaceprefix); Namespaceprefix = Swig_symbol_qualifiedscopename(0); } ; /* ------------------------------------------------------------ %warn "text" %warn(no) ------------------------------------------------------------ */ warn_directive : WARN string { Swig_warning(0,cparse_file, cparse_line,"%s\n", $2); $$ = 0; } ; /* ====================================================================== * C Parsing * ====================================================================== */ c_declaration : c_decl { $$ = $1; if ($$) { add_symbols($$); default_arguments($$); } } | c_enum_decl { $$ = $1; } | c_enum_forward_decl { $$ = $1; } /* An extern C type declaration, disable cparse_cplusplus if needed. */ | EXTERN string LBRACE { if (Strcmp($2,"C") == 0) { cparse_externc = 1; } } interface RBRACE { cparse_externc = 0; if (Strcmp($2,"C") == 0) { Node *n = firstChild($5); $$ = new_node("extern"); Setattr($$,"name",$2); appendChild($$,n); while (n) { SwigType *decl = Getattr(n,"decl"); if (SwigType_isfunction(decl) && Strcmp(Getattr(n, "storage"), "typedef") != 0) { Setattr(n,"storage","externc"); } n = nextSibling(n); } } else { Swig_warning(WARN_PARSE_UNDEFINED_EXTERN,cparse_file, cparse_line,"Unrecognized extern type \"%s\".\n", $2); $$ = new_node("extern"); Setattr($$,"name",$2); appendChild($$,firstChild($5)); } } ; /* ------------------------------------------------------------ A C global declaration of some kind (may be variable, function, typedef, etc.) ------------------------------------------------------------ */ c_decl : storage_class type declarator initializer c_decl_tail { $$ = new_node("cdecl"); if ($4.qualifier) SwigType_push($3.type,$4.qualifier); Setattr($$,"type",$2); Setattr($$,"storage",$1); Setattr($$,"name",$3.id); Setattr($$,"decl",$3.type); Setattr($$,"parms",$3.parms); Setattr($$,"value",$4.val); Setattr($$,"throws",$4.throws); Setattr($$,"throw",$4.throwf); if (!$5) { if (Len(scanner_ccode)) { String *code = Copy(scanner_ccode); Setattr($$,"code",code); Delete(code); } } else { Node *n = $5; /* Inherit attributes */ while (n) { String *type = Copy($2); Setattr(n,"type",type); Setattr(n,"storage",$1); n = nextSibling(n); Delete(type); } } if ($4.bitfield) { Setattr($$,"bitfield", $4.bitfield); } /* Look for "::" declarations (ignored) */ if (Strstr($3.id,"::")) { /* This is a special case. If the scope name of the declaration exactly matches that of the declaration, then we will allow it. Otherwise, delete. */ String *p = Swig_scopename_prefix($3.id); if (p) { if ((Namespaceprefix && Strcmp(p,Namespaceprefix) == 0) || (inclass && Strcmp(p,Classprefix) == 0)) { String *lstr = Swig_scopename_last($3.id); Setattr($$,"name",lstr); Delete(lstr); set_nextSibling($$,$5); } else { Delete($$); $$ = $5; } Delete(p); } else { Delete($$); $$ = $5; } } else { set_nextSibling($$,$5); } } ; /* Allow lists of variables and functions to be built up */ c_decl_tail : SEMI { $$ = 0; Clear(scanner_ccode); } | COMMA declarator initializer c_decl_tail { $$ = new_node("cdecl"); if ($3.qualifier) SwigType_push($2.type,$3.qualifier); Setattr($$,"name",$2.id); Setattr($$,"decl",$2.type); Setattr($$,"parms",$2.parms); Setattr($$,"value",$3.val); Setattr($$,"throws",$3.throws); Setattr($$,"throw",$3.throwf); if ($3.bitfield) { Setattr($$,"bitfield", $3.bitfield); } if (!$4) { if (Len(scanner_ccode)) { String *code = Copy(scanner_ccode); Setattr($$,"code",code); Delete(code); } } else { set_nextSibling($$,$4); } } | LBRACE { skip_balanced('{','}'); $$ = 0; } ; initializer : def_args { $$ = $1; $$.qualifier = 0; $$.throws = 0; $$.throwf = 0; } | type_qualifier def_args { $$ = $2; $$.qualifier = $1; $$.throws = 0; $$.throwf = 0; } | THROW LPAREN parms RPAREN def_args { $$ = $5; $$.qualifier = 0; $$.throws = $3; $$.throwf = NewString("1"); } | type_qualifier THROW LPAREN parms RPAREN def_args { $$ = $6; $$.qualifier = $1; $$.throws = $4; $$.throwf = NewString("1"); } ; /* ------------------------------------------------------------ enum Name; ------------------------------------------------------------ */ c_enum_forward_decl : storage_class ENUM ID SEMI { SwigType *ty = 0; $$ = new_node("enumforward"); ty = NewStringf("enum %s", $3); Setattr($$,"name",$3); Setattr($$,"type",ty); Setattr($$,"sym:weak", "1"); add_symbols($$); } ; /* ------------------------------------------------------------ enum { ... } * ------------------------------------------------------------ */ c_enum_decl : storage_class ENUM ename LBRACE enumlist RBRACE SEMI { SwigType *ty = 0; $$ = new_node("enum"); ty = NewStringf("enum %s", $3); Setattr($$,"name",$3); Setattr($$,"type",ty); appendChild($$,$5); add_symbols($$); /* Add to tag space */ add_symbols($5); /* Add enum values to id space */ } | storage_class ENUM ename LBRACE enumlist RBRACE declarator initializer c_decl_tail { Node *n; SwigType *ty = 0; String *unnamed = 0; int unnamedinstance = 0; $$ = new_node("enum"); if ($3) { Setattr($$,"name",$3); ty = NewStringf("enum %s", $3); } else if ($7.id) { unnamed = make_unnamed(); ty = NewStringf("enum %s", unnamed); Setattr($$,"unnamed",unnamed); /* name is not set for unnamed enum instances, e.g. enum { foo } Instance; */ if ($1 && Cmp($1,"typedef") == 0) { Setattr($$,"name",$7.id); } else { unnamedinstance = 1; } Setattr($$,"storage",$1); } if ($7.id && Cmp($1,"typedef") == 0) { Setattr($$,"tdname",$7.id); Setattr($$,"allows_typedef","1"); } appendChild($$,$5); n = new_node("cdecl"); Setattr(n,"type",ty); Setattr(n,"name",$7.id); Setattr(n,"storage",$1); Setattr(n,"decl",$7.type); Setattr(n,"parms",$7.parms); Setattr(n,"unnamed",unnamed); if (unnamedinstance) { SwigType *cty = NewString("enum "); Setattr($$,"type",cty); SetFlag($$,"unnamedinstance"); SetFlag(n,"unnamedinstance"); Delete(cty); } if ($9) { Node *p = $9; set_nextSibling(n,p); while (p) { SwigType *cty = Copy(ty); Setattr(p,"type",cty); Setattr(p,"unnamed",unnamed); Setattr(p,"storage",$1); Delete(cty); p = nextSibling(p); } } else { if (Len(scanner_ccode)) { String *code = Copy(scanner_ccode); Setattr(n,"code",code); Delete(code); } } /* Ensure that typedef enum ABC {foo} XYZ; uses XYZ for sym:name, like structs. * Note that class_rename/yyrename are bit of a mess so used this simple approach to change the name. */ if ($7.id && $3 && Cmp($1,"typedef") == 0) { String *name = NewString($7.id); Setattr($$, "parser:makename", name); Delete(name); } add_symbols($$); /* Add enum to tag space */ set_nextSibling($$,n); Delete(n); add_symbols($5); /* Add enum values to id space */ add_symbols(n); Delete(unnamed); } ; c_constructor_decl : storage_class type LPAREN parms RPAREN ctor_end { /* This is a sick hack. If the ctor_end has parameters, and the parms parameter only has 1 parameter, this could be a declaration of the form: type (id)(parms) Otherwise it's an error. */ int err = 0; $$ = 0; if ((ParmList_len($4) == 1) && (!Swig_scopename_check($2))) { SwigType *ty = Getattr($4,"type"); String *name = Getattr($4,"name"); err = 1; if (!name) { $$ = new_node("cdecl"); Setattr($$,"type",$2); Setattr($$,"storage",$1); Setattr($$,"name",ty); if ($6.have_parms) { SwigType *decl = NewStringEmpty(); SwigType_add_function(decl,$6.parms); Setattr($$,"decl",decl); Setattr($$,"parms",$6.parms); if (Len(scanner_ccode)) { String *code = Copy(scanner_ccode); Setattr($$,"code",code); Delete(code); } } if ($6.defarg) { Setattr($$,"value",$6.defarg); } Setattr($$,"throws",$6.throws); Setattr($$,"throw",$6.throwf); err = 0; } } if (err) { Swig_error(cparse_file,cparse_line,"Syntax error in input(2).\n"); exit(1); } } ; /* ====================================================================== * C++ Support * ====================================================================== */ cpp_declaration : cpp_class_decl { $$ = $1; } | cpp_forward_class_decl { $$ = $1; } | cpp_template_decl { $$ = $1; } | cpp_using_decl { $$ = $1; } | cpp_namespace_decl { $$ = $1; } | cpp_catch_decl { $$ = 0; } ; /* A simple class/struct/union definition */ cpp_class_decl : storage_class cpptype idcolon inherit LBRACE { if (nested_template == 0) { String *prefix; List *bases = 0; Node *scope = 0; $$ = new_node("class"); Setline($$,cparse_start_line); Setattr($$,"kind",$2); if ($4) { Setattr($$,"baselist", Getattr($4,"public")); Setattr($$,"protectedbaselist", Getattr($4,"protected")); Setattr($$,"privatebaselist", Getattr($4,"private")); } Setattr($$,"allows_typedef","1"); /* preserve the current scope */ prev_symtab = Swig_symbol_current(); /* If the class name is qualified. We need to create or lookup namespace/scope entries */ scope = resolve_node_scope($3); Setfile(scope,cparse_file); Setline(scope,cparse_line); $3 = scope; /* support for old nested classes "pseudo" support, such as: %rename(Ala__Ola) Ala::Ola; class Ala::Ola { public: Ola() {} }; this should disappear when a proper implementation is added. */ if (nscope_inner && Strcmp(nodeType(nscope_inner),"namespace") != 0) { if (Namespaceprefix) { String *name = NewStringf("%s::%s", Namespaceprefix, $3); $3 = name; Namespaceprefix = 0; nscope_inner = 0; } } Setattr($$,"name",$3); Delete(class_rename); class_rename = make_name($$,$3,0); Classprefix = NewString($3); /* Deal with inheritance */ if ($4) { bases = make_inherit_list($3,Getattr($4,"public")); } prefix = SwigType_istemplate_templateprefix($3); if (prefix) { String *fbase, *tbase; if (Namespaceprefix) { fbase = NewStringf("%s::%s", Namespaceprefix,$3); tbase = NewStringf("%s::%s", Namespaceprefix, prefix); } else { fbase = Copy($3); tbase = Copy(prefix); } Swig_name_inherit(tbase,fbase); Delete(fbase); Delete(tbase); } if (strcmp($2,"class") == 0) { cplus_mode = CPLUS_PRIVATE; } else { cplus_mode = CPLUS_PUBLIC; } Swig_symbol_newscope(); Swig_symbol_setscopename($3); if (bases) { Iterator s; for (s = First(bases); s.item; s = Next(s)) { Symtab *st = Getattr(s.item,"symtab"); if (st) { Setfile(st,Getfile(s.item)); Setline(st,Getline(s.item)); Swig_symbol_inherit(st); } } Delete(bases); } Delete(Namespaceprefix); Namespaceprefix = Swig_symbol_qualifiedscopename(0); cparse_start_line = cparse_line; /* If there are active template parameters, we need to make sure they are placed in the class symbol table so we can catch shadows */ if (template_parameters) { Parm *tp = template_parameters; while(tp) { String *tpname = Copy(Getattr(tp,"name")); Node *tn = new_node("templateparm"); Setattr(tn,"name",tpname); Swig_symbol_cadd(tpname,tn); tp = nextSibling(tp); Delete(tpname); } } if (class_level >= max_class_levels) { if (!max_class_levels) { max_class_levels = 16; } else { max_class_levels *= 2; } class_decl = (Node**) realloc(class_decl, sizeof(Node*) * max_class_levels); if (!class_decl) { Swig_error(cparse_file, cparse_line, "realloc() failed\n"); } } class_decl[class_level++] = $$; Delete(prefix); inclass = 1; } } cpp_members RBRACE cpp_opt_declarators { (void) $6; if (nested_template == 0) { Node *p; SwigType *ty; Symtab *cscope = prev_symtab; Node *am = 0; String *scpname = 0; $$ = class_decl[--class_level]; inclass = 0; /* Check for pure-abstract class */ Setattr($$,"abstract", pure_abstract($7)); /* This bit of code merges in a previously defined %extend directive (if any) */ if (extendhash) { String *clsname = Swig_symbol_qualifiedscopename(0); am = Getattr(extendhash,clsname); if (am) { merge_extensions($$,am); Delattr(extendhash,clsname); } Delete(clsname); } if (!classes) classes = NewHash(); scpname = Swig_symbol_qualifiedscopename(0); Setattr(classes,scpname,$$); Delete(scpname); appendChild($$,$7); if (am) append_previous_extension($$,am); p = $9; if (p) { set_nextSibling($$,p); } if (cparse_cplusplus && !cparse_externc) { ty = NewString($3); } else { ty = NewStringf("%s %s", $2,$3); } while (p) { Setattr(p,"storage",$1); Setattr(p,"type",ty); p = nextSibling(p); } /* Dump nested classes */ { String *name = $3; if ($9) { SwigType *decltype = Getattr($9,"decl"); if (Cmp($1,"typedef") == 0) { if (!decltype || !Len(decltype)) { String *cname; name = Getattr($9,"name"); cname = Copy(name); Setattr($$,"tdname",cname); Delete(cname); /* Use typedef name as class name */ if (class_rename && (Strcmp(class_rename,$3) == 0)) { Delete(class_rename); class_rename = NewString(name); } if (!Getattr(classes,name)) { Setattr(classes,name,$$); } Setattr($$,"decl",decltype); } } } appendChild($$,dump_nested(Char(name))); } if (cplus_mode != CPLUS_PUBLIC) { /* we 'open' the class at the end, to allow %template to add new members */ Node *pa = new_node("access"); Setattr(pa,"kind","public"); cplus_mode = CPLUS_PUBLIC; appendChild($$,pa); Delete(pa); } Setattr($$,"symtab",Swig_symbol_popscope()); Classprefix = 0; if (nscope_inner) { /* this is tricky */ /* we add the declaration in the original namespace */ appendChild(nscope_inner,$$); Swig_symbol_setscope(Getattr(nscope_inner,"symtab")); Delete(Namespaceprefix); Namespaceprefix = Swig_symbol_qualifiedscopename(0); add_symbols($$); if (nscope) $$ = nscope; /* but the variable definition in the current scope */ Swig_symbol_setscope(cscope); Delete(Namespaceprefix); Namespaceprefix = Swig_symbol_qualifiedscopename(0); add_symbols($9); } else { Delete(yyrename); yyrename = Copy(class_rename); Delete(Namespaceprefix); Namespaceprefix = Swig_symbol_qualifiedscopename(0); add_symbols($$); add_symbols($9); } Swig_symbol_setscope(cscope); Delete(Namespaceprefix); Namespaceprefix = Swig_symbol_qualifiedscopename(0); } else { $$ = new_node("class"); Setattr($$,"kind",$2); Setattr($$,"name",NewString($3)); SetFlag($$,"nestedtemplateclass"); } } /* An unnamed struct, possibly with a typedef */ | storage_class cpptype LBRACE { String *unnamed; unnamed = make_unnamed(); $$ = new_node("class"); Setline($$,cparse_start_line); Setattr($$,"kind",$2); Setattr($$,"storage",$1); Setattr($$,"unnamed",unnamed); Setattr($$,"allows_typedef","1"); Delete(class_rename); class_rename = make_name($$,0,0); if (strcmp($2,"class") == 0) { cplus_mode = CPLUS_PRIVATE; } else { cplus_mode = CPLUS_PUBLIC; } Swig_symbol_newscope(); cparse_start_line = cparse_line; if (class_level >= max_class_levels) { if (!max_class_levels) { max_class_levels = 16; } else { max_class_levels *= 2; } class_decl = (Node**) realloc(class_decl, sizeof(Node*) * max_class_levels); if (!class_decl) { Swig_error(cparse_file, cparse_line, "realloc() failed\n"); } } class_decl[class_level++] = $$; inclass = 1; Classprefix = NewStringEmpty(); Delete(Namespaceprefix); Namespaceprefix = Swig_symbol_qualifiedscopename(0); } cpp_members RBRACE declarator initializer c_decl_tail { String *unnamed; Node *n; (void) $4; Classprefix = 0; $$ = class_decl[--class_level]; inclass = 0; unnamed = Getattr($$,"unnamed"); /* Check for pure-abstract class */ Setattr($$,"abstract", pure_abstract($5)); n = new_node("cdecl"); Setattr(n,"name",$7.id); Setattr(n,"unnamed",unnamed); Setattr(n,"type",unnamed); Setattr(n,"decl",$7.type); Setattr(n,"parms",$7.parms); Setattr(n,"storage",$1); if ($9) { Node *p = $9; set_nextSibling(n,p); while (p) { String *type = Copy(unnamed); Setattr(p,"name",$7.id); Setattr(p,"unnamed",unnamed); Setattr(p,"type",type); Delete(type); Setattr(p,"storage",$1); p = nextSibling(p); } } set_nextSibling($$,n); Delete(n); { /* If a proper typedef name was given, we'll use it to set the scope name */ String *name = 0; if ($1 && (strcmp($1,"typedef") == 0)) { if (!Len($7.type)) { String *scpname = 0; name = $7.id; Setattr($$,"tdname",name); Setattr($$,"name",name); Swig_symbol_setscopename(name); /* If a proper name was given, we use that as the typedef, not unnamed */ Clear(unnamed); Append(unnamed, name); n = nextSibling(n); set_nextSibling($$,n); /* Check for previous extensions */ if (extendhash) { String *clsname = Swig_symbol_qualifiedscopename(0); Node *am = Getattr(extendhash,clsname); if (am) { /* Merge the extension into the symbol table */ merge_extensions($$,am); append_previous_extension($$,am); Delattr(extendhash,clsname); } Delete(clsname); } if (!classes) classes = NewHash(); scpname = Swig_symbol_qualifiedscopename(0); Setattr(classes,scpname,$$); Delete(scpname); } else { Swig_symbol_setscopename(""); } } appendChild($$,$5); appendChild($$,dump_nested(Char(name))); } /* Pop the scope */ Setattr($$,"symtab",Swig_symbol_popscope()); if (class_rename) { Delete(yyrename); yyrename = NewString(class_rename); } Delete(Namespaceprefix); Namespaceprefix = Swig_symbol_qualifiedscopename(0); add_symbols($$); add_symbols(n); Delete(unnamed); } ; cpp_opt_declarators : SEMI { $$ = 0; } | declarator initializer c_decl_tail { $$ = new_node("cdecl"); Setattr($$,"name",$1.id); Setattr($$,"decl",$1.type); Setattr($$,"parms",$1.parms); set_nextSibling($$,$3); } ; /* ------------------------------------------------------------ class Name; ------------------------------------------------------------ */ cpp_forward_class_decl : storage_class cpptype idcolon SEMI { if ($1 && (Strcmp($1,"friend") == 0)) { /* Ignore */ $$ = 0; } else { $$ = new_node("classforward"); Setfile($$,cparse_file); Setline($$,cparse_line); Setattr($$,"kind",$2); Setattr($$,"name",$3); Setattr($$,"sym:weak", "1"); add_symbols($$); } } ; /* ------------------------------------------------------------ template<...> decl ------------------------------------------------------------ */ cpp_template_decl : TEMPLATE LESSTHAN template_parms GREATERTHAN { template_parameters = $3; if (inclass) nested_template++; } cpp_temp_possible { /* Don't ignore templated functions declared within a class, unless the templated function is within a nested class */ if (nested_template <= 1) { int is_nested_template_class = $6 && GetFlag($6, "nestedtemplateclass"); if (is_nested_template_class) { $$ = 0; /* Nested template classes would probably better be ignored like ordinary nested classes using cpp_nested, but that introduces shift/reduce conflicts */ if (cplus_mode == CPLUS_PUBLIC) { /* Treat the nested class/struct/union as a forward declaration until a proper nested class solution is implemented */ String *kind = Getattr($6, "kind"); String *name = Getattr($6, "name"); $$ = new_node("template"); Setattr($$,"kind",kind); Setattr($$,"name",name); Setattr($$,"sym:weak", "1"); Setattr($$,"templatetype","classforward"); Setattr($$,"templateparms", $3); add_symbols($$); if (GetFlag($$, "feature:nestedworkaround")) { Swig_symbol_remove($$); $$ = 0; } else { SWIG_WARN_NODE_BEGIN($$); Swig_warning(WARN_PARSE_NAMED_NESTED_CLASS, cparse_file, cparse_line, "Nested template %s not currently supported (%s ignored).\n", kind, name); SWIG_WARN_NODE_END($$); } } Delete($6); } else { String *tname = 0; int error = 0; /* check if we get a namespace node with a class declaration, and retrieve the class */ Symtab *cscope = Swig_symbol_current(); Symtab *sti = 0; Node *ntop = $6; Node *ni = ntop; SwigType *ntype = ni ? nodeType(ni) : 0; while (ni && Strcmp(ntype,"namespace") == 0) { sti = Getattr(ni,"symtab"); ni = firstChild(ni); ntype = nodeType(ni); } if (sti) { Swig_symbol_setscope(sti); Delete(Namespaceprefix); Namespaceprefix = Swig_symbol_qualifiedscopename(0); $6 = ni; } $$ = $6; if ($$) tname = Getattr($$,"name"); /* Check if the class is a template specialization */ if (($$) && (Strchr(tname,'<')) && (!is_operator(tname))) { /* If a specialization. Check if defined. */ Node *tempn = 0; { String *tbase = SwigType_templateprefix(tname); tempn = Swig_symbol_clookup_local(tbase,0); if (!tempn || (Strcmp(nodeType(tempn),"template") != 0)) { SWIG_WARN_NODE_BEGIN(tempn); Swig_warning(WARN_PARSE_TEMPLATE_SP_UNDEF, Getfile($$),Getline($$),"Specialization of non-template '%s'.\n", tbase); SWIG_WARN_NODE_END(tempn); tempn = 0; error = 1; } Delete(tbase); } Setattr($$,"specialization","1"); Setattr($$,"templatetype",nodeType($$)); set_nodeType($$,"template"); /* Template partial specialization */ if (tempn && ($3) && ($6)) { List *tlist; String *targs = SwigType_templateargs(tname); tlist = SwigType_parmlist(targs); /* Printf(stdout,"targs = '%s' %s\n", targs, tlist); */ if (!Getattr($$,"sym:weak")) { Setattr($$,"sym:typename","1"); } if (Len(tlist) != ParmList_len(Getattr(tempn,"templateparms"))) { Swig_error(Getfile($$),Getline($$),"Inconsistent argument count in template partial specialization. %d %d\n", Len(tlist), ParmList_len(Getattr(tempn,"templateparms"))); } else { /* This code builds the argument list for the partial template specialization. This is a little hairy, but the idea is as follows: $3 contains a list of arguments supplied for the template. For example template. tlist is a list of the specialization arguments--which may be different. For example class. tp is a copy of the arguments in the original template definition. The patching algorithm walks through the list of supplied arguments ($3), finds the position in the specialization arguments (tlist), and then patches the name in the argument list of the original template. */ { String *pn; Parm *p, *p1; int i, nargs; Parm *tp = CopyParmList(Getattr(tempn,"templateparms")); nargs = Len(tlist); p = $3; while (p) { for (i = 0; i < nargs; i++){ pn = Getattr(p,"name"); if (Strcmp(pn,SwigType_base(Getitem(tlist,i))) == 0) { int j; Parm *p1 = tp; for (j = 0; j < i; j++) { p1 = nextSibling(p1); } Setattr(p1,"name",pn); Setattr(p1,"partialarg","1"); } } p = nextSibling(p); } p1 = tp; i = 0; while (p1) { if (!Getattr(p1,"partialarg")) { Delattr(p1,"name"); Setattr(p1,"type", Getitem(tlist,i)); } i++; p1 = nextSibling(p1); } Setattr($$,"templateparms",tp); Delete(tp); } #if 0 /* Patch the parameter list */ if (tempn) { Parm *p,*p1; ParmList *tp = CopyParmList(Getattr(tempn,"templateparms")); p = $3; p1 = tp; while (p && p1) { String *pn = Getattr(p,"name"); Printf(stdout,"pn = '%s'\n", pn); if (pn) Setattr(p1,"name",pn); else Delattr(p1,"name"); pn = Getattr(p,"type"); if (pn) Setattr(p1,"type",pn); p = nextSibling(p); p1 = nextSibling(p1); } Setattr($$,"templateparms",tp); Delete(tp); } else { Setattr($$,"templateparms",$3); } #endif Delattr($$,"specialization"); Setattr($$,"partialspecialization","1"); /* Create a specialized name for matching */ { Parm *p = $3; String *fname = NewString(Getattr($$,"name")); String *ffname = 0; ParmList *partialparms = 0; char tmp[32]; int i, ilen; while (p) { String *n = Getattr(p,"name"); if (!n) { p = nextSibling(p); continue; } ilen = Len(tlist); for (i = 0; i < ilen; i++) { if (Strstr(Getitem(tlist,i),n)) { sprintf(tmp,"$%d",i+1); Replaceid(fname,n,tmp); } } p = nextSibling(p); } /* Patch argument names with typedef */ { Iterator tt; Parm *parm_current = 0; List *tparms = SwigType_parmlist(fname); ffname = SwigType_templateprefix(fname); Append(ffname,"<("); for (tt = First(tparms); tt.item; ) { SwigType *rtt = Swig_symbol_typedef_reduce(tt.item,0); SwigType *ttr = Swig_symbol_type_qualify(rtt,0); Parm *newp = NewParmWithoutFileLineInfo(ttr, 0); if (partialparms) set_nextSibling(parm_current, newp); else partialparms = newp; parm_current = newp; Append(ffname,ttr); tt = Next(tt); if (tt.item) Putc(',',ffname); Delete(rtt); Delete(ttr); } Delete(tparms); Append(ffname,")>"); } { Node *new_partial = NewHash(); String *partials = Getattr(tempn,"partials"); if (!partials) { partials = NewList(); Setattr(tempn,"partials",partials); Delete(partials); } /* Printf(stdout,"partial: fname = '%s', '%s'\n", fname, Swig_symbol_typedef_reduce(fname,0)); */ Setattr(new_partial, "partialparms", partialparms); Setattr(new_partial, "templcsymname", ffname); Append(partials, new_partial); } Setattr($$,"partialargs",ffname); Swig_symbol_cadd(ffname,$$); } } Delete(tlist); Delete(targs); } else { /* An explicit template specialization */ /* add default args from primary (unspecialized) template */ String *ty = Swig_symbol_template_deftype(tname,0); String *fname = Swig_symbol_type_qualify(ty,0); Swig_symbol_cadd(fname,$$); Delete(ty); Delete(fname); } } else if ($$) { Setattr($$,"templatetype",nodeType($6)); set_nodeType($$,"template"); Setattr($$,"templateparms", $3); if (!Getattr($$,"sym:weak")) { Setattr($$,"sym:typename","1"); } add_symbols($$); default_arguments($$); /* We also place a fully parameterized version in the symbol table */ { Parm *p; String *fname = NewStringf("%s<(", Getattr($$,"name")); p = $3; while (p) { String *n = Getattr(p,"name"); if (!n) n = Getattr(p,"type"); Append(fname,n); p = nextSibling(p); if (p) Putc(',',fname); } Append(fname,")>"); Swig_symbol_cadd(fname,$$); } } $$ = ntop; Swig_symbol_setscope(cscope); Delete(Namespaceprefix); Namespaceprefix = Swig_symbol_qualifiedscopename(0); if (error) $$ = 0; } } else { $$ = 0; } template_parameters = 0; if (inclass) nested_template--; } | TEMPLATE cpptype idcolon { Swig_warning(WARN_PARSE_EXPLICIT_TEMPLATE, cparse_file, cparse_line, "Explicit template instantiation ignored.\n"); $$ = 0; } ; cpp_temp_possible: c_decl { $$ = $1; } | cpp_class_decl { $$ = $1; } | cpp_constructor_decl { $$ = $1; } | cpp_template_decl { $$ = 0; } | cpp_forward_class_decl { $$ = $1; } | cpp_conversion_operator { $$ = $1; } ; template_parms : templateparameters { /* Rip out the parameter names */ Parm *p = $1; $$ = $1; while (p) { String *name = Getattr(p,"name"); if (!name) { /* Hmmm. Maybe it's a 'class T' parameter */ char *type = Char(Getattr(p,"type")); /* Template template parameter */ if (strncmp(type,"template ",16) == 0) { type += 16; } if ((strncmp(type,"class ",6) == 0) || (strncmp(type,"typename ", 9) == 0)) { char *t = strchr(type,' '); Setattr(p,"name", t+1); } else { /* Swig_error(cparse_file, cparse_line, "Missing template parameter name\n"); $$.rparms = 0; $$.parms = 0; break; */ } } p = nextSibling(p); } } ; templateparameters : templateparameter templateparameterstail { set_nextSibling($1,$2); $$ = $1; } | empty { $$ = 0; } ; templateparameter : templcpptype { $$ = NewParmWithoutFileLineInfo(NewString($1), 0); } | parm { $$ = $1; } ; templateparameterstail : COMMA templateparameter templateparameterstail { set_nextSibling($2,$3); $$ = $2; } | empty { $$ = 0; } ; /* Namespace support */ cpp_using_decl : USING idcolon SEMI { String *uname = Swig_symbol_type_qualify($2,0); String *name = Swig_scopename_last($2); $$ = new_node("using"); Setattr($$,"uname",uname); Setattr($$,"name", name); Delete(uname); Delete(name); add_symbols($$); } | USING NAMESPACE idcolon SEMI { Node *n = Swig_symbol_clookup($3,0); if (!n) { Swig_error(cparse_file, cparse_line, "Nothing known about namespace '%s'\n", $3); $$ = 0; } else { while (Strcmp(nodeType(n),"using") == 0) { n = Getattr(n,"node"); } if (n) { if (Strcmp(nodeType(n),"namespace") == 0) { Symtab *current = Swig_symbol_current(); Symtab *symtab = Getattr(n,"symtab"); $$ = new_node("using"); Setattr($$,"node",n); Setattr($$,"namespace", $3); if (current != symtab) { Swig_symbol_inherit(symtab); } } else { Swig_error(cparse_file, cparse_line, "'%s' is not a namespace.\n", $3); $$ = 0; } } else { $$ = 0; } } } ; cpp_namespace_decl : NAMESPACE idcolon LBRACE { Hash *h; $1 = Swig_symbol_current(); h = Swig_symbol_clookup($2,0); if (h && ($1 == Getattr(h,"sym:symtab")) && (Strcmp(nodeType(h),"namespace") == 0)) { if (Getattr(h,"alias")) { h = Getattr(h,"namespace"); Swig_warning(WARN_PARSE_NAMESPACE_ALIAS, cparse_file, cparse_line, "Namespace alias '%s' not allowed here. Assuming '%s'\n", $2, Getattr(h,"name")); $2 = Getattr(h,"name"); } Swig_symbol_setscope(Getattr(h,"symtab")); } else { Swig_symbol_newscope(); Swig_symbol_setscopename($2); } Delete(Namespaceprefix); Namespaceprefix = Swig_symbol_qualifiedscopename(0); } interface RBRACE { Node *n = $5; set_nodeType(n,"namespace"); Setattr(n,"name",$2); Setattr(n,"symtab", Swig_symbol_popscope()); Swig_symbol_setscope($1); $$ = n; Delete(Namespaceprefix); Namespaceprefix = Swig_symbol_qualifiedscopename(0); add_symbols($$); } | NAMESPACE LBRACE { Hash *h; $1 = Swig_symbol_current(); h = Swig_symbol_clookup((char *)" ",0); if (h && (Strcmp(nodeType(h),"namespace") == 0)) { Swig_symbol_setscope(Getattr(h,"symtab")); } else { Swig_symbol_newscope(); /* we don't use "__unnamed__", but a long 'empty' name */ Swig_symbol_setscopename(" "); } Namespaceprefix = 0; } interface RBRACE { $$ = $4; set_nodeType($$,"namespace"); Setattr($$,"unnamed","1"); Setattr($$,"symtab", Swig_symbol_popscope()); Swig_symbol_setscope($1); Delete(Namespaceprefix); Namespaceprefix = Swig_symbol_qualifiedscopename(0); add_symbols($$); } | NAMESPACE ID EQUAL idcolon SEMI { /* Namespace alias */ Node *n; $$ = new_node("namespace"); Setattr($$,"name",$2); Setattr($$,"alias",$4); n = Swig_symbol_clookup($4,0); if (!n) { Swig_error(cparse_file, cparse_line, "Unknown namespace '%s'\n", $4); $$ = 0; } else { if (Strcmp(nodeType(n),"namespace") != 0) { Swig_error(cparse_file, cparse_line, "'%s' is not a namespace\n",$4); $$ = 0; } else { while (Getattr(n,"alias")) { n = Getattr(n,"namespace"); } Setattr($$,"namespace",n); add_symbols($$); /* Set up a scope alias */ Swig_symbol_alias($2,Getattr(n,"symtab")); } } } ; cpp_members : cpp_member cpp_members { $$ = $1; /* Insert cpp_member (including any siblings) to the front of the cpp_members linked list */ if ($$) { Node *p = $$; Node *pp =0; while (p) { pp = p; p = nextSibling(p); } set_nextSibling(pp,$2); } else { $$ = $2; } } | EXTEND LBRACE { if (cplus_mode != CPLUS_PUBLIC) { Swig_error(cparse_file,cparse_line,"%%extend can only be used in a public section\n"); } } cpp_members RBRACE cpp_members { $$ = new_node("extend"); tag_nodes($4,"feature:extend",(char*) "1"); appendChild($$,$4); set_nextSibling($$,$6); } | include_directive { $$ = $1; } | empty { $$ = 0;} | error { int start_line = cparse_line; skip_decl(); Swig_error(cparse_file,start_line,"Syntax error in input(3).\n"); exit(1); } cpp_members { $$ = $3; } ; /* ====================================================================== * C++ Class members * ====================================================================== */ /* A class member. May be data or a function. Static or virtual as well */ cpp_member : c_declaration { $$ = $1; } | cpp_constructor_decl { $$ = $1; if (extendmode) { String *symname; symname= make_name($$,Getattr($$,"name"), Getattr($$,"decl")); if (Strcmp(symname,Getattr($$,"name")) == 0) { /* No renaming operation. Set name to class name */ Delete(yyrename); yyrename = NewString(Getattr(current_class,"sym:name")); } else { Delete(yyrename); yyrename = symname; } } add_symbols($$); default_arguments($$); } | cpp_destructor_decl { $$ = $1; } | cpp_protection_decl { $$ = $1; } | cpp_swig_directive { $$ = $1; } | cpp_conversion_operator { $$ = $1; } | cpp_forward_class_decl { $$ = $1; } | cpp_nested { $$ = $1; } | storage_class idcolon SEMI { $$ = 0; } | cpp_using_decl { $$ = $1; } | cpp_template_decl { $$ = $1; } | cpp_catch_decl { $$ = 0; } | template_directive { $$ = $1; } | warn_directive { $$ = $1; } | anonymous_bitfield { $$ = 0; } | fragment_directive {$$ = $1; } | types_directive {$$ = $1; } | SEMI { $$ = 0; } ; /* Possibly a constructor */ /* Note: the use of 'type' is here to resolve a shift-reduce conflict. For example: typedef Foo (); typedef Foo (*ptr)(); */ cpp_constructor_decl : storage_class type LPAREN parms RPAREN ctor_end { if (Classprefix) { SwigType *decl = NewStringEmpty(); $$ = new_node("constructor"); Setattr($$,"storage",$1); Setattr($$,"name",$2); Setattr($$,"parms",$4); SwigType_add_function(decl,$4); Setattr($$,"decl",decl); Setattr($$,"throws",$6.throws); Setattr($$,"throw",$6.throwf); if (Len(scanner_ccode)) { String *code = Copy(scanner_ccode); Setattr($$,"code",code); Delete(code); } SetFlag($$,"feature:new"); } else { $$ = 0; } } ; /* A destructor (hopefully) */ cpp_destructor_decl : NOT idtemplate LPAREN parms RPAREN cpp_end { String *name = NewStringf("%s",$2); if (*(Char(name)) != '~') Insert(name,0,"~"); $$ = new_node("destructor"); Setattr($$,"name",name); Delete(name); if (Len(scanner_ccode)) { String *code = Copy(scanner_ccode); Setattr($$,"code",code); Delete(code); } { String *decl = NewStringEmpty(); SwigType_add_function(decl,$4); Setattr($$,"decl",decl); Delete(decl); } Setattr($$,"throws",$6.throws); Setattr($$,"throw",$6.throwf); add_symbols($$); } /* A virtual destructor */ | VIRTUAL NOT idtemplate LPAREN parms RPAREN cpp_vend { String *name; char *c = 0; $$ = new_node("destructor"); /* Check for template names. If the class is a template and the constructor is missing the template part, we add it */ if (Classprefix) { c = strchr(Char(Classprefix),'<'); if (c && !Strchr($3,'<')) { $3 = NewStringf("%s%s",$3,c); } } Setattr($$,"storage","virtual"); name = NewStringf("%s",$3); if (*(Char(name)) != '~') Insert(name,0,"~"); Setattr($$,"name",name); Delete(name); Setattr($$,"throws",$7.throws); Setattr($$,"throw",$7.throwf); if ($7.val) { Setattr($$,"value","0"); } if (Len(scanner_ccode)) { String *code = Copy(scanner_ccode); Setattr($$,"code",code); Delete(code); } { String *decl = NewStringEmpty(); SwigType_add_function(decl,$5); Setattr($$,"decl",decl); Delete(decl); } add_symbols($$); } ; /* C++ type conversion operator */ cpp_conversion_operator : storage_class COPERATOR type pointer LPAREN parms RPAREN cpp_vend { $$ = new_node("cdecl"); Setattr($$,"type",$3); Setattr($$,"name",$2); Setattr($$,"storage",$1); SwigType_add_function($4,$6); if ($8.qualifier) { SwigType_push($4,$8.qualifier); } Setattr($$,"decl",$4); Setattr($$,"parms",$6); Setattr($$,"conversion_operator","1"); add_symbols($$); } | storage_class COPERATOR type AND LPAREN parms RPAREN cpp_vend { SwigType *decl; $$ = new_node("cdecl"); Setattr($$,"type",$3); Setattr($$,"name",$2); Setattr($$,"storage",$1); decl = NewStringEmpty(); SwigType_add_reference(decl); SwigType_add_function(decl,$6); if ($8.qualifier) { SwigType_push(decl,$8.qualifier); } Setattr($$,"decl",decl); Setattr($$,"parms",$6); Setattr($$,"conversion_operator","1"); add_symbols($$); } | storage_class COPERATOR type pointer AND LPAREN parms RPAREN cpp_vend { SwigType *decl; $$ = new_node("cdecl"); Setattr($$,"type",$3); Setattr($$,"name",$2); Setattr($$,"storage",$1); decl = NewStringEmpty(); SwigType_add_pointer(decl); SwigType_add_reference(decl); SwigType_add_function(decl,$7); if ($9.qualifier) { SwigType_push(decl,$9.qualifier); } Setattr($$,"decl",decl); Setattr($$,"parms",$7); Setattr($$,"conversion_operator","1"); add_symbols($$); } | storage_class COPERATOR type LPAREN parms RPAREN cpp_vend { String *t = NewStringEmpty(); $$ = new_node("cdecl"); Setattr($$,"type",$3); Setattr($$,"name",$2); Setattr($$,"storage",$1); SwigType_add_function(t,$5); if ($7.qualifier) { SwigType_push(t,$7.qualifier); } Setattr($$,"decl",t); Setattr($$,"parms",$5); Setattr($$,"conversion_operator","1"); add_symbols($$); } ; /* isolated catch clause. */ cpp_catch_decl : CATCH LPAREN parms RPAREN LBRACE { skip_balanced('{','}'); $$ = 0; } ; /* public: */ cpp_protection_decl : PUBLIC COLON { $$ = new_node("access"); Setattr($$,"kind","public"); cplus_mode = CPLUS_PUBLIC; } /* private: */ | PRIVATE COLON { $$ = new_node("access"); Setattr($$,"kind","private"); cplus_mode = CPLUS_PRIVATE; } /* protected: */ | PROTECTED COLON { $$ = new_node("access"); Setattr($$,"kind","protected"); cplus_mode = CPLUS_PROTECTED; } ; /* ------------------------------------------------------------ Named nested structs: struct sname { }; struct sname { } id; struct sname : bases { }; struct sname : bases { } id; typedef sname struct { } td; typedef sname struct : bases { } td; Adding inheritance, ie replacing 'ID' with 'idcolon inherit' added one shift/reduce ------------------------------------------------------------ */ cpp_nested : storage_class cpptype idcolon inherit LBRACE { cparse_start_line = cparse_line; skip_balanced('{','}'); $$ = NewString(scanner_ccode); /* copied as initializers overwrite scanner_ccode */ } cpp_opt_declarators { $$ = 0; if (cplus_mode == CPLUS_PUBLIC) { if (cparse_cplusplus) { $$ = nested_forward_declaration($1, $2, $3, $3, $7); } else if ($7) { nested_new_struct($2, $6, $7); } } Delete($6); } /* ------------------------------------------------------------ Unnamed/anonymous nested structs: struct { }; struct { } id; struct : bases { }; struct : bases { } id; typedef struct { } td; typedef struct : bases { } td; ------------------------------------------------------------ */ | storage_class cpptype inherit LBRACE { cparse_start_line = cparse_line; skip_balanced('{','}'); $$ = NewString(scanner_ccode); /* copied as initializers overwrite scanner_ccode */ } cpp_opt_declarators { $$ = 0; if (cplus_mode == CPLUS_PUBLIC) { if (cparse_cplusplus) { const char *name = $6 ? Getattr($6, "name") : 0; $$ = nested_forward_declaration($1, $2, 0, name, $6); } else { if ($6) { nested_new_struct($2, $5, $6); } else { Swig_warning(WARN_PARSE_UNNAMED_NESTED_CLASS, cparse_file, cparse_line, "Nested %s not currently supported (ignored).\n", $2); } } } Delete($5); } /* This unfortunately introduces 4 shift/reduce conflicts, so instead the somewhat hacky nested_template is used for ignore nested template classes. */ /* | TEMPLATE LESSTHAN template_parms GREATERTHAN cpptype idcolon LBRACE { cparse_start_line = cparse_line; skip_balanced('{','}'); } SEMI { $$ = 0; if (cplus_mode == CPLUS_PUBLIC) { Swig_warning(WARN_PARSE_NAMED_NESTED_CLASS, cparse_file, cparse_line,"Nested %s not currently supported (%s ignored)\n", $5, $6); } } */ ; /* These directives can be included inside a class definition */ cpp_swig_directive: pragma_directive { $$ = $1; } /* A constant (includes #defines) inside a class */ | constant_directive { $$ = $1; } /* This is the new style rename */ | name_directive { $$ = $1; } /* rename directive */ | rename_directive { $$ = $1; } | feature_directive { $$ = $1; } | varargs_directive { $$ = $1; } | insert_directive { $$ = $1; } | typemap_directive { $$ = $1; } | apply_directive { $$ = $1; } | clear_directive { $$ = $1; } | echo_directive { $$ = $1; } ; cpp_end : cpp_const SEMI { Clear(scanner_ccode); $$.throws = $1.throws; $$.throwf = $1.throwf; } | cpp_const LBRACE { skip_balanced('{','}'); $$.throws = $1.throws; $$.throwf = $1.throwf; } ; cpp_vend : cpp_const SEMI { Clear(scanner_ccode); $$.val = 0; $$.qualifier = $1.qualifier; $$.bitfield = 0; $$.throws = $1.throws; $$.throwf = $1.throwf; } | cpp_const EQUAL definetype SEMI { Clear(scanner_ccode); $$.val = $3.val; $$.qualifier = $1.qualifier; $$.bitfield = 0; $$.throws = $1.throws; $$.throwf = $1.throwf; } | cpp_const LBRACE { skip_balanced('{','}'); $$.val = 0; $$.qualifier = $1.qualifier; $$.bitfield = 0; $$.throws = $1.throws; $$.throwf = $1.throwf; } ; anonymous_bitfield : storage_class type COLON expr SEMI { }; /* ====================================================================== * PRIMITIVES * ====================================================================== */ storage_class : EXTERN { $$ = "extern"; } | EXTERN string { if (strcmp($2,"C") == 0) { $$ = "externc"; } else { Swig_warning(WARN_PARSE_UNDEFINED_EXTERN,cparse_file, cparse_line,"Unrecognized extern type \"%s\".\n", $2); $$ = 0; } } | STATIC { $$ = "static"; } | TYPEDEF { $$ = "typedef"; } | VIRTUAL { $$ = "virtual"; } | FRIEND { $$ = "friend"; } | EXPLICIT { $$ = "explicit"; } | empty { $$ = 0; } ; /* ------------------------------------------------------------------------------ Function parameter lists ------------------------------------------------------------------------------ */ parms : rawparms { Parm *p; $$ = $1; p = $1; while (p) { Replace(Getattr(p,"type"),"typename ", "", DOH_REPLACE_ANY); p = nextSibling(p); } } ; rawparms : parm ptail { set_nextSibling($1,$2); $$ = $1; } | empty { $$ = 0; } ; ptail : COMMA parm ptail { set_nextSibling($2,$3); $$ = $2; } | empty { $$ = 0; } ; parm : rawtype parameter_declarator { SwigType_push($1,$2.type); $$ = NewParmWithoutFileLineInfo($1,$2.id); Setfile($$,cparse_file); Setline($$,cparse_line); if ($2.defarg) { Setattr($$,"value",$2.defarg); } } | TEMPLATE LESSTHAN cpptype GREATERTHAN cpptype idcolon def_args { $$ = NewParmWithoutFileLineInfo(NewStringf("template %s %s", $5,$6), 0); Setfile($$,cparse_file); Setline($$,cparse_line); if ($7.val) { Setattr($$,"value",$7.val); } } | PERIOD PERIOD PERIOD { SwigType *t = NewString("v(...)"); $$ = NewParmWithoutFileLineInfo(t, 0); Setfile($$,cparse_file); Setline($$,cparse_line); } ; valparms : rawvalparms { Parm *p; $$ = $1; p = $1; while (p) { if (Getattr(p,"type")) { Replace(Getattr(p,"type"),"typename ", "", DOH_REPLACE_ANY); } p = nextSibling(p); } } ; rawvalparms : valparm valptail { set_nextSibling($1,$2); $$ = $1; } | empty { $$ = 0; } ; valptail : COMMA valparm valptail { set_nextSibling($2,$3); $$ = $2; } | empty { $$ = 0; } ; valparm : parm { $$ = $1; { /* We need to make a possible adjustment for integer parameters. */ SwigType *type; Node *n = 0; while (!n) { type = Getattr($1,"type"); n = Swig_symbol_clookup(type,0); /* See if we can find a node that matches the typename */ if ((n) && (Strcmp(nodeType(n),"cdecl") == 0)) { SwigType *decl = Getattr(n,"decl"); if (!SwigType_isfunction(decl)) { String *value = Getattr(n,"value"); if (value) { String *v = Copy(value); Setattr($1,"type",v); Delete(v); n = 0; } } } else { break; } } } } | valexpr { $$ = NewParmWithoutFileLineInfo(0,0); Setfile($$,cparse_file); Setline($$,cparse_line); Setattr($$,"value",$1.val); } ; def_args : EQUAL definetype { $$ = $2; if ($2.type == T_ERROR) { Swig_warning(WARN_PARSE_BAD_DEFAULT,cparse_file, cparse_line, "Can't set default argument (ignored)\n"); $$.val = 0; $$.rawval = 0; $$.bitfield = 0; $$.throws = 0; $$.throwf = 0; } } | EQUAL definetype LBRACKET expr RBRACKET { $$ = $2; if ($2.type == T_ERROR) { Swig_warning(WARN_PARSE_BAD_DEFAULT,cparse_file, cparse_line, "Can't set default argument (ignored)\n"); $$ = $2; $$.val = 0; $$.rawval = 0; $$.bitfield = 0; $$.throws = 0; $$.throwf = 0; } else { $$.val = NewStringf("%s[%s]",$2.val,$4.val); } } | EQUAL LBRACE { skip_balanced('{','}'); $$.val = 0; $$.rawval = 0; $$.type = T_INT; $$.bitfield = 0; $$.throws = 0; $$.throwf = 0; } | COLON expr { $$.val = 0; $$.rawval = 0; $$.type = 0; $$.bitfield = $2.val; $$.throws = 0; $$.throwf = 0; } | empty { $$.val = 0; $$.rawval = 0; $$.type = T_INT; $$.bitfield = 0; $$.throws = 0; $$.throwf = 0; } ; parameter_declarator : declarator def_args { $$ = $1; $$.defarg = $2.rawval ? $2.rawval : $2.val; } | abstract_declarator def_args { $$ = $1; $$.defarg = $2.rawval ? $2.rawval : $2.val; } | def_args { $$.type = 0; $$.id = 0; $$.defarg = $1.rawval ? $1.rawval : $1.val; } ; typemap_parameter_declarator : declarator { $$ = $1; if (SwigType_isfunction($1.type)) { Delete(SwigType_pop_function($1.type)); } else if (SwigType_isarray($1.type)) { SwigType *ta = SwigType_pop_arrays($1.type); if (SwigType_isfunction($1.type)) { Delete(SwigType_pop_function($1.type)); } else { $$.parms = 0; } SwigType_push($1.type,ta); Delete(ta); } else { $$.parms = 0; } } | abstract_declarator { $$ = $1; if (SwigType_isfunction($1.type)) { Delete(SwigType_pop_function($1.type)); } else if (SwigType_isarray($1.type)) { SwigType *ta = SwigType_pop_arrays($1.type); if (SwigType_isfunction($1.type)) { Delete(SwigType_pop_function($1.type)); } else { $$.parms = 0; } SwigType_push($1.type,ta); Delete(ta); } else { $$.parms = 0; } } | empty { $$.type = 0; $$.id = 0; $$.parms = 0; } ; declarator : pointer notso_direct_declarator { $$ = $2; if ($$.type) { SwigType_push($1,$$.type); Delete($$.type); } $$.type = $1; } | pointer AND notso_direct_declarator { $$ = $3; SwigType_add_reference($1); if ($$.type) { SwigType_push($1,$$.type); Delete($$.type); } $$.type = $1; } | direct_declarator { $$ = $1; if (!$$.type) $$.type = NewStringEmpty(); } | AND notso_direct_declarator { $$ = $2; $$.type = NewStringEmpty(); SwigType_add_reference($$.type); if ($2.type) { SwigType_push($$.type,$2.type); Delete($2.type); } } | idcolon DSTAR notso_direct_declarator { SwigType *t = NewStringEmpty(); $$ = $3; SwigType_add_memberpointer(t,$1); if ($$.type) { SwigType_push(t,$$.type); Delete($$.type); } $$.type = t; } | pointer idcolon DSTAR notso_direct_declarator { SwigType *t = NewStringEmpty(); $$ = $4; SwigType_add_memberpointer(t,$2); SwigType_push($1,t); if ($$.type) { SwigType_push($1,$$.type); Delete($$.type); } $$.type = $1; Delete(t); } | pointer idcolon DSTAR AND notso_direct_declarator { $$ = $5; SwigType_add_memberpointer($1,$2); SwigType_add_reference($1); if ($$.type) { SwigType_push($1,$$.type); Delete($$.type); } $$.type = $1; } | idcolon DSTAR AND notso_direct_declarator { SwigType *t = NewStringEmpty(); $$ = $4; SwigType_add_memberpointer(t,$1); SwigType_add_reference(t); if ($$.type) { SwigType_push(t,$$.type); Delete($$.type); } $$.type = t; } ; notso_direct_declarator : idcolon { /* Note: This is non-standard C. Template declarator is allowed to follow an identifier */ $$.id = Char($1); $$.type = 0; $$.parms = 0; $$.have_parms = 0; } | NOT idcolon { $$.id = Char(NewStringf("~%s",$2)); $$.type = 0; $$.parms = 0; $$.have_parms = 0; } /* This generate a shift-reduce conflict with constructors */ | LPAREN idcolon RPAREN { $$.id = Char($2); $$.type = 0; $$.parms = 0; $$.have_parms = 0; } /* | LPAREN AND idcolon RPAREN { $$.id = Char($3); $$.type = 0; $$.parms = 0; $$.have_parms = 0; } */ /* Technically, this should be LPAREN declarator RPAREN, but we get reduce/reduce conflicts */ | LPAREN pointer notso_direct_declarator RPAREN { $$ = $3; if ($$.type) { SwigType_push($2,$$.type); Delete($$.type); } $$.type = $2; } | LPAREN idcolon DSTAR notso_direct_declarator RPAREN { SwigType *t; $$ = $4; t = NewStringEmpty(); SwigType_add_memberpointer(t,$2); if ($$.type) { SwigType_push(t,$$.type); Delete($$.type); } $$.type = t; } | notso_direct_declarator LBRACKET RBRACKET { SwigType *t; $$ = $1; t = NewStringEmpty(); SwigType_add_array(t,(char*)""); if ($$.type) { SwigType_push(t,$$.type); Delete($$.type); } $$.type = t; } | notso_direct_declarator LBRACKET expr RBRACKET { SwigType *t; $$ = $1; t = NewStringEmpty(); SwigType_add_array(t,$3.val); if ($$.type) { SwigType_push(t,$$.type); Delete($$.type); } $$.type = t; } | notso_direct_declarator LPAREN parms RPAREN { SwigType *t; $$ = $1; t = NewStringEmpty(); SwigType_add_function(t,$3); if (!$$.have_parms) { $$.parms = $3; $$.have_parms = 1; } if (!$$.type) { $$.type = t; } else { SwigType_push(t, $$.type); Delete($$.type); $$.type = t; } } ; direct_declarator : idcolon { /* Note: This is non-standard C. Template declarator is allowed to follow an identifier */ $$.id = Char($1); $$.type = 0; $$.parms = 0; $$.have_parms = 0; } | NOT idcolon { $$.id = Char(NewStringf("~%s",$2)); $$.type = 0; $$.parms = 0; $$.have_parms = 0; } /* This generate a shift-reduce conflict with constructors */ /* | LPAREN idcolon RPAREN { $$.id = Char($2); $$.type = 0; $$.parms = 0; $$.have_parms = 0; } */ /* Technically, this should be LPAREN declarator RPAREN, but we get reduce/reduce conflicts */ | LPAREN pointer direct_declarator RPAREN { $$ = $3; if ($$.type) { SwigType_push($2,$$.type); Delete($$.type); } $$.type = $2; } | LPAREN AND direct_declarator RPAREN { $$ = $3; if (!$$.type) { $$.type = NewStringEmpty(); } SwigType_add_reference($$.type); } | LPAREN idcolon DSTAR direct_declarator RPAREN { SwigType *t; $$ = $4; t = NewStringEmpty(); SwigType_add_memberpointer(t,$2); if ($$.type) { SwigType_push(t,$$.type); Delete($$.type); } $$.type = t; } | direct_declarator LBRACKET RBRACKET { SwigType *t; $$ = $1; t = NewStringEmpty(); SwigType_add_array(t,(char*)""); if ($$.type) { SwigType_push(t,$$.type); Delete($$.type); } $$.type = t; } | direct_declarator LBRACKET expr RBRACKET { SwigType *t; $$ = $1; t = NewStringEmpty(); SwigType_add_array(t,$3.val); if ($$.type) { SwigType_push(t,$$.type); Delete($$.type); } $$.type = t; } | direct_declarator LPAREN parms RPAREN { SwigType *t; $$ = $1; t = NewStringEmpty(); SwigType_add_function(t,$3); if (!$$.have_parms) { $$.parms = $3; $$.have_parms = 1; } if (!$$.type) { $$.type = t; } else { SwigType_push(t, $$.type); Delete($$.type); $$.type = t; } } ; abstract_declarator : pointer { $$.type = $1; $$.id = 0; $$.parms = 0; $$.have_parms = 0; } | pointer direct_abstract_declarator { $$ = $2; SwigType_push($1,$2.type); $$.type = $1; Delete($2.type); } | pointer AND { $$.type = $1; SwigType_add_reference($$.type); $$.id = 0; $$.parms = 0; $$.have_parms = 0; } | pointer AND direct_abstract_declarator { $$ = $3; SwigType_add_reference($1); if ($$.type) { SwigType_push($1,$$.type); Delete($$.type); } $$.type = $1; } | direct_abstract_declarator { $$ = $1; } | AND direct_abstract_declarator { $$ = $2; $$.type = NewStringEmpty(); SwigType_add_reference($$.type); if ($2.type) { SwigType_push($$.type,$2.type); Delete($2.type); } } | AND { $$.id = 0; $$.parms = 0; $$.have_parms = 0; $$.type = NewStringEmpty(); SwigType_add_reference($$.type); } | idcolon DSTAR { $$.type = NewStringEmpty(); SwigType_add_memberpointer($$.type,$1); $$.id = 0; $$.parms = 0; $$.have_parms = 0; } | pointer idcolon DSTAR { SwigType *t = NewStringEmpty(); $$.type = $1; $$.id = 0; $$.parms = 0; $$.have_parms = 0; SwigType_add_memberpointer(t,$2); SwigType_push($$.type,t); Delete(t); } | pointer idcolon DSTAR direct_abstract_declarator { $$ = $4; SwigType_add_memberpointer($1,$2); if ($$.type) { SwigType_push($1,$$.type); Delete($$.type); } $$.type = $1; } ; direct_abstract_declarator : direct_abstract_declarator LBRACKET RBRACKET { SwigType *t; $$ = $1; t = NewStringEmpty(); SwigType_add_array(t,(char*)""); if ($$.type) { SwigType_push(t,$$.type); Delete($$.type); } $$.type = t; } | direct_abstract_declarator LBRACKET expr RBRACKET { SwigType *t; $$ = $1; t = NewStringEmpty(); SwigType_add_array(t,$3.val); if ($$.type) { SwigType_push(t,$$.type); Delete($$.type); } $$.type = t; } | LBRACKET RBRACKET { $$.type = NewStringEmpty(); $$.id = 0; $$.parms = 0; $$.have_parms = 0; SwigType_add_array($$.type,(char*)""); } | LBRACKET expr RBRACKET { $$.type = NewStringEmpty(); $$.id = 0; $$.parms = 0; $$.have_parms = 0; SwigType_add_array($$.type,$2.val); } | LPAREN abstract_declarator RPAREN { $$ = $2; } | direct_abstract_declarator LPAREN parms RPAREN { SwigType *t; $$ = $1; t = NewStringEmpty(); SwigType_add_function(t,$3); if (!$$.type) { $$.type = t; } else { SwigType_push(t,$$.type); Delete($$.type); $$.type = t; } if (!$$.have_parms) { $$.parms = $3; $$.have_parms = 1; } } | LPAREN parms RPAREN { $$.type = NewStringEmpty(); SwigType_add_function($$.type,$2); $$.parms = $2; $$.have_parms = 1; $$.id = 0; } ; pointer : STAR type_qualifier pointer { $$ = NewStringEmpty(); SwigType_add_pointer($$); SwigType_push($$,$2); SwigType_push($$,$3); Delete($3); } | STAR pointer { $$ = NewStringEmpty(); SwigType_add_pointer($$); SwigType_push($$,$2); Delete($2); } | STAR type_qualifier { $$ = NewStringEmpty(); SwigType_add_pointer($$); SwigType_push($$,$2); } | STAR { $$ = NewStringEmpty(); SwigType_add_pointer($$); } ; type_qualifier : type_qualifier_raw { $$ = NewStringEmpty(); if ($1) SwigType_add_qualifier($$,$1); } | type_qualifier_raw type_qualifier { $$ = $2; if ($1) SwigType_add_qualifier($$,$1); } ; type_qualifier_raw : CONST_QUAL { $$ = "const"; } | VOLATILE { $$ = "volatile"; } | REGISTER { $$ = 0; } ; /* Data type must be a built in type or an identifier for user-defined types This type can be preceded by a modifier. */ type : rawtype { $$ = $1; Replace($$,"typename ","", DOH_REPLACE_ANY); } ; rawtype : type_qualifier type_right { $$ = $2; SwigType_push($$,$1); } | type_right { $$ = $1; } | type_right type_qualifier { $$ = $1; SwigType_push($$,$2); } | type_qualifier type_right type_qualifier { $$ = $2; SwigType_push($$,$3); SwigType_push($$,$1); } ; type_right : primitive_type { $$ = $1; /* Printf(stdout,"primitive = '%s'\n", $$);*/ } | TYPE_BOOL { $$ = $1; } | TYPE_VOID { $$ = $1; } | TYPE_TYPEDEF template_decl { $$ = NewStringf("%s%s",$1,$2); } | ENUM idcolon { $$ = NewStringf("enum %s", $2); } | TYPE_RAW { $$ = $1; } | idcolon { $$ = $1; } | cpptype idcolon { $$ = NewStringf("%s %s", $1, $2); } ; primitive_type : primitive_type_list { if (!$1.type) $1.type = NewString("int"); if ($1.us) { $$ = NewStringf("%s %s", $1.us, $1.type); Delete($1.us); Delete($1.type); } else { $$ = $1.type; } if (Cmp($$,"signed int") == 0) { Delete($$); $$ = NewString("int"); } else if (Cmp($$,"signed long") == 0) { Delete($$); $$ = NewString("long"); } else if (Cmp($$,"signed short") == 0) { Delete($$); $$ = NewString("short"); } else if (Cmp($$,"signed long long") == 0) { Delete($$); $$ = NewString("long long"); } } ; primitive_type_list : type_specifier { $$ = $1; } | type_specifier primitive_type_list { if ($1.us && $2.us) { Swig_error(cparse_file, cparse_line, "Extra %s specifier.\n", $2.us); } $$ = $2; if ($1.us) $$.us = $1.us; if ($1.type) { if (!$2.type) $$.type = $1.type; else { int err = 0; if ((Cmp($1.type,"long") == 0)) { if ((Cmp($2.type,"long") == 0) || (Strncmp($2.type,"double",6) == 0)) { $$.type = NewStringf("long %s", $2.type); } else if (Cmp($2.type,"int") == 0) { $$.type = $1.type; } else { err = 1; } } else if ((Cmp($1.type,"short")) == 0) { if (Cmp($2.type,"int") == 0) { $$.type = $1.type; } else { err = 1; } } else if (Cmp($1.type,"int") == 0) { $$.type = $2.type; } else if (Cmp($1.type,"double") == 0) { if (Cmp($2.type,"long") == 0) { $$.type = NewString("long double"); } else if (Cmp($2.type,"complex") == 0) { $$.type = NewString("double complex"); } else { err = 1; } } else if (Cmp($1.type,"float") == 0) { if (Cmp($2.type,"complex") == 0) { $$.type = NewString("float complex"); } else { err = 1; } } else if (Cmp($1.type,"complex") == 0) { $$.type = NewStringf("%s complex", $2.type); } else { err = 1; } if (err) { Swig_error(cparse_file, cparse_line, "Extra %s specifier.\n", $1.type); } } } } ; type_specifier : TYPE_INT { $$.type = NewString("int"); $$.us = 0; } | TYPE_SHORT { $$.type = NewString("short"); $$.us = 0; } | TYPE_LONG { $$.type = NewString("long"); $$.us = 0; } | TYPE_CHAR { $$.type = NewString("char"); $$.us = 0; } | TYPE_WCHAR { $$.type = NewString("wchar_t"); $$.us = 0; } | TYPE_FLOAT { $$.type = NewString("float"); $$.us = 0; } | TYPE_DOUBLE { $$.type = NewString("double"); $$.us = 0; } | TYPE_SIGNED { $$.us = NewString("signed"); $$.type = 0; } | TYPE_UNSIGNED { $$.us = NewString("unsigned"); $$.type = 0; } | TYPE_COMPLEX { $$.type = NewString("complex"); $$.us = 0; } | TYPE_NON_ISO_INT8 { $$.type = NewString("__int8"); $$.us = 0; } | TYPE_NON_ISO_INT16 { $$.type = NewString("__int16"); $$.us = 0; } | TYPE_NON_ISO_INT32 { $$.type = NewString("__int32"); $$.us = 0; } | TYPE_NON_ISO_INT64 { $$.type = NewString("__int64"); $$.us = 0; } ; definetype : { /* scanner_check_typedef(); */ } expr { $$ = $2; if ($$.type == T_STRING) { $$.rawval = NewStringf("\"%(escape)s\"",$$.val); } else if ($$.type != T_CHAR) { $$.rawval = 0; } $$.bitfield = 0; $$.throws = 0; $$.throwf = 0; scanner_ignore_typedef(); } /* | string { $$.val = NewString($1); $$.rawval = NewStringf("\"%(escape)s\"",$$.val); $$.type = T_STRING; $$.bitfield = 0; $$.throws = 0; $$.throwf = 0; } */ ; /* Some stuff for handling enums */ ename : ID { $$ = $1; } | empty { $$ = (char *) 0;} ; enumlist : enumlist COMMA edecl { /* Ignore if there is a trailing comma in the enum list */ if ($3) { Node *leftSibling = Getattr($1,"_last"); if (!leftSibling) { leftSibling=$1; } set_nextSibling(leftSibling,$3); Setattr($1,"_last",$3); } $$ = $1; } | edecl { $$ = $1; if ($1) { Setattr($1,"_last",$1); } } ; edecl : ID { SwigType *type = NewSwigType(T_INT); $$ = new_node("enumitem"); Setattr($$,"name",$1); Setattr($$,"type",type); SetFlag($$,"feature:immutable"); Delete(type); } | ID EQUAL etype { SwigType *type = NewSwigType($3.type == T_BOOL ? T_BOOL : ($3.type == T_CHAR ? T_CHAR : T_INT)); $$ = new_node("enumitem"); Setattr($$,"name",$1); Setattr($$,"type",type); SetFlag($$,"feature:immutable"); Setattr($$,"enumvalue", $3.val); Setattr($$,"value",$1); Delete(type); } | empty { $$ = 0; } ; etype : expr { $$ = $1; if (($$.type != T_INT) && ($$.type != T_UINT) && ($$.type != T_LONG) && ($$.type != T_ULONG) && ($$.type != T_SHORT) && ($$.type != T_USHORT) && ($$.type != T_SCHAR) && ($$.type != T_UCHAR) && ($$.type != T_CHAR) && ($$.type != T_BOOL)) { Swig_error(cparse_file,cparse_line,"Type error. Expecting an integral type\n"); } } ; /* Arithmetic expressions. Used for constants, C++ templates, and other cool stuff. */ expr : valexpr { $$ = $1; } | type { Node *n; $$.val = $1; $$.type = T_INT; /* Check if value is in scope */ n = Swig_symbol_clookup($1,0); if (n) { /* A band-aid for enum values used in expressions. */ if (Strcmp(nodeType(n),"enumitem") == 0) { String *q = Swig_symbol_qualified(n); if (q) { $$.val = NewStringf("%s::%s", q, Getattr(n,"name")); Delete(q); } } } } ; valexpr : exprnum { $$ = $1; } | string { $$.val = NewString($1); $$.type = T_STRING; } | SIZEOF LPAREN type parameter_declarator RPAREN { SwigType_push($3,$4.type); $$.val = NewStringf("sizeof(%s)",SwigType_str($3,0)); $$.type = T_ULONG; } | exprcompound { $$ = $1; } | CHARCONST { $$.val = NewString($1); if (Len($$.val)) { $$.rawval = NewStringf("'%(escape)s'", $$.val); } else { $$.rawval = NewString("'\\0'"); } $$.type = T_CHAR; $$.bitfield = 0; $$.throws = 0; $$.throwf = 0; } /* grouping */ | LPAREN expr RPAREN %prec CAST { $$.val = NewStringf("(%s)",$2.val); $$.type = $2.type; } /* A few common casting operations */ | LPAREN expr RPAREN expr %prec CAST { $$ = $4; if ($4.type != T_STRING) { switch ($2.type) { case T_FLOAT: case T_DOUBLE: case T_LONGDOUBLE: case T_FLTCPLX: case T_DBLCPLX: $$.val = NewStringf("(%s)%s", $2.val, $4.val); /* SwigType_str and decimal points don't mix! */ break; default: $$.val = NewStringf("(%s) %s", SwigType_str($2.val,0), $4.val); break; } } } | LPAREN expr pointer RPAREN expr %prec CAST { $$ = $5; if ($5.type != T_STRING) { SwigType_push($2.val,$3); $$.val = NewStringf("(%s) %s", SwigType_str($2.val,0), $5.val); } } | LPAREN expr AND RPAREN expr %prec CAST { $$ = $5; if ($5.type != T_STRING) { SwigType_add_reference($2.val); $$.val = NewStringf("(%s) %s", SwigType_str($2.val,0), $5.val); } } | LPAREN expr pointer AND RPAREN expr %prec CAST { $$ = $6; if ($6.type != T_STRING) { SwigType_push($2.val,$3); SwigType_add_reference($2.val); $$.val = NewStringf("(%s) %s", SwigType_str($2.val,0), $6.val); } } | AND expr { $$ = $2; $$.val = NewStringf("&%s",$2.val); } | STAR expr { $$ = $2; $$.val = NewStringf("*%s",$2.val); } ; exprnum : NUM_INT { $$ = $1; } | NUM_FLOAT { $$ = $1; } | NUM_UNSIGNED { $$ = $1; } | NUM_LONG { $$ = $1; } | NUM_ULONG { $$ = $1; } | NUM_LONGLONG { $$ = $1; } | NUM_ULONGLONG { $$ = $1; } | NUM_BOOL { $$ = $1; } ; exprcompound : expr PLUS expr { $$.val = NewStringf("%s+%s",$1.val,$3.val); $$.type = promote($1.type,$3.type); } | expr MINUS expr { $$.val = NewStringf("%s-%s",$1.val,$3.val); $$.type = promote($1.type,$3.type); } | expr STAR expr { $$.val = NewStringf("%s*%s",$1.val,$3.val); $$.type = promote($1.type,$3.type); } | expr SLASH expr { $$.val = NewStringf("%s/%s",$1.val,$3.val); $$.type = promote($1.type,$3.type); } | expr MODULO expr { $$.val = NewStringf("%s%%%s",$1.val,$3.val); $$.type = promote($1.type,$3.type); } | expr AND expr { $$.val = NewStringf("%s&%s",$1.val,$3.val); $$.type = promote($1.type,$3.type); } | expr OR expr { $$.val = NewStringf("%s|%s",$1.val,$3.val); $$.type = promote($1.type,$3.type); } | expr XOR expr { $$.val = NewStringf("%s^%s",$1.val,$3.val); $$.type = promote($1.type,$3.type); } | expr LSHIFT expr { $$.val = NewStringf("%s << %s",$1.val,$3.val); $$.type = promote_type($1.type); } | expr RSHIFT expr { $$.val = NewStringf("%s >> %s",$1.val,$3.val); $$.type = promote_type($1.type); } | expr LAND expr { $$.val = NewStringf("%s&&%s",$1.val,$3.val); $$.type = cparse_cplusplus ? T_BOOL : T_INT; } | expr LOR expr { $$.val = NewStringf("%s||%s",$1.val,$3.val); $$.type = cparse_cplusplus ? T_BOOL : T_INT; } | expr EQUALTO expr { $$.val = NewStringf("%s==%s",$1.val,$3.val); $$.type = cparse_cplusplus ? T_BOOL : T_INT; } | expr NOTEQUALTO expr { $$.val = NewStringf("%s!=%s",$1.val,$3.val); $$.type = cparse_cplusplus ? T_BOOL : T_INT; } /* Sadly this causes 2 reduce-reduce conflicts with templates. FIXME resolve these. | expr GREATERTHAN expr { $$.val = NewStringf("%s < %s", $1.val, $3.val); $$.type = cparse_cplusplus ? T_BOOL : T_INT; } | expr LESSTHAN expr { $$.val = NewStringf("%s > %s", $1.val, $3.val); $$.type = cparse_cplusplus ? T_BOOL : T_INT; } */ | expr GREATERTHANOREQUALTO expr { $$.val = NewStringf("%s >= %s", $1.val, $3.val); $$.type = cparse_cplusplus ? T_BOOL : T_INT; } | expr LESSTHANOREQUALTO expr { $$.val = NewStringf("%s <= %s", $1.val, $3.val); $$.type = cparse_cplusplus ? T_BOOL : T_INT; } | expr QUESTIONMARK expr COLON expr %prec QUESTIONMARK { $$.val = NewStringf("%s?%s:%s", $1.val, $3.val, $5.val); /* This may not be exactly right, but is probably good enough * for the purposes of parsing constant expressions. */ $$.type = promote($3.type, $5.type); } | MINUS expr %prec UMINUS { $$.val = NewStringf("-%s",$2.val); $$.type = $2.type; } | PLUS expr %prec UMINUS { $$.val = NewStringf("+%s",$2.val); $$.type = $2.type; } | NOT expr { $$.val = NewStringf("~%s",$2.val); $$.type = $2.type; } | LNOT expr { $$.val = NewStringf("!%s",$2.val); $$.type = T_INT; } | type LPAREN { String *qty; skip_balanced('(',')'); qty = Swig_symbol_type_qualify($1,0); if (SwigType_istemplate(qty)) { String *nstr = SwigType_namestr(qty); Delete(qty); qty = nstr; } $$.val = NewStringf("%s%s",qty,scanner_ccode); Clear(scanner_ccode); $$.type = T_INT; Delete(qty); } ; inherit : raw_inherit { $$ = $1; } ; raw_inherit : COLON { inherit_list = 1; } base_list { $$ = $3; inherit_list = 0; } | empty { $$ = 0; } ; base_list : base_specifier { Hash *list = NewHash(); Node *base = $1; Node *name = Getattr(base,"name"); List *lpublic = NewList(); List *lprotected = NewList(); List *lprivate = NewList(); Setattr(list,"public",lpublic); Setattr(list,"protected",lprotected); Setattr(list,"private",lprivate); Delete(lpublic); Delete(lprotected); Delete(lprivate); Append(Getattr(list,Getattr(base,"access")),name); $$ = list; } | base_list COMMA base_specifier { Hash *list = $1; Node *base = $3; Node *name = Getattr(base,"name"); Append(Getattr(list,Getattr(base,"access")),name); $$ = list; } ; base_specifier : opt_virtual { $$ = cparse_line; } idcolon { $$ = NewHash(); Setfile($$,cparse_file); Setline($$,$2); Setattr($$,"name",$3); Setfile($3,cparse_file); Setline($3,$2); if (last_cpptype && (Strcmp(last_cpptype,"struct") != 0)) { Setattr($$,"access","private"); Swig_warning(WARN_PARSE_NO_ACCESS, Getfile($$), Getline($$), "No access specifier given for base class '%s' (ignored).\n", SwigType_namestr($3)); } else { Setattr($$,"access","public"); } } | opt_virtual access_specifier { $$ = cparse_line; } opt_virtual idcolon { $$ = NewHash(); Setfile($$,cparse_file); Setline($$,$3); Setattr($$,"name",$5); Setfile($5,cparse_file); Setline($5,$3); Setattr($$,"access",$2); if (Strcmp($2,"public") != 0) { Swig_warning(WARN_PARSE_PRIVATE_INHERIT, Getfile($$), Getline($$), "%s inheritance from base '%s' (ignored).\n", $2, SwigType_namestr($5)); } } ; access_specifier : PUBLIC { $$ = (char*)"public"; } | PRIVATE { $$ = (char*)"private"; } | PROTECTED { $$ = (char*)"protected"; } ; templcpptype : CLASS { $$ = (char*)"class"; if (!inherit_list) last_cpptype = $$; } | TYPENAME { $$ = (char *)"typename"; if (!inherit_list) last_cpptype = $$; } ; cpptype : templcpptype { $$ = $1; } | STRUCT { $$ = (char*)"struct"; if (!inherit_list) last_cpptype = $$; } | UNION { $$ = (char*)"union"; if (!inherit_list) last_cpptype = $$; } ; opt_virtual : VIRTUAL | empty ; cpp_const : type_qualifier { $$.qualifier = $1; $$.throws = 0; $$.throwf = 0; } | THROW LPAREN parms RPAREN { $$.qualifier = 0; $$.throws = $3; $$.throwf = NewString("1"); } | type_qualifier THROW LPAREN parms RPAREN { $$.qualifier = $1; $$.throws = $4; $$.throwf = NewString("1"); } | empty { $$.qualifier = 0; $$.throws = 0; $$.throwf = 0; } ; ctor_end : cpp_const ctor_initializer SEMI { Clear(scanner_ccode); $$.have_parms = 0; $$.defarg = 0; $$.throws = $1.throws; $$.throwf = $1.throwf; } | cpp_const ctor_initializer LBRACE { skip_balanced('{','}'); $$.have_parms = 0; $$.defarg = 0; $$.throws = $1.throws; $$.throwf = $1.throwf; } | LPAREN parms RPAREN SEMI { Clear(scanner_ccode); $$.parms = $2; $$.have_parms = 1; $$.defarg = 0; $$.throws = 0; $$.throwf = 0; } | LPAREN parms RPAREN LBRACE { skip_balanced('{','}'); $$.parms = $2; $$.have_parms = 1; $$.defarg = 0; $$.throws = 0; $$.throwf = 0; } | EQUAL definetype SEMI { $$.have_parms = 0; $$.defarg = $2.val; $$.throws = 0; $$.throwf = 0; } ; ctor_initializer : COLON mem_initializer_list | empty ; mem_initializer_list : mem_initializer | mem_initializer_list COMMA mem_initializer ; mem_initializer : idcolon LPAREN { skip_balanced('(',')'); Clear(scanner_ccode); } ; template_decl : LESSTHAN valparms GREATERTHAN { String *s = NewStringEmpty(); SwigType_add_template(s,$2); $$ = Char(s); scanner_last_id(1); } | empty { $$ = (char*)""; } ; idstring : ID { $$ = $1; } | string { $$ = $1; } ; idstringopt : idstring { $$ = $1; } | empty { $$ = 0; } ; idcolon : idtemplate idcolontail { $$ = 0; if (!$$) $$ = NewStringf("%s%s", $1,$2); Delete($2); } | NONID DCOLON idtemplate idcolontail { $$ = NewStringf("::%s%s",$3,$4); Delete($4); } | idtemplate { $$ = NewString($1); } | NONID DCOLON idtemplate { $$ = NewStringf("::%s",$3); } | OPERATOR { $$ = NewString($1); } | NONID DCOLON OPERATOR { $$ = NewStringf("::%s",$3); } ; idcolontail : DCOLON idtemplate idcolontail { $$ = NewStringf("::%s%s",$2,$3); Delete($3); } | DCOLON idtemplate { $$ = NewStringf("::%s",$2); } | DCOLON OPERATOR { $$ = NewStringf("::%s",$2); } /* | DCOLON COPERATOR { $$ = NewString($2); } */ | DCNOT idtemplate { $$ = NewStringf("::~%s",$2); } ; idtemplate : ID template_decl { $$ = NewStringf("%s%s",$1,$2); /* if (Len($2)) { scanner_last_id(1); } */ } ; /* Identifier, but no templates */ idcolonnt : ID idcolontailnt { $$ = 0; if (!$$) $$ = NewStringf("%s%s", $1,$2); Delete($2); } | NONID DCOLON ID idcolontailnt { $$ = NewStringf("::%s%s",$3,$4); Delete($4); } | ID { $$ = NewString($1); } | NONID DCOLON ID { $$ = NewStringf("::%s",$3); } | OPERATOR { $$ = NewString($1); } | NONID DCOLON OPERATOR { $$ = NewStringf("::%s",$3); } ; idcolontailnt : DCOLON ID idcolontailnt { $$ = NewStringf("::%s%s",$2,$3); Delete($3); } | DCOLON ID { $$ = NewStringf("::%s",$2); } | DCOLON OPERATOR { $$ = NewStringf("::%s",$2); } | DCNOT ID { $$ = NewStringf("::~%s",$2); } ; /* Concatenated strings */ string : string STRING { $$ = (char *) malloc(strlen($1)+strlen($2)+1); strcpy($$,$1); strcat($$,$2); } | STRING { $$ = $1;} ; stringbrace : string { $$ = NewString($1); } | LBRACE { skip_balanced('{','}'); $$ = NewString(scanner_ccode); } | HBLOCK { $$ = $1; } ; options : LPAREN kwargs RPAREN { Hash *n; $$ = NewHash(); n = $2; while(n) { String *name, *value; name = Getattr(n,"name"); value = Getattr(n,"value"); if (!value) value = (String *) "1"; Setattr($$,name, value); n = nextSibling(n); } } | empty { $$ = 0; }; /* Keyword arguments */ kwargs : idstring EQUAL stringnum { $$ = NewHash(); Setattr($$,"name",$1); Setattr($$,"value",$3); } | idstring EQUAL stringnum COMMA kwargs { $$ = NewHash(); Setattr($$,"name",$1); Setattr($$,"value",$3); set_nextSibling($$,$5); } | idstring { $$ = NewHash(); Setattr($$,"name",$1); } | idstring COMMA kwargs { $$ = NewHash(); Setattr($$,"name",$1); set_nextSibling($$,$3); } | idstring EQUAL stringtype { $$ = $3; Setattr($$,"name",$1); } | idstring EQUAL stringtype COMMA kwargs { $$ = $3; Setattr($$,"name",$1); set_nextSibling($$,$5); } ; stringnum : string { $$ = $1; } | exprnum { $$ = Char($1.val); } ; empty : ; %% SwigType *Swig_cparse_type(String *s) { String *ns; ns = NewStringf("%s;",s); Seek(ns,0,SEEK_SET); scanner_file(ns); top = 0; scanner_next_token(PARSETYPE); yyparse(); /* Printf(stdout,"typeparse: '%s' ---> '%s'\n", s, top); */ return top; } Parm *Swig_cparse_parm(String *s) { String *ns; ns = NewStringf("%s;",s); Seek(ns,0,SEEK_SET); scanner_file(ns); top = 0; scanner_next_token(PARSEPARM); yyparse(); /* Printf(stdout,"typeparse: '%s' ---> '%s'\n", s, top); */ Delete(ns); return top; } ParmList *Swig_cparse_parms(String *s, Node *file_line_node) { String *ns; char *cs = Char(s); if (cs && cs[0] != '(') { ns = NewStringf("(%s);",s); } else { ns = NewStringf("%s;",s); } Setfile(ns, Getfile(file_line_node)); Setline(ns, Getline(file_line_node)); Seek(ns,0,SEEK_SET); scanner_file(ns); top = 0; scanner_next_token(PARSEPARMS); yyparse(); /* Printf(stdout,"typeparse: '%s' ---> '%s'\n", s, top); */ return top; }