Как бих внедрил нещо подобно на директивата на компилатора Objective-C @encode() в ANSI C?

Директивата @encode връща const char *, който е дескриптор на кодиран тип на различните елементи от типа данни, който е предаден. Следва пример:

struct test
{ int ti ;
  char tc ;
} ;

printf( "%s", @encode(struct test) ) ;
// returns "{test=ic}"

Виждах използването на sizeof() за определяне на примитивни типове - и ако беше пълен обект, можех да използвам методите на класа, за да направя интроспекция.

Как обаче се определя всеки елемент от непрозрачна структура?


person Anderson    schedule 12.02.2010    source източник
comment
Той може да ги определи, защото е част от реализацията на компилатора. Вашият код не е, така че не може.   -  person    schedule 13.02.2010
comment
Не можете да направите „@encode(blob)“, без да докоснете компилатора, но бихте ли се съгласили с нещо като „encode(blob, size)“, в което също предавате размера на структурата на функцията за кодиране? Това би било доста лесно, въпреки че няма да е преносимо или ефективно, защото няма да знае опаковането/endian/подравняването на структурата.   -  person Casey Barker    schedule 18.02.2010
comment
но все още не би могъл да знае какъв е всеки структурен елемент...   -  person Anderson    schedule 18.02.2010
comment
Не, но не е необходимо да знае структурата на данните, за да ги превърне в плосък поток от байтове, ако всичко, което трябва да направите, е по-късно да възпроизведете обекта с decode(). Така че докато структурата остава същата, можете просто да memcpy() необработените данни. Ще имате няколко фалшиви байта за подпълване и всички многобайтови полета ще бъдат в целева форма, но ще работи в смисъл, че данните, които сте кодирали в байтов поток, могат след това да бъдат декодирани в същата структура. Това със сигурност е глупаво, но не бях сигурен към какво се стремиш. Ако това изглежда очевидно и тривиално, просто ме игнорирайте. :)   -  person Casey Barker    schedule 18.02.2010


Отговори (3)


Отговорът на @Lothars може да е „циничен“, но за съжаление е доста близо до целта. За да приложите нещо като @encode(), имате нужда от пълен анализатор, за да извлечете информацията за типа. Е, поне за нещо различно от "тривиални" @encode() твърдения (т.е. @encode(char *)). Съвременните компилатори обикновено имат два или три основни компонента:

  • Предният край.
  • Междинният край (за някои компилатори).
  • Задният край.

Предният край трябва да анализира целия изходен код и основно преобразува текста на изходния код във вътрешна, „машинно използваема“ форма.

Задната част превежда вътрешната, „използваема от машината“ форма в изпълним код.

Компилаторите, които имат "междинен край", обикновено го правят поради някаква нужда: те поддържат множество "предни части", вероятно съставени от напълно различни езици. Друга причина е да се опрости оптимизацията: всички пасове за оптимизация работят върху едно и също междинно представяне. Компилаторният пакет gcc е пример за "тристепенен" компилатор. llvm може да се счита за компилатор на етап "междинен и заден край": "Виртуалната машина от ниско ниво" е междинното представяне и цялата оптимизация се извършва в тази форма. llvm също може да го запази в това междинно представяне до последната секунда - това позволява "оптимизиране на времето за връзка". Компилаторът clang наистина е "преден край", който (ефективно) извежда llvm междинно представяне.

Така че, ако искате да добавите @encode() функционалност към „съществуващ“ компилатор, вероятно ще трябва да го направите като „компилатор/препроцесор“ от „източник към източник“. Това беше начинът, по който бяха написани оригиналните компилатори на Objective-C и C++ - те анализираха входния изходен текст и го преобразуваха в "обикновен C", който след това беше въведен в стандартния C компилатор. Има няколко начина да направите това:

Навийте своя собствена

  • Използвайте yacc и lex, за да съставите анализатор на ANSI-C. Ще ви е необходима граматика - ANSI C граматика (Yacc) е добро начало. Всъщност, за да бъде ясно, когато казвам yacc, наистина имам предвид bison и flex. И също така, свободно, другите различни yacc и lex подобни на C-базирани инструменти: lemon, dparser и др...
  • Използвайте perl с Yapp или EYapp, които са псевдо-yacc клонинги в perl. Вероятно по-добре за бързо прототипиране на идея в сравнение с базираните на C yacc и lex - все пак е perl: регулярни изрази, асоциативни масиви, без управление на паметта и т.н.
  • Създайте своя анализатор с Antlr. Нямам опит с тази верига от инструменти, но това е друг инструмент за „компилиращ компилатор“, който (изглежда) е насочен повече към разработчиците на Java. Изглежда, че има свободно достъпни C и Objective-C граматики.

Хакнете друг инструмент

