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

@encode директива возвращает символ константы *, который является кодированным дескриптором типа различных элементов типа данных, который был передан в. Пример следует:

struct test
{ int ti ;
  char tc ;
} ;

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

Я видел использование sizeof () для определения типов примитивов - и если бы это был полный объект, то я мог бы использовать методы класса сделать самоанализ.

Однако, Как это определяет каждый элемент непрозрачной структуры?

8
задан Anderson 12 February 2010 в 22:44
поделиться

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: лимон , dparser и т. Д.
  • Используйте perl с Yapp или EYapp , которые являются псевдо yacc клонами в perl . Вероятно, лучше для быстрого прототипирования идеи по сравнению с yacc и lex на основе C - в конце концов, это perl : регулярные выражения, ассоциативные массивы, без управления памятью и т. Д. .
  • Создайте свой синтаксический анализатор с помощью Antlr . У меня нет опыта работы с этой цепочкой инструментов, но это еще один инструмент «компилятор компилятора», который (кажется) больше ориентирован на разработчиков Java.Кажется, есть свободно доступные грамматики C и Objective-C.

Взломать другой инструмент

Примечание: У меня нет личного опыта использования этих инструментов для чего-либо вроде добавления @encode () , но я подозреваю, что они могут мне очень помочь.

  • CIL - Нет личного опыта работы с этим инструментом, но он разработан для анализа исходного кода C и последующего «выполнения чего-то» с ним. Из того, что я могу почерпнуть из документации, этот инструмент должен позволить вам извлекать необходимую информацию о типе.
  • Редкий - Стоит посмотреть, но не уверен.
  • clang - Я не использовал его для этой цели, но якобы одной из целей было сделать его «легко взломанным» для такого рода вещей. В частности (и опять же, без личного опыта) в выполнении «тяжелой работы» всего синтаксического анализа, позволяя вам сосредоточиться на «интересной» части, которая в данном случае будет извлекать контекстную и синтаксическую информацию, чувствительную к типу, а затем преобразовывать ее в в простую строку C.
  • Плагины gcc - Плагины представляют собой функцию gcc 4.5 (которая является текущей альфа / бета-версией компилятора) и «могут» позволить вам легко подключиться к компилятору для извлечения необходимой информации о типе. . Не знаю, позволяет ли архитектура плагина такое делать.

Прочее

  • Coccinelle - Недавно добавили в закладки, чтобы «посмотреть позже». Это «могло бы» сделать то, что вы хотите, и «могло бы» сделать это без особых усилий.
  • MetaC - Недавно тоже добавили в закладки. Не знаю, насколько это было бы полезно.
  • mygcc - «Могу» делать, что хочешь.Это интересная идея, но она напрямую не применима к тому, что вы хотите. С веб-страницы: «Mygcc позволяет программистам добавлять свои собственные проверки, которые принимают во внимание синтаксис, поток управления и информацию о потоках данных»

Ссылки.

Редактировать №1, бонусные ссылки.

@Lothar хорошо подметил в своем комментарии. На самом деле я намеревался включить lcc , но похоже, что он потерялся по пути.

  • lcc - Компилятор C lcc . Это компилятор C, который особенно мал, по крайней мере, с точки зрения размера исходного кода. Там же есть книга , которую я очень рекомендую.
  • tcc - Компилятор tcc C. Не такой педагогический, как lcc , но все же стоит посмотреть.
  • poc - Компилятор poc Objective-C. Это компилятор Objective-C "от источника к исходному". Он анализирует исходный код Objective-C и выдает исходный код C, который затем передает в gcc (ну, обычно gcc ). Имеет ряд расширений / функций Objective-C, которые недоступны в gcc . Определенно стоит посмотреть.
15
ответ дан 5 December 2019 в 07:58
поделиться

Вы могли бы реализовать это, сначала реализовав компилятор ANSI C, а затем добавив к нему некоторые прагмы и функции, специфичные для конкретной реализации.

Да, я знаю, что это циничный ответ, и я согласен на понижение голосов.

4
ответ дан 5 December 2019 в 07:58
поделиться

Один из способов сделать это - написать препроцессор, который читает исходный код для определения типов, а также заменяет @encode... на соответствующий строковый литерал.

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

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

2
ответ дан 5 December 2019 в 07:58
поделиться
Другие вопросы по тегам:

Похожие вопросы: