[英]Parsing namespaces with clang: AST differences in when including a header in another source file or parsing it directly
對於冗長的問題感到抱歉,但我看不出任何其他方法可以說明問題。 我正在編寫一個工具,將C ++頭文件轉換為SWIG接口文件,作為進一步微調的啟動器。
在這樣做的過程中,我注意到了clang(v3.0)的一些奇怪行為。 如果我解析頭文件,我會得到一個與我解析包含頭文件的源文件截然不同的AST。
為了便於說明,以下是一些示例源文件:
源文件:
// example.cpp: Test case for nsbug.py
//
#include "example.h"
標題:
// 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
名稱空間是VAR_DECL? 我預計沒有區別,除了預處理器游標。
解決方法很明顯 - 只需在內存中創建包含標題的臨時文件 - 但這並不令人滿意。 有人可以開導我嗎?
由於您沒有明確指定語言,因此Clang從文件擴展名中確定語言,導致"example.h"
被解析為C,而不是C ++。 因此,文件很大程度上是不正確的,索引器試圖盡可能地恢復。 namespace Geom
被視為具有未知類型namespace
Geom
的變量聲明,並且跳過以下意外{
... }
塊。
嘗試:
tu = index.parse(sys.argv[1], args=['-x', 'c++'])
雖然理查德的答案在這種情況下確實有效,但我可以解決同樣的問題,這對我來說不起作用。 事實證明,python clang綁定隱藏了錯誤消息。 如果您運行以下內容:
clang -Xclang -ast-dump -fsyntax-only yourfile.cpp
這將打印出AST信息。 在我的情況下,它找不到頭文件,因為它在不同的目錄中。 所以,我必須添加-I
和傳入的args
的附加包含路徑並且它有效。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.