2016-07-08 23 views
0

Hallo Ich habe einen AST-Besucher implementiert, der recht gut funktioniert und in der Konsole die Informationen aus dem AST drucken kann, wie Variablendeklarationen, Funktionsdeklarationen und Funktionsaufrufe . Heute, während ich experimentiert habe, bin ich auf einen Funktionsaufruf gestoßen, der nicht als Funktionsaufruf erkannt wird. Syntaktisch ist das gleiche wie ein Funktionsaufruf. Hier ist der Code:AST Besucherfunktion Anrufausdruck erkennt den Funktionsaufruf nicht korrekt

void 
TIFFError(const char* module, const char* fmt, ...) 
{ 
    va_list ap; 
    va_start(ap, fmt); <------------------------------ THIS IS THE FUNCTION CALL 
    if (_TIFFerrorHandler) 
     (*_TIFFerrorHandler)(module, fmt, ap); 
    if (_TIFFerrorHandlerExt) 
     (*_TIFFerrorHandlerExt)(0, module, fmt, ap); 
    va_end(ap);   <--------------------------------AND THIS ONE 
} 

Mein Code des ASTVisitor ist dies:

bool VisitStmt(Stmt *st) 
{ 
    FullSourceLoc FullLocation = astContext->getFullLoc(st->getLocStart()); 
    FileID fileID = FullLocation.getFileID(); 
    unsigned int thisFileID = fileID.getHashValue(); 
    if(thisFileID == 1) //checks if the node is in the main = input file. 
    { 
     if (CallExpr *call = dyn_cast<CallExpr>(st)) 
     { 
      numFuncCalls++; 
      //call->dump(); //prints the corresponding line of the AST. 
      FunctionDecl *func_decl; 
      if(call->getDirectCallee()) 
      { 
       func_decl = call ->getDirectCallee(); 
       string funcCall = func_decl->getNameInfo().getName().getAsString(); 
       cout << "Function call: " << funcCall << " with arguments "; 
       APIs << funcCall << ","; 
       for(int i=0, j = call->getNumArgs(); i<j; i++) 
       { 
        //For each argument it prints its type. The function must be declared otherwise it will return int-for unknown argument type. 
        APIs << call->getArg(i)->getType().getAsString()<< ","; 
        cout << call->getArg(i)->getType().getAsString() << ", "; 
       } 
       cout << "\n"; 
      } 
      else 
      { 
       Expr *expr = call->getCallee(); 
       string exprCall = expr->getStmtClassName(); 
       cout << "Expression call: " << exprCall << " with arguments "; 
       APIs << exprCall << ","; 
       for(int i=0, j = call->getNumArgs(); i<j; i++) 
       { 
        //For each argument it prints its type. The function must be declared otherwise it will return int-for unknown argument type. 
        APIs << call->getArg(i)->getType().getAsString()<< ","; 
        cout << call->getArg(i)->getType().getAsString() << ", "; 
       } 
       cout << "\n"; 
      } 
     } 
    } 
    return true; 
} 

Der Ausdruck if (Call-> getDirectCallee()) ist nicht wahr, für die Anrufe.

Wie kann ich den "Funktionsnamen" und seine Argumente extrahieren, wie ich es mit den "normalen" Funktionsaufrufen mache? Oder sogar jemand gibt mir einen Einblick, warum diese Anrufe von AST rekursive Besucher nicht als normale Funktionsaufrufe erkannt werden.

Vielen Dank.

Antwort

0

Der Grund, warum es Ihnen nicht als Funktion angezeigt wird, ist, dass es in Wirklichkeit keine Funktion ist. Wenn Sie Blick auf <cstdarg> Header-Datei gehen sehen Sie, dass die Funktion eine MACRO

#define va_start(ap, param) __builtin_va_start(ap, param) 

Nun, es ist etwas, das LinkageSpecDecl genannt, die mit dem tatsächlichen functiondecl verknüpfen wird es zeigen.

Etwas, was Sie tun können, um solche Probleme zu lösen, ist die rohe ASTDump des Codes, den Sie analysieren wollen, da es Ihnen sagt, was zu erwarten ist.

Zum Beispiel habe ich Ihre Funktion auf diese geändert.

#include <cstdarg> 

void TIFFError(const char* module, const char* fmt, ...) 
{ 
    va_list ap; 
    va_start(ap, fmt); <------------------------------ THIS IS THE FUNCTION CALL 
    if (_TIFFerrorHandler) 
     (*_TIFFerrorHandler)(module, fmt, ap); 
    if (_TIFFerrorHandlerExt) 
     (*_TIFFerrorHandlerExt)(0, module, fmt, ap); 
    va_end(ap);   <--------------------------------AND THIS ONE 
} 

Und dann erzeugt es ast Dump ist mit (den oberen Code übernehmen in temp.cpp gespeichert ist):

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

Ein weiterer Zeiger wird statt visitStmt sein und für functiondecl, dass die Überprüfung, was Sie tun können ist, visitFuncDecl, visitDeclRef und andere zu implementieren, weil das sie separat besuchen würde. Sie müssen keine Fälle formulieren und pflegen, da alles in einer angemessenen Funktion zu Ihnen kommt. Sie können mehr darüber lesen, wie Besuchermuster dafür funktionieren. Ich habe keine sehr gute Verbindung, sonst hätte ich dir das auch gegeben.

+0

Vielen Dank für Ihre Antwort. Das wird die Dinge klären und mich weiterbringen. Ich dump die entsprechende Zeile und ich kann den __builtin_va_start (ap, param) sehen, aber ich bin nie zuvor über so etwas gekommen (Definieren eines Makros für einen Funktionsaufruf.). Zu Ihrem letzten Punkt habe ich VisitVarDecl und VisitFuctionDecl bereits implementiert. Der VisitStmt soll mir helfen, die Funktionsaufrufe zu bekommen. Wenn es einen besseren Weg gibt, sie zu bekommen, lass es mich wissen. –

+0

Sie können Funktionen wie visitCallExpr, visitCXXMemberCallExpr für eine reguläre Funktion und einen Funktionsaufruf aufrufen. Es könnte mehr geben, aber ich bin mir dessen nicht bewusst. Auch, wenn Ihre ursprüngliche Frage gelöst ist, werde ich schätzen, wenn Sie es markieren. –

+0

Vielen Dank für Ihren Kommentar. Ich wusste nicht, dass visitCallExpr existiert !! Ich bin im Doxygen auf diese Funktion nicht gestoßen. Ich benutzte diese Quelle http://clang.llvm.org/doxygen/classclang_1_1idx_1_1ASTVisitor.html Sie haben Recht. VisitCallExpr() existiert auch .. –