Как найти функции в файле cpp, которые содержат определенное слово - PullRequest
5 голосов
/ 06 мая 2009

используя grep, vim's grep или другую команду оболочки unix, я хотел бы найти функции в большом файле cpp, который содержит определенное слово в своем теле.

В файлах, с которыми я работаю, словом, которое я ищу, является строка с отступом, соответствующий заголовок функции - это первая строка над строкой с отступом, которая начинается с позиции 0 и не является '{'.

Например, поиск JOHN_DOE в следующем фрагменте кода

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

должен дать мне

void bar ( std::string arg2  )

Алгоритм, который я надеюсь поймать в сценариях оболочки grep / vim / unix, вероятно, будет лучше использовать допущения отступа и форматирования, чем пытаться проанализировать C / C ++.

Спасибо за ваши предложения.

Ответы [ 8 ]

3 голосов
/ 07 мая 2009

Мне, вероятно, за это проголосуют!

Я заядлый (G) пользователь VIM, но когда я хочу просмотреть или понять некоторый код, я использую Source Insight . Я почти никогда не использую его как настоящий редактор.

Он делает именно то, что вы хотите в этом случае, например показать все функции / методы, которые используют какой-либо выделенный тип данных / define / constant / etc ... в окне отношений ...

gif of the relations window from the source insight website
(источник: sourceinsight.com )

Ой! Вот мой представитель.

2 голосов
/ 06 мая 2009

Насколько я знаю, это невозможно сделать. И вот почему:

Во-первых, вы должны искать между строками. Нет проблем, в vim добавление _ к символьному классу говорит ему включать новые строки. поэтому {_. *} будет соответствовать всему, что находится в скобках в нескольких строках.

Итак, теперь вам нужно сопоставить любой шаблон для заголовка функции (хрупкий, даже если он работает), и вот в чем проблема, независимо от того, какие строки находятся между ним и строкой поиска и, наконец, соответствует строке поиска. Таким образом, вы можете иметь регулярное выражение типа

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

Но что происходит, когда vim в первый раз находит заголовок функции и начинает сопоставлять. Затем соответствует каждому символу , пока не найдет JOHN_DOE. Который включает в себя все заголовки функций в файле.

Так что проблема в том, что, насколько я знаю, нет никакого способа сказать vim, что он соответствует каждому символу, кроме этого шаблона регулярного выражения. И даже если бы и было, регулярное выражение не является инструментом для этой работы. Это как открыть пиво молотком. Что мы должны сделать, это написать простой скрипт, который даст вам эту информацию, и у меня есть.

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

Это должно дать вам желаемый результат, и гораздо проще поделиться, отладить и повторно использовать, чем выплевывать регулярные выражения из уст самого Ктулху.

1 голос
/ 06 мая 2009

Arggh! Я признаю, что это немного чрезмерно:

Небольшая программа для фильтрации стандартного ввода, удаления комментариев и размещения тел функций в одной строке. Помимо всего прочего, его одурачат пространства имен и определения функций внутри объявлений классов. Но это может быть хорошим началом:

#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;
}

Это c ++, поэтому просто поместите его в файл, скомпилируйте в файл с именем 'stripper', а затем:

cat my_source.cpp | ./stripper | grep JOHN_DOE

Итак, рассмотрим ввод:

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

Вывод "cat example.cpp | ./stripper":

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

Вывод "cat example.cpp | ./stripper | grep JOHN_DOE":

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

Работа по поиску имени функции (предположим, что последний идентификатор предшествует «(») оставлена ​​читателю в качестве упражнения.

1 голос
/ 06 мая 2009

Для такого рода вещей, хотя это снова касается примитивного поиска, я бы рекомендовал плагин compview . Откроется окно поиска, так что вы сможете увидеть всю строку, где произошел поиск, и автоматически перейти к ней. Дает хороший обзор.

alt text
(источник: axisym3.net )

1 голос
/ 06 мая 2009

Вы не можете сделать это надежно с помощью регулярного выражения, потому что код не является регулярным языком. Вам нужен настоящий парсер для рассматриваемого языка.

1 голос
/ 06 мая 2009

Сложный вызов, хотя в качестве отправной точки я бы предложил этот замечательный VIM Regex Tutorial .

0 голосов
/ 06 мая 2009

Как сказал Роберт, Регекс поможет. В командном режиме запустите поиск по регулярному выражению, введя символ "/", а затем свой регулярное выражение.

Ctags 1 также могут быть вам полезны. Он может генерировать файл тегов для проекта. Этот файл тегов позволяет пользователю напрямую переходить от вызова функции к его определению, даже если он находится в другом файле с помощью «CTRL +]».

0 голосов
/ 06 мая 2009

вы можете использовать grep -r -n -H JOHN_DOE * он будет искать "JOHN_DOE" в файлах, рекурсивно начиная с текущего каталога

Вы можете использовать следующий код, чтобы практически найти функцию, которая содержит текстовое выражение:

    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();
    }
}

Я написал это на JAVA, проверил и работает как шарм. Есть несколько недостатков, но для начала это хорошо. не добавлена ​​поддержка нескольких функций, содержащих одно и то же выражение и, возможно, некоторые другие вещи. попробуй.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...