很抱歉这个冗长的问题,但是我看不到其他任何方法可以弄清楚。我正在编写一个工具,将C++头文件转换为SWIG接口(interface)文件,作为进一步优化的入门工具。
在执行此过程的过程中,我注意到clang(v3.0)出现了一些奇怪的行为。如果我解析头文件,则得到的AST与解析包含头文件的源文件时的AST截然不同。
为了便于说明,以下是一些示例源文件:
源文件:
// example.cpp: Test case for nsbug.py
//
#include "example.h"
header :
// example.h: Test case for nsbug.py
//
namespace Geom {
struct Location
{
double x, y;
};
class Shape
{
public:
Shape();
void set_location(const Location &where)
{
m_pos = where;
};
const Location &get_location() const
// Draw it...
virtual void draw() const = 0;
protected:
Location m_pos;
};
class Circle : public Shape
{
Circle();
virtual void draw() const;
};
} // namespace Geom
我使用以下Python代码来解析它并转储AST:
# Usage: python nsbug.py <file>
import sys
import clang.cindex
def indent(level):
""" Indentation string for pretty-printing
"""
return ' '*level
def output_cursor(cursor, level):
""" Low level cursor output
"""
spelling = ''
displayname = ''
if cursor.spelling:
spelling = cursor.spelling
if cursor.displayname:
displayname = cursor.displayname
kind = cursor.kind;
print indent(level) + spelling, '<' + str(kind) + '>'
print indent(level+1) + '"' + displayname + '"'
def output_cursor_and_children(cursor, level=0):
""" Output this cursor and its children with minimal formatting.
"""
output_cursor(cursor, level)
if cursor.kind.is_reference():
print indent(level) + 'reference to:'
output_cursor(clang.cindex.Cursor_ref(cursor), level+1)
# Recurse for children of this cursor
has_children = False;
for c in cursor.get_children():
if not has_children:
print indent(level) + '{'
has_children = True
output_cursor_and_children(c, level+1)
if has_children:
print indent(level) + '}'
index = clang.cindex.Index.create()
tu = index.parse(sys.argv[1], options=1)
output_cursor_and_children(tu.cursor)
当我在example.cpp上运行时,我得到了(我认为正确):
<CursorKind.TRANSLATION_UNIT>
"example.cpp"
{
(Deleted lots of clang-generated declarations such as __VERSION__)
Geom <CursorKind.NAMESPACE>
"Geom"
{
Location <CursorKind.STRUCT_DECL>
"Location"
{
x <CursorKind.FIELD_DECL>
"x"
y <CursorKind.FIELD_DECL>
"y"
}
Shape <CursorKind.CLASS_DECL>
"Shape"
{
<CursorKind.CXX_ACCESS_SPEC_DECL>
""
<CursorKind.CXX_ACCESS_SPEC_DECL>
""
Shape <CursorKind.CONSTRUCTOR>
"Shape()"
set_location <CursorKind.CXX_METHOD>
"set_location(const Geom::Location &)"
{
where <CursorKind.PARM_DECL>
"where"
{
<CursorKind.TYPE_REF>
"struct Geom::Location"
reference to:
Location <CursorKind.STRUCT_DECL>
"Location"
}
<CursorKind.COMPOUND_STMT>
""
{
<CursorKind.CALL_EXPR>
"operator="
{
<CursorKind.MEMBER_REF_EXPR>
"m_pos"
<CursorKind.UNEXPOSED_EXPR>
"operator="
{
<CursorKind.DECL_REF_EXPR>
"operator="
}
<CursorKind.DECL_REF_EXPR>
"where"
}
}
}
get_location <CursorKind.CXX_METHOD>
"get_location()"
{
<CursorKind.TYPE_REF>
"struct Geom::Location"
reference to:
Location <CursorKind.STRUCT_DECL>
"Location"
}
<CursorKind.CXX_ACCESS_SPEC_DECL>
""
<CursorKind.CXX_ACCESS_SPEC_DECL>
""
m_pos <CursorKind.FIELD_DECL>
"m_pos"
{
<CursorKind.TYPE_REF>
"struct Geom::Location"
reference to:
Location <CursorKind.STRUCT_DECL>
"Location"
}
}
Circle <CursorKind.CLASS_DECL>
"Circle"
{
<CursorKind.CXX_BASE_SPECIFIER>
"class Geom::Shape"
reference to:
Shape <CursorKind.CLASS_DECL>
"Shape"
{
<CursorKind.TYPE_REF>
"class Geom::Shape"
reference to:
Shape <CursorKind.CLASS_DECL>
"Shape"
}
Circle <CursorKind.CONSTRUCTOR>
"Circle()"
draw <CursorKind.CXX_METHOD>
"draw()"
}
}
}
但是,当我将其与
python nsbug.py example.py
一起在头文件上尝试时,只会得到: <CursorKind.TRANSLATION_UNIT>
"example.h"
{
(deleted lots of clang-generated definitions such as __VERSION__)
Geom <CursorKind.VAR_DECL>
"Geom"
}
为什么AST中的
Geom
namespace 是VAR_DECL?我希望没有任何区别,除了在预处理器游标中。解决方法很明显-只需在内存中创建一个包含 header 的临时文件-但这并不是很令人满意。有人可以启发我吗?
最佳答案
由于您未明确指定语言,因此Clang会从文件扩展名中确定语言,从而将"example.h"
解析为C,而不是C++。因此,文件很大程度上是格式错误的,因此索引器会尽力恢复。 namespace Geom
被视为类型未知的Geom
的namespace
的变量声明,并且跳过了以下意外的{
... }
块。
尝试:
tu = index.parse(sys.argv[1], args=['-x', 'c++'])
关于c++ - 使用Clang : AST differences in when including a header in another source file or parsing it directly解析 namespace ,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/10561212/