2009-05-06 12 views
5

używając grep, greim vima lub innego polecenia powłoki unix, chciałbym znaleźć funkcje w dużym pliku cpp, który zawiera konkretne słowo w ich ciele.Jak znaleźć funkcje w pliku cpp, które zawierają konkretne słowo

W plikach, w których używam szukanego słowa znajduje się na wciętej linii, odpowiedni nagłówek funkcji jest pierwszym wierszem powyżej linii wciętej, która zaczyna się od pozycji 0 i nie jest "{" .

Na przykład szukając john_doe w poniższym fragmencie kodu

int foo (int arg1) 
{ 
    /// code 
} 
void bar (std::string arg2 ) 
{ 
    /// code 
    aFunctionCall(JOHN_DOE); 
    /// more code 
} 

powinien dać mi

void bar (std::string arg2 ) 

algorytmu, który mam nadzieję złapać w grep/vim/Unix skryptów powłoki prawdopodobnie najlepsze wykorzystanie z wcięciami i założeniami formatowania, zamiast próbować parsować C/C++.

Dzięki za sugestie.

Odpowiedz

2

O ile wiem, to nie można zrobić. Oto dlaczego:

Najpierw należy przeszukać linie. Nie ma problemu, w vimie dodanie _ do klasy postaci mówi, żeby zawierało nowe linie. więc {_. *} dopasuje wszystko do tych nawiasów w wielu liniach.

Teraz musisz dopasować dowolny wzorzec do nagłówka funkcji (kruchy, nawet jeśli działa), a następnie, tutaj jest problem, dowolne linie między nim a ciągiem wyszukiwania, a na końcu dopasuj swój ciąg wyszukiwania. Więc może masz regex jak

/^\(void \+\a\+ *(.*)\)\_.*JOHN_DOE 

Ale co się dzieje, jest to pierwszy raz vim znajdzie nagłówek funkcji, zaczyna dopasowanie. Następnie dopasowuje każdy znak, aż znajdzie JOHN_DOE. Który zawiera wszystkie nagłówki funkcji w pliku.

Problem polega na tym, że o ile wiem, nie ma sposobu, aby powiedzieć vimowi, że pasuje do każdej postaci z wyjątkiem tego wzoru regex. A nawet jeśli tak było, regex nie jest narzędziem do tej pracy. To jak otwieranie piwa młotkiem. Powinniśmy napisać prosty skrypt, który poda ci te informacje i ja je mam.

fun! FindMyFunction(searchPattern, funcPattern) 
    call search(a:searchPattern) 
    let lineNumber = line(".") 
    let lineNumber = lineNumber - 1 
    "call setpos(".", [0, lineNumber, 0, 0]) 

    let lineString = getline(lineNumber) 
    while lineString !~ a:funcPattern 
    let lineNumber = lineNumber - 1 
    if lineNumber < 0 
     echo "Function not found :/" 
    endif 
    let lineString = getline(lineNumber) 
    endwhile 

    echo lineString 

endfunction 

To powinno dać wynik chcesz i jest to sposób łatwiej dzielić, debugowanie i modyfikowanie niż wyrażenia regularnego pluć od ujścia sam Cthulhu.

1

Nie można zrobić tego niezawodnie z wyrażeniem regularnym, ponieważ kod nie jest zwykłym językiem. Potrzebujesz potrzebnego parsera dla danego języka.

1

u mogą korzystać grep -r -n -H JOHN_DOE * będzie wyglądać na „john_doe” w plikach rekurencyjnie począwszy od bieżącego katalogu

można użyć następującego kodu do praktycznie znaleźć funkcję, która zawiera wyrażenie tekstowe:

public void findFunction(File file, String expression) { 
    Reader r = null; 
    try { 
     r = new FileReader(file); 
    } catch (FileNotFoundException ex) { 
     ex.printStackTrace(); 
    } 
    BufferedReader br = new BufferedReader(r); 

    String match = ""; 
    String lineWithNameOfFunction = ""; 

    Boolean matchFound = false; 

    try { 
     while(br.read() > 0) { 
      match = br.readLine(); 
      if((match.endsWith(") {")) || 
        (match.endsWith("){")) || 
        (match.endsWith("()")) || 
        (match.endsWith(")")) || 
        (match.endsWith("()"))) { 
       // this here is because i guessed that method will start 
       // at the 0 
       if((match.charAt(0)!=' ') && !(match.startsWith("\t"))) { 
        lineWithNameOfFunction = match;       
       } 
      } 

      if(match.contains(expression)) { 
       matchFound = true; 
       break; 
      } 
     } 
     if(matchFound) 
      System.out.println(lineWithNameOfFunction); 
     else 
      System.out.println("No matching function found"); 
    } catch (IOException ex) { 
     ex.printStackTrace(); 
    } 
} 

