最近一直在搞基于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. Oracle 的几种循环方式介绍

    1 Oracle 中的Goto 用法: declare x number; begin x:=10; --定义的初始值 <<repeat_loop>> --循环点 x:= x- ...

  2. pycharm环境下用Python+Django开发web搭建

    1.安装pycharm: 2.安装Python: 3.安装mysql: 4.安装Django; pip3 install django 5.创建Django工程命令方式: # 创建Django程序 d ...

  3. goroutine和channel

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

  4. String Method的字符串变换的一个例子

    <!DOCTYPE html> <html lang="en"><head> <meta charset="UTF-8" ...

  5. Hadoop学习------Hadoop安装方式之(一):单机部署

    Hadoop 默认模式为单机(非分布式模式),无需进行其他配置即可运行.非分布式即单 Java 进程,方便进行调试. 1.创建用户 1.1创建hadoop用户组和用户 一般我们不会经常使用root用户 ...

  6. java 反射简说

    1 Class类 就是类的类型.研究反射先了解下Class类. 获取类的类型的三种方法: Class c1 = 对象.getClass(); Class c2 = Class.forName(&quo ...

  7. Linux命令 ls 和 ll 的使用方法与基本区别

    Linux 命令 ls 和 ll 的使用方法: ll:罗列出当前文件或目录的详细信息,含有时间.读写权限.大小.时间等信息 ,像Windows显示的详细信息.ll是“ls -l"的别名.相当 ...

  8. JPype1使用总结

    目的:使用Locust+Python压测账号资料接口,使用JPype调用java代码,缩短压测脚本编写 前提条件:进行性能压测过程中,需要压测账号相关接口,由于账号相关接口设计到加密解密,用Pytho ...

  9. vue打包后接口报错

    最近自己和朋友做了一个小的项目,用的是vue3.x版本,本地dev运行的时候接口什么的都是正常的,但是build打包后本地使用anywhere启动一个本地服务的时候发现接口报错405状态,发布到线上接 ...

  10. MySQL基本操作——1

    1.命令行启动或关闭MySQL服务:方式一:计算机--右击管理--服务方式二:net start MySQL服务器名称net stop MySQL服务器名称 2.登录和退出(必须在MySQL服务启动的 ...