环境:win7_64旗舰版,VS2008

场景:C++与lua交互是比较繁琐的,当我们编写一个C++类后,如果要给lua使用,就必须写一个lua包装类,将lua与原始C++类关联起来。其实这部分代码编写完全可以通过工具生成,前提是我们能解析C++头文件,然后根据解析出来的"类"和“函数”信息就可以自动生成相关的代码。

cpp_class_grammar.h

#pragma once

#define BOOST_REGEX_NO_LIB
#include "boost/spirit.hpp"
#include <list> namespace bs = boost::spirit; namespace cpp_grammar { // 类型
enum type {
t_undifined = ,
t_void,
t_int,
t_float,
t_double,
t_c_str,
}; // 函数参数信息
struct _func_param {
type m_paramType; // 参数类型
std::string m_paramName; // 参数名称
}; // 函数信息
struct _function {
type m_returnType;
std::string m_funcName;
std::list<_func_param> m_funcParams;
}; // 类信息
struct _class {
std::string m_className;
std::list<_function> m_funcs;
}; // 树结构
template<class _Value>
class Tree {
public:
Tree(Tree* parent) : m_parent(parent) {} Tree* parent() { return m_parent; } Tree* newTree(const _Value& value);
void addChild(Tree* tree);
void print(); public:
_Value m_value; // 当前节点存储的值
std::vector<Tree*> m_childlers; // 子节点列表 private:
Tree* m_parent; // 父节点
};
typedef Tree<_class> class_tree; class class_action;
} struct CppClassGrammar : public bs::grammar < CppClassGrammar > { CppClassGrammar();
~CppClassGrammar(); cpp_grammar::class_tree& getTree(); bool doParse(const std::string& input); template<typename ScannerT>
struct definition { bs::rule<ScannerT> _cpp_key; // 类关键字(class)
bs::rule<ScannerT> _cpp_type; // 类型
bs::rule<ScannerT> _cpp_comment; // 单行注释 bs::rule<ScannerT> _identifier; // 标示(解析类名、函数名、参数名等)
bs::rule<ScannerT> _access_ctrl; // 访问控制权限(public、protected、private) bs::rule<ScannerT> _tag_brace_nest; // 函数内的嵌套大括号(包括函数体)
bs::rule<ScannerT> _func_param; // 函数参数(类型 + 参数名)
bs::rule<ScannerT> _function; // 函数 bs::rule<ScannerT> _class; // 类
bs::rule<ScannerT> _root; definition(const CppClassGrammar& self);
const bs::rule<ScannerT>& start() { return _root; }
}; cpp_grammar::class_action* m_class_action;
};

cpp_class_grammar.cpp

