rti2code.cppGo to the documentation of this file.00001 /** rti2code.cpp Utility to generate registry initialisation code from rti files */ 00002 00003 /* FAU Discrete Event Systems Library (libfaudes) 00004 00005 Copyright (C) 2009 Ruediger Berndt 00006 Copyright (C) 2009 Thomas Moor 00007 00008 This library is free software; you can redistribute it and/or 00009 modify it under the terms of the GNU Lesser General Public 00010 License as published by the Free Software Foundation; either 00011 version 2.1 of the License, or (at your option) any later version. 00012 00013 This library is distributed in the hope that it will be useful, 00014 but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 Lesser General Public License for more details. 00017 00018 You should have received a copy of the GNU Lesser General Public 00019 License along with this library; if not, write to the Free Software 00020 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ 00021 00022 00023 #include <string> 00024 #include <iostream> 00025 #include <fstream> 00026 #include "corefaudes.h" 00027 00028 00029 using namespace faudes; 00030 00031 // ****************************************************************** 00032 // error exit 00033 // ****************************************************************** 00034 00035 void Usage(const std::string& rMessage="") { 00036 // UI hints 00037 if(rMessage!="") { 00038 std::cerr << rMessage << std::endl; 00039 std::cout << "" << std::endl; 00040 } 00041 std::cerr << "rti2code: " << VersionString() << std::endl; 00042 std::cerr << std::endl; 00043 std::cerr << "utility to generates c code from an rti-file to " << std::endl; 00044 std::cerr << "1) register faudes-types and -functions with the run-time interface," << std::endl; 00045 std::cerr << "2) extract c declarations for luabindings interface code." << std::endl; 00046 std::cerr << std::endl; 00047 std::cerr << "usage:" << std::endl; 00048 std::cerr << " rti2code <rti input file> <output basename>" << std::endl; 00049 std::cerr << " rti2code -merge <rti input files> <output rti-file>" << std::endl; 00050 exit(1); 00051 } 00052 00053 00054 // ****************************************************************** 00055 // main programm 00056 // ****************************************************************** 00057 00058 int main(int argc, char *argv[]) { 00059 00060 // Min args 00061 if(argc < 3) Usage(); 00062 00063 // Merge mode 00064 if(std::string(argv[1])=="-merge") { 00065 // Bail out 00066 if(argc < 4) Usage(); 00067 // Load from files 00068 for(int i=2; i< argc-1; i++) { 00069 TypeRegistry::G()->MergeDocumentation(std::string(argv[i])); 00070 FunctionRegistry::G()->MergeDocumentation(std::string(argv[i])); 00071 } 00072 // Dump 00073 if(std::string(argv[argc-1]) != "-") { 00074 SaveRegistry(std::string(argv[argc-1])); 00075 } else { 00076 SaveRegistry(); 00077 } 00078 return 0; 00079 } 00080 00081 // Std mode: generate code 00082 if(argc != 3) Usage(); 00083 00084 // Load registry file 00085 LoadRegistry(argv[1]); 00086 00087 // Code output streams 00088 std::ofstream rtiheader; 00089 rtiheader.open((std::string(argv[argc-1])+".h").c_str(), std::ios::out); 00090 std::ofstream rticode; 00091 rticode.open((std::string(argv[argc-1])+".cpp").c_str(), std::ios::out); 00092 std::ofstream luaheader; 00093 luaheader.open((std::string(argv[argc-1])+".i").c_str(), std::ios::out); 00094 00095 // Introduce myself 00096 rtiheader << "/* rti2code: autogenerated libFAUDES rti registration: "; 00097 rtiheader << VersionString() << " " << PluginsString() << " */" << std::endl << std::endl; 00098 rticode << "/* rti2code: autogenerated libFAUDES rti registration: "; 00099 rticode << VersionString() << " " << PluginsString() << " */" << std::endl << std::endl; 00100 luaheader << "/* rti2code: autogenerated libFAUDES luabindings declarations: "; 00101 luaheader << VersionString() << " " << PluginsString() << " */" << std::endl << std::endl; 00102 00103 // C++ static objects: auto load types 00104 rticode << "namespace faudes {" << std::endl; 00105 rticode << "/* Auto-register faudes types */" << std::endl; 00106 00107 // Traverse type registry to figure faudes types 00108 TypeRegistry::Iterator tit; 00109 int tcnt; 00110 for(tit=TypeRegistry::G()->Begin(), tcnt=1; tit!=TypeRegistry::G()->End();tit++,tcnt++) { 00111 // Get c/f type 00112 std::string ctype=tit->second->CType(); 00113 std::string ftype=tit->second->Name(); 00114 // Bail out if no C type specified 00115 if(ctype=="") continue; 00116 // Remove name space faudes 00117 size_t pos=ctype.find("faudes::"); 00118 if(pos!=std::string::npos) 00119 ctype=ctype.substr(std::string("faudes::").length()); 00120 // Bail out no auto-registration specified 00121 if(!tit->second->AutoRegistered()) continue; 00122 // report 00123 std::cout << "Generating auto-registration code for \"" << ftype << "\"" << std::endl; 00124 // Produce c code 00125 std::string rtiname = std::string("gRti") + ToStringInteger(tcnt) + "Register" + ftype; 00126 rticode << "AutoRegisterType<" << ctype << "> " << rtiname << "(\"" << ftype <<"\");"; 00127 rticode << std::endl; 00128 // Extra data set: element tag 00129 if(tit->second->XElementTag()!="") { 00130 rtiname = std::string("gRti") + ToStringInteger(tcnt) + "XElementTag" + ftype; 00131 rticode << "AutoRegisterXElementTag<" << ctype << "> " << rtiname << "(\"" << ftype << 00132 "\", \"" << tit->second->XElementTag() << "\");"; 00133 rticode << std::endl; 00134 } 00135 } 00136 00137 // C++ static objects: auto load types end 00138 rticode << "} // namespace" << std::endl; 00139 00140 // C++ function declaration: load types 00141 rtiheader << "namespace faudes {" << std::endl; 00142 rtiheader << "void LoadRegisteredTypes(void);" << std::endl; 00143 rtiheader << "} // namespace" << std::endl; 00144 00145 // C++ function definition: load types 00146 rticode << "namespace faudes {" << std::endl; 00147 rticode << "/* Register faudes types */" << std::endl; 00148 rticode << "void LoadRegisteredTypes(void) {" << std::endl; 00149 00150 // Traverse type registry to figure faudes types 00151 for(tit=TypeRegistry::G()->Begin(); tit!=TypeRegistry::G()->End();tit++) { 00152 // Get C type 00153 std::string ctype=tit->second->CType(); 00154 // Bail out if no c type specified 00155 if(ctype=="") continue; 00156 // Remove name space faudes 00157 size_t pos=ctype.find("faudes::"); 00158 if(pos!=std::string::npos) 00159 ctype=ctype.substr(std::string("faudes::").length()); 00160 // Report 00161 std::cout << "Generating registration code for \"" << tit->second->Name() << "\"" << std::endl; 00162 // Produce c code 00163 rticode << " TypeRegistry::G()->Insert<" << ctype << ">(\"" << tit->second->Name() <<"\");"; 00164 rticode << std::endl; 00165 } 00166 00167 // C++ function definition: load types end 00168 rticode << "}" << std::endl; 00169 rticode << "} // namespace" << std::endl; 00170 00171 00172 // C++ function declaration: load functions 00173 rtiheader << "namespace faudes {" << std::endl; 00174 rtiheader << "void LoadRegisteredFunctions(void);" << std::endl; 00175 rtiheader << "} // namespace" << std::endl; 00176 00177 // C++ function definition: load functions 00178 rticode << "namespace faudes {" << std::endl; 00179 rticode << "/* Register faudes functions */" << std::endl; 00180 rticode << "void LoadRegisteredFunctions(void) {" << std::endl; 00181 00182 // C++ class definition: Function derivates 00183 rtiheader << "namespace faudes {" << std::endl; 00184 00185 // Traverse function registry: define rti functions 00186 int fcnt=0; 00187 FunctionRegistry::Iterator fit; 00188 for(fit=FunctionRegistry::G()->Begin(); fit!=FunctionRegistry::G()->End();fit++, fcnt++) { 00189 // Current function definition 00190 const FunctionDefinition* fdef = fit->second; 00191 // Get C type and faudes function name 00192 std::string ctype=fdef->CType(); 00193 std::string fname = fdef->Name(); 00194 // Bail out if no c type specified 00195 if(ctype=="") continue; 00196 // Remove name space faudes 00197 size_t pos=ctype.find("faudes::"); 00198 if(pos!=std::string::npos) 00199 ctype=ctype.substr(std::string("faudes::").length()); 00200 // Bail out if no signature 00201 if(fdef->VariantsSize()==0) { 00202 std::cout << "Function registration: " << fname << ": no signatures" << std::endl; 00203 continue; 00204 } 00205 // Interpret signatures: set up type array 00206 std::vector< std::vector<std::string> > cparams; 00207 std::vector< std::vector<Parameter::ParamAttr> > cattrib; 00208 std::vector< std::vector<bool> > cretval; 00209 cparams.resize(fdef->VariantsSize()); 00210 cattrib.resize(fdef->VariantsSize()); 00211 cretval.resize(fdef->VariantsSize()); 00212 // Loop all signatures 00213 for(int i=0; i<fdef->VariantsSize(); i++) { 00214 const Signature& sigi=fdef->Variant(i); 00215 int retcount=0; 00216 for(int j=0; j<sigi.Size(); j++) { 00217 // Retrieve faudes type and attrib 00218 std::string ftype=sigi.At(j).Type(); 00219 Parameter::ParamAttr fattr=sigi.At(j).Attribute(); 00220 bool fcret=sigi.At(j).CReturn(); 00221 // Count ret values 00222 if(fcret) retcount++; 00223 // Bail out on unknown faudestype 00224 if(!TypeRegistry::G()->Exists(ftype)) break; 00225 // Get corresponding ctype 00226 std::string ctype=TypeRegistry::G()->Definition(ftype).CType(); 00227 // Bail out on unknown ctype 00228 if(ctype=="") break; 00229 // bail out on non-out ret value 00230 if(fcret && !(fattr==Parameter::Out)) break; 00231 // Bail out on undef attribute 00232 if(fattr==Parameter::UnDef) break; 00233 // Bail out on more than one ret values 00234 if(retcount>1) break; 00235 // Remove name space faudes 00236 size_t pos=ctype.find("faudes::"); 00237 if(pos!=std::string::npos) 00238 ctype=ctype.substr(std::string("faudes::").length()); 00239 // Param ok 00240 cparams.at(i).push_back(ctype); 00241 cattrib.at(i).push_back(fattr); 00242 cretval.at(i).push_back(fcret); 00243 } 00244 // Test for signature error 00245 if((int) cparams.at(i).size()!=sigi.Size()) { 00246 std::cout << "Function registration: " << fname << ": cannot interpret signature " 00247 << sigi.Name() << std::endl; 00248 cparams.resize(i); 00249 break; 00250 } 00251 } 00252 // Report 00253 std::cout << "Generating rti wrapper for \"" << fdef->Name() << "\"" << 00254 " #" << cparams.size() << " variants" << std::endl; 00255 // Produce c code: register all functions function 00256 std::string rtiname = std::string("Rti") + ToStringInteger(fcnt) + ctype; 00257 rticode << " FunctionRegistry::G()->Insert<" << rtiname << ">(\"" << fname <<"\");" << std::endl; 00258 // Produce c code: class declaration intro 00259 rtiheader << "/* Function class for C++ function " << ctype << "*/" << std::endl; 00260 rtiheader << "class " << rtiname << " : public Function { " << std::endl; 00261 rtiheader << "public:" << std::endl; 00262 rtiheader << rtiname << "(const FunctionDefinition* fdef) : Function(fdef) {};" << std::endl; 00263 rtiheader << "virtual Function* New(void) const { return new " << rtiname << "(pFuncDef); };" << std::endl; 00264 rtiheader << "protected:" << std::endl; 00265 // Produce c code: function class: have typed param 00266 for(unsigned int i=0; i<cparams.size(); i++) 00267 for(unsigned int j=0; j<cparams.at(i).size(); j++) 00268 rtiheader << cparams.at(i).at(j) << "* " << "mP_" << i << "_" << j << ";" << std::endl; 00269 // Produce c code: function class: do type check 00270 rtiheader << "virtual bool DoTypeCheck(int n) {" << std::endl; 00271 rtiheader << " bool res=false;" << std::endl; 00272 rtiheader << " switch(mVariantIndex) { "<< std::endl; 00273 for(unsigned int i=0; i<cparams.size(); i++) { 00274 rtiheader << " case " << i << ": { // variant " << fdef->Variant(i).Name() << std::endl; 00275 rtiheader << " switch(n) { "<< std::endl; 00276 for(unsigned int j=0; j<cparams.at(i).size(); j++) { 00277 rtiheader << " case " << j << ": "; 00278 rtiheader << " res=DoTypeCast<" << cparams.at(i).at(j) << ">(" << j << ", mP_" << i <<"_" << j << "); "; 00279 rtiheader << "break; "<< std::endl; 00280 } 00281 rtiheader << " default: break; " << std::endl; 00282 rtiheader << " } "<< std::endl; 00283 rtiheader << " break; "<< std::endl; 00284 rtiheader << " } "<< std::endl; 00285 } 00286 rtiheader << " default: break; " << std::endl; 00287 rtiheader << " } "<< std::endl; 00288 rtiheader << " return res;" << std::endl; 00289 rtiheader << "};" << std::endl; 00290 // Produce c code: function class: do execute 00291 rtiheader << "virtual void DoExecute(void) {" << std::endl; 00292 // Produce c code: do execute: switch variant 00293 rtiheader << " switch(mVariantIndex) { "<< std::endl; 00294 for(unsigned int i=0; i<cparams.size(); i++) { 00295 rtiheader << " case " << i << ": { // variant " << fdef->Variant(i).Name() << std::endl; 00296 rtiheader << " "; 00297 // Figure return value (if any) 00298 for(unsigned int j=0; j<cparams.at(i).size(); j++) { 00299 if(!cretval.at(i).at(j)) continue; 00300 // Special case: integer 00301 if(cparams.at(i).at(j) == "Integer") { 00302 rtiheader << "*(mP_" << i << "_" << j << "->CReference()) = "; 00303 } else 00304 // Special case: boolean 00305 if(cparams.at(i).at(j) == "Boolean") { 00306 rtiheader << "*(mP_" << i << "_" << j << "->CReference()) = "; 00307 } else 00308 // Special case: integer 00309 if(cparams.at(i).at(j) == "String") { 00310 rtiheader << "*(mP_" << i << "_" << j << "->CReference()) = "; 00311 } else 00312 // Std case 00313 rtiheader << "*mP_" << i << "_" << j << " = "; 00314 } 00315 // Function name 00316 rtiheader << ctype <<"("; 00317 // Parameters 00318 int parpos=0; 00319 for(unsigned int j=0; j<cparams.at(i).size(); j++) { 00320 if(cretval.at(i).at(j)) continue; 00321 if((parpos++)!=0) rtiheader << " ,"; 00322 // Special case: integer 00323 if(cparams.at(i).at(j) == "Integer") { 00324 rtiheader << "*(mP_" << i << "_" << j << "->CReference())"; 00325 } else 00326 // Special case: boolean 00327 if(cparams.at(i).at(j) == "Boolean") { 00328 rtiheader << "*(mP_" << i << "_" << j << "->CReference())"; 00329 } else 00330 // Special case: integer 00331 if(cparams.at(i).at(j) == "String") { 00332 rtiheader << "*(mP_" << i << "_" << j << "->CReference())"; 00333 } else 00334 // Std case 00335 rtiheader << "*mP_" << i << "_" << j; 00336 } 00337 rtiheader << "); break; };" << std::endl; 00338 } 00339 // Produce c code: switch variant; done 00340 rtiheader << " default: break; " << std::endl; 00341 rtiheader << " }; "<< std::endl; 00342 // Produce c code: do execute: done 00343 rtiheader << "}; "<< std::endl; 00344 // Produce c code: function class: done 00345 rtiheader << "};" << std::endl; 00346 00347 // Produce swig code: lua function definition(s) 00348 luaheader << "/* faudes-function \"" << fname << "\" */" << std::endl; 00349 // Figure my plugin to insert a conditional 00350 std::string plugin=fdef->PlugIn(); 00351 luaheader << "#if " << "SwigModule == \"Swig" << plugin << "\"" << std::endl; 00352 // Use C-type function name 00353 if(ctype!=fname) 00354 luaheader << "%rename(" << fname << ") " << ctype << ";" << std::endl; 00355 00356 // Prepare swig code: preprocessed array 00357 std::vector< std::string > lfdefs; 00358 std::vector< std::string > lrtypes; 00359 std::vector< std::string > lhelp; 00360 // Prepare swig code: generate per signature 00361 for(unsigned int i=0; i<cparams.size(); i++) { 00362 // Create ctype function declaration: return value 00363 std::string lrtype="void"; 00364 for(unsigned int j=0; j<cparams.at(i).size(); j++) { 00365 if(!cretval.at(i).at(j)) continue; 00366 // Special case: integer 00367 if(cparams.at(i).at(j) == "Integer") { 00368 lrtype="long int"; 00369 } else 00370 // Special case: boolean 00371 if(cparams.at(i).at(j) == "Boolean") { 00372 lrtype="bool"; 00373 } else 00374 // Special case: string 00375 if(cparams.at(i).at(j) == "String") { 00376 lrtype="std::string"; 00377 } else 00378 // Std case ctype as refernce 00379 lrtype + cparams.at(i).at(j); 00380 // No more than one return value 00381 break; 00382 } 00383 lrtypes.push_back(lrtype); 00384 // Create ctype function declaration: function body 00385 std::string lfdef = ctype + "("; 00386 // Create ctype function declaration: parameters 00387 int parpos=0; 00388 for(unsigned int j=0; j<cparams.at(i).size(); j++) { 00389 if(cretval.at(i).at(j)) continue; 00390 if((parpos++)!=0) lfdef += ", "; 00391 // Have const for +In+ 00392 if(cattrib.at(i).at(j)==Parameter::In) 00393 lfdef += "const "; 00394 // Special case: integer 00395 if(cparams.at(i).at(j) == "Integer") { 00396 lfdef += "long int&"; 00397 } else 00398 // Special case: boolean 00399 if(cparams.at(i).at(j) == "Boolean") { 00400 lfdef += "bool&"; 00401 } else 00402 // Special case: string 00403 if(cparams.at(i).at(j) == "String") { 00404 lfdef += "std::string&"; 00405 } else 00406 // Std case ctype as refernce 00407 lfdef += cparams.at(i).at(j) + "&"; 00408 // Mark elementary outputs 00409 if(cparams.at(i).at(j) == "Boolean" || cparams.at(i).at(j) == "String" 00410 || cparams.at(i).at(j) == "Integer") 00411 if(cattrib.at(i).at(j)==Parameter::Out) 00412 lfdef += " OUTPUT"; 00413 } 00414 // End of function declaration 00415 lfdef += ")"; 00416 lfdefs.push_back(lfdef); 00417 // Add help entry: build nice signature 00418 std::string luasig = " " + fname + "("; 00419 bool leftcomma = false; 00420 bool rightcomma = false; 00421 for(unsigned int j=0; j<cparams.at(i).size(); j++) { 00422 // Special case: elementary output 00423 if(cparams.at(i).at(j) == "Boolean" || cparams.at(i).at(j) == "String" 00424 || cparams.at(i).at(j) == "Integer") 00425 if(cattrib.at(i).at(j)==Parameter::Out) { 00426 if(leftcomma) luasig = "," + luasig; 00427 // if(leftcomma) luasig = ", " + luasig; // need tab in help system? 00428 luasig=cparams.at(i).at(j) + luasig; 00429 leftcomma=true; 00430 continue; 00431 } 00432 // Std case 00433 if(rightcomma) luasig += ", "; 00434 const Signature& sigi=fdef->Variant(i); 00435 luasig += sigi.At(j).Str(); 00436 rightcomma=true; 00437 } 00438 luasig+=")"; 00439 // Add help entry: add with topic 00440 if(fdef->TextDoc()!=""){ 00441 std::string topic= fdef->PlugIn(); 00442 std::string key1=fdef->KeywordAt(1); 00443 if(topic=="CoreFaudes") { 00444 topic=fdef->KeywordAt(1); 00445 key1=fdef->KeywordAt(2); 00446 } 00447 if(topic.length()>0) topic.at(0)=toupper(topic.at(0)); 00448 if(key1.length()>0) key1.at(0)=toupper(key1.at(0)); 00449 lhelp.push_back("SwigHelpEntry(\"" + topic + "\", \"" + key1 + "\", \"" + 00450 luasig + "\")"); 00451 } else { 00452 lhelp.push_back(""); 00453 } 00454 } 00455 // Filter pseudo doublets (only differ in lrtype) 00456 for(unsigned int i=1; i<lfdefs.size();i++) { 00457 unsigned int j; 00458 for(j=0; j<i; j++) 00459 if(lfdefs.at(i)==lfdefs.at(j)) break; 00460 if(j==i) continue; 00461 // Invalidate entry? 00462 if(lrtypes.at(j)=="void") 00463 {lfdefs[j]=""; continue;} 00464 if(lrtypes.at(i)=="void") 00465 {lfdefs[i]=""; continue;} 00466 } // Done: prepare per signature 00467 00468 // Generate swig definitions: write 00469 int lcount=0; 00470 for(unsigned int i=0; i<lfdefs.size(); i++) { 00471 if(lfdefs.at(i)=="") continue; 00472 luaheader << lrtypes.at(i) << " " << lfdefs.at(i) << ";" << std::endl; 00473 lcount++; 00474 if(lhelp.at(i)=="") continue; 00475 luaheader << lhelp.at(i) << ";" << std::endl; 00476 } 00477 std::cout << "Generating swig interface for function \"" << fdef->Name() << "\"" << 00478 " #" << lcount << " variants" << std::endl; 00479 00480 // End all signatures, incl conditional 00481 luaheader << "#endif " << std::endl; 00482 luaheader << std::endl; 00483 00484 00485 } // Loop all functions 00486 00487 // C++ class definition: function class: all such done 00488 rtiheader << "} // namespace" << std::endl; 00489 00490 // C++ class definition: register function prototypes: done 00491 rticode << "}" << std::endl; 00492 rticode << "} // namespace" << std::endl; 00493 00494 return(0); 00495 } libFAUDES 2.23h --- 2014.04.03 --- c++ api documentaion by doxygen |