zoukankan      html  css  js  c++  java
  • 探索C++头文件解析方法(LLVM + Clang)

      最近一直在搞基于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库,用起来倒是非常简单, 也能够分析头文件并拿到函数原型,非常接近我需要的目标了!可万万没想到居然不解析函数体内容,功亏一篑啊。。。

      例如这样一个头文件:

     1 #ifndef _TEST_H
     2 #define _TEST_H
     3 
     4 #include <string>
     5 
     6 class MyClass {
     7 public:
     8     MyClass() : _iValue(123), _fValue(3.14) {
     9         _strValue = "Hello";
    10     }
    11 
    12     int GetIValue() const;
    13 
    14 private:
    15     int _iValue;
    16     float _fValue;
    17     std::string _strValue;
    18 };
    19 
    20 #endif
    View Code

      用 CppHeaderParser 解析出来的信息为:

     1 class MyClass
     2 {
     3 public
     4     // Methods
     5    {'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': '	 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': '	 MyClass ( ) : 	 _iValue ( 123 ) , 	 _fValue ( 3.16 ) 	 {', 'explicit': False, 'virtual': False, 'destructor': False, 'returns': '', 'template': False, 'constructor': True, 'override': False, 'inline': False, 'final': False, 'friend': False, 'returns_class': False}
     6    {'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': '	 MyClass ( ) : 	 _iValue ( 123 ) , 	 _fValue ( 3.16 ) 	 {', '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': '	 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}
     7 protected
     8 private
     9     // Properties
    10     {'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}
    11     {'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}
    12     {'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}
    13 }
    View Code

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

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

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

      看来看去,感觉只有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
  • 相关阅读:
    oracle的网络服务名和监听程序
    ArcGIS 产品许可模型
    老鸟对菜鸟的一些建议(转)
    ajax简介(转载)
    dim redim
    投影选择的一般原则
    *.prj文件
    cup性能对比感受
    treeview 数据库 递归
    简论两句话
  • 原文地址:https://www.cnblogs.com/kuliuheng/p/10769192.html
Copyright © 2011-2022 走看看