218 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			C++
		
	
	
			
		
		
	
	
			218 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			C++
		
	
	
| /**
 | |
|  * file: Module.ccp
 | |
|  * Author: Frank Dellaert
 | |
|  **/
 | |
| 
 | |
| #include <iostream>
 | |
| #include <fstream>
 | |
| 
 | |
| //#define BOOST_SPIRIT_DEBUG
 | |
| #include <boost/spirit/include/classic_core.hpp>
 | |
| #include <boost/foreach.hpp>
 | |
| 
 | |
| #include "Module.h"
 | |
| #include "utilities.h"
 | |
| 
 | |
| using namespace std;
 | |
| using namespace BOOST_SPIRIT_CLASSIC_NS;
 | |
| 
 | |
| typedef rule<BOOST_SPIRIT_CLASSIC_NS::phrase_scanner_t> Rule;
 | |
| 
 | |
| /* ************************************************************************* */
 | |
| // We parse an interface file into a Module object.
 | |
| // The grammar is defined using the boost/spirit combinatorial parser.
 | |
| // For example, str_p("const") parses the string "const", and the >>
 | |
| // operator creates a sequence parser. The grammar below, composed of rules
 | |
| // and with start rule [class_p], doubles as the specs for our interface files.
 | |
| /* ************************************************************************* */
 | |
| 
 | |
| Module::Module(const string& interfacePath,
 | |
| 	       const string& moduleName) : name(moduleName)
 | |