#include "cpp_class_grammar.h"
#include "boost/function.hpp"
#include "boost/bind.hpp"
#include "boost/algorithm/string.hpp" using namespace cpp_grammar; namespace cpp_grammar { template<class _Value>
Tree<_Value>* Tree<_Value>::newTree(const _Value& value)
{
Tree<_Value>* tree = new Tree(NULL);
tree->m_value = value;
return tree;
} template<class _Value>
void Tree<_Value>::addChild(Tree<_Value>* tree)
{
tree->m_parent = this;
m_childlers.push_back(tree);
} template<class _Value>
void Tree<_Value>::print() {
std::cout << m_value.c_str() << std::endl;
std::vector<Tree*>::iterator iter = m_childlers.begin();
for (; iter != m_childlers.end(); ++iter) {
(*iter)->print();
} } // 解析CLASS结构后特定的行为操作
class class_action {
public:
typedef boost::function<void(char)> CallbackOne;
typedef boost::function<void(const char*, const char*)> CallbackTwo; CallbackTwo m_comment; // 注释
CallbackTwo m_className; // 类名
CallbackOne m_innerClass; // 进类
CallbackOne m_outterClass; // 出类 CallbackTwo m_funcReturn; // 函数返回类型
CallbackTwo m_funcName; // 函数名
CallbackTwo m_funcParamType; // 函数参数类型
CallbackTwo m_funcParamName; // 函数参数名称 class_action()
: m_root(NULL)
, m_node(&m_root)
, m_newNode(NULL)
{
m_comment = boost::bind(&class_action::comment, this, _1, _2);
m_className = boost::bind(&class_action::className, this, _1, _2);
m_innerClass = boost::bind(&class_action::innerClass, this, _1);
m_outterClass = boost::bind(&class_action::outterClass, this, _1);
m_funcReturn = boost::bind(&class_action::funcReturn, this, _1, _2);
m_funcName = boost::bind(&class_action::funcName, this, _1, _2);
m_funcParamType = boost::bind(&class_action::funcParamType, this, _1, _2);
m_funcParamName = boost::bind(&class_action::funcParamName, this, _1, _2);
} class_tree& getTree() { return m_root; } private:
// 单行注释
void comment(const char* start, const char* end) {
std::string s(start, end);
}
// 类名
void className(const char* start, const char* end) {
_class c;
c.m_className.assign(start, end);
delete m_newNode;
m_newNode = m_node->newTree(c);
}
// 进/出类
void innerClass(char) { m_node->addChild(m_newNode); m_node = m_newNode; m_newNode = NULL; }
void outterClass(char) { m_node = m_node->parent(); }
// 函数返回类型
void funcReturn(const char* start, const char* end) {
_function f;
f.m_returnType = ParseType(start, end);
m_node->m_value.m_funcs.push_back(f);
}
// 函数名称
void funcName(const char* start, const char* end) {
m_node->m_value.m_funcs.back().m_funcName.assign(start, end);
}
// 函数参数类型
void funcParamType(const char* start, const char* end) {
_func_param fp;
fp.m_paramName.assign(start, end);
m_node->m_value.m_funcs.back().m_funcParams.push_back(fp);
}
// 函数参数名称
void funcParamName(const char* start, const char* end) {
m_node->m_value.m_funcs.back().m_funcParams.back().m_paramType = ParseType(start, end);
}
// 将字符串转换为类型
static type ParseType(const char* start, const char* end) {
std::string s(start, end);
if (s == "void")
return t_void;
if (s == "float")
return t_float;
if (s == "double")
return t_double;
if (s.find("char") != s.npos && s.find("*") != s.npos)
return t_c_str;
return t_undifined;
} private:
class_tree m_root; // 树根节点
class_tree* m_node; // 当前所在节点
class_tree* m_newNode; // 新添加的子节点
}; // 删除多行注释/**/
struct EraseComment { EraseComment(const std::string& source) {
m_source.reserve(source.size());
bs::parse_info<> pi = bs::parse(source.c_str(), *(
bs::comment_p("/*", "*/")[boost::bind(&EraseComment::Comment, this, _1, _2)]
| bs::anychar_p[boost::bind(&EraseComment::Anychar, this, _1)]
));
} const std::string& str() const { return m_source; } private:
static void Comment(EraseComment* self, const char* start, const char* end) {
std::string s(start, end);
}
static void Anychar(EraseComment* self, char ch) {
self->m_source.push_back(ch);
} mutable std::string m_source;
};
} CppClassGrammar::CppClassGrammar()
{
m_class_action = new class_action();
} CppClassGrammar::~CppClassGrammar()
{
delete m_class_action;
m_class_action = NULL;
} bool CppClassGrammar::doParse(const std::string& input)
{
cpp_grammar::EraseComment cmt(input); bs::parse_info<> pi = bs::parse(cmt.str().c_str(), *this, bs::space_p);
return pi.hit;
} cpp_grammar::class_tree& CppClassGrammar::getTree()
{
return m_class_action->getTree();
} template<typename ScannerT>
CppClassGrammar::definition<ScannerT>::definition(const CppClassGrammar& self)
{
// 解析CPP关键字和类型
_cpp_key = bs::str_p("class");
_cpp_type = bs::str_p("void") | "int" | "float" | "double"
| (!bs::str_p("const") >> "char" >> '*'); /* 解析单行注释 */
_cpp_comment = bs::comment_p("//")[self.m_class_action->m_comment]; /* 解析标示和访问控制权限 */
// 1.class class_name; // 类名
// 2.class class_name {} // 类名
// 3.class class_name : public base {} // 类名
// 4.void func(); // 函数名
// 5.void func(int name); // 函数参数名
// 6.void func(int, int name); // 函数参数名
_identifier = *(~bs::space_p - (bs::ch_p('{') | '(' | ')' | ',' | ';' | ':'));
_access_ctrl = (bs::str_p("public") | "protected" | "private") >> ':'; /* 解析函数体(目前只解析括号) */
// 1.{ { 123 };; };;
_tag_brace_nest = (*(bs::anychar_p - '{' - '}')) // 匹配任意字符到'{'或'}'为止
>> '{' // 匹配'{'
>> *_tag_brace_nest // 递归嵌套(括号内可以嵌套括号)
>> *~bs::ch_p('}') >> '}' // 匹配任意字符到'}'为止,匹配'}'
>> *bs::ch_p(';'); // 匹配';' /* 解析函数参数 */
// 1.() // 无参函数
// 2.(int a, int b) // 有参函数(包括参数类型和参数名称)
// 3.(int, int) // 有参函数(只包括参数类型,省略参数名称)
_func_param = _cpp_type[self.m_class_action->m_funcParamType]
>> _identifier[self.m_class_action->m_funcParamName]
>> *(bs::ch_p(',')
>> _cpp_type[self.m_class_action->m_funcParamType]
>> _identifier[self.m_class_action->m_funcParamName]); /* 解析函数 */
// 1.void fun() const;
// 2.void fun() const {}
_function = _cpp_type[self.m_class_action->m_funcReturn] // 匹配函数返回值类型
>> _identifier[self.m_class_action->m_funcName] // 匹配函数名称
>> '(' >> !_func_param >> ')' // 匹配函数参数(匹配0次或1次)
>> *(bs::anychar_p - ';' - '{') // 匹配任意字符到';'或'{'为止
>> (bs::ch_p(';') | _tag_brace_nest); // 匹配';'或函数体(函数体是用'{'和'}'组成的成对字符) /*解析CLASS*/
// 1.class test; 类声明
// 2.class test : public base {}; 类定义
// 当匹配到特定的字符后,便会执行特定的操作[]
_class = bs::str_p("class") // 匹配字符串"class"
>> _identifier[self.m_class_action->m_className] // 匹配类名
>> *(bs::anychar_p - '{' - ';') // 匹配任意字符到'{'或';'为止(前者是识别类定义,后者是识别类声明)
>> bs::ch_p('{')[self.m_class_action->m_innerClass] // 匹配到'{',表示进类主体
>> *(_cpp_comment // 匹配单行注释
| _access_ctrl // 匹配访问权限
| _class // 匹配嵌套类(递归嵌套,理论上N层嵌套类,既嵌套类中也可能存在嵌套类)
| _function // 匹配类成员函数
)
>> bs::ch_p('}')[self.m_class_action->m_outterClass] // 匹配'}',表示出类主体
>> *bs::ch_p(';'); // 类定义结束 /**解析整个.h文件,在一个.h文件内,可能会定义多个类*/
_root = *(_cpp_comment | _function | _class | bs::anychar_p);
}

