Fawkes API
Fawkes Development Version
|
00001 00002 /*************************************************************************** 00003 * tolua_generator.cpp - ToLua++ Interface generator 00004 * 00005 * Created: Tue Mar 11 15:33:26 2006 00006 * Copyright 2006-2008 Tim Niemueller [www.niemueller.de] 00007 * 00008 ****************************************************************************/ 00009 00010 /* This program is free software; you can redistribute it and/or modify 00011 * it under the terms of the GNU General Public License as published by 00012 * the Free Software Foundation; either version 2 of the License, or 00013 * (at your option) any later version. 00014 * 00015 * This program is distributed in the hope that it will be useful, 00016 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00018 * GNU Library General Public License for more details. 00019 * 00020 * Read the full text in the LICENSE.GPL file in the doc directory. 00021 */ 00022 00023 #include "tolua_generator.h" 00024 #include "exceptions.h" 00025 00026 #include <utils/misc/string_conversions.h> 00027 00028 #include <algorithm> 00029 #include <iostream> 00030 #include <vector> 00031 #include <time.h> 00032 #include <fstream> 00033 00034 using namespace std; 00035 00036 00037 /** @class ToLuaInterfaceGenerator <interfaces/generator/tolua_generator.h> 00038 * Generator that transforms input from the InterfaceParser into valid 00039 * ToLua++ package file. 00040 * @author Tim Niemueller 00041 */ 00042 00043 /** Constructor. 00044 * @param directory Directory where to create the files 00045 * @param interface_name name of the interface, should end with Interface 00046 * @param config_basename basename of the config without suffix 00047 * @param author author of interface 00048 * @param year year of copyright 00049 * @param creation_date user-supplied creation date of interface 00050 * @param data_comment comment in data block. 00051 * @param hash MD5 hash of the config file that was used to generate the interface 00052 * @param hash_size size in bytes of hash 00053 * @param constants constants 00054 * @param enum_constants constants defined as an enum 00055 * @param data_fields data fields of the interface 00056 * @param pseudo_maps pseudo maps of the interface 00057 * @param messages messages defined in the interface 00058 */ 00059 ToLuaInterfaceGenerator::ToLuaInterfaceGenerator(std::string directory, std::string interface_name, 00060 std::string config_basename, std::string author, 00061 std::string year, std::string creation_date, 00062 std::string data_comment, 00063 const unsigned char *hash, size_t hash_size, 00064 const std::vector<InterfaceConstant> &constants, 00065 const std::vector<InterfaceEnumConstant> &enum_constants, 00066 const std::vector<InterfaceField> &data_fields, 00067 const std::vector<InterfacePseudoMap> &pseudo_maps, 00068 const std::vector<InterfaceMessage> &messages 00069 ) 00070 { 00071 this->dir = directory; 00072 if ( dir.find_last_of("/") != (dir.length() - 1) ) { 00073 dir += "/"; 00074 } 00075 this->author = author; 00076 this->year = year; 00077 this->creation_date = creation_date; 00078 this->data_comment = data_comment; 00079 this->hash = hash; 00080 this->hash_size = hash_size; 00081 this->constants = constants; 00082 this->enum_constants = enum_constants; 00083 this->data_fields = data_fields; 00084 this->pseudo_maps = pseudo_maps; 00085 this->messages = messages; 00086 00087 filename_tolua = config_basename + ".tolua"; 00088 filename_h = config_basename + ".h"; 00089 00090 if ( interface_name.find("Interface", 0) == string::npos ) { 00091 // append Interface 00092 class_name = interface_name + "Interface"; 00093 } else { 00094 class_name = interface_name; 00095 } 00096 } 00097 00098 00099 /** Destructor */ 00100 ToLuaInterfaceGenerator::~ToLuaInterfaceGenerator() 00101 { 00102 } 00103 00104 00105 /** Convert C type to Lua type. 00106 * tolua++ does not deal well with stdint types, therefore we convert them 00107 * to "traditional" types. 00108 * @param c_type C type to convert 00109 * @return constant string of the Lua compatible type 00110 */ 00111 const char * 00112 ToLuaInterfaceGenerator::convert_type(std::string c_type) 00113 { 00114 if (c_type == "uint8_t") { 00115 return "unsigned char"; 00116 } else if (c_type == "uint16_t") { 00117 return "unsigned short"; 00118 } else if (c_type == "uint32_t") { 00119 return "unsigned int"; 00120 } else if (c_type == "uint64_t") { 00121 #if __WORDSIZE == 64 00122 return "unsigned long"; 00123 #else 00124 return "unsigned long long"; 00125 #endif 00126 } else if (c_type == "int8_t") { 00127 return "char"; 00128 } else if (c_type == "int16_t") { 00129 return "short"; 00130 } else if (c_type == "int32_t") { 00131 return "int"; 00132 } else if (c_type == "int64_t") { 00133 #if __WORDSIZE == 64 00134 return "long"; 00135 #else 00136 return "long long"; 00137 #endif 00138 } else if (c_type == "uint8_t *") { 00139 return "unsigned char *"; 00140 } else if (c_type == "uint16_t *") { 00141 return "unsigned short *"; 00142 } else if (c_type == "uint32_t *") { 00143 return "unsigned int *"; 00144 } else if (c_type == "uint64_t *") { 00145 #if __WORDSIZE == 64 00146 return "unsigned long *"; 00147 #else 00148 return "unsigned long long *"; 00149 #endif 00150 } else if (c_type == "int8_t *") { 00151 return "char *"; 00152 } else if (c_type == "int16_t *") { 00153 return "short *"; 00154 } else if (c_type == "int32_t *") { 00155 return "int *"; 00156 } else if (c_type == "int64_t *") { 00157 #if __WORDSIZE == 64 00158 return "long *"; 00159 #else 00160 return "long long *"; 00161 #endif 00162 } else { 00163 return c_type.c_str(); 00164 } 00165 } 00166 00167 00168 00169 /** Write header to file. 00170 * @param f file to write to 00171 * @param filename name of file 00172 */ 00173 void 00174 ToLuaInterfaceGenerator::write_header(FILE *f, std::string filename) 00175 { 00176 fprintf(f, "\n/***************************************************************************\n"); 00177 fprintf(f, " * %s - Fawkes BlackBoard Interface - %s - tolua++ wrapper\n", filename.c_str(), class_name.c_str()); 00178 fprintf(f, " *\n"); 00179 if ( creation_date.length() > 0 ) { 00180 fprintf(f, " * Interface created: %s\n", creation_date.c_str()); 00181 } 00182 fprintf(f, " * Templated created: Thu Oct 12 10:49:19 2006\n"); 00183 fprintf(f, " * Copyright %s %s\n", year.c_str(), 00184 ((author.length() > 0) ? author.c_str() : "AllemaniACs RoboCup Team") ); 00185 fprintf(f, " *\n"); 00186 fprintf(f, " ****************************************************************************/\n\n"); 00187 fprintf(f, "/*\n"); 00188 fprintf(f, " * This program is free software; you can redistribute it and/or modify\n"); 00189 fprintf(f, " * it under the terms of the GNU General Public License as published by\n"); 00190 fprintf(f, " * the Free Software Foundation; either version 2 of the License, or\n"); 00191 fprintf(f, " * (at your option) any later version.\n"); 00192 fprintf(f, " *\n"); 00193 fprintf(f, " * This program is distributed in the hope that it will be useful,\n"); 00194 fprintf(f, " * but WITHOUT ANY WARRANTY; without even the implied warranty of\n"); 00195 fprintf(f, " * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"); 00196 fprintf(f, " * GNU Library General Public License for more details.\n"); 00197 fprintf(f, " *\n"); 00198 fprintf(f, " * You should have received a copy of the GNU General Public License\n"); 00199 fprintf(f, " * along with this program; if not, write to the Free Software Foundation,\n"); 00200 fprintf(f, " * Inc., 51 Franklin Street, Fifth floor, Boston, MA 02111-1307, USA.\n"); 00201 fprintf(f, " */\n\n"); 00202 } 00203 00204 00205 /** Write constants to h file 00206 * @param f file to write to 00207 */ 00208 void 00209 ToLuaInterfaceGenerator::write_constants_h(FILE *f) 00210 { 00211 for ( vector<InterfaceConstant>::iterator i = constants.begin(); i != constants.end(); ++i) { 00212 fprintf(f, " static const %s %s;\n", convert_type(i->getType()), 00213 i->getName().c_str()); 00214 } 00215 fprintf(f, "\n"); 00216 00217 for ( vector<InterfaceEnumConstant>::iterator i = enum_constants.begin(); i != enum_constants.end(); ++i) { 00218 fprintf(f, " typedef enum {\n"); 00219 vector< pair<string,string> > items = (*i).getItems(); 00220 vector< pair<string,string> >::iterator j = items.begin(); 00221 while (j != items.end()) { 00222 fprintf(f, " %s", (*j).first.c_str()); 00223 ++j; 00224 if ( j != items.end() ) { 00225 fprintf(f, ",\n"); 00226 } else { 00227 fprintf(f, "\n"); 00228 } 00229 } 00230 fprintf(f, " } %s;\n\n", (*i).getName().c_str()); 00231 } 00232 } 00233 00234 00235 /** Write messages to h file. 00236 * @param f file to write to 00237 */ 00238 void 00239 ToLuaInterfaceGenerator::write_messages_h(FILE *f) 00240 { 00241 for (vector<InterfaceMessage>::iterator i = messages.begin(); i != messages.end(); ++i) { 00242 fprintf(f, " class %s : public Message\n" 00243 " {\n", (*i).getName().c_str()); 00244 write_message_ctor_dtor_h(f, " ", (*i).getName(), (*i).getFields()); 00245 write_methods_h(f, " ", (*i).getFields()); 00246 00247 fprintf(f, " };\n\n"); 00248 } 00249 00250 } 00251 00252 00253 /** Write constructor and destructor to h file. 00254 * @param f file to write to 00255 * @param is indentation space 00256 * @param classname name of class 00257 */ 00258 void 00259 ToLuaInterfaceGenerator::write_ctor_dtor_h(FILE *f, std::string /* indent space */ is, 00260 std::string classname) 00261 { 00262 fprintf(f, 00263 "%s%s();\n" 00264 "%s~%s();\n\n", 00265 is.c_str(), classname.c_str(), 00266 is.c_str(), classname.c_str()); 00267 } 00268 00269 00270 /** Write constructor and destructor for message to h file. 00271 * @param f file to write to 00272 * @param is indentation space 00273 * @param classname name of class 00274 * @param fields vector of data fields of message 00275 */ 00276 void 00277 ToLuaInterfaceGenerator::write_message_ctor_dtor_h(FILE *f, std::string /* indent space */ is, 00278 std::string classname, 00279 std::vector<InterfaceField> fields) 00280 { 00281 vector<InterfaceField>::iterator i; 00282 00283 if ( fields.size() > 0 ) { 00284 00285 fprintf(f, "%s%s(", is.c_str(), classname.c_str()); 00286 00287 i = fields.begin(); 00288 while (i != fields.end()) { 00289 fprintf(f, "%s ini_%s", 00290 convert_type(i->getAccessType()), i->getName().c_str()); 00291 ++i; 00292 if ( i != fields.end() ) { 00293 fprintf(f, ", "); 00294 } 00295 } 00296 00297 fprintf(f, ");\n"); 00298 } 00299 00300 00301 write_ctor_dtor_h(f, is, classname); 00302 } 00303 00304 /** Write superclass methods. 00305 * @param f file to write to 00306 */ 00307 void 00308 ToLuaInterfaceGenerator::write_superclass_h(FILE *f) 00309 { 00310 fprintf(f, 00311 " bool oftype(const char *interface_type) const;\n" 00312 " const void * datachunk() const;\n" 00313 " unsigned int datasize() const;\n" 00314 " const char * type() const;\n" 00315 " const char * id() const;\n" 00316 " const char * uid() const;\n" 00317 " unsigned int serial() const;\n" 00318 " unsigned int mem_serial() const;\n" 00319 " bool operator== (Interface &comp) const;\n" 00320 " const unsigned char * hash() const;\n" 00321 " int hash_size() const;\n" 00322 " const char * hash_printable() const;\n" 00323 " bool is_writer() const;\n" 00324 00325 " void set_from_chunk(void *chunk);\n" 00326 00327 " virtual Message * create_message(const char *type) const = 0;\n" 00328 00329 " void read();\n" 00330 " void write();\n" 00331 00332 " bool has_writer() const;\n" 00333 " unsigned int num_readers() const;\n" 00334 00335 00336 " unsigned int msgq_enqueue_copy(Message *message);\n" 00337 " void msgq_remove(Message *message);\n" 00338 " void msgq_remove(unsigned int message_id);\n" 00339 " unsigned int msgq_size();\n" 00340 " void msgq_flush();\n" 00341 " void msgq_lock();\n" 00342 " bool msgq_try_lock();\n" 00343 " void msgq_unlock();\n" 00344 " void msgq_pop();\n" 00345 " Message * msgq_first();\n" 00346 " bool msgq_empty();\n" 00347 "\n"); 00348 } 00349 00350 /** Write methods to h file. 00351 * @param f file to write to 00352 * @param is indentation space. 00353 * @param fields fields to write accessor methods for. 00354 */ 00355 void 00356 ToLuaInterfaceGenerator::write_methods_h(FILE *f, std::string /* indent space */ is, 00357 std::vector<InterfaceField> fields) 00358 { 00359 for (vector<InterfaceField>::iterator i = fields.begin(); i != fields.end(); ++i) { 00360 00361 if ( (i->getLengthValue() > 0) && (i->getType() != "string" ) ) { 00362 fprintf(f, 00363 "%s%s %s%s(int index);\n", 00364 is.c_str(), 00365 (i->getType() == "byte") ? "unsigned int" : convert_type(i->getPlainAccessType()), 00366 ( ((*i).getType() == "bool" ) ? "is_" : ""), 00367 (*i).getName().c_str()); 00368 00369 fprintf(f, 00370 "%svoid set_%s(unsigned int index, const %s new_%s);\n", 00371 is.c_str(), (*i).getName().c_str(), 00372 convert_type(i->getPlainAccessType()), i->getName().c_str()); 00373 } else { 00374 fprintf(f, 00375 "%s%s %s%s();\n", 00376 is.c_str(), convert_type(i->getAccessType()), 00377 ( ((*i).getType() == "bool" ) ? "is_" : ""), 00378 (*i).getName().c_str()); 00379 00380 fprintf(f, 00381 "%svoid set_%s(const %s new_%s);\n", 00382 is.c_str(), (*i).getName().c_str(), 00383 convert_type(i->getAccessType()), i->getName().c_str()); 00384 } 00385 fprintf(f, 00386 "%sint maxlenof_%s() const;\n", 00387 is.c_str(), (*i).getName().c_str() 00388 ); 00389 } 00390 } 00391 00392 00393 /** Write methods to h file. 00394 * @param f file to write to 00395 * @param is indentation space. 00396 * @param fields fields to write accessor methods for. 00397 * @param pseudo_maps pseudo maps 00398 */ 00399 void 00400 ToLuaInterfaceGenerator::write_methods_h(FILE *f, std::string /* indent space */ is, 00401 std::vector<InterfaceField> fields, 00402 std::vector<InterfacePseudoMap> pseudo_maps) 00403 { 00404 write_methods_h(f, is, fields); 00405 00406 for (vector<InterfacePseudoMap>::iterator i = pseudo_maps.begin(); i != pseudo_maps.end(); ++i) { 00407 fprintf(f, 00408 "%s%s %s(%s key) const;\n" 00409 "%svoid set_%s(const %s key, const %s new_value);\n", 00410 is.c_str(), convert_type(i->getType()), 00411 (*i).getName().c_str(), convert_type(i->getKeyType()), 00412 is.c_str(), (*i).getName().c_str(), 00413 convert_type(i->getKeyType()), convert_type(i->getType())); 00414 } 00415 } 00416 00417 00418 /** Write h file. 00419 * @param f file to write to 00420 */ 00421 void 00422 ToLuaInterfaceGenerator::write_toluaf(FILE *f) 00423 { 00424 fprintf(f, 00425 "$#include <interfaces/%s>\n" 00426 "$using namespace fawkes;\n" 00427 "namespace fawkes {\n" 00428 "class %s : public Interface\n" 00429 "{\n", 00430 filename_h.c_str(), 00431 class_name.c_str()); 00432 00433 write_constants_h(f); 00434 write_messages_h(f); 00435 //write_ctor_dtor_h(f, " ", class_name); 00436 write_methods_h(f, " ", data_fields, pseudo_maps); 00437 write_superclass_h(f); 00438 fprintf(f, "\n};\n\n}\n"); 00439 } 00440 00441 00442 /** Generator cpp and h files. 00443 */ 00444 void 00445 ToLuaInterfaceGenerator::generate() 00446 { 00447 char timestring[26]; // 26 is mentioned in man asctime_r 00448 struct tm timestruct; 00449 time_t t = time(NULL); 00450 localtime_r(&t, ×truct); 00451 asctime_r(×truct, timestring); 00452 gendate = timestring; 00453 00454 FILE *toluaf; 00455 00456 toluaf = fopen(string(dir + filename_tolua).c_str(), "w"); 00457 00458 if ( toluaf == NULL ) { 00459 printf("Cannot open tolua file %s%s\n", dir.c_str(), filename_tolua.c_str()); 00460 } 00461 00462 write_toluaf(toluaf); 00463 00464 fclose(toluaf); 00465 }