Определение запуска функции C # или C ++ в программе с количеством строк - PullRequest
3 голосов
/ 19 января 2010

У меня есть программа, написанная на C #, которая при получении файла C ++ или C # подсчитывает строки в файле, подсчитывает, сколько в комментариях и в сгенерированных дизайнером блоках кода. Я хочу добавить возможность подсчитать, сколько функций в файле и сколько строк в этих функциях. Я не могу понять, как определить, является ли линия (или серия линий) началом функции (или метода).

Как минимум, объявление функции - это тип возвращаемого значения, за которым следуют идентификатор и список аргументов. Есть ли способ определить в C #, что токен является допустимым типом возврата? Если нет, есть ли способ легко определить, является ли строка кода началом функции? В основном мне нужно уметь надежно различать что-то вроде.

bool isThere() 
{
...
}

от

bool isHere = isThere()

и от

isThere()

Как и любые другие объявления функций, похожие на.

Ответы [ 5 ]

2 голосов
/ 19 января 2010

Проблема в том, чтобы сделать это точно, вы должны принять во внимание все возможные способы определения функции C #. По сути, вам нужно написать парсер. Это выходит за рамки простого ответа SO.

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

int
?
/* this 
is */
main /* legal */ (code c) { 
}
1 голос
/ 19 января 2010

Начните с сканирования областей. Вам нужно посчитать открытые скобки {и закрывающие скобки} при прохождении через файл, чтобы вы знали, в какой области вы находитесь. Вам также нужно анализировать // и / * ... * / при сканировании файла , так что вы можете сказать, когда что-то есть в комментарии, а не в реальном коде. Также есть #if, но вам придется скомпилировать код, чтобы знать, как их интерпретировать.

Затем вам нужно разобрать текст непосредственно перед открытием некоторых фигурных скобок, чтобы понять, что они из себя представляют. Ваши функции могут находиться в глобальной области видимости, области классов или области пространства имен, поэтому вы должны иметь возможность анализировать пространства имен и классы, чтобы определить тип рассматриваемой области. Обычно вы можете обойтись довольно простым анализом (большинство программистов используют похожий стиль - например, редко кто-то ставит пустые строки между «классом Fred» и его открытой фигурной скобкой. Но они могут написать «класс Fred {». также есть вероятность того, что они добавят лишнюю строку в строку - например, «шаблон класса __DECLSPEC MYWEIRDMACRO Фред {». Однако, вы можете обойтись довольно простым: «содержит ли строка слово« класс »с пробелами с обеих сторон?» эвристика, которая будет работать в большинстве случаев.

ОК, теперь вы знаете, что находитесь внутри пространства имен и внутри класса, и вы нашли новую открытую область. Это метод?

Основные характеристики метода:

  • тип возврата. Это может быть любая последовательность символов и может быть много токенов ("__DLLEXPORT const unsigned myInt32typedef * &"). Если вы не скомпилируете весь проект, у вас нет шансов.
  • имя функции. Один токен (но обратите внимание на «operator =» и т. Д.)
  • пара скобок, содержащих ноль или более параметров или пустота. Это ваша лучшая подсказка.
  • Объявление функции не будет включать в себя определенные зарезервированные слова, которые будут предшествовать многим областям (например, enum, class, struct и т. Д.). И он может использовать некоторые зарезервированные слова (template, const и т. Д.), Которые вам не следует использовать.

Так что вы можете искать пустую строку или строку, оканчивающуюся на; {или}, обозначающий конец предыдущего оператора / области видимости. Затем возьмите весь текст между этой точкой и открытой скобой вашей области видимости. Затем извлеките список токенов и попытайтесь сопоставить скобки со списком параметров. Убедитесь, что ни один из токенов не является зарезервированным словом (перечисление, структура, класс и т. Д.).

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

1 голос
/ 19 января 2010

Я бы, вероятно, использовал бы регулярное выражение, хотя, учитывая количество типов данных и опций объявления и пользовательских типов / предложений, это было бы нетривиально.Чтобы просто избежать захвата назначений из вызовов функций, вы могли бы начать с регулярного выражения (не проверенного), например:

(private|public|internal|protected|virtual)?\s+(static)?\s+(int|bool|string|byte|char|double|long)\s+([A-Za-z][A-Za-z_0-9]*)\s*\(

Это (далеко не все) перехватывает все, и вам нужно настроитьup.

Другой подход может включать рефлексию для определения объявлений функций, но это, вероятно, не подходит для статического анализа исходного кода.

0 голосов
/ 19 января 2010

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

0 голосов
/ 19 января 2010

Есть ли способ определить в C #, что токен является допустимым типом возврата?

Вы можете легко определить, что это либо тип возвращаемого значения, либо ошибка (убедившись, что в этой позиции больше ничего не может быть). И вам, вероятно, не нужно гарантировать «правильное» поведение недействительного кода.

Тогда вы ищите скобки.

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