Подтвердить что ты не робот

Regex вытащить объявления прототипа функции C?

Я где-то на кривой обучения, когда дело доходит до регулярных выражений, и мне нужно использовать их для автоматического изменения прототипов функций в кучке заголовков C. Кто-нибудь знает о приличном регулярном выражении для поиска любых и всех прототипов функций в заголовке C, исключая все остальное?

Изменить: три вещи, которые были непонятны изначально:

  • Я не забочусь о заботе о С++, только прямой C. Это означает отсутствие шаблонов и т.д., чтобы беспокоиться.
  • Решение должно работать с typedefs и structs, не ограничиваясь только базовыми типами C.
  • Это своего рода одноразовая вещь. Это не должно быть красивым. Меня не волнует, сколько от него осталось до тех пор, пока оно работает, но мне не нужно сложное и сложное решение.
4b9b3361

Ответ 2

Чтобы сделать это правильно, вам нужно проанализировать в соответствии с грамматикой языка С. Но если это только для языка C и только для файлов заголовков, возможно, вы можете взять несколько ярлыков и обойтись без полномасштабного BNF.

^
\s*
(unsigned|signed)?
\s+
(void|int|char|short|long|float|double)  # return type
\s+
(\w+)                                    # function name
\s*
\(
[^)]*                                    # args - total cop out
\)
\s*
;

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

Обратите внимание, что BNF можно преобразовать в регулярное выражение. Это будет большое сложное регулярное выражение, но оно выполнимо.

Ответ 3

Для одноразового упражнения вы, вероятно, сделаете все возможное, запустив простой и посмотрев на код, который вы должны сканировать. Выберите три худших заголовка, создайте регулярное выражение или ряд регулярных выражений, которые выполняют эту работу. Вы должны решить, будете ли и как вы будете обрабатывать комментарии, содержащие объявления функций (и, действительно, объявления функций, содержащие комментарии). Работа с:

extern void (*function(int, void (*)(int)))(int);

(которая может быть стандартной функцией C signal()) жесткой в ​​регулярном выражении из-за вложенных круглых скобок. Если у вас нет таких прототипов функций, время, затрачиваемое на то, как справляться с ними, - это потраченное время. Аналогичные комментарии относятся к указателям на многомерные массивы. Скорее всего, у вас есть стилистические соглашения, чтобы упростить вашу жизнь. Вы не можете использовать комментарии C99 (С++); вам не нужно кодировать их. Вероятно, вы не ставите несколько деклараций в одну строку, либо с общим типом, либо без него, поэтому вам не нужно иметь дело с этим.

extern int func1(int), func2(double); double func3(int);  // Nasty!

Ответ 4

Предполагая, что ваш код отформатирован примерно как

type name function_name(variables **here, variables &here)
{
    code
}

Вот один лайнер для Powershell:

ls *.c, *.h | sls "^(\w+( )?){2,}\([^[email protected]#$+%^]+?\)"

Что возвращает результаты, например:

...
common.h:37:float max(float a, float b)
common.h:42:float fclamp(float val, float fmin, float fmax)
common.h:51:float lerp(float a, float b, float b_interp)
common.h:60:float scale(float val, float valmin, float valmax, float min,
float max)
complex.h:3:typedef struct complex {
complex.h:8:double complexabs(complex in)
complex.h:13:void complexmult(complex *out, complex a, complex b)
complex.h:20:void complexadd(complex *out, complex a, complex b)
complex.h:27:int mandlebrot(complex c, int i)
...

Чтобы увидеть только строку без спецификаций файла, добавьте format-table -property line (или сокращенно как ft -p line):

ls *.c, *.h | sls "^(\w+( )?){2,}\([^[email protected]#$+%^]+?\)" | format-table -p line

Что возвращает:

Line
----
void render(SDL_Surface *screen)
void saveframe(SDL_Surface *screen)
int handleevents(SDL_Surface *screen)
int WinMain(/*int argc, char* args[]*/)
void printscreen(SDL_Surface *screen, unsigned int exclude)
void testsection(char name[])
void sdltests(SDL_Surface *screen, SDL_Window *window, int width, int height)
int WinMain(/*int argc, char *argv[]*/)
int random(int min, int max) {
int main(int argc, char *argv[])

БОНУС: Объяснение регулярного выражения:

^(\w+(\s+)?){2,}\([^[email protected]#$+%^]+?\)
^                                Start of a line
 (         ){2,}                 Create atom to appear to or more times
                                 (as many as possible)
  \w+(\s+)?                      A group of word characters followed by
                                 an optional space
                \(            \) Literal parenthesis containing
                  [^[email protected]#$+%^]+?   A group of 0 or more characters
                                 that AREN'T in "[email protected]#$+%^"

Ответ 5

Одно языковое regex звучит очень сложно. Я лично использую perl script для этого. Это легко. Основной подход → 1. Вызовите свой любимый препроцессор c, чтобы исключить комментарии и расширить макросы. (так проще) 2. Подсчитайте символы '{' '}'. Для функций в простой C они имеют предсказуемое поведение, которое позволит вам определять имена функций. 3. Посмотрите имена функций в исходный источник (перед предварительной обработкой, чтобы получить подпись, которая имеет typedefs) Это неэффективный подход, но для меня это работает очень хорошо. Шаг 1 не нужен, но это облегчит вам жизнь.

Ответ 6

Здесь регулярное выражение, которое является хорошей отправной точкой для поиска имен функций C:

^\s*(?:(?:inline|static)\s+){0,2}(?!else|typedef|return)\w+\s+\*?\s*(\w+)\s*\([^0]+\)\s*;?

И это некоторые тестовые примеры для проверки выражения:

// good cases
static BCB_T   *UsbpBufCtrlRemoveBack   (BCB_Q_T *pBufCtrl);
inline static AT91_REG *UDP_EpIER               (UDP_ENDPOINT_T *pEndpnt);
int UsbpEnablePort (USBP_CTRL_T *pCtrl)
bool_t IsHostConnected(void)
inline AT91_REG *UDP_EpCSR (UDP_ENDPOINT_T *pEndpnt)

// shouldn't match
typedef void (*pfXferCB)(void *pEndpnt, uint16_t Status);
    else if (bIsNulCnt && bIsBusyCnt)
            return UsbpDump(Buffer, BufSize, Option);

Наконец, здесь простой TCL script для чтения файла и извлечения всех прототипов функций и имен функций.

set fh [open "usbp.c" r]
set contents [read $fh]
close $fh
set fileLines [split $contents \n]
set lineNum 0
set funcCount 0
set funcRegexp {^\s*(?:(?:inline|static)\s+){0,2}(?!else|typedef|return)\w+\s+\*?\s*(\w+)\s*\([^0]+\)\s*;?}
foreach line $fileLines {
    incr lineNum
    if {[regexp $funcRegexp $line -> funcName]} {
        puts "line:$lineNum, $funcName"
        incr funcCount
    }; #end if

}; #end foreach
puts "$funcCount functions found."

Ответ 7

Скажем, у вас есть весь файл c, который читается в $buffer. * сначала создайте регулярное выражение, которое заменяет все комментарии одинаковым количеством пробелов и строк, чтобы позиции строк и столбцов не менялись * создать регулярное выражение, которое может обрабатывать строку в скобках * then regexp, как это находит функции: (Статический |)\s + (\ W +)\с * $parenthezized_regexp + * {

этот reg exp не обрабатывает функции, в определении функции которых используются директивы препроцессора.

если вы идете на lex/yacc, вам нужно комбинировать ansi c и препроцессорные грамматики для обработки этих директив препроцессора внутри определений функций

Ответ 8

Как продолжение великого Дин TH ответ

Это найдет

  • Только функции, а не декларация.
  • И функция, возвращающая указатели

^([\w\*]+( )*?){2,}\(([^[email protected]#$+%^;]+?)\)(?!\s*;)