rti2code.cpp

Go 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