void dclspec(void) { char temp[MAXTOKEN]; temp[0]='\0'; gettoken(); do{ if(tokentype!=NAME) { prevtoken = YES; dcl(); } else if(typespec()==YES) { strcat(temp," "); strcat(temp,token); gettoken(); }else if(typequal()==YES) { strcat(temp," "); strcat(temp,token); gettoken(); } else errmsg("unknown type in parameter list \n"); }while(tokentype!=',' && tokentype!=')'); strcat(out,temp); if(tokentype==',') strcat(out,","); }
void ASTNode::printchildren (std::ostream &out, int indentlevel) const { for (size_t i = 0; i < m_children.size(); ++i) { if (! child(i)) continue; indent (out, indentlevel); if (childname(i)) out << " " << childname(i); else out << " child" << i; out << ": "; if (typespec() != TypeSpec() && ! child(i)->next()) out << " (type: " << typespec().string() << ")"; out << "\n"; printlist (out, child(i), indentlevel+1); } }
void ASTNode::print (std::ostream &out, int indentlevel) const { indent (out, indentlevel); out << "(" << nodetypename() << " : " << " (type: " << typespec().string() << ") " << (opname() ? opname() : "") << "\n"; printchildren (out, indentlevel); indent (out, indentlevel); out << ")\n"; }
TypeSpec ASTtype_constructor::typecheck (TypeSpec expected) { // FIXME - closures typecheck_children (); // Hijack the usual function arg-checking routines. // So we have a set of valid patterns for each type constructor: static const char *float_patterns[] = { "ff", "fi", NULL }; static const char *triple_patterns[] = { "cf", "cfff", "csfff", "cc", "cp", "cv", "cn", NULL }; static const char *matrix_patterns[] = { "mf", "msf", "mss", "mffffffffffffffff", "msffffffffffffffff", "mm", NULL }; static const char *int_patterns[] = { "if", "ii", NULL }; // Select the pattern for the type of constructor we are... const char **patterns = NULL; if (typespec().is_float()) patterns = float_patterns; else if (typespec().is_triple()) patterns = triple_patterns; else if (typespec().is_matrix()) patterns = matrix_patterns; else if (typespec().is_int()) patterns = int_patterns; if (! patterns) { error ("Cannot construct type '%s'", type_c_str(typespec())); return m_typespec; } // Try to get a match, first without type coercion of the arguments, // then with coercion. for (int co = 0; co < 2; ++co) { bool coerce = co; for (const char **pat = patterns; *pat; ++pat) { const char *code = *pat; if (check_arglist (type_c_str(typespec()), args(), code + 1, coerce)) return m_typespec; } } // If we made it this far, no match could be found. std::string err = Strutil::format ("Cannot construct %s (", type_c_str(typespec())); for (ref a = args(); a; a = a->next()) { err += a->typespec().string(); if (a->next()) err += ", "; } err += ")"; error ("%s", err.c_str()); // FIXME -- it might be nice here to enumerate for the user all the // valid combinations. return m_typespec; }
ASTfunction_declaration::ASTfunction_declaration (OSLCompilerImpl *comp, TypeSpec type, ustring name, ASTNode *form, ASTNode *stmts, ASTNode *meta) : ASTNode (function_declaration_node, comp, 0, meta, form, stmts), m_name(name), m_sym(NULL), m_is_builtin(false) { m_typespec = type; Symbol *f = comp->symtab().clash (name); if (f && f->symtype() != SymTypeFunction) { error ("\"%s\" already declared in this scope as a ", name.c_str(), f->typespec().string().c_str()); // FIXME -- print the file and line of the other definition f = NULL; } // FIXME -- allow multiple function declarations, but only if they // aren't the same polymorphic type. if (name[0] == '_' && name[1] == '_' && name[2] == '_') { error ("\"%s\" : sorry, can't start with three underscores", name.c_str()); } m_sym = new FunctionSymbol (name, type, this); func()->nextpoly ((FunctionSymbol *)f); std::string argcodes = oslcompiler->code_from_type (m_typespec); for (ASTNode *arg = form; arg; arg = arg->nextptr()) { const TypeSpec &t (arg->typespec()); if (t == TypeSpec() /* UNKNOWN */) { m_typespec = TypeDesc::UNKNOWN; return; } argcodes += oslcompiler->code_from_type (t); ASSERT (arg->nodetype() == variable_declaration_node); ASTvariable_declaration *v = (ASTvariable_declaration *)arg; if (v->init()) v->error ("function parameter '%s' may not have a default initializer.", v->name().c_str()); } func()->argcodes (ustring (argcodes)); oslcompiler->symtab().insert (m_sym); // Typecheck it right now, upon declaration typecheck (typespec ()); }
std::ostream & Symbol::print (std::ostream &out, int maxvals) const { out << Symbol::symtype_shortname(symtype()) << " " << typespec().string() << " " << name(); if (everused()) out << " (used " << firstuse() << ' ' << lastuse() << " read " << firstread() << ' ' << lastread() << " write " << firstwrite() << ' ' << lastwrite(); else out << " (unused"; out << (has_derivs() ? " derivs" : "") << ")"; if (symtype() == SymTypeParam || symtype() == SymTypeOutputParam) { if (has_init_ops()) out << " init [" << initbegin() << ',' << initend() << ")"; if (connected()) out << " connected"; if (connected_down()) out << " down-connected"; if (!connected() && !connected_down()) out << " unconnected"; if (renderer_output()) out << " renderer-output"; if (symtype() == SymTypeParam && ! lockgeom()) out << " lockgeom=0"; } out << "\n"; if (symtype() == SymTypeConst) { out << "\tconst: "; print_vals (out, maxvals); out << "\n"; } else if (symtype() == SymTypeParam || symtype() == SymTypeOutputParam) { if (valuesource() == Symbol::DefaultVal && !has_init_ops()) { out << "\tdefault: "; print_vals (out, maxvals); out << "\n"; } else if (valuesource() == Symbol::InstanceVal) { out << "\tvalue: "; print_vals (out, maxvals); out << "\n"; } } return out; }
std::ostream & Symbol::print_vals (std::ostream &out, int maxvals) const { if (! data()) return out; TypeDesc t = typespec().simpletype(); int n = std::min (int(t.aggregate * t.numelements()), maxvals); if (t.basetype == TypeDesc::FLOAT) { for (int j = 0; j < n; ++j) out << (j ? " " : "") << ((float *)data())[j]; } else if (t.basetype == TypeDesc::INT) { for (int j = 0; j < n; ++j) out << (j ? " " : "") << ((int *)data())[j]; } else if (t.basetype == TypeDesc::STRING) { for (int j = 0; j < n; ++j) out << (j ? " " : "") << "\"" << Strutil::escape_chars(((ustring *)data())[j].string()) << "\""; } if (int(t.aggregate * t.numelements()) > maxvals) out << "..."; return out; }
void ASTfunction_call::typecheck_builtin_specialcase () { if (m_name == "transform") { // Special case for transform: under the covers, it selects // vector or normal special versions depending on its use. if (typespec().simpletype() == TypeDesc::TypeVector) m_name = ustring ("transformv"); else if (typespec().simpletype() == TypeDesc::TypeNormal) m_name = ustring ("transformn"); } // Void functions DO read their first arg, DON'T write it if (typespec().is_void()) { argread (0, true); argwrite (0, false); } if (func()->readwrite_special_case()) { if (m_name == "fresnel") { // This function has some output args argwriteonly (3); argwriteonly (4); argwriteonly (5); argwriteonly (6); } else if (m_name == "sincos") { argwriteonly (1); argwriteonly (2); } else if (m_name == "getattribute" || m_name == "getmessage" || m_name == "gettextureinfo" || m_name == "dict_value") { // these all write to their last argument argwriteonly ((int)listlength(args())); } else if (func()->texture_args()) { // texture-like function, look out for "alpha" std::vector<ASTNode::ref> argvec; list_to_vec (args(), argvec); // Find the beginning of the optional arguments -- it will be // the first string argument AFTER the filename. int nargs = (int) listlength(args()); int firstopt = 2; while (firstopt < nargs && ! argvec[firstopt]->typespec().is_string()) ++firstopt; // Loop through the optional args, look for "alpha" for (int a = firstopt; a < (int)argvec.size()-1; a += 2) { ASTNode *s = argvec[a].get(); if (s->typespec().is_string() && s->nodetype() == ASTNode::literal_node && ! strcmp (((ASTliteral *)s)->strval(), "alpha")) { // 'alpha' writes to the next arg! if (a+2 < 32) argwriteonly (a+2); // mark writeable else { // We can only designate the first 32 args // writeable. So swap it with earlier optional args. std::swap (argvec[firstopt], argvec[a]); std::swap (argvec[firstopt+1], argvec[a+1]); argwriteonly (firstopt+1); firstopt += 2; // advance in case another is needed } } } m_children[0] = vec_to_list (argvec); } } if (func()->takes_derivs()) { // Special handling for the few functions that take derivatives // of their arguments. Mark those with argtakesderivs. // N.B. This counts arguments in the same way that opcodes do -- // assuming "arg 0" is the return value. size_t nargs = listlength(args()); if (m_name == "area") { argtakesderivs (1, true); } else if (m_name == "aastep") { // all but the 5-arg version take derivs of edge param argtakesderivs (1, nargs<5); // aastep(f,f) and aastep(f,f,str) take derivs of s param if (nargs == 2 || list_nth(args(),2)->typespec().is_string()) argtakesderivs (2, true); } else if (m_name == "bump" || m_name == "displace") { // FIXME -- come back to this } else if (m_name == "calculatenormal") { argtakesderivs (1, true); } else if (m_name == "Dx" || m_name == "Dy") { argtakesderivs (1, true); } else if (m_name == "texture") { if (nargs == 3 || list_nth(args(),3)->typespec().is_string()) { argtakesderivs (2, true); argtakesderivs (3, true); } } else if (m_name == "texture3d") { if (nargs == 2 || list_nth(args(),2)->typespec().is_string()) { argtakesderivs (2, true); } } else if (m_name == "environment") { if (nargs == 2 || list_nth(args(),2)->typespec().is_string()) { argtakesderivs (2, true); } } else if (m_name == "trace") { argtakesderivs (1, true); argtakesderivs (2, true); } else { ASSERT (0 && "Missed a takes_derivs case!"); } } }