Regex за анализиране на декларации на C/C++ функции

Трябва да анализирам и разделя функциите на C и C++ на основните компоненти (тип връщане, име на функция/клас и метод, параметри и т.н.).

Работя или от заглавки, или от списък, където подписите са под формата:

public: void __thiscall myClass::method(int, class myOtherClass *)

Имам следния регулярен израз, който работи за повечето функции:

(?<expo>public\:|protected\:|private\:) (?<ret>(const )*(void|int|unsigned int|long|unsigned long|float|double|(class .*)|(enum .*))) (?<decl>__thiscall|__cdecl|__stdcall|__fastcall|__clrcall) (?<ns>.*)\:\:(?<class>(.*)((<.*>)*))\:\:(?<method>(.*)((<.*>)*))\((?<params>((.*(<.*>)?)(,)?)*)\)

Има няколко функции, които не обича да анализира, но изглежда, че съответстват на модела. Не се притеснявам за съвпадение на функции, които не са членове на клас в момента (мога да се справя с това по-късно). Изразът се използва в C# програма, така че <label>s са за лесно извличане на групите.

Чудя се дали има стандартен регулярен израз за анализиране на всички функции или как да подобря моята, за да се справя със странните изключения?


person ssube    schedule 04.08.2010    source източник
comment
Какво точно трябва да анализирате? Изглежда, че анализирате декларации на функции, а не самите функции. Това стандартен синтаксис на C и C++ ли е или някаква друга форма?   -  person David Thornley    schedule 04.08.2010
comment
Това са декларации на функции, сбърках в заглавието.   -  person ssube    schedule 04.08.2010
comment
Има инструменти на командния ред като ctag, които вършат работа. Например: ctags --c++-kinds=f -x myfile.h   -  person karlphillip    schedule 04.08.2010
comment
Компилатори 101: C++ не е обикновен език, той дори не може да бъде представен с контекстно-свободна граматика. Вие не можете да го анализирате чрез регулярен израз, нито дори базираните/вдъхновени от Perl регулярни изрази на стероиди.   -  person Juliano    schedule 05.08.2010
comment
@Juliano: Самият C++ може да не е нормален език, но декларациите на функции със сигурност изглежда следват някои доста редовни модели. Не се притеснявам от анализирането на телата или езика като цяло, просто декларации.   -  person ssube    schedule 05.08.2010
comment
@karlphillip: Опитах SWIG за кратко, но не се получи толкова добре. ctag изглежда, че може да е това, което търся, ще видя дали работи.   -  person ssube    schedule 05.08.2010
comment
Имайте предвид, че функциите не трябва да имат предварително дефинирани типове като връщани типове. Дори в C всеки идентификатор може да бъде тип връщане (помислете typedef). FWIW, никога не съм виждал имена на класове с предшествие от class. Накратко, вероятно е законно, но няма да го видите.   -  person David Thornley    schedule 05.08.2010
comment
@David: Вярно. Първата ви точка, за която забравих, може да обясни защо някои функции са пропуснати. Що се отнася до class в тип, това би било незаконно, но това всъщност не е от заглавки, а от списък с функции, които друга програма изплюва (което показва класове, enums и т.н., като ги префиксира със съответната ключова дума). Събличам ги по-късно.   -  person ssube    schedule 05.08.2010
comment
@peachykeen: декларациите на функциите зависят от типовете, които се дефинират динамично по време на етапа на анализиране от enums, structs, classes и typedefs. Само това го прави чувствителна към контекста граматика. Добавете към този шаблон дефиниции и вижте докъде ще стигнете.   -  person Juliano    schedule 05.08.2010
comment
@peachykeen: Фактът, че една функция може да има произволен брой аргументи, означава, че декларациите не формират нормален език.   -  person Oliver Charlesworth    schedule 05.08.2010
comment
@Oli: Декларациите на функциите не образуват нормален език по няколко причини, но произволният брой аргументи не е една от тях. Това се постига лесно с Kleene Closure.   -  person Juliano    schedule 05.08.2010
comment
Да кажем, че реших да премахна обработката от заглавки и просто да използвам списъците, създадени от другата ми програма (която отпечатва DLL експорти). Всички експортни списъци са във формата, която имам във въпроса. Typedefs се заменят с техния действителен тип, classes/structs/enums винаги се префиксират като такива, шаблоните винаги се дават изрично и т.н. Сега третирайте всички параметри като една единица (всичко между скобите е param-list). Дали тогава това ще стане достатъчно редовно, за да има един израз да го анализира? Опитвам се да избягвам да правя синтактичния анализ на ръка, така че е добре да променям няколко.   -  person ssube    schedule 06.08.2010


