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) 2010, 2023, 2024 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 << "rti2code: 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 << "rti2code: 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 << "rti2cocde: 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 << "rti2code: function registration: " << fname << ": cannot interpret signature "
252  << sigi.Name() << std::endl;
253  cparams.resize(i);
254  break;
255  }
256  }
257  // Report
258  std::cout << "rti2code: 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 << " using Function::operator=;" << std::endl;
268  rtiheader << rtiname << "(const FunctionDefinition* fdef) : Function(fdef) {};" << std::endl;
269  rtiheader << "virtual Function* New(void) const { return new " << rtiname << "(pFuncDef); };" << std::endl;
270  rtiheader << "protected:" << std::endl;
271  // Produce c code: function class: have typed param
272  for(unsigned int i=0; i<cparams.size(); i++)
273  for(unsigned int j=0; j<cparams.at(i).size(); j++)
274  rtiheader << cparams.at(i).at(j) << "* " << "mP_" << i << "_" << j << ";" << std::endl;
275  // Produce c code: function class: do type check
276  rtiheader << "virtual bool DoTypeCheck(int n) {" << std::endl;
277  rtiheader << " bool res=false;" << std::endl;
278  rtiheader << " switch(mVariantIndex) { "<< std::endl;
279  for(unsigned int i=0; i<cparams.size(); i++) {
280  rtiheader << " case " << i << ": { // variant " << fdef->Variant(i).Name() << std::endl;
281  rtiheader << " switch(n) { "<< std::endl;
282  for(unsigned int j=0; j<cparams.at(i).size(); j++) {
283  rtiheader << " case " << j << ": ";
284  rtiheader << " res=DoTypeCast<" << cparams.at(i).at(j) << ">(" << j << ", mP_" << i <<"_" << j << "); ";
285  rtiheader << "break; "<< std::endl;
286  }
287  rtiheader << " default: break; " << std::endl;
288  rtiheader << " } "<< std::endl;
289  rtiheader << " break; "<< std::endl;
290  rtiheader << " } "<< std::endl;
291  }
292  rtiheader << " default: break; " << std::endl;
293  rtiheader << " } "<< std::endl;
294  rtiheader << " return res;" << std::endl;
295  rtiheader << "};" << std::endl;
296  // Produce c code: function class: do execute
297  rtiheader << "virtual void DoExecute(void) {" << std::endl;
298  // Produce c code: do execute: switch variant
299  rtiheader << " switch(mVariantIndex) { "<< std::endl;
300  for(unsigned int i=0; i<cparams.size(); i++) {
301  rtiheader << " case " << i << ": { // variant " << fdef->Variant(i).Name() << std::endl;
302  rtiheader << " ";
303  // Figure return value (if any)
304  for(unsigned int j=0; j<cparams.at(i).size(); j++) {
305  if(!cretval.at(i).at(j)) continue;
306  // Special case: integer
307  if(cparams.at(i).at(j) == "Integer") {
308  rtiheader << "*(mP_" << i << "_" << j << "->CReference()) = ";
309  } else
310  // Special case: boolean
311  if(cparams.at(i).at(j) == "Boolean") {
312  rtiheader << "*(mP_" << i << "_" << j << "->CReference()) = ";
313  } else
314  // Special case: integer
315  if(cparams.at(i).at(j) == "String") {
316  rtiheader << "*(mP_" << i << "_" << j << "->CReference()) = ";
317  } else
318  // Std case
319  rtiheader << "*mP_" << i << "_" << j << " = ";
320  }
321  // Function name
322  rtiheader << ctype <<"(";
323  // Parameters
324  int parpos=0;
325  for(unsigned int j=0; j<cparams.at(i).size(); j++) {
326  if(cretval.at(i).at(j)) continue;
327  if((parpos++)!=0) rtiheader << " ,";
328  // Special case: integer
329  if(cparams.at(i).at(j) == "Integer") {
330  rtiheader << "*(mP_" << i << "_" << j << "->CReference())";
331  } else
332  // Special case: boolean
333  if(cparams.at(i).at(j) == "Boolean") {
334  rtiheader << "*(mP_" << i << "_" << j << "->CReference())";
335  } else
336  // Special case: integer
337  if(cparams.at(i).at(j) == "String") {
338  rtiheader << "*(mP_" << i << "_" << j << "->CReference())";
339  } else
340  // Std case
341  rtiheader << "*mP_" << i << "_" << j;
342  }
343  rtiheader << "); break; };" << std::endl;
344  }
345  // Produce c code: switch variant; done
346  rtiheader << " default: break; " << std::endl;
347  rtiheader << " }; "<< std::endl;
348  // Produce c code: do execute: done
349  rtiheader << "}; "<< std::endl;
350  // Produce c code: function class: done
351  rtiheader << "};" << std::endl;
352 
353  // Produce swig code: lua function definition(s)
354  luaheader << "/* faudes-function \"" << fname << "\" */" << std::endl;
355  // Figure my plugin to insert a conditional
356  if(!flat) {
357  std::string plugin=fdef->PlugIn();
358  luaheader << "#if " << "( SwigModule == \"Swig" << plugin << "\")";
359  //luaheader << " || ( SwigModule == \"SwigLibFaudes\")"; // requires SWIG 4.1
360  luaheader << std::endl;
361  }
362  // Use C-type function name
363  if(ctype!=fname)
364  luaheader << "%rename(" << fname << ") " << ctype << ";" << std::endl;
365 
366  // Prepare swig code: preprocessed array
367  std::vector< std::string > lfdefs;
368  std::vector< std::string > lrtypes;
369  std::vector< std::string > lhelp;
370  // Prepare swig code: generate per signature
371  for(unsigned int i=0; i<cparams.size(); i++) {
372  // Create ctype function declaration: return value
373  std::string lrtype="void";
374  for(unsigned int j=0; j<cparams.at(i).size(); j++) {
375  if(!cretval.at(i).at(j)) continue;
376  // Special case: integer
377  if(cparams.at(i).at(j) == "Integer") {
378  lrtype="long int";
379  } else
380  // Special case: boolean
381  if(cparams.at(i).at(j) == "Boolean") {
382  lrtype="bool";
383  } else
384  // Special case: string
385  if(cparams.at(i).at(j) == "String") {
386  lrtype="std::string";
387  } else
388  // Std case ctype as refernce
389  lrtype = cparams.at(i).at(j);
390  // No more than one return value
391  break;
392  }
393  lrtypes.push_back(lrtype);
394  // Create ctype function declaration: function body
395  std::string lfdef = ctype + "(";
396  // Create ctype function declaration: parameters
397  int parpos=0;
398  for(unsigned int j=0; j<cparams.at(i).size(); j++) {
399  if(cretval.at(i).at(j)) continue;
400  if((parpos++)!=0) lfdef += ", ";
401  // Have const for +In+
402  if(cattrib.at(i).at(j)==Parameter::In)
403  lfdef += "const ";
404  // Special case: integer
405  if(cparams.at(i).at(j) == "Integer") {
406  lfdef += "long int&";
407  } else
408  // Special case: boolean
409  if(cparams.at(i).at(j) == "Boolean") {
410  lfdef += "bool&";
411  } else
412  // Special case: string
413  if(cparams.at(i).at(j) == "String") {
414  lfdef += "std::string&";
415  } else
416  // Std case ctype as refernce
417  lfdef += cparams.at(i).at(j) + "&";
418  // Mark elementary outputs
419  if(cparams.at(i).at(j) == "Boolean" || cparams.at(i).at(j) == "String"
420  || cparams.at(i).at(j) == "Integer")
421  if(cattrib.at(i).at(j)==Parameter::Out)
422  lfdef += " OUTPUT";
423  }
424  // End of function declaration
425  lfdef += ")";
426  lfdefs.push_back(lfdef);
427  // Add help entry: build nice signature
428  std::string luasig = " " + fname + "(";
429  bool leftcomma = false;
430  bool rightcomma = false;
431  for(unsigned int j=0; j<cparams.at(i).size(); j++) {
432  // Special case: elementary output
433  if(cparams.at(i).at(j) == "Boolean" || cparams.at(i).at(j) == "String"
434  || cparams.at(i).at(j) == "Integer")
435  if(cattrib.at(i).at(j)==Parameter::Out) {
436  if(leftcomma) luasig = "," + luasig;
437  // if(leftcomma) luasig = ", " + luasig; // need tab in help system?
438  luasig=cparams.at(i).at(j) + luasig;
439  leftcomma=true;
440  continue;
441  }
442  // Std case
443  if(rightcomma) luasig += ", ";
444  const Signature& sigi=fdef->Variant(i);
445  luasig += sigi.At(j).Str();
446  rightcomma=true;
447  }
448  luasig+=")";
449  // Add help entry: add with topic
450  if(fdef->TextDoc()!=""){
451  std::string topic= fdef->PlugIn();
452  std::string key1=fdef->KeywordAt(1);
453  if(topic=="CoreFaudes") {
454  topic=fdef->KeywordAt(1);
455  key1=fdef->KeywordAt(2);
456  }
457  if(topic.length()>0) topic.at(0)=toupper(topic.at(0));
458  if(key1.length()>0) key1.at(0)=toupper(key1.at(0));
459  lhelp.push_back("SwigHelpEntry(\"" + topic + "\", \"" + key1 + "\", \"" +
460  luasig + "\")");
461  } else {
462  lhelp.push_back("");
463  }
464  }
465  // Filter pseudo doublets (only differ in lrtype)
466  for(unsigned int i=1; i<lfdefs.size();i++) {
467  unsigned int j;
468  for(j=0; j<i; j++)
469  if(lfdefs.at(i)==lfdefs.at(j)) break;
470  if(j==i) continue;
471  // Invalidate entry?
472  if(lrtypes.at(j)=="void")
473  {lfdefs[j]=""; continue;}
474  if(lrtypes.at(i)=="void")
475  {lfdefs[i]=""; continue;}
476  } // Done: prepare per signature
477 
478  // Generate swig definitions: write
479  int lcount=0;
480  for(unsigned int i=0; i<lfdefs.size(); i++) {
481  if(lfdefs.at(i)=="") continue;
482  luaheader << lrtypes.at(i) << " " << lfdefs.at(i) << ";" << std::endl;
483  lcount++;
484  if(lhelp.at(i)=="") continue;
485  luaheader << lhelp.at(i) << ";" << std::endl;
486  }
487  std::cout << "rti2code: generating swig interface for function \"" << fdef->Name() << "\"" <<
488  " #" << lcount << " variants" << std::endl;
489 
490  // End all signatures, incl conditional
491  if(!flat) {
492  luaheader << "#endif " << std::endl;
493  }
494  luaheader << std::endl;
495 
496 
497  } // Loop all functions
498 
499  // C++ class definition: function class: all such done
500  rtiheader << "} // namespace" << std::endl;
501 
502  // C++ class definition: register function prototypes: done
503  rticode << "}" << std::endl;
504  rticode << "} // namespace" << std::endl;
505 
506  return(0);
507 }
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:505
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:54
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_utils.cpp:131
std::string PluginsString()
Return FAUDES_PLUGINS as std::string.
Definition: cfl_utils.cpp:136
std::string ToStringInteger(Int number)
integer to string
Definition: cfl_utils.cpp:43
int main(int argc, char *argv[])
Definition: rti2code.cpp:60
void Usage(const std::string &rMessage="")
Definition: rti2code.cpp:35

libFAUDES 2.32f --- 2024.12.22 --- c++ api documentaion by doxygen