rti2code.cpp
Go to the documentation of this file.
1 /** rti2code.cpp Utility to generate registry initialisation code from rti files */
2 
3 /* FAU Discrete Event Systems Library (libfaudes)
4 
5 Copyright (C) 2009 Ruediger Berndt
6 Copyright (C) 2023 Thomas Moor
7 
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Lesser General Public
10 License as published by the Free Software Foundation; either
11 version 2.1 of the License, or (at your option) any later version.
12 
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17 
18 You should have received a copy of the GNU Lesser General Public
19 License along with this library; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
21 
22 
23 #include <string>
24 #include <iostream>
25 #include <fstream>
26 #include "corefaudes.h"
27 
28 
29 using namespace faudes;
30 
31 // ******************************************************************
32 // error exit
33 // ******************************************************************
34 
35 void Usage(const std::string& rMessage="") {
36  // UI hints
37  if(rMessage!="") {
38  std::cerr << rMessage << std::endl;
39  std::cout << "" << std::endl;
40  }
41  std::cerr << "rti2code: " << VersionString() << std::endl;
42  std::cerr << std::endl;
43  std::cerr << "utility to generates c code from an rti-file to " << std::endl;
44  std::cerr << "1) register faudes-types and -functions with the run-time interface," << std::endl;
45  std::cerr << "2) extract c declarations for bindings interface code." << std::endl;
46  std::cerr << std::endl;
47  std::cerr << "usage:" << std::endl;
48  std::cerr << " rti2code [-flat] <rti input file> <output basename>" << std::endl;
49  std::cerr << " rti2code -merge <rti input files> <output rti-file>" << std::endl;
50  std::cerr << std::endl;
51  std::cerr << "[note: the -flat option circumvents an issue with SWIG pre 4.1.0]" << std::endl;
52  exit(1);
53 }
54 
55 
56 // ******************************************************************
57 // main programm
58 // ******************************************************************
59 
60 int main(int argc, char *argv[]) {
61 
62  // Min args
63  if(argc < 3) Usage();
64 
65  // Merge mode
66  if(std::string(argv[1])=="-merge") {
67  // Bail out
68  if(argc < 4) Usage();
69  // Load from files
70  for(int i=2; i< argc-1; i++) {
71  TypeRegistry::G()->MergeDocumentation(std::string(argv[i]));
72  FunctionRegistry::G()->MergeDocumentation(std::string(argv[i]));
73  }
74  // Dump
75  if(std::string(argv[argc-1]) != "-") {
76  SaveRegistry(std::string(argv[argc-1]));
77  } else {
78  SaveRegistry();
79  }
80  return 0;
81  }
82 
83  // Test for "-flat" flag
84  bool flat=false;
85  if(std::string(argv[1])=="-flat") flat=true;
86  if(flat && argc != 4) Usage();
87  if(!flat && argc != 3) Usage();
88 
89  // Load registry file
90  LoadRegistry(argv[argc-2]);
91 
92  // Code output streams
93  std::ofstream rtiheader;
94  rtiheader.open((std::string(argv[argc-1])+".h").c_str(), std::ios::out);
95  std::ofstream rticode;
96  rticode.open((std::string(argv[argc-1])+".cpp").c_str(), std::ios::out);
97  std::ofstream luaheader;
98  luaheader.open((std::string(argv[argc-1])+".i").c_str(), std::ios::out);
99 
100  // Introduce myself
101  rtiheader << "/* rti2code: autogenerated libFAUDES rti registration: ";
102  rtiheader << VersionString() << " " << PluginsString() << " */" << std::endl << std::endl;
103  rticode << "/* rti2code: autogenerated libFAUDES rti registration: ";
104  rticode << VersionString() << " " << PluginsString() << " */" << std::endl << std::endl;
105  luaheader << "/* rti2code: autogenerated libFAUDES swig bindings declarations: ";
106  luaheader << VersionString() << " " << PluginsString() << " */" << std::endl << std::endl;
107 
108  // C++ static objects: auto load types
109  rticode << "namespace faudes {" << std::endl;
110  rticode << "/* Auto-register faudes types */" << std::endl;
111 
112  // Traverse type registry to figure faudes types
114  int tcnt;
115  for(tit=TypeRegistry::G()->Begin(), tcnt=1; tit!=TypeRegistry::G()->End();tit++,tcnt++) {
116  // Get c/f type
117  std::string ctype=tit->second->CType();
118  std::string ftype=tit->second->Name();
119  // Bail out if no C type specified
120  if(ctype=="") continue;
121  // Remove name space faudes
122  size_t pos=ctype.find("faudes::");
123  if(pos!=std::string::npos)
124  ctype=ctype.substr(std::string("faudes::").length());
125  // Bail out no auto-registration specified
126  if(!tit->second->AutoRegistered()) continue;
127  // report
128  std::cout << "Generating auto-registration code for \"" << ftype << "\"" << std::endl;
129  // Produce c code
130  std::string rtiname = std::string("gRti") + ToStringInteger(tcnt) + "Register" + ftype;
131  rticode << "AutoRegisterType<" << ctype << "> " << rtiname << "(\"" << ftype <<"\");";
132  rticode << std::endl;
133  // Extra data set: element tag
134  if(tit->second->XElementTag()!="") {
135  rtiname = std::string("gRti") + ToStringInteger(tcnt) + "XElementTag" + ftype;
136  rticode << "AutoRegisterXElementTag<" << ctype << "> " << rtiname << "(\"" << ftype <<
137  "\", \"" << tit->second->XElementTag() << "\");";
138  rticode << std::endl;
139  }
140  }
141 
142  // C++ static objects: auto load types end
143  rticode << "} // namespace" << std::endl;
144 
145  // C++ function declaration: load types
146  rtiheader << "namespace faudes {" << std::endl;
147  rtiheader << "void LoadRegisteredTypes(void);" << std::endl;
148  rtiheader << "} // namespace" << std::endl;
149 
150  // C++ function definition: load types
151  rticode << "namespace faudes {" << std::endl;
152  rticode << "/* Register faudes types */" << std::endl;
153  rticode << "void LoadRegisteredTypes(void) {" << std::endl;
154 
155  // Traverse type registry to figure faudes types
156  for(tit=TypeRegistry::G()->Begin(); tit!=TypeRegistry::G()->End();tit++) {
157  // Get C type
158  std::string ctype=tit->second->CType();
159  // Bail out if no c type specified
160  if(ctype=="") continue;
161  // Remove name space faudes
162  size_t pos=ctype.find("faudes::");
163  if(pos!=std::string::npos)
164  ctype=ctype.substr(std::string("faudes::").length());
165  // Report
166  std::cout << "Generating registration code for \"" << tit->second->Name() << "\"" << std::endl;
167  // Produce c code
168  rticode << " TypeRegistry::G()->Insert<" << ctype << ">(\"" << tit->second->Name() <<"\");";
169  rticode << std::endl;
170  }
171 
172  // C++ function definition: load types end
173  rticode << "}" << std::endl;
174  rticode << "} // namespace" << std::endl;
175 
176 
177  // C++ function declaration: load functions
178  rtiheader << "namespace faudes {" << std::endl;
179  rtiheader << "void LoadRegisteredFunctions(void);" << std::endl;
180  rtiheader << "} // namespace" << std::endl;
181 
182  // C++ function definition: load functions
183  rticode << "namespace faudes {" << std::endl;
184  rticode << "/* Register faudes functions */" << std::endl;
185  rticode << "void LoadRegisteredFunctions(void) {" << std::endl;
186 
187  // C++ class definition: Function derivates
188  rtiheader << "namespace faudes {" << std::endl;
189 
190  // Traverse function registry: define rti functions
191  int fcnt=0;
193  for(fit=FunctionRegistry::G()->Begin(); fit!=FunctionRegistry::G()->End();fit++, fcnt++) {
194  // Current function definition
195  const FunctionDefinition* fdef = fit->second;
196  // Get C type and faudes function name
197  std::string ctype=fdef->CType();
198  std::string fname = fdef->Name();
199  // Bail out if no c type specified
200  if(ctype=="") continue;
201  // Remove name space faudes
202  size_t pos=ctype.find("faudes::");
203  if(pos!=std::string::npos)
204  ctype=ctype.substr(std::string("faudes::").length());
205  // Bail out if no signature
206  if(fdef->VariantsSize()==0) {
207  std::cout << "Function registration: " << fname << ": no signatures" << std::endl;
208  continue;
209  }
210  // Interpret signatures: set up type array
211  std::vector< std::vector<std::string> > cparams;
212  std::vector< std::vector<Parameter::ParamAttr> > cattrib;
213  std::vector< std::vector<bool> > cretval;
214  cparams.resize(fdef->VariantsSize());
215  cattrib.resize(fdef->VariantsSize());
216  cretval.resize(fdef->VariantsSize());
217  // Loop all signatures
218  for(int i=0; i<fdef->VariantsSize(); i++) {
219  const Signature& sigi=fdef->Variant(i);
220  int retcount=0;
221  for(int j=0; j<sigi.Size(); j++) {
222  // Retrieve faudes type and attrib
223  std::string ftype=sigi.At(j).Type();
224  Parameter::ParamAttr fattr=sigi.At(j).Attribute();
225  bool fcret=sigi.At(j).CReturn();
226  // Count ret values
227  if(fcret) retcount++;
228  // Bail out on unknown faudestype
229  if(!TypeRegistry::G()->Exists(ftype)) break;
230  // Get corresponding ctype
231  std::string ctype=TypeRegistry::G()->Definition(ftype).CType();
232  // Bail out on unknown ctype
233  if(ctype=="") break;
234  // bail out on non-out ret value
235  if(fcret && !(fattr==Parameter::Out)) break;
236  // Bail out on undef attribute
237  if(fattr==Parameter::UnDef) break;
238  // Bail out on more than one ret values
239  if(retcount>1) break;
240  // Remove name space faudes
241  size_t pos=ctype.find("faudes::");
242  if(pos!=std::string::npos)
243  ctype=ctype.substr(std::string("faudes::").length());
244  // Param ok
245  cparams.at(i).push_back(ctype);
246  cattrib.at(i).push_back(fattr);
247  cretval.at(i).push_back(fcret);
248  }
249  // Test for signature error
250  if((int) cparams.at(i).size()!=sigi.Size()) {
251  std::cout << "Function registration: " << fname << ": cannot interpret signature "
252  << sigi.Name() << std::endl;
253  cparams.resize(i);
254  break;
255  }
256  }
257  // Report
258  std::cout << "Generating rti wrapper for \"" << fdef->Name() << "\"" <<
259  " #" << cparams.size() << " variants" << std::endl;
260  // Produce c code: register all functions function
261  std::string rtiname = std::string("Rti") + ToStringInteger(fcnt) + ctype;
262  rticode << " FunctionRegistry::G()->Insert<" << rtiname << ">(\"" << fname <<"\");" << std::endl;
263  // Produce c code: class declaration intro
264  rtiheader << "/* Function class for C++ function " << ctype << "*/" << std::endl;
265  rtiheader << "class " << rtiname << " : public Function { " << std::endl;
266  rtiheader << "public:" << std::endl;
267  rtiheader << rtiname << "(const FunctionDefinition* fdef) : Function(fdef) {};" << std::endl;
268  rtiheader << "virtual Function* New(void) const { return new " << rtiname << "(pFuncDef); };" << std::endl;
269  rtiheader << "protected:" << std::endl;
270  // Produce c code: function class: have typed param
271  for(unsigned int i=0; i<cparams.size(); i++)
272  for(unsigned int j=0; j<cparams.at(i).size(); j++)
273  rtiheader << cparams.at(i).at(j) << "* " << "mP_" << i << "_" << j << ";" << std::endl;
274  // Produce c code: function class: do type check
275  rtiheader << "virtual bool DoTypeCheck(int n) {" << std::endl;
276  rtiheader << " bool res=false;" << std::endl;
277  rtiheader << " switch(mVariantIndex) { "<< std::endl;
278  for(unsigned int i=0; i<cparams.size(); i++) {
279  rtiheader << " case " << i << ": { // variant " << fdef->Variant(i).Name() << std::endl;
280  rtiheader << " switch(n) { "<< std::endl;
281  for(unsigned int j=0; j<cparams.at(i).size(); j++) {
282  rtiheader << " case " << j << ": ";
283  rtiheader << " res=DoTypeCast<" << cparams.at(i).at(j) << ">(" << j << ", mP_" << i <<"_" << j << "); ";
284  rtiheader << "break; "<< std::endl;
285  }
286  rtiheader << " default: break; " << std::endl;
287  rtiheader << " } "<< std::endl;
288  rtiheader << " break; "<< std::endl;
289  rtiheader << " } "<< std::endl;
290  }
291  rtiheader << " default: break; " << std::endl;
292  rtiheader << " } "<< std::endl;
293  rtiheader << " return res;" << std::endl;
294  rtiheader << "};" << std::endl;
295  // Produce c code: function class: do execute
296  rtiheader << "virtual void DoExecute(void) {" << std::endl;
297  // Produce c code: do execute: switch variant
298  rtiheader << " switch(mVariantIndex) { "<< std::endl;
299  for(unsigned int i=0; i<cparams.size(); i++) {
300  rtiheader << " case " << i << ": { // variant " << fdef->Variant(i).Name() << std::endl;
301  rtiheader << " ";
302  // Figure return value (if any)
303  for(unsigned int j=0; j<cparams.at(i).size(); j++) {
304  if(!cretval.at(i).at(j)) continue;
305  // Special case: integer
306  if(cparams.at(i).at(j) == "Integer") {
307  rtiheader << "*(mP_" << i << "_" << j << "->CReference()) = ";
308  } else
309  // Special case: boolean
310  if(cparams.at(i).at(j) == "Boolean") {
311  rtiheader << "*(mP_" << i << "_" << j << "->CReference()) = ";
312  } else
313  // Special case: integer
314  if(cparams.at(i).at(j) == "String") {
315  rtiheader << "*(mP_" << i << "_" << j << "->CReference()) = ";
316  } else
317  // Std case
318  rtiheader << "*mP_" << i << "_" << j << " = ";
319  }
320  // Function name
321  rtiheader << ctype <<"(";
322  // Parameters
323  int parpos=0;
324  for(unsigned int j=0; j<cparams.at(i).size(); j++) {
325  if(cretval.at(i).at(j)) continue;
326  if((parpos++)!=0) rtiheader << " ,";
327  // Special case: integer
328  if(cparams.at(i).at(j) == "Integer") {
329  rtiheader << "*(mP_" << i << "_" << j << "->CReference())";
330  } else
331  // Special case: boolean
332  if(cparams.at(i).at(j) == "Boolean") {
333  rtiheader << "*(mP_" << i << "_" << j << "->CReference())";
334  } else
335  // Special case: integer
336  if(cparams.at(i).at(j) == "String") {
337  rtiheader << "*(mP_" << i << "_" << j << "->CReference())";
338  } else
339  // Std case
340  rtiheader << "*mP_" << i << "_" << j;
341  }
342  rtiheader << "); break; };" << std::endl;
343  }
344  // Produce c code: switch variant; done
345  rtiheader << " default: break; " << std::endl;
346  rtiheader << " }; "<< std::endl;
347  // Produce c code: do execute: done
348  rtiheader << "}; "<< std::endl;
349  // Produce c code: function class: done
350  rtiheader << "};" << std::endl;
351 
352  // Produce swig code: lua function definition(s)
353  luaheader << "/* faudes-function \"" << fname << "\" */" << std::endl;
354  // Figure my plugin to insert a conditional
355  if(!flat) {
356  std::string plugin=fdef->PlugIn();
357  luaheader << "#if " << "( SwigModule == \"Swig" << plugin << "\")";
358  //luaheader << " || ( SwigModule == \"SwigLibFaudes\")"; // requires SWIG 4.1
359  luaheader << std::endl;
360  }
361  // Use C-type function name
362  if(ctype!=fname)
363  luaheader << "%rename(" << fname << ") " << ctype << ";" << std::endl;
364 
365  // Prepare swig code: preprocessed array
366  std::vector< std::string > lfdefs;
367  std::vector< std::string > lrtypes;
368  std::vector< std::string > lhelp;
369  // Prepare swig code: generate per signature
370  for(unsigned int i=0; i<cparams.size(); i++) {
371  // Create ctype function declaration: return value
372  std::string lrtype="void";
373  for(unsigned int j=0; j<cparams.at(i).size(); j++) {
374  if(!cretval.at(i).at(j)) continue;
375  // Special case: integer
376  if(cparams.at(i).at(j) == "Integer") {
377  lrtype="long int";
378  } else
379  // Special case: boolean
380  if(cparams.at(i).at(j) == "Boolean") {
381  lrtype="bool";
382  } else
383  // Special case: string
384  if(cparams.at(i).at(j) == "String") {
385  lrtype="std::string";
386  } else
387  // Std case ctype as refernce
388  lrtype + cparams.at(i).at(j);
389  // No more than one return value
390  break;
391  }
392  lrtypes.push_back(lrtype);
393  // Create ctype function declaration: function body
394  std::string lfdef = ctype + "(";
395  // Create ctype function declaration: parameters
396  int parpos=0;
397  for(unsigned int j=0; j<cparams.at(i).size(); j++) {
398  if(cretval.at(i).at(j)) continue;
399  if((parpos++)!=0) lfdef += ", ";
400  // Have const for +In+
401  if(cattrib.at(i).at(j)==Parameter::In)
402  lfdef += "const ";
403  // Special case: integer
404  if(cparams.at(i).at(j) == "Integer") {
405  lfdef += "long int&";
406  } else
407  // Special case: boolean
408  if(cparams.at(i).at(j) == "Boolean") {
409  lfdef += "bool&";
410  } else
411  // Special case: string
412  if(cparams.at(i).at(j) == "String") {
413  lfdef += "std::string&";
414  } else
415  // Std case ctype as refernce
416  lfdef += cparams.at(i).at(j) + "&";
417  // Mark elementary outputs
418  if(cparams.at(i).at(j) == "Boolean" || cparams.at(i).at(j) == "String"
419  || cparams.at(i).at(j) == "Integer")
420  if(cattrib.at(i).at(j)==Parameter::Out)
421  lfdef += " OUTPUT";
422  }
423  // End of function declaration
424  lfdef += ")";
425  lfdefs.push_back(lfdef);
426  // Add help entry: build nice signature
427  std::string luasig = " " + fname + "(";
428  bool leftcomma = false;
429  bool rightcomma = false;
430  for(unsigned int j=0; j<cparams.at(i).size(); j++) {
431  // Special case: elementary output
432  if(cparams.at(i).at(j) == "Boolean" || cparams.at(i).at(j) == "String"
433  || cparams.at(i).at(j) == "Integer")
434  if(cattrib.at(i).at(j)==Parameter::Out) {
435  if(leftcomma) luasig = "," + luasig;
436  // if(leftcomma) luasig = ", " + luasig; // need tab in help system?
437  luasig=cparams.at(i).at(j) + luasig;
438  leftcomma=true;
439  continue;
440  }
441  // Std case
442  if(rightcomma) luasig += ", ";
443  const Signature& sigi=fdef->Variant(i);
444  luasig += sigi.At(j).Str();
445  rightcomma=true;
446  }
447  luasig+=")";
448  // Add help entry: add with topic
449  if(fdef->TextDoc()!=""){
450  std::string topic= fdef->PlugIn();
451  std::string key1=fdef->KeywordAt(1);
452  if(topic=="CoreFaudes") {
453  topic=fdef->KeywordAt(1);
454  key1=fdef->KeywordAt(2);
455  }
456  if(topic.length()>0) topic.at(0)=toupper(topic.at(0));
457  if(key1.length()>0) key1.at(0)=toupper(key1.at(0));
458  lhelp.push_back("SwigHelpEntry(\"" + topic + "\", \"" + key1 + "\", \"" +
459  luasig + "\")");
460  } else {
461  lhelp.push_back("");
462  }
463  }
464  // Filter pseudo doublets (only differ in lrtype)
465  for(unsigned int i=1; i<lfdefs.size();i++) {
466  unsigned int j;
467  for(j=0; j<i; j++)
468  if(lfdefs.at(i)==lfdefs.at(j)) break;
469  if(j==i) continue;
470  // Invalidate entry?
471  if(lrtypes.at(j)=="void")
472  {lfdefs[j]=""; continue;}
473  if(lrtypes.at(i)=="void")
474  {lfdefs[i]=""; continue;}
475  } // Done: prepare per signature
476 
477  // Generate swig definitions: write
478  int lcount=0;
479  for(unsigned int i=0; i<lfdefs.size(); i++) {
480  if(lfdefs.at(i)=="") continue;
481  luaheader << lrtypes.at(i) << " " << lfdefs.at(i) << ";" << std::endl;
482  lcount++;
483  if(lhelp.at(i)=="") continue;
484  luaheader << lhelp.at(i) << ";" << std::endl;
485  }
486  std::cout << "Generating swig interface for function \"" << fdef->Name() << "\"" <<
487  " #" << lcount << " variants" << std::endl;
488 
489  // End all signatures, incl conditional
490  if(!flat) {
491  luaheader << "#endif " << std::endl;
492  }
493  luaheader << std::endl;
494 
495 
496  } // Loop all functions
497 
498  // C++ class definition: function class: all such done
499  rtiheader << "} // namespace" << std::endl;
500 
501  // C++ class definition: register function prototypes: done
502  rticode << "}" << std::endl;
503  rticode << "} // namespace" << std::endl;
504 
505  return(0);
506 }
const std::string & Name(void) const
Get name of the entety to document (aka faudes-type or faudes-function).
Definition: cfl_types.cpp:396
std::string KeywordAt(int pos) const
Definition: cfl_types.cpp:452
const std::string & PlugIn(void) const
Get name of plugin.
Definition: cfl_types.cpp:397
const std::string & TextDoc(void) const
Definition: cfl_types.cpp:399
const std::string & CType(void) const
Get corresponding C++ type.
Definition: cfl_types.cpp:398
A FunctionDefinition defines the interface to a faudes-function.
const Signature & Variant(const std::string &rName) const
Return reference to Signature by name.
int VariantsSize(void) const
Return number of supported Signature instances.
Iterator End(void) const
STL interator to the internal function-name map.
static FunctionRegistry * G()
Method to access the single global instance of the registry.
std::map< std::string, FunctionDefinition * >::const_iterator Iterator
Convenience typedef to access registry entries.
Definition: cfl_registry.h:501
void MergeDocumentation(TokenReader &rTr)
Scan token input for function documentation.
Iterator Begin(void) const
STL interator to the internal function-name map.
std::string Str(void) const
Convenience method to produce a textual representation of a parameter.
bool CReturn(void) const
Get C-Return flag.
ParamAttr
A function parameter has has one out of four so called io-attrributes;.
Definition: cfl_functions.h:52
const std::string & Type(void) const
Get type.
const ParamAttr & Attribute(void) const
Get Attribute.
Signature of a Function.
int Size(void) const
Return number of parameters.
const std::string & Name(void) const
Return signature name.
const Parameter & At(int n) const
Get parameter type by position.
void MergeDocumentation(TokenReader &rTr)
Scan token input for type documentation.
const TypeDefinition & Definition(const std::string &rTypeName) const
Look up the type definition by faudes-type name.
static TypeRegistry * G()
Method to access the single global instance of the registry.
bool Exists(const std::string &rName) const
Test existence of a faudes-type by its name.
Iterator End(void) const
STL interator to the internal type-name map.
std::map< std::string, TypeDefinition * >::const_iterator Iterator
Convenience typedef to access registry entries.
Definition: cfl_registry.h:52
Includes all libFAUDES headers, no plugins.
void SaveRegistry(const std::string &rPath)
Dump all registered types and functions.
void LoadRegistry(const std::string &rPath)
Load all registered types and functions.
libFAUDES resides within the namespace faudes.
std::string VersionString()
Return FAUDES_VERSION as std::string.
Definition: cfl_helper.cpp:131
std::string PluginsString()
Return FAUDES_PLUGINS as std::string.
Definition: cfl_helper.cpp:136
std::string ToStringInteger(Int number)
integer to string
Definition: cfl_helper.cpp:43
int main(int argc, char *argv[])
Definition: rti2code.cpp:60
void Usage(const std::string &rMessage="")
Definition: rti2code.cpp:35

libFAUDES 2.32b --- 2024.03.01 --- c++ api documentaion by doxygen