2012-06-18 14 views
13

Dato un oggetto AST in clang, come posso ottenere il codice dietro di esso? Ho provato la modifica del codice nella tutorial, e ha aggiunto:Ottenere il codice sorgente di clang AST

clang::SourceLocation _b = d->getLocStart(), _e = d->getLocEnd(); 
char *b = sourceManager->getCharacterData(_b), 
     e = sourceManager->getCharacterData(_E); 
llvm:errs() << std::string(b, e-b) << "\n"; 

ma ahimè, non è stato stampato nella dichiarazione typedef, solo circa la metà di esso! Lo stesso fenomeno si è verificato durante la stampa di Expr.

Come posso stampare e visualizzare l'intera stringa originale che costituisce la dichiarazione?

+0

Credo che i punti di locazione fonte fine l'ultimo token nel campo (non uno dopo la fine) e così vi perderete l'ultimo token. – bames53

+0

@ bames53 sembra che tu abbia ragione! Come ottengo quest'ultimo token? – mikebloch

+0

A parte il fatto che probabilmente dovrebbe essere '_e' non' _w' nella terza riga, la differenza nell'ultima riga non è la differenza? (Ie 'e - b' non' b - e') –

risposta

14

utilizzare il modulo Lexer:

clang::SourceManager *sm; 
clang::LangOptions lopt; 

std::string decl2str(clang::Decl *d) { 
    clang::SourceLocation b(d->getLocStart()), _e(d->getLocEnd()); 
    clang::SourceLocation e(clang::Lexer::getLocForEndOfToken(_e, 0, *sm, lopt)); 
    return std::string(sm->getCharacterData(b), 
     sm->getCharacterData(e)-sm->getCharacterData(b)); 
} 
+1

Questa è davvero una buona risposta, ma quando provo a stampare un commento di paragrafo '/ ** ... * /' usando questa funzione 'std :: string fullComment2str (commenti :: FullComment * commento, clang :: SourceManager * sm, clang :: LangOptions lopt) { if (! comment) { return std :: string(); } clang :: SourceLocation b (comment-> getLocStart()), _e (comment-> getLocEnd()); clang :: SourceLocation e (clang :: Lexer :: getLocForEndOfToken (_e, 0, * sm, lopt)); return std :: string (sm-> getCharacterData (b), sm-> getCharacterData (e) -sm-> getCharacterData (b)); } L'output non contiene marker di inizio + fine. –

+1

Attenzione, ho eseguito alcuni test con questo approccio e, a volte, per quantità estremamente elevate di codice, i risultati di 'getCharacterData()' non restituiscono puntatori di caratteri dallo stesso buffer ... Ho avuto il puntatore di "fine" atterrare in pila mentre il puntatore "inizio" punta da qualche parte nell'heap ... Questo porta allo strumento che si blocca o inondando il terminale con la memoria inutile. –

+0

@StevenLu Hai capito cosa c'è di sbagliato nei metodi? Come posso ripararlo? –

5

Il seguente codice funziona per me.

std::string decl2str(clang::Decl *d, SourceManager &sm) { 
    // (T, U) => "T,," 
    string text = Lexer::getSourceText(CharSourceRange::getTokenRange(d->getSourceRange()), sm, LangOptions(), 0); 
    if (text.size() > 0 && (text.at(text.size()-1) == ',')) //the text can be "" 
     return Lexer::getSourceText(CharSourceRange::getCharRange(d->getSourceRange()), sm, LangOptions(), 0); 
    return text; 
} 
0

Il metodo di Elazar ha funzionato per me tranne quando era coinvolta una macro. La seguente correzione ha deliberato che:

std::string decl2str(clang::Decl *d) { 
    clang::SourceLocation b(d->getLocStart()), _e(d->getLocEnd()); 
    if (b.isMacroID()) 
     b = sm->getSpellingLoc(b); 
    if (e.isMacroID()) 
     e = sm->getSpellingLoc(e); 
    clang::SourceLocation e(clang::Lexer::getLocForEndOfToken(_e, 0, *sm, lopt)); 
    return std::string(sm->getCharacterData(b), 
     sm->getCharacterData(e)-sm->getCharacterData(b)); 
} 
Problemi correlati