| {
 | |
|   // these variables will be imperatively updated to gradually build [cls]
 | |
|   // The one with postfix 0 are used to reset the variables after parse.
 | |
|   Argument arg0, arg;
 | |
|   ArgumentList args0, args;
 | |
|   Constructor constructor0, constructor;
 | |
|   Method method0, method;
 | |
|   Class cls0,cls;
 | |
| 
 | |
|   //----------------------------------------------------------------------------
 | |
|   // Grammar with actions that build the Class object. Actions are
 | |
|   // defined within the square brackets [] and are executed whenever a
 | |
|   // rule is successfully parsed. Define BOOST_SPIRIT_DEBUG to debug.
 | |
|   // The grammar is allows a very restricted C++ header:
 | |
|   // - No comments allowed.
 | |
|   //  -Only types allowed are string, bool, size_t int, double, Vector, and Matrix
 | |
|   //   as well as class names that start with an uppercase letter
 | |
|   // - The types unsigned int and bool should be specified as int.
 | |
|   // ----------------------------------------------------------------------------
 | |
| 
 | |
|   // lexeme_d turns off white space skipping
 | |
|   // http://www.boost.org/doc/libs/1_37_0/libs/spirit/classic/doc/directives.html
 | |
| 
 | |
|   Rule className_p  = lexeme_d[upper_p >> *(alnum_p | '_')];
 | |
| 
 | |
|   Rule classPtr_p =
 | |
|     className_p     [assign_a(arg.type)] >> 
 | |
|     ch_p('*')       [assign_a(arg.is_ptr,true)];
 | |
| 
 | |
|   Rule classRef_p =
 | |
|     !str_p("const") [assign_a(arg.is_const,true)] >> 
 | |
|     className_p     [assign_a(arg.type)] >> 
 | |
|     ch_p('&')       [assign_a(arg.is_ref,true)];
 | |
| 
 | |
|   Rule basisType_p = 
 | |
|     (str_p("string") | "bool" | "size_t" | "int" | "double");
 | |
| 
 | |
|   Rule ublasType = 
 | |
|     (str_p("Vector") | "Matrix")[assign_a(arg.type)] >>
 | |
|     !ch_p('*')[assign_a(arg.is_ptr,true)];
 | |
| 
 | |
|   Rule name_p = lexeme_d[alpha_p >> *(alnum_p | '_')];
 | |
| 
 | |
|   Rule argument_p = 
 | |
|     ((basisType_p[assign_a(arg.type)] | ublasType | classPtr_p | classRef_p) >> name_p[assign_a(arg.name)])
 | |
|     [push_back_a(args, arg)]
 | |
|     [assign_a(arg,arg0)];
 | |
| 
 | |
|   Rule argumentList_p = !argument_p >> * (',' >> argument_p);
 | |
| 
 | |
|   Rule constructor_p = 
 | |
|     (className_p >> '(' >> argumentList_p >> ')' >> ';')
 | |
|     [assign_a(constructor.args,args)]
 | |
|     [assign_a(args,args0)]
 | |
|     [push_back_a(cls.constructors, constructor)]
 | |
|     [assign_a(constructor,constructor0)];
 | |
| 
 | |
|   Rule returnType1_p =
 | |
|     basisType_p[assign_a(method.returns)] | 
 | |
|     ((className_p | "Vector" | "Matrix")[assign_a(method.returns)] >>
 | |
|      !ch_p('*')  [assign_a(method.returns_ptr,true)]);
 | |
| 
 | |
|   Rule returnType2_p =
 | |
|     basisType_p[assign_a(method.returns2)] | 
 | |
|     ((className_p | "Vector" | "Matrix")[assign_a(method.returns2)] >>
 | |
|      !ch_p('*')  [assign_a(method.returns_ptr2,true)]);
 | |
| 
 | |
|   Rule pair_p = 
 | |
|     (str_p("pair") >> '<' >> returnType1_p >> ',' >> returnType2_p >> '>')
 | |
|     [assign_a(method.returns_pair,true)];
 | |
| 
 | |
|   Rule void_p = str_p("void")[assign_a(method.returns)];
 | |
| 
 | |
|   Rule returnType_p = void_p | returnType1_p | pair_p;
 | |
| 
 | |
|   Rule methodName_p = lexeme_d[lower_p >> *(alnum_p | '_')];
 | |
| 
 | |
|   Rule method_p = 
 | |
|     (returnType_p >> methodName_p[assign_a(method.name)] >> 
 | |
|      '(' >> argumentList_p >> ')' >> 
 | |
|      !str_p("const")[assign_a(method.is_const,true)] >> ';')
 | |
|     [assign_a(method.args,args)]
 | |
|     [assign_a(args,args0)]
 | |
|     [push_back_a(cls.methods, method)]
 | |
|     [assign_a(method,method0)];
 | |
| 
 | |
|   Rule class_p = str_p("class") >> className_p[assign_a(cls.name)] >> '{' >> 
 | |
|     *constructor_p >> 
 | |
|     *method_p >> 
 | |
|     '}' >> ";";
 | |
| 
 | |
|   Rule module_p = +class_p
 | |
|     [push_back_a(classes,cls)]
 | |
|     [assign_a(cls,cls0)] 
 | |
|     >> !end_p;
 | |
| 
 | |
|   //----------------------------------------------------------------------------
 | |
|   // for debugging, define BOOST_SPIRIT_DEBUG
 | |
| # ifdef BOOST_SPIRIT_DEBUG
 | |
|   BOOST_SPIRIT_DEBUG_NODE(className_p);
 | |
|   BOOST_SPIRIT_DEBUG_NODE(classPtr_p);
 | |
|   BOOST_SPIRIT_DEBUG_NODE(classRef_p);
 | |
|   BOOST_SPIRIT_DEBUG_NODE(basisType_p);
 | |
|   BOOST_SPIRIT_DEBUG_NODE(name_p);
 | |
|   BOOST_SPIRIT_DEBUG_NODE(argument_p);
 | |
|   BOOST_SPIRIT_DEBUG_NODE(argumentList_p);
 | |
|   BOOST_SPIRIT_DEBUG_NODE(constructor_p);
 | |
|   BOOST_SPIRIT_DEBUG_NODE(returnType1_p);
 | |
|   BOOST_SPIRIT_DEBUG_NODE(returnType2_p);
 | |
|   BOOST_SPIRIT_DEBUG_NODE(pair_p);
 | |
|   BOOST_SPIRIT_DEBUG_NODE(void_p);
 | |
|   BOOST_SPIRIT_DEBUG_NODE(returnType_p);
 | |
|   BOOST_SPIRIT_DEBUG_NODE(methodName_p);
 | |
|   BOOST_SPIRIT_DEBUG_NODE(method_p);
 | |
|   BOOST_SPIRIT_DEBUG_NODE(class_p);
 | |
|   BOOST_SPIRIT_DEBUG_NODE(module_p);
 | |
| # endif
 | |
|   //----------------------------------------------------------------------------
 | |
| 
 | |
|   // read interface file
 | |
|   string interfaceFile = interfacePath + "/" + moduleName + ".h";
 | |
|   string contents = file_contents(interfaceFile);
 | |
| 
 | |
|   // Comment parser : does not work for some reason
 | |
|   rule<> comment_p = str_p("/*") >> +anychar_p >> "*/";
 | |
|   rule<> skip_p = space_p; // | comment_p;
 | |
| 
 | |
|   // and parse contents
 | |
|   parse_info<const char*> info = parse(contents.c_str(), module_p, skip_p); 
 | |
|   if(!info.full) {
 | |
|     printf("parsing stopped at \n%.20s\n",info.stop);
 | |
|     throw ParseFailed(info.length);
 | |
|   }
 | |
| }
 | |
