Xin lỗi vì câu hỏi tiết, nhưng tôi không thể thấy cách nào khác để làm rõ. Tôi đang viết một công cụ để chuyển đổi các tệp tiêu đề C++ thành các tệp giao diện SWIG làm khởi động để tinh chỉnh thêm.Phân tích không gian tên bằng tiếng kêu: AST khác biệt khi bao gồm tiêu đề trong tệp nguồn khác hoặc phân tích cú pháp trực tiếp
Trong quá trình thực hiện việc này, tôi đã nhận thấy một số hành vi lạ của clang (v3.0). Nếu tôi phân tích cú pháp tệp tiêu đề, tôi nhận được AST khác biệt đáng kể so với khi tôi phân tích cú pháp tệp nguồn bao gồm tiêu đề.
Đối với mục đích minh họa, đây là một số file nguồn mẫu: tập tin
Nguồn:
// example.cpp: Test case for nsbug.py
//
#include "example.h"
Tiêu đề:
// 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
Tôi đã sử dụng mã Python sau đây để phân tích nó và đổ 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)
Khi tôi chạy trên example.cpp tôi nhận được (chính xác tôi nghĩ):
<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()"
}
}
}
Nhưng khi tôi thử nó trên các tập tin tiêu đề cùng với python nsbug.py example.py
tôi chỉ nhận được:
<CursorKind.TRANSLATION_UNIT>
"example.h"
{
(deleted lots of clang-generated definitions such as __VERSION__)
Geom <CursorKind.VAR_DECL>
"Geom"
}
Tại sao không gian tên Geom
trong AST dưới dạng VAR_DECL? Tôi đã có thể mong đợi không có sự khác biệt, ngoại trừ trong con trỏ tiền xử lý.
Công việc xung quanh là hiển nhiên - chỉ cần tạo một tệp tạm thời trong bộ nhớ bao gồm tiêu đề - nhưng điều đó không thỏa mãn lắm. Ai đó có thể khai sáng cho tôi không?
Người đàn ông gremlins. Họ ở khắp mọi nơi. –