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) 2009 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 luabindings interface code." << std::endl;
46  std::cerr << std::endl;
47  std::cerr << "usage:" << std::endl;
48  std::cerr << " rti2code <rti input file> <output basename>" << std::endl;
49  std::cerr << " rti2code -merge <rti input files> <output rti-file>" << std::endl;
50  exit(1);
51 }
52 
53 
54 // ******************************************************************
55 // main programm
56 // ******************************************************************
57 
58 int main(int argc, char *argv[]) {
59 
60  // Min args
61  if(argc < 3) Usage();
62 
63  // Merge mode
64  if(std::string(argv[1])=="-merge") {
65  // Bail out
66  if(argc < 4) Usage();
67  // Load from files
68  for(int i=2; i< argc-1; i++) {
69  TypeRegistry::G()->MergeDocumentation(std::string(argv[i]));
70  FunctionRegistry::G()->MergeDocumentation(std::string(argv[i]));
71  }
72  // Dump
73  if(std::string(argv[argc-1]) != "-") {
74  SaveRegistry(std::string(argv[argc-1]));
75  } else {
76  SaveRegistry();
77  }
78  return 0;
79  }
80 
81  // Std mode: generate code
82  if(argc != 3) Usage();
83 
84  // Load registry file
85  LoadRegistry(argv[1]);
86 
87  // Code output streams
88  std::ofstream rtiheader;
89  rtiheader.open((std::string(argv[argc-1])+".h").c_str(), std::ios::out);
90  std::ofstream rticode;
91  rticode.open((std::string(argv[argc-1])+".cpp").c_str(), std::ios::out);
92  std::ofstream luaheader;
93  luaheader.open((std::string(argv[argc-1])+".i").c_str(), std::ios::out);
94 
95  // Introduce myself
96  rtiheader << "/* rti2code: autogenerated libFAUDES rti registration: ";
97  rtiheader << VersionString() << " " << PluginsString() << " */" << std::endl << std::endl;
98  rticode << "/* rti2code: autogenerated libFAUDES rti registration: ";
99  rticode << VersionString() << " " << PluginsString() << " */" << std::endl << std::endl;
100  luaheader << "/* rti2code: autogenerated libFAUDES luabindings declarations: ";
101  luaheader << VersionString() << " " << PluginsString() << " */" << std::endl << std::endl;
102 
103  // C++ static objects: auto load types
104  rticode << "namespace faudes {" << std::endl;
105  rticode << "/* Auto-register faudes types */" << std::endl;
106 
107  // Traverse type registry to figure faudes types
109  int tcnt;
110  for(tit=TypeRegistry::G()->Begin(), tcnt=1; tit!=TypeRegistry::G()->End();tit++,tcnt++) {
111  // Get c/f type
112  std::string ctype=tit->second->CType();
113  std::string ftype=tit->second->Name();
114  // Bail out if no C type specified
115  if(ctype=="") continue;
116  // Remove name space faudes
117  size_t pos=ctype.find("faudes::");
118  if(pos!=std::string::npos)
119  ctype=ctype.substr(std::string("faudes::").length());
120  // Bail out no auto-registration specified
121  if(!tit->second->AutoRegistered()) continue;
122  // report
123  std::cout << "Generating auto-registration code for \"" << ftype << "\"" << std::endl;
124  // Produce c code
125  std::string rtiname = std::string("gRti") + ToStringInteger(tcnt) + "Register" + ftype;
126  rticode << "AutoRegisterType<" << ctype << "> " << rtiname << "(\"" << ftype <<"\");";
127  rticode << std::endl;
128  // Extra data set: element tag
129  if(tit->second->XElementTag()!="") {
130  rtiname = std::string("gRti") + ToStringInteger(tcnt) + "XElementTag" + ftype;
131  rticode << "AutoRegisterXElementTag<" << ctype << "> " << rtiname << "(\"" << ftype <<
132  "\", \"" << tit->second->XElementTag() << "\");";
133  rticode << std::endl;
134  }
135  }
136 
137  // C++ static objects: auto load types end
138  rticode << "} // namespace" << std::endl;
139 
140  // C++ function declaration: load types
141  rtiheader << "namespace faudes {" << std::endl;
142  rtiheader << "void LoadRegisteredTypes(void);" << std::endl;
143  rtiheader << "} // namespace" << std::endl;
144 
145  // C++ function definition: load types
146  rticode << "namespace faudes {" << std::endl;
147  rticode << "/* Register faudes types */" << std::endl;
148  rticode << "void LoadRegisteredTypes(void) {" << std::endl;
149 
150  // Traverse type registry to figure faudes types
151  for(tit=TypeRegistry::G()->Begin(); tit!=TypeRegistry::G()->End();tit++) {
152  // Get C type
153  std::string ctype=tit->second->CType();
154  // Bail out if no c type specified
155  if(ctype=="") continue;
156  // Remove name space faudes
157  size_t pos=ctype.find("faudes::");
158  if(pos!=std::string::npos)
159  ctype=ctype.substr(std::string("faudes::").length());
160  // Report
161  std::cout << "Generating registration code for \"" << tit->second->Name() << "\"" << std::endl;
162  // Produce c code
163  rticode << " TypeRegistry::G()->Insert<" << ctype << ">(\"" << tit->second->Name() <<"\");";
164  rticode << std::endl;
165  }
166 
167  // C++ function definition: load types end
168  rticode << "}" << std::endl;
169  rticode << "} // namespace" << std::endl;
170 
171 
172  // C++ function declaration: load functions
173  rtiheader << "namespace faudes {" << std::endl;
174  rtiheader << "void LoadRegisteredFunctions(void);" << std::endl;
175  rtiheader << "} // namespace" << std::endl;
176 
177  // C++ function definition: load functions
178  rticode << "namespace faudes {" << std::endl;
179  rticode << "/* Register faudes functions */" << std::endl;
180  rticode << "void LoadRegisteredFunctions(void) {" << std::endl;
181 
182  // C++ class definition: Function derivates
183  rtiheader << "namespace faudes {" << std::endl;
184 
185  // Traverse function registry: define rti functions
186  int fcnt=0;
188  for(fit=FunctionRegistry::G()->Begin(); fit!=FunctionRegistry::G()->End();fit++, fcnt++) {
189  // Current function definition
190  const FunctionDefinition* fdef = fit->second;
191  // Get C type and faudes function name
192  std::string ctype=fdef->CType();
193  std::string fname = fdef->Name();
194  // Bail out if no c type specified
195  if(ctype=="") continue;
196  // Remove name space faudes
197  size_t pos=ctype.find("faudes::");
198  if(pos!=std::string::npos)
199  ctype=ctype.substr(std::string("faudes::").length());
200  // Bail out if no signature
201  if(fdef->VariantsSize()==0) {
202  std::cout << "Function registration: " << fname << ": no signatures" << std::endl;
203  continue;
204  }
205  // Interpret signatures: set up type array
206  std::vector< std::vector<std::string> > cparams;
207  std::vector< std::vector<Parameter::ParamAttr> > cattrib;
208  std::vector< std::vector<bool> > cretval;
209  cparams.resize(fdef->VariantsSize());
210  cattrib.resize(fdef->VariantsSize());
211  cretval.resize(fdef->VariantsSize());
212  // Loop all signatures
213  for(int i=0; i<fdef->VariantsSize(); i++) {
214  const Signature& sigi=fdef->Variant(i);
215  int retcount=0;
216  for(int j=0; j<sigi.Size(); j++) {
217  // Retrieve faudes type and attrib
218  std::string ftype=sigi.At(j).Type();
219  Parameter::ParamAttr fattr=sigi.At(j).Attribute();
220  bool fcret=sigi.At(j).CReturn();
221  // Count ret values
222  if(fcret) retcount++;
223  // Bail out on unknown faudestype
224  if(!TypeRegistry::G()->Exists(ftype)) break;
225  // Get corresponding ctype
226  std::string ctype=TypeRegistry::G()->Definition(ftype).CType();
227  // Bail out on unknown ctype
228  if(ctype=="") break;
229  // bail out on non-out ret value
230  if(fcret && !(fattr==Parameter::Out)) break;
231  // Bail out on undef attribute
232  if(fattr==Parameter::UnDef) break;
233  // Bail out on more than one ret values
234  if(retcount>1) break;
235  // Remove name space faudes
236  size_t pos=ctype.find("faudes::");
237  if(pos!=std::string::npos)
238  ctype=ctype.substr(std::string("faudes::").length());
239  // Param ok
240  cparams.at(i).push_back(ctype);
241  cattrib.at(i).push_back(fattr);
242  cretval.at(i).push_back(fcret);
243  }
244  // Test for signature error
245  if((int) cparams.at(i).size()!=sigi.Size()) {
246  std::cout << "Function registration: " << fname << ": cannot interpret signature "
247  << sigi.Name() << std::endl;
248  cparams.resize(i);
249  break;
250  }
251  }
252  // Report
253  std::cout << "Generating rti wrapper for \"" << fdef->Name() << "\"" <<
254  " #" << cparams.size() << " variants" << std::endl;
255  // Produce c code: register all functions function
256  std::string rtiname = std::string("Rti") + ToStringInteger(fcnt) + ctype;
257  rticode << " FunctionRegistry::G()->Insert<" << rtiname << ">(\"" << fname <<"\");" << std::endl;
258  // Produce c code: class declaration intro
259  rtiheader << "/* Function class for C++ function " << ctype << "*/" << std::endl;
260  rtiheader << "class " << rtiname << " : public Function { " << std::endl;
261  rtiheader << "public:" << std::endl;
262  rtiheader << rtiname << "(const FunctionDefinition* fdef) : Function(fdef) {};" << std::endl;
263  rtiheader << "virtual Function* New(void) const { return new " << rtiname << "(pFuncDef); };" << std::endl;
264  rtiheader << "protected:" << std::endl;
265  // Produce c code: function class: have typed param
266  for(unsigned int i=0; i<cparams.size(); i++)
267  for(unsigned int j=0; j<cparams.at(i).size(); j++)
268  rtiheader << cparams.at(i).at(j) << "* " << "mP_" << i << "_" << j << ";" << std::endl;
269  // Produce c code: function class: do type check
270  rtiheader << "virtual bool DoTypeCheck(int n) {" << std::endl;
271  rtiheader << " bool res=false;" << std::endl;
272  rtiheader << " switch(mVariantIndex) { "<< std::endl;
273  for(unsigned int i=0; i<cparams.size(); i++) {
274  rtiheader << " case " << i << ": { // variant " << fdef->Variant(i).Name() << std::endl;
275  rtiheader << " switch(n) { "<< std::endl;
276  for(unsigned int j=0; j<cparams.at(i).size(); j++) {
277  rtiheader << " case " << j << ": ";
278  rtiheader << " res=DoTypeCast<" << cparams.at(i).at(j) << ">(" << j << ", mP_" << i <<"_" << j << "); ";
279  rtiheader << "break; "<< std::endl;
280  }
281  rtiheader << " default: break; " << std::endl;
282  rtiheader << " } "<< std::endl;
283  rtiheader << " break; "<< std::endl;
284  rtiheader << " } "<< std::endl;
285  }
286  rtiheader << " default: break; " << std::endl;
287  rtiheader << " } "<< std::endl;
288  rtiheader << " return res;" << std::endl;
289  rtiheader << "};" << std::endl;
290  // Produce c code: function class: do execute
291  rtiheader << "virtual void DoExecute(void) {" << std::endl;
292  // Produce c code: do execute: switch variant
293  rtiheader << " switch(mVariantIndex) { "<< std::endl;
294  for(unsigned int i=0; i<cparams.size(); i++) {
295  rtiheader << " case " << i << ": { // variant " << fdef->Variant(i).Name() << std::endl;
296  rtiheader << " ";
297  // Figure return value (if any)
298  for(unsigned int j=0; j<cparams.at(i).size(); j++) {
299  if(!cretval.at(i).at(j)) continue;
300  // Special case: integer
301  if(cparams.at(i).at(j) == "Integer") {
302  rtiheader << "*(mP_" << i << "_" << j << "->CReference()) = ";
303  } else
304  // Special case: boolean
305  if(cparams.at(i).at(j) == "Boolean") {
306  rtiheader << "*(mP_" << i << "_" << j << "->CReference()) = ";
307  } else
308  // Special case: integer
309  if(cparams.at(i).at(j) == "String") {
310  rtiheader << "*(mP_" << i << "_" << j << "->CReference()) = ";
311  } else
312  // Std case
313  rtiheader << "*mP_" << i << "_" << j << " = ";
314  }
315  // Function name
316  rtiheader << ctype <<"(";
317  // Parameters
318  int parpos=0;
319  for(unsigned int j=0; j<cparams.at(i).size(); j++) {
320  if(cretval.at(i).at(j)) continue;
321  if((parpos++)!=0) rtiheader << " ,";
322  // Special case: integer
323  if(cparams.at(i).at(j) == "Integer") {
324  rtiheader << "*(mP_" << i << "_" << j << "->CReference())";
325  } else
326  // Special case: boolean
327  if(cparams.at(i).at(j) == "Boolean") {
328  rtiheader << "*(mP_" << i << "_" << j << "->CReference())";
329  } else
330  // Special case: integer
331  if(cparams.at(i).at(j) == "String") {
332  rtiheader << "*(mP_" << i << "_" << j << "->CReference())";
333  } else
334  // Std case
335  rtiheader << "*mP_" << i << "_" << j;
336  }
337  rtiheader << "); break; };" << std::endl;
338  }
339  // Produce c code: switch variant; done
340  rtiheader << " default: break; " << std::endl;
341  rtiheader << " }; "<< std::endl;
342  // Produce c code: do execute: done
343  rtiheader << "}; "<< std::endl;
344  // Produce c code: function class: done
345  rtiheader << "};" << std::endl;
346 
347  // Produce swig code: lua function definition(s)
348  luaheader << "/* faudes-function \"" << fname << "\" */" << std::endl;
349  // Figure my plugin to insert a conditional
350  std::string plugin=fdef->PlugIn();
351  luaheader << "#if " << "SwigModule == \"Swig" << plugin << "\"" << std::endl;
352  // Use C-type function name
353  if(ctype!=fname)
354  luaheader << "%rename(" << fname << ") " << ctype << ";" << std::endl;
355 
356  // Prepare swig code: preprocessed array
357  std::vector< std::string > lfdefs;
358  std::vector< std::string > lrtypes;
359  std::vector< std::string > lhelp;
360  // Prepare swig code: generate per signature
361  for(unsigned int i=0; i<cparams.size(); i++) {
362  // Create ctype function declaration: return value
363  std::string lrtype="void";
364  for(unsigned int j=0; j<cparams.at(i).size(); j++) {
365  if(!cretval.at(i).at(j)) continue;
366  // Special case: integer
367  if(cparams.at(i).at(j) == "Integer") {
368  lrtype="long int";
369  } else
370  // Special case: boolean
371  if(cparams.at(i).at(j) == "Boolean") {
372  lrtype="bool";
373  } else
374  // Special case: string
375  if(cparams.at(i).at(j) == "String") {
376  lrtype="std::string";
377  } else
378  // Std case ctype as refernce
379  lrtype + cparams.at(i).at(j);
380  // No more than one return value
381  break;
382  }
383  lrtypes.push_back(lrtype);
384  // Create ctype function declaration: function body
385  std::string lfdef = ctype + "(";
386  // Create ctype function declaration: parameters
387  int parpos=0;
388  for(unsigned int j=0; j<cparams.at(i).size(); j++) {
389  if(cretval.at(i).at(j)) continue;
390  if((parpos++)!=0) lfdef += ", ";
391  // Have const for +In+
392  if(cattrib.at(i).at(j)==Parameter::In)
393  lfdef += "const ";
394  // Special case: integer
395  if(cparams.at(i).at(j) == "Integer") {
396  lfdef += "long int&";
397  } else
398  // Special case: boolean
399  if(cparams.at(i).at(j) == "Boolean") {
400  lfdef += "bool&";
401  } else
402  // Special case: string
403  if(cparams.at(i).at(j) == "String") {
404  lfdef += "std::string&";
405  } else
406  // Std case ctype as refernce
407  lfdef += cparams.at(i).at(j) + "&";
408  // Mark elementary outputs
409  if(cparams.at(i).at(j) == "Boolean" || cparams.at(i).at(j) == "String"
410  || cparams.at(i).at(j) == "Integer")
411  if(cattrib.at(i).at(j)==Parameter::Out)
412  lfdef += " OUTPUT";
413  }
414  // End of function declaration
415  lfdef += ")";
416  lfdefs.push_back(lfdef);
417  // Add help entry: build nice signature
418  std::string luasig = " " + fname + "(";
419  bool leftcomma = false;
420  bool rightcomma = false;
421  for(unsigned int j=0; j<cparams.at(i).size(); j++) {
422  // Special case: elementary output
423  if(cparams.at(i).at(j) == "Boolean" || cparams.at(i).at(j) == "String"
424  || cparams.at(i).at(j) == "Integer")
425  if(cattrib.at(i).at(j)==Parameter::Out) {
426  if(leftcomma) luasig = "," + luasig;
427  // if(leftcomma) luasig = ", " + luasig; // need tab in help system?
428  luasig=cparams.at(i).at(j) + luasig;
429  leftcomma=true;
430  continue;
431  }
432  // Std case
433  if(rightcomma) luasig += ", ";
434  const Signature& sigi=fdef->Variant(i);
435  luasig += sigi.At(j).Str();
436  rightcomma=true;
437  }
438  luasig+=")";
439  // Add help entry: add with topic
440  if(fdef->TextDoc()!=""){
441  std::string topic= fdef->PlugIn();
442  std::string key1=fdef->KeywordAt(1);
443  if(topic=="CoreFaudes") {
444  topic=fdef->KeywordAt(1);
445  key1=fdef->KeywordAt(2);
446  }
447  if(topic.length()>0) topic.at(0)=toupper(topic.at(0));
448  if(key1.length()>0) key1.at(0)=toupper(key1.at(0));
449  lhelp.push_back("SwigHelpEntry(\"" + topic + "\", \"" + key1 + "\", \"" +
450  luasig + "\")");
451  } else {
452  lhelp.push_back("");
453  }
454  }
455  // Filter pseudo doublets (only differ in lrtype)
456  for(unsigned int i=1; i<lfdefs.size();i++) {
457  unsigned int j;
458  for(j=0; j<i; j++)
459  if(lfdefs.at(i)==lfdefs.at(j)) break;
460  if(j==i) continue;
461  // Invalidate entry?
462  if(lrtypes.at(j)=="void")
463  {lfdefs[j]=""; continue;}
464  if(lrtypes.at(i)=="void")
465  {lfdefs[i]=""; continue;}
466  } // Done: prepare per signature
467 
468  // Generate swig definitions: write
469  int lcount=0;
470  for(unsigned int i=0; i<lfdefs.size(); i++) {
471  if(lfdefs.at(i)=="") continue;
472  luaheader << lrtypes.at(i) << " " << lfdefs.at(i) << ";" << std::endl;
473  lcount++;
474  if(lhelp.at(i)=="") continue;
475  luaheader << lhelp.at(i) << ";" << std::endl;
476  }
477  std::cout << "Generating swig interface for function \"" << fdef->Name() << "\"" <<
478  " #" << lcount << " variants" << std::endl;
479 
480  // End all signatures, incl conditional
481  luaheader << "#endif " << std::endl;
482  luaheader << std::endl;
483 
484 
485  } // Loop all functions
486 
487  // C++ class definition: function class: all such done
488  rtiheader << "} // namespace" << std::endl;
489 
490  // C++ class definition: register function prototypes: done
491  rticode << "}" << std::endl;
492  rticode << "} // namespace" << std::endl;
493 
494  return(0);
495 }

libFAUDES 2.28a --- 2016.09.13 --- c++ api documentaion by doxygen