| 
 | |
| /* ************************************************************************* */
 | |
| void Module::matlab_code(const string& toolboxPath, 
 | |
| 			 const string& nameSpace, 
 | |
| 			 const string& mexFlags) 
 | |
| {
 | |
|   try {
 | |
|     string installCmd = "install -d " + toolboxPath;
 | |
|     system(installCmd.c_str());
 | |
| 
 | |
|     // create make m-file
 | |
|     string makeFile = toolboxPath + "/make_" + name + ".m";
 | |
|     ofstream ofs(makeFile.c_str());
 | |
|     if(!ofs) throw CantOpenFile(makeFile);
 | |
| 
 | |
|     cerr << "generating " << makeFile << endl;
 | |
|     emit_header_comment(ofs,"%");
 | |
|     ofs << "echo on" << endl << endl;
 | |
|     ofs << "toolboxpath = pwd" << endl;
 | |
|     ofs << "addpath(toolboxpath);" << endl << endl;
 | |
| 
 | |
|     // generate proxy classes and wrappers
 | |
|     BOOST_FOREACH(Class cls, classes) {
 | |
|       // create directory if needed
 | |
|       string classPath = toolboxPath + "/@" + cls.name;
 | |
|       string installCmd = "install -d " + classPath;
 | |
|       system(installCmd.c_str());
 | |
| 
 | |
|       // create proxy class
 | |
|       string classFile = classPath + "/" + cls.name + ".m";
 | |
|       cls.matlab_proxy(classFile);
 | |
| 
 | |
|       // create constructor and method wrappers
 | |
|       cls.matlab_constructors(toolboxPath,nameSpace);
 | |
|       cls.matlab_methods(classPath,nameSpace);
 | |
| 
 | |
|       // add lines to make m-file
 | |
|       ofs << "cd(toolboxpath)" << endl;
 | |
|       cls.matlab_make_fragment(ofs, toolboxPath, mexFlags);
 | |
|     }  
 | |
| 
 | |
|     // finish make m-file
 | |
|     ofs << "cd(toolboxpath)" << endl << endl;
 | |
|     ofs << "echo off" << endl;
 | |
|     ofs.close();
 | |
|   }
 | |
|   catch(exception &e) {
 | |
|     cerr << "generate_matlab_toolbox failed because " << e.what() << endl;
 | |
|   }
 | |
| 
 | |
| }
 | |
| 
 | |
| /* ************************************************************************* */
 |