2012-12-14 11 views
9

Niedawno zacząłem używać libclang do parsowania plików C. Problem, który mam, polega na tym, że libclang inicjuje preprocesor przed wygenerowaniem AST. Chciałbym zakazać preprocesor z systemem, a zamiast być podana informacja, że ​​dyrektywy preprocesora są w pliku ...Pobieranie informacji o dyrektywach pre-procesora

używam następujący skrypt Pythona (cindex.py i libclang)

import codecs 
from clang.cindex import * 

class SourceFile(object): 
    def __init__(self, path): 
     with codecs.open(path, 'r', 'utf-8') as file: 
      self.file_content = file.read() 

     index = Index.create() 
     root_node = index.parse(path) 

     for included in root_node.get_includes(): 
      print included.include 

     self.print_declerations(root_node.cursor) 

    def print_declerations(self, root, recurse=True): 
     print root.kind.name, root.spelling 
     if root.kind.is_declaration(): 
      node_def = root.get_definition() 
      if node_def is not None: 
       start_offset = node_def.extent.start.offset 
       end_offset = node_def.extent.end.offset + 1 
       print self.file_content[start_offset:end_offset], '\n' 

     if recurse: 
      for child in root.get_children(): 
       self.print_declerations(child, False) 

if __name__ == '__main__': 
    path = 'Sample.cpp' 
    print 'Translation unit:', path 
    source = SourceFile(path) 

Która wyjścia

Translation unit: Sample.cpp 
/mingw/include\stdio.h 
/mingw/include\_mingw.h 
/mingw/include\sys/types.h 
TRANSLATION_UNIT None 
TYPEDEF_DECL __builtin_va_list 

STRUCT_DECL _iobuf 

TYPEDEF_DECL FILE 

VAR_DECL _iob 
UNEXPOSED_DECL 

FUNCTION_DECL main 
int main() 
{ 
    printf(HELLO_WORLD); 
    return 0; 
} 

w następnym kod C:

#include <stdio.h> 
#define HELLO_WORLD "HELLO!" 

int main() 
{ 
    printf(HELLO_WORLD); 
    return 0; 
} 

Chciałbym uzyskać DEFINE_DECL HELLO_WORLD dla mojego #define w kodzie (obecnie nic nie dostaję). I oczywiście otrzymuję podobne stwierdzenia dla moich # include. czy to możliwe?

EDYCJA: Zasadniczo chcę przeanalizować plik bez rozszerzonej dyrektywy preprocesora.

+0

Jeśli jesteś gotów rozważyć coś innego niż Clang, mam alternatywne rozwiązanie. –

Odpowiedz

4

Kilka dni temu zadałem to samo pytanie na kanale IRC#llvm freenode. Odpowiedź brzmi: "makroses nie jest częścią AST, więc nie możesz", ale prawdopodobnie opcja "-fsyntax-only" i plugin clang zamiast libclang mogą ci pomóc.

Zmieniano: teraz wygląda to rzeczywiście możliwe, patrz odpowiedź przez bradtgmurray

+0

Czy chcesz napisać własną wtyczkę clang? czy istnieje wtyczka rzeczywiście nazywana pluginem clang? Nie jest to najłatwiejsza fraza do użycia w google. –

+1

Sprawdź "clang" i zajrzyj do folderu "examples". "PrintFunctionNames" i "wtyczka analizatora" mogą być na miejscu. –

19

Jeśli dodać PARSE_DETAILED_PROCESSING_RECORD jako opcja na wezwanie do index.parse() dostaniesz dostęp do węzłów preprocesora.

index = clang.cindex.Index.create()                   
tu = index.parse(filename, options=clang.cindex.TranslationUnit.PARSE_DETAILED_PROCESSING_RECORD) 

Ta opcja zamienia na następującą wartość opcji API C libclang. Tam jest komentarz, który zawiera trochę więcej kontekstu.

/**                   
* \brief Used to indicate that the parser should construct a "detailed"  
* preprocessing record, including all macro definitions and instantiations. 
*                   
* Constructing a detailed preprocessing record requires more memory   
* and time to parse, since the information contained in the record   
* is usually not retained. However, it can be useful for     
* applications that require more detailed information about the    
* behavior of the preprocessor.            
*/                   
CXTranslationUnit_DetailedPreprocessingRecord = 0x01, 
+0

Znaleźliśmy to także dzisiaj. Wróć tutaj, aby dodać nową odpowiedź, ale oto jest. Nic do dodania. –

+0

Należy pamiętać, że dokumentacja jest nieprawidłowa. Nie obejmuje wszystkich wystąpień makr, ale tylko te, które same nie są w fazie tworzenia makr (dlatego śledzony jest tylko jeden poziom rozszerzenia makr). Możesz skomentować 'if' na początku' PreprocessingRecord :: addMacroExpansion', aby to zmienić. – Cameron

1

Jeśli używasz argumentów wiersza poleceń jako sposób powoływania libclang, tutaj jest odpowiedni kod z realizacji libclang C API:

// Do we need the detailed preprocessing record? 
if (options & CXTranslationUnit_DetailedPreprocessingRecord) { 
    Args->push_back("-Xclang"); 
    Args->push_back("-detailed-preprocessing-record"); 
} 
Powiązane problemy