Pisałem to w JAVA, testowałem i działałem jak czar. ma kilka wad, ale na początek jest w porządku. nie dodawało obsługi wielu funkcji zawierających to samo wyrażenie i może kilka innych rzeczy. Spróbuj.

+0

Skąd więc pochodzi nazwa funkcji? –

+0

Tak, powinien pochodzić z powyższego kodu, ale moje polecenie grep nie było w stanie uzyskać nazwy funkcji. –

0

Tak jak Robert powiedział, że Regex pomoże. W trybie poleceń uruchom wyszukiwanie regex, wpisując znak "/", a następnie wyrażenie regularne.

Ctags 1 może być również użyteczny. Może wygenerować plik znacznika dla projektu. Ten plik znaczników pozwala użytkownikowi przejść bezpośrednio z wywołania funkcji do jego definicji, nawet jeśli znajduje się w innym pliku przy użyciu "CTRL +]".

1

Arggh! Przyznaję, że jest to trochę przesadzone:

Mały program do filtrowania stdin, komentowania pasków i umieszczania ciał funkcji na tej samej linii. Zostanie oszukany przez przestrzeń nazw i definicje funkcji wewnątrz deklaracji klasowych, poza innymi rzeczami. Ale może to być dobry początek:

#include <stdio.h> 
#include <assert.h> 

int main() { 
    enum { 
     NORMAL, 
     LINE_COMMENT, 
     MULTI_COMMENT, 
     IN_STRING, 
    } state = NORMAL; 
    unsigned depth = 0; 
    for(char c=getchar(),prev=0; !feof(stdin); prev=c,c=getchar()) { 
     switch(state) { 
     case NORMAL: 
      if('/'==c && '/'==prev) 
       state = LINE_COMMENT; 
      else if('*'==c && '/'==prev) 
       state = MULTI_COMMENT; 
      else if('#'==c) 
       state = LINE_COMMENT; 
      else if('\"'==c) { 
       state = IN_STRING; 
       putchar(c); 
      } else { 
       if(('}'==c && !--depth) || (';'==c && !depth)) { 
        putchar(c); 
        putchar('\n'); 
       } else { 
        if('{'==c) 
         depth++; 
        else if('/'==prev && NORMAL==state) 
         putchar(prev); 
        else if('\t'==c) 
         c = ' '; 
        if(' '==c && ' '!=prev) 
         putchar(c); 
        else if(' '<c && '/'!=c) 
         putchar(c); 
       } 
      } 
      break; 
     case LINE_COMMENT: 
      if(' '>c) 
       state = NORMAL; 
      break; 
     case MULTI_COMMENT: 
      if('/'==c && '*'==prev) { 
       c = '\0'; 
       state = NORMAL; 
      } 
      break; 
     case IN_STRING: 
      if('\"'==c && '\\'!=prev) 
       state = NORMAL; 
      putchar(c); 
      break; 
     default: 
      assert(!"bug"); 
     } 
    } 
    putchar('\n'); 
    return 0; 
} 

Jego C++, więc po prostu go w pliku, skompilować go do pliku o nazwie 'spychacz', a następnie:

cat my_source.cpp | ./stripper | grep JOHN_DOE 

więc rozważyć wejście:

int foo (int arg1) 
{ 
    /// code 
} 
void bar (std::string arg2 ) 
{ 
    /// code 
    aFunctionCall(JOHN_DOE); 
    /// more code 
} 

wyjście "cat example.cpp | ./stripper" to:

int foo (int arg1) { } 
void bar (std::string arg2){ aFunctionCall(JOHN_DOE); } 

Wyjście „cat example.cpp | ./stripper | grep JOHN_DOE” jest:

void bar (std::string arg2){ aFunctionCall(JOHN_DOE); } 

Zadanie znalezienia nazwy funkcji (odgadnąć jego ostatni identyfikator do poprzedzać „(”) pozostawiamy jako ćwiczenie dla czytelnika.

3

Prawdopodobnie zostaniesz za to odrzucony!

Jestem zapalonym użytkownikiem (G) VIM, ale gdy chcę przejrzeć lub zrozumieć kod, używam Source Insight. Prawie nigdy nie używam go jako rzeczywistego edytora.

Wykonuje dokładnie to, co chcesz w tym przypadku, np. pokaż wszystkich funkcji/metod, które wykorzystują niektóre podświetlony typ danych/zdefiniować/stała/etc ... w oknie relacji ...

gif of the relations window from the source insight website http://www.sourceinsight.com/docs35/ae1183f1.gif

Ała! Idzie mój przedstawiciel.

+0

Nie martw się, zajmie to kilka minut, aby pozbyć się mojego pomysłu. Wprawdzie wolę vimscript Whaledawg, ponieważ pasuje on dokładnie do pytania, podczas gdy wymaga to użycia dodatkowego oprogramowania. – Andy

Powiązane problemy