最近一直在搞基于SWIG的C++接口翻译Java代码的工作。SWIG内部基于Bison(Yacc)的C/C++解析器,最近纠结于SWIG不能解析C++构造函数中的默认初始化赋值操作,想找一个能够补充此项能力的工具。

  尝试了Cast-xml,因为官网上说编译需要依赖llvm+clang,结果浪费我半天的时间去研究怎么编译llvm+clang,耗费巨大的磁盘空间(12GB才到70%)作罢。后来发现Ubuntu上可以直接安装编译好的Cast-xml,试了一把发现解析出来的AST(抽象语法树)根本就没有初始值的相关的内容,只有大量的符号表之类的。坑~~幸亏没有在编译llvm+clang的路上一根筋搞下去。

  又尝试了好几个cpp开源库发现也不行,最后找到了一个名为 CppHeaderParser (可pip安装)的Python库,用起来倒是非常简单, 也能够分析头文件并拿到函数原型,非常接近我需要的目标了!可万万没想到居然不解析函数体内容,功亏一篑啊。。。

  例如这样一个头文件:

 #ifndef _TEST_H
#define _TEST_H #include <string> class MyClass {
public:
MyClass() : _iValue(), _fValue(3.14) {
_strValue = "Hello";
} int GetIValue() const; private:
int _iValue;
float _fValue;
std::string _strValue;
}; #endif

  用 CppHeaderParser 解析出来的信息为:

 class MyClass
{
public
// Methods
{'line_number': 8, 'parent': {'inherits': [], 'line_number': 6, 'forward_declares': {'protected': [], 'public': [], 'private': []}, 'name': 'MyClass', 'parent': None, 'abstract': False, 'namespace': '', 'declaration_method': 'class', 'properties': {'protected': [], 'public': [], 'private': [{'line_number': 18, 'constant': 0, 'reference': 0, 'raw_type': 'int', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': [], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'int', 'property_of_class': 'MyClass', 'parent': None, 'ctypes_type': 'ctypes.c_int', 'typedefs': 0, 'extern': False, 'class': 0, 'unresolved': False, 'name': '_iValue', 'fundamental': True}, {'line_number': 19, 'constant': 0, 'reference': 0, 'raw_type': 'float', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': [], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'float', 'property_of_class': 'MyClass', 'parent': None, 'ctypes_type': 'ctypes.c_float', 'typedefs': 0, 'extern': False, 'class': 0, 'unresolved': False, 'name': '_fValue', 'fundamental': True}, {'line_number': 20, 'constant': 0, 'reference': 0, 'raw_type': 'std::string', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': ['std::string'], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'std::string', 'property_of_class': 'MyClass', 'parent': None, 'ctypes_type': 'ctypes.c_void_p', 'typedefs': 0, 'extern': False, 'class': 0, 'unresolved': True, 'name': '_strValue', 'fundamental': 0}]}, 'typedefs': {'protected': [], 'public': [], 'private': []}, 'structs': {'protected': [], 'public': [], 'private': []}, 'enums': {'protected': [], 'public': [], 'private': []}, 'final': False, 'nested_classes': [], 'methods': {'protected': [], 'public': [{...}, {'line_number': 15, 'parent': {...}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'int', 'extern': False, 'path': 'MyClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'const': True, 'name': 'GetIValue', 'pure_virtual': False, 'debug': '\t int GetIValue ( ) const ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'int', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}], 'private': []}}, 'defined': True, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void', 'extern': False, 'path': 'MyClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'const': False, 'name': 'MyClass', 'pure_virtual': False, 'debug': '\t MyClass ( ) : \t _iValue ( 123 ) , \t _fValue ( 3.16 ) \t {', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': '', 'template': False, 'constructor': True, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}
{'line_number': 15, 'parent': {'inherits': [], 'line_number': 6, 'forward_declares': {'protected': [], 'public': [], 'private': []}, 'name': 'MyClass', 'parent': None, 'abstract': False, 'namespace': '', 'declaration_method': 'class', 'properties': {'protected': [], 'public': [], 'private': [{'line_number': 18, 'constant': 0, 'reference': 0, 'raw_type': 'int', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': [], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'int', 'property_of_class': 'MyClass', 'parent': None, 'ctypes_type': 'ctypes.c_int', 'typedefs': 0, 'extern': False, 'class': 0, 'unresolved': False, 'name': '_iValue', 'fundamental': True}, {'line_number': 19, 'constant': 0, 'reference': 0, 'raw_type': 'float', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': [], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'float', 'property_of_class': 'MyClass', 'parent': None, 'ctypes_type': 'ctypes.c_float', 'typedefs': 0, 'extern': False, 'class': 0, 'unresolved': False, 'name': '_fValue', 'fundamental': True}, {'line_number': 20, 'constant': 0, 'reference': 0, 'raw_type': 'std::string', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': ['std::string'], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'std::string', 'property_of_class': 'MyClass', 'parent': None, 'ctypes_type': 'ctypes.c_void_p', 'typedefs': 0, 'extern': False, 'class': 0, 'unresolved': True, 'name': '_strValue', 'fundamental': 0}]}, 'typedefs': {'protected': [], 'public': [], 'private': []}, 'structs': {'protected': [], 'public': [], 'private': []}, 'enums': {'protected': [], 'public': [], 'private': []}, 'final': False, 'nested_classes': [], 'methods': {'protected': [], 'public': [{'line_number': 8, 'parent': {...}, 'defined': True, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'void', 'extern': False, 'path': 'MyClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'const': False, 'name': 'MyClass', 'pure_virtual': False, 'debug': '\t MyClass ( ) : \t _iValue ( 123 ) , \t _fValue ( 3.16 ) \t {', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': '', 'template': False, 'constructor': True, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}, {...}], 'private': []}}, 'defined': False, 'namespace': '', 'operator': False, 'static': False, 'returns_fundamental': True, 'rtnType': 'int', 'extern': False, 'path': 'MyClass', 'returns_pointer': 0, 'parameters': [], 'class': None, 'returns_reference': False, 'const': True, 'name': 'GetIValue', 'pure_virtual': False, 'debug': '\t int GetIValue ( ) const ;', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': 'int', 'template': False, 'constructor': False, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}
protected
private
// Properties
{'line_number': 18, 'constant': 0, 'reference': 0, 'raw_type': 'int', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': [], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'int', 'property_of_class': 'MyClass', 'parent': None, 'ctypes_type': 'ctypes.c_int', 'typedefs': 0, 'extern': False, 'class': 0, 'unresolved': False, 'name': '_iValue', 'fundamental': True}
{'line_number': 19, 'constant': 0, 'reference': 0, 'raw_type': 'float', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': [], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'float', 'property_of_class': 'MyClass', 'parent': None, 'ctypes_type': 'ctypes.c_float', 'typedefs': 0, 'extern': False, 'class': 0, 'unresolved': False, 'name': '_fValue', 'fundamental': True}
{'line_number': 20, 'constant': 0, 'reference': 0, 'raw_type': 'std::string', 'static': 0, 'array': 0, 'pointer': 0, 'aliases': ['std::string'], 'typedef': None, 'namespace': '', 'function_pointer': 0, 'mutable': False, 'type': 'std::string', 'property_of_class': 'MyClass', 'parent': None, 'ctypes_type': 'ctypes.c_void_p', 'typedefs': 0, 'extern': False, 'class': 0, 'unresolved': True, 'name': '_strValue', 'fundamental': 0}
}

  确实有构造函数的初始化列表的内容,但是少了构造函数体中的赋值操作。总不好意思去要求所有人都必须用初始化列表来初始化吧?更何况确实有赋值语句给初值的情况。。

  谁有更好的开源库方法?多谢!

==========================================

  看来看去,感觉只有clang最靠谱最有希望。快来看 LLVM 官方文档,既可以下载源码,也可以下载编译好的包,非常靠谱!

  要利用clang来解析C++语法树,感觉还是尽可能用Python接口吧,方便啊,转下一篇《利用Clang(Python接口)来解析C++》

1 参考LLVM介绍

  引用博文《LLVM原理和使用

  在理解LLVM时,我们可以认为它包括了一个狭义的LLVM和一个广义的LLVM。广义的LLVM其实就是指整个LLVM编译器架构,包括了前端、后端、优化器、众多的库函数以及很多的模块;而狭义的LLVM其实就是聚焦于编译器后端功能(代码生成、代码优化、JIT等)的一系列模块和库。

1.1 LLVM三段式架构

  (1)传统编译器的三段式:前端(Frontend)-- 优化器(Optimizer)-- 后端(Backend)

  (2)LLVM的三段式:

前端可以使用不同的编译工具对代码文件做词法分析以形成抽象语法树AST,然后将分析好的代码转换成LLVM的中间表示IR(intermediate representation);中间部分的优化器只对中间表示IR操作,通过一系列的pass对IR做优化;后端负责将优化好的IR解释成对应平台的机器码。LLVM的优点在于,中间表示IR代码编写良好,而且不同的前端语言最终都转换成同一种的IR。

1.2 Clang与LLVM的关系

  Clang是一个C++编写、基于LLVM、发布于LLVM BSD许可证下的C/C++/Objective-C/Objective-C++编译器。那么为什么已经有了GCC还要开发Clang呢?Clang相比于GCC有什么优势呢?   其实,这也是Clang当初在设计开发的时候所主要考虑的原因。Clang是一个高度模块化开发的轻量级编译器,它的编译速度快、占用内存小、非常方便进行二次开发。

  LLVM与Clang是C/C++编译器套件。对于整个LLVM的框架来说,包含了Clang,因为Clang是LLVM的框架的一部分,是它的一个C/C++的前端。Clang使用了LLVM中的一些功能,目前知道的就是针对中间格式代码的优化,或许还有一部分生成代码的功能。从源代码角度来讲,clang是基于LLVM的一个工具。而功能的角度来说,LLVM可以认为是一个编译器的后端,而clang是一个编译器的前端。

1.3 LLVM 编译流程

  LLVM编译一个源文件的过程:预处理 -> 词法分析 -> Token -> 语法分析 -> AST -> 代码生成 -> LLVM IR -> 优化 -> 生成汇编代码 -> Link -> 目标文件。

2 CLang工具命令

2.1 打印语法树

  可以用如下命令打印语法树:

clang -Xclang -ast-dump -fsyntax-only -Iinclude -x c++ test.h > out.txt

2.2 打印分词(词法分析)

  如下命令:

clang -Xclang -dump-tokens -Iinclude test.h > out2.txt

2.3 打印语法分析(语法分析) 

  如下命令:

clang -fsyntax-only -Xclang -ast-dump -x c++ -Iinclude test.h > out3.txt

探索C++头文件解析方法的更多相关文章

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

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

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

    本章接着NSObject头文件解析 / 消息机制 / Runtime解读(一)写 给类添加属性: BOOL class_addProperty(Class cls, const char *name, ...

  3. 八、Android学习第七天——XML文件解析方法(转)

    (转自:http://wenku.baidu.com/view/af39b3164431b90d6c85c72f.html) 八.Android学习第七天——XML文件解析方法 XML文件:exten ...

  4. Spring的配置文件ApplicationContext.xml配置头文件解析

    Spring的配置文件ApplicationContext.xml配置头文件解析 原创 2016年12月16日 14:22:43 标签: spring配置文件 5446 spring中的applica ...

  5. linux(kali,centos)安装vm及其提示缺少c头文件解决方法

    我电脑系统是kali最新版 首先去官网下一个vm安装包,给个直达网址 http://www.vmware.com/cn/products/workstation/workstation-evaluat ...

  6. 在Eclipse中设置进行JNI的头文件编译方法(转 http://blog.csdn.net/mirkerson/article/details/17187109)

    这两天在搞NDK开发,JNI的头文件进行编译的时候,要跑到对应的class文件路径下(通常是工程的bin目录),进行编译生成,很是不便,也容易出错,所以考虑在Eclipse中作为外部工具引入,所以便查 ...

  7. MSP430G2553头文件解析

    MSP430寄存器中文注释---P1/2口(带中断功能)       /************************************************************     ...

  8. TC297B - 外设头文件解析(以IO为例)

    打开例程,目录树下的Includes中包含了各个片上资源对应的头文件,这些头文件定义了相应外设的寄存器地址(寄存器是内置于各个 IP 外设中,是一种用于配置外设功能的存储器,就是一种内存,并且有相对应 ...

  9. C/C++不同文件夹下包含头文件的方法及#include的使用

    转自:http://blog.sina.com.cn/s/blog_6e0693f70100so42.html 本文主要介绍了如何不同文件夹下使用预处理器指示符#include. 假设我们有如下一个工 ...

随机推荐

  1. goroutine和channel

    近期在学习golang的goroutine和channel时候有一些疑惑: 带缓冲的channel和不带缓冲的channel有什么区别? goroutine和主进程的有哪些影响和关系? 多个gorou ...

  2. Java学习NO.3

    今日学习重点: while循环: 语法:while(条件表达式){ 循环操作 } 条件表达式符合,循环继续执行:否则,退出循环. 循环四要素:循环初始化.循环条件.循环操作.循环变量的改变 do-wh ...

  3. python之99乘法表

    #99乘法表 fir=1 while fir<=9: sec=1 while sec<=fir: print(str(fir)+'*'+str(sec)+'='+str(fir*sec)) ...

  4. python中的 uuid 模块使用示例

    此模块提供不可变的 UUID 对象 (类 uuid) 和函数uuid1().uuid3().uuid4().uuid5(), 用于生成在 RFC 4122 中指定版本1.3.4和5UUIDs .如果你 ...

  5. ASP.NET项目答辩系统课件使用中的问题记录

    使用软件:VS2008 模块一:登录模块 1-08 问题:显示属性“background”不是元素"td"的有效属性 解决:style="background-image ...

  6. JavaScript构造函数原理

    1.var obj={} plainObject 对象字面量/对象直接量2.构造函数创建 1).系统自带的构造函数 Object() var obj=new Object(); 和 var obj = ...

  7. Excel 常用属性的一小部分

    1.由于工作需要,最近积累了一些Excel中的相关知识,特此记录 Workbooks xlbooks = xlApp.Workbooks; Workbook xlbook = xlbooks.Add( ...

  8. 日志管理中获取浏览器、操作系统、IP等信息。。。

    今天在书写日志管理的模块的时候,遇到了一些问题,首先是日志的添加,就是在登录的时候记下他登录的名字以及登录的时间和登录的一些信息给存入到日志表中,这一下给蒙了,于是就查找资源,在这里我就简单地总结一下 ...

  9. 【oracle】dmp导数据库

    假定数据库A为源数据库,数据库B为目标数据库 step1在数据库A中,导出生成.dmp文件,操作流程如下(以下操作均在系统用户ora11g下执行) 1.该操作只需要在第一次使用时执行,A_dump_d ...

  10. 一种hyperscan API使用(1)

    hyperscan: 编译和安装:http://www.cnblogs.com/zzqcn/p/4900643.html 简单介绍:http://www.cnblogs.com/zzqcn/p/489 ...