test.cpp

#include "stdafx.h"
#include <fstream>
#include <sstream>
#include <locale> #include "cpp_class_grammar.h" int _tmain(int argc, _TCHAR* argv[])
{
std::vector<std::wstring> filelist;
filelist.reserve(argc - );
for (int i = ; i < argc; ++i) {
std::wstring file = argv[i];
if (file.substr(file.length() - , ) == L".h") {
filelist.push_back(argv[i]);
}
} if (filelist.empty())
return ; std::ifstream fs;
fs.open(filelist.front().c_str());
if (!fs.is_open()) {
return ;
} std::stringstream buffer;
buffer << fs.rdbuf();
std::string input = buffer.str(); CppClassGrammar gramar;
bool ret = gramar.doParse(input); // 解析后,生成一个class信息树 return ;
}

boost.spirit之解析C++头文件的更多相关文章

  1. WOSA/XFS PTR Form解析库—头文件

    class AFX_EX_CLASS CNuXfsForm {public: CNuXfsForm(); ~CNuXfsForm(); /******************************* ...

  2. C++解析头文件-Qt自动生成信号定义

    目录 一.概述 二.实现思路 三.代码讲解 1.类图 2.QtCppDescription 3.测试 四.源代码 一.概述 上一篇文章C++解析头文件-Qt自动生成信号声明我们主要讲解了怎么去解析C+ ...

  3. boost之词法解析器spirit

    摘要:解析器就是编译原理中的语言的词法分析器,可以按照文法规则提取字符或者单词.功能:接受扫描器的输入,并根据语法规则对输入流进行匹配,匹配成功后执行语义动作,进行输入数据的处理. C++ 程序员需要 ...

  4. 单片机中用c编程时头文件reg51.h及reg52.h解析

    单片机中用c编程时头文件reg51.h及reg52.h解析 我们在用c语言编程是往往第一行就是reg51.h或者其他的自定义头文件,我们怎么样来理解呢? 1)“文件包含”处理. 程序的第一行是一个“文 ...

  5. boost::property_tree读取解析.xml文件

    boost::property_tree读取解析.xml文件 1)read_xml 支持中文路径  boost::property_tree::wptree wpt;    std::locale:: ...

  6. boost::property_tree读取解析ini文件--推荐

    boost::property_tree读取解析ini文件 #include "stdafx.h" #include <iostream> #include <b ...

  7. 头文件 boost/cstdint.hpp

    Header boost/cstdint.hpp 头文件 boost/cstdint.hpp  头文件 <boost/cstdint.hpp> 提供了用于编写要求指定整数宽度的可移植代码的 ...

  8. NSObject头文件解析 / 消息机制 / Runtime解读 (一)

    NSObject头文件解析 当我们需要自定义类都会创建一个NSObject子类, 比如: #import <Foundation/Foundation.h> @interface Clas ...

  9. cstring头文件函数解析

    原创作品,转载请注明来源:http://www.cnblogs.com/shrimp-can/p/5643829.html 在使用由字符数组或指针组成的字符串的时候,要用到一些函数,这些函数通常包含在 ...

随机推荐

  1. Gulp安装使用教程

    题记:为什么要使用gulp,网上有很多关于gulp的优势,而在我看来,这些都是工具的优势!工具的优势最主要体现在易用性上,听说gulp比grunt更易用,所以这里写个文档记录. 同样要保证nodejs ...

  2. NOIP2015-普及组复赛-第一题-金币

    题目描述 Description 国王将金币作为工资,发放给忠诚的骑士.第一天,骑士收到一枚金币:之后两天(第二天和第三天),每天收到两枚金币:之后三天(第四.五.六天),每天收到三枚金币:之后四天( ...

  3. [Jmeter]jmeter之参数化

    一.同一个服务器不同界面访问 a 准备工作: 1.启动jmeter: 2.创建需要访问的url文件,内容示例如下: 即比如:http://www.cnblogs.com/amberly/p/59651 ...

  4. php 便利数组方法

    数组在PHP中是一个非常强大的武器,用起来方便.容易,由于使用起来异常灵活,用它就可以实现数据结构中的链表.栈.队列.堆以及所谓的字典.集合等,也可以转换成XML格式. 1.使用for for语句遍历 ...

  5. 解决Mac Linux USB Loader“Couldn't get security scoped bookmarks”错误

    Mac Linux USB Loader出现 "Couldn't get security scoped bookmarks"错误时, 需要删除 ~/Library/Contain ...

  6. php添加扩展插件

    给PHP安装扩展的方式有好多 一.重新编译 进入PHP源码目录./configure --prefix=/usr/local/php ...[其他编译参数] 二.通过phpize添加扩展 进入PHP源 ...

  7. 用两个栈实现队列,剑指offer P59

    public class QueueByStack { private Stack<Integer> stack1; private Stack<Integer> stack2 ...

  8. JavaScript——Cookie

    JavaScript中的Cookie基础 页面用来保存信息的,比如登录.记住用户名. [cookie的特性] (1)同一个网站中所有页面共享一套cookie: (2)数量.大小有限: (3)有保质期, ...

  9. java 守护线程

    守护线程生命周期: 守护线程是运行在后台的一种特殊线程, 它独立于控制终端并且周期性地执行某种任务或者等待处理某些发生的事件. 也就是说守护线程不依赖于终端,但是依赖于系统,与系统“同生共死”. 当J ...

  10. Windows下WordPress搭建博客过程

    搭建环境:Win7 + XAMPP5.5 + wordpress4.5.1 官网下载安装包,解压,拷贝到网站根目录(D:\IT\XAMPP5.5\htdocs\),重命名为blog(随意) 创建数据库 ...