Забележка: Нямам личен опит с използването на който и да е от тези инструменти, за да направя нещо като добавяне на @encode(), но подозирам, че биха били голяма помощ.

  • CIL – Нямам личен опит с този инструмент, но е предназначен за анализиране на изходния код на C и след това „правене неща" с него. От това, което мога да намеря от документите, този инструмент трябва да ви позволи да извлечете информацията за типа, от която се нуждаете.
  • Sparse – Струва си да се разгледа, но не съм сигурен.
  • clang – Не съм го използвал за тази цел, но се твърди, че една от целите е била да го направя „лесно хакващ "само за такива неща. По-специално (и отново, без личен опит) в извършването на "тежката работа" на цялото анализиране, което ви позволява да се концентрирате върху "интересната" част, която в този случай би била извличане на чувствителна към контекста и синтаксиса информация за типа и след това да я преобразувате в към обикновен C низ.
  • gcc плъгини – плъгините са gcc 4.5 (което е текущата алфа/ бета версия на компилатора) и „може“ да ви позволи лесно да се свържете с компилатора, за да извлечете информацията за типа, от която се нуждаете. Нямам представа дали архитектурата на плъгина позволява подобни неща.

други

  • Coccinelle – Маркирахте това наскоро, за да „разгледате по-късно“. Това „може“ да е в състояние да направи това, което искате, и „може“ да е в състояние да го направи с много усилия.
  • MetaC – Маркирах и този наскоро. Нямам представа колко полезно би било това.
  • mygcc - „Може“ да направи това, което искате. Това е интересна идея, но не е пряко приложима към това, което искате. От уеб страницата: "Mygcc позволява на програмистите да добавят свои собствени проверки, които вземат предвид синтаксиса, контролния поток и информацията за потока от данни."

Връзки.

  • CocoaDev Objective-C Parsing – Струва си да се разгледа. Има някои връзки към лексери и граматики.

Редактиране #1, бонус връзките.

@Lothar прави добра точка в коментара си. Всъщност възнамерявах да включа lcc, но изглежда, че се е загубил по пътя.

  • lcclcc C компилаторът. Това е C компилатор, който е особено малък, поне по отношение на размера на изходния код. Освен това има книга, която силно препоръчвам.
  • tcc – Компилаторът tcc C. Не е толкова педагогически като lcc, но определено все пак си заслужава да бъде разгледан.
  • poc – Компилаторът poc Objective-C. Това е Objective-C компилатор от източник към източник. Той анализира изходния код на Objective-C и излъчва изходния код на C, който след това предава на gcc (е, обикновено gcc). Има редица разширения/функции на Objective-C, които не са налични в gcc. Определено си заслужава да се разгледа.
person johne    schedule 14.02.2010
comment
Уау, това е добър и дълъг отговор. Запазих подробностите за моя отговор, защото някой, който задава такъв наивен въпрос, е IMHO, че не може да напише C анализатор. В списъка си с връзки забравяте за простите c компилатори като LCC или TinyCC. По-добри са за начинаещ. GCC, clang/LLVM са толкова сложни, че дори опитен потребител без работа на пълно работно време като компилатор може да разбере изходния код. - person Lothar; 14.02.2010
comment
@Lothar Не мисля, че въпросът ми беше наивен. Зададох го открито, за да не повлияя на посоката на отговора. Когато го попитах първия път, включих, че смятах, че трябва да бъде имплементирано в компилатора, но не бях сигурен коя част; количеството проницателни отговори и мнения бяха нищожни в сравнение. Да, това е СТРАХОТЕН отговор и такъв, който определено ще използвам като бъдеща справка! И очаквам много други потребители също да намерят отговора му за полезен. Благодаря Джон! - person Anderson; 18.02.2010

Бихте приложили това, като първо внедрите ANSI C компилатора и след това добавите някои специфични за изпълнението прагми и функции към него.

Да, знам, че това е циничен отговор и приемам отрицателните гласове.

person Lothar    schedule 13.02.2010
comment
...и си помислих, че внедряването на препроцесор може да се разглежда като твърде трудно. - person mark4o; 14.02.2010

Един от начините да го направите е да напишете препроцесор, който чете изходния код за дефинициите на типове и също така замества @encode... със съответния низов литерал.

Друг подход, ако вашата програма е компилирана с -g, би бил да напишете функция, която чете дефиницията на типа от информацията за отстраняване на грешки на програмата по време на изпълнение, или да използвате gdb или друга програма, за да я прочете вместо вас и след това да я преформатира по желание. Командата gdb ptype може да се използва за отпечатване на определението на конкретен тип (или ако това не е достатъчно, има и maint print type, която със сигурност ще отпечата много повече информация, отколкото бихте искали).

Ако използвате компилатор, който поддържа плъгини (напр. GCC 4.5), може също да е възможно да напиша плъгин за компилатор за това. След това вашият плъгин може да се възползва от информацията за типа, която компилаторът вече е анализирал. Очевидно този подход би бил много специфичен за компилатора.

person mark4o    schedule 12.02.2010
comment
Имайте предвид, че ако това е пътят, по който сте избрали да тръгнете, вашият @encode препроцесор трябва да работи след C препроцесора, така че типовете, дефинирани между макросите #ifdef на C препроцесора, също да бъдат тези, анализирани от @encode препроцесора . - person dreamlax; 13.02.2010
comment
Благодаря mark4o! Исках да разделя отговора между теб и Джон, но не ми позволи. Харесвам твоя, защото е по-сбит, но той предлага няколко възможни пътя, по които да се стигне до същото решение. - person Anderson; 18.02.2010