@encode директива возвращает символ константы *, который является кодированным дескриптором типа различных элементов типа данных, который был передан в. Пример следует:
struct test
{ int ti ;
char tc ;
} ;
printf( "%s", @encode(struct test) ) ;
// returns "{test=ic}"
Я видел использование sizeof () для определения типов примитивов - и если бы это был полный объект, то я мог бы использовать методы класса сделать самоанализ.
Однако, Как это определяет каждый элемент непрозрачной структуры?
Ответ @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
: регулярные выражения, ассоциативные массивы, без управления памятью и т. Д. . Примечание: У меня нет личного опыта использования этих инструментов для чего-либо вроде добавления @encode ()
, но я подозреваю, что они могут мне очень помочь.
@Lothar хорошо подметил в своем комментарии. На самом деле я намеревался включить lcc
, но похоже, что он потерялся по пути.
lcc
. Это компилятор C, который особенно мал, по крайней мере, с точки зрения размера исходного кода. Там же есть книга , которую я очень рекомендую. tcc
C. Не такой педагогический, как lcc
, но все же стоит посмотреть. poc
Objective-C. Это компилятор Objective-C "от источника к исходному". Он анализирует исходный код Objective-C и выдает исходный код C, который затем передает в gcc
(ну, обычно gcc
). Имеет ряд расширений / функций Objective-C, которые недоступны в gcc
. Определенно стоит посмотреть. Вы могли бы реализовать это, сначала реализовав компилятор ANSI C, а затем добавив к нему некоторые прагмы и функции, специфичные для конкретной реализации.
Да, я знаю, что это циничный ответ, и я согласен на понижение голосов.
Один из способов сделать это - написать препроцессор, который читает исходный код для определения типов, а также заменяет @encode
... на соответствующий строковый литерал.
Другой подход, если ваша программа скомпилирована с -g
, заключается в написании функции, которая считывает определение типа из отладочной информации программы во время выполнения, или использовании gdb
или другой программы, которая считывает его для вас и затем переформатирует его по желанию. Команда gdb
ptype
может быть использована для печати определения конкретного типа (а если этого недостаточно, есть еще maint print type
, которая обязательно выведет гораздо больше информации, чем вам может понадобиться).
Если вы используете компилятор, который поддерживает плагины (например, GCC 4.5), то можно написать плагин для компилятора. Тогда ваш плагин сможет воспользоваться информацией о типах, которую компилятор уже разобрал. Очевидно, что такой подход зависит от конкретного компилятора.