2012-05-12 9 views
8

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?

+3

Người đàn ông gremlins. Họ ở khắp mọi nơi. –

Trả lời

10

Vì bạn không chỉ định rõ ngôn ngữ, Clang sẽ xác định ngôn ngữ từ phần mở rộng tệp, dẫn đến việc phân tích cú pháp là C, chứ không phải C++ là "example.h". Do đó, tệp hầu như không được định dạng và trình lập chỉ mục cố khôi phục cũng như có thể. namespace Geom đang được coi là khai báo biến cho Geom với loại không xác định namespace và các khối bất ngờ sau đây { ... } bị bỏ qua.

Hãy thử:

tu = index.parse(sys.argv[1], args=['-x', 'c++']) 
+1

Điều đó có hiệu quả, cảm ơn! Lạ lùng là nó không tạo ra lỗi. –

4

Trong khi câu trả lời của Richard làm việc trong trường hợp này, tôi có thể trên cùng một vấn đề và điều này không làm việc cho tôi. Nó bật ra các ràng buộc clang trăn đã được ẩn thông báo lỗi. Nếu bạn chạy như sau:

clang -Xclang -ast-dump -fsyntax-only yourfile.cpp 

Điều này sẽ in ra thông tin AST. Trong trường hợp của tôi, nó không thể tìm thấy tập tin tiêu đề vì nó nằm trong một thư mục khác. Vì vậy, tôi phải thêm -I và đường dẫn bổ sung bao gồm vào số args được chuyển vào và nó hoạt động.