Отговори (3)


C++ е известен като труден за анализ; невъзможно е да се напише регулярен израз, който да улавя всички случаи. Например, може да има неограничен брой вложени скоби, което показва, че дори това подмножество на езика C++ не е редовно.

Но изглежда, че търсите практичност, а не теоретична коректност. Просто продължавайте да подобрявате регулярния си израз, докато улови случаите, които трябва да улови, и се опитайте да го направите възможно най-строг, за да не получавате фалшиви съвпадения.

Без да знаем "странните изключения", които не улавя, е трудно да се каже как да се подобри регулярният израз.

person Thomas    schedule 04.08.2010
comment
От друга страна, популярната имплементация на регулярен израз е идеална за съвпадение на необикновени езици. Например, възможно е да напишете регулярен израз, който съвпада с безкрайни дълбоки вложени двойки скоби. - person Tamás Szelei; 29.05.2013

Разгледайте Boost.Spirit, това е библиотека за усилване, която позволява прилагането на рекурсивни анализатори на спускане използвайки само C++ код и без препроцесори. Трябва да посочите BNF граматика и след това да подадете низ за да го анализирате. Можете дори да генерирате абстрактно-синтактично дърво (AST), което е полезно за обработка на анализираните данни.

BNF спецификацията изглежда така за списък от цели числа или думи, разделени може да изглежда така:

using spirit::alpha_p;
using spirit::digit_p;
using spirit::anychar_p;
using spirit::end_p;
using spirit::space_p;

// Inside the definition...
integer    = +digit_p;                      // One or more digits.
word       = +alpha_p;                      // One or more letters.
token      = integer | word;                // An integer or a word.
token_list = token >> *(+space_p >> token)  // A token, followed by 0 or more tokens.

За повече информация вижте документацията, библиотеката е малко сложна в началото, но след това става по-лесна за използване (и по-мощна).

person jbernadas    schedule 04.08.2010

Не. Дори прототипите на функции могат да имат произволни нива на влагане, така че не могат да бъдат изразени с един регулярен израз.

Ако наистина се ограничавате до неща, много близки до вашия пример (точно 2 аргумента и т.н.), тогава можете ли да дадете пример за нещо, което не съвпада?

person Oliver Charlesworth    schedule 04.08.2010
comment
.NET регулярният израз е единственият вариант досега, който може да има произволни нива на влагане. Но ако го използвам за този тип работа, не бих го направил. - person Abel; 04.08.2010
comment
@Abel: Вкусът на .Net regex е рекурсивен и прави обратно проследяване (следователно не е DFA). Това е копирано от Perl, който съществува от много и много години преди изобретяването на .Net. - person Juliano; 05.08.2010
comment
@Juliano, не съм сигурен какво искаш да кажеш. Всъщност и Perl, и .NET са NFA, както и повечето разновидности на регулярни изрази. .NET никога не е криел, че следва точно синтаксиса на Perl. Но .NET въведе балансиращи групи, което имах предвид с произволни нива на влагане. Той следи броя на отворените спрямо затворените скоби (или нещо друго) и успява да съпостави само ако отварящите и затварящите двойки са с еднакъв брой и са сдвоени. Досега, afaik, .NET е единственият вариант, който поддържа това. - person Abel; 05.08.2010
comment
Това няма нищо общо с NFA/DFA. Дори NFA може да разпознае само обикновен език и е възможно да се трансформира NFA в DFA (въпреки че броят на състоянията може да нарасне експоненциално). Вместо това регулярните изрази на Perl/.NET имат ограничена поддръжка на контекстно-свободен езиков анализ, който съответства на пушаунд автомат. - person Arne Vogel; 16.03.2018