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;
|
|
}
|
|
|
|
}
|
|
|
|
/* ************************************************************************* */
|