Как мне реализовать что-то похожее на директиву компилятора @encode () Objective-C в ANSI C? - PullRequest
8 голосов
/ 13 февраля 2010

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

struct test
{ int ti ;
  char tc ;
} ;

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

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

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

Ответы [ 3 ]

15 голосов
/ 14 февраля 2010

@ Ответ Lothars может быть "циничным", но, к сожалению, он довольно близок к цели Чтобы реализовать что-то вроде @encode(), вам нужен полноценный парсер, чтобы извлечь информацию о типе. Ну, по крайней мере, для чего-то другого, кроме «тривиальных» @encode() утверждений (то есть @encode(char *)). Современные компиляторы обычно имеют два или три основных компонента:

  • Передняя часть.
  • Промежуточный конец (для некоторых компиляторов).
  • Бэкэнд.

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

Серверная часть переводит внутреннюю форму, пригодную для использования в машине, в исполняемый код.

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

Итак, если вы хотите добавить функциональность @encode() к «существующему» компилятору, вам, вероятно, придется сделать это как «источник к источнику» «компилятор / препроцессор». Именно так были написаны оригинальные компиляторы Objective-C и C ++ - они анализировали исходный текст и преобразовывали его в «обычный C», который затем вводили в стандартный компилятор C. Есть несколько способов сделать это:

Раскатайся

  • Используйте yacc и lex, чтобы собрать анализатор ANSI-C. Вам понадобится грамматика - ANSI C грамматика (Yacc) - хорошее начало. На самом деле, чтобы было ясно, когда я говорю yacc, я действительно имею в виду зубров и flex. А также, свободно, другие различные yacc и lex подобные инструменты на основе C: lemon , 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, бонусные ссылки.

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

  • lcc - Компилятор lcc C. Это компилятор C, который особенно мал, по крайней мере, с точки зрения размера исходного кода. У этого также есть книга , которую я очень рекомендую.
  • tcc - Компилятор tcc C. Не такой педагогический, как lcc, но определенно стоит посмотреть.
  • poc - Компилятор Objective-C poc. Это компилятор Objective-C "источник-источник". Он анализирует исходный код Objective-C и испускает исходный код C, который затем передает в gcc (ну, обычно gcc). Имеет ряд расширений / функций Objective-C, которые недоступны в gcc. Определенно стоит посмотреть.
4 голосов
/ 13 февраля 2010

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

Да, я знаю, что это циничный ответ, и я принимаю отрицательные ответы.

2 голосов
/ 13 февраля 2010

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

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

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

...