|
Препроцессоры создают входной поток информации для компилятора. С их помощью можно выполнить следующие функции.
1. Обработка макросов. Пользователь может определить макросы — краткие записи длинных конструкций.
2. Включение файлов. В текст программы можно включить заголовочные файлы. Например, при обработке файла препроцессор С заменяет выражение #include <global. h> содержимым файла global. h.
3. "Интеллектуальные" препроцессоры. К старым языкам добавляются более современные возможности управления выполнением программы и работы со сложными структурами данных. Например, с помощью таких препроцессоров можно использовать встроенные макросы для построения циклов while или условных конструкций, отсутствующих в языке программирования.
4. Языковые расширения. Примером может послужить язык Equel ([413])— язык запросов к базе данных, внедренный в код С. Препроцессор получает инструкции, начинающиеся с # # (это инструкции доступа к базе данных, не имеющие никакого отношения к С), и переводит их в вызовы процедур, реализующих обращения к базе данных.
Обработчики макросов работают с двумя видами инструкций — определение макросов и их использование. Определения обычно указываются с помощью определенного символа или ключевого слова типа define или macro и состоят из имени определяемого макроса и его тела, формируя определение макроса. Зачастую макропроцессоры позволяют применять в определениях макросов формальные параметры, т.е. символы, заменяемые значениями при использовании макроса (в данном контексте "значение" — строка символов). Использование макроса представляет собой его имя с фактическими параметрами, т.е. значениями для подстановки вместо формальных параметров. Макропроцессор подставляет в тело макроса фактические значения вместо формальных параметров; затем преобразованное тело макроса замещает его имя в программе.
Пример 1.2
ТЕХ, о котором упоминалось в разделе 1.2, позволяет работать с макросами. Определение макроса имеет вид
\define <имя макроса> <шаблон> {<тело>}
Имя макроса представляет собой строку символов, начинающуюся с обратной косой черты. Шаблон — строка символов, в которой строки типа #1, #2... #9 рассматриваются как формальные параметры. Эти символы могут появляться в теле макроса сколько угодно раз. Например, следующий макрос определяет ссылку на Journal of the ACM.
\define \JACM #1;#2;#3.
{{\s1 J. ACM} {\bf #1}:#2, pp. #3.}
Имя макроса— \JACM, а шаблон— "# 1; #2; #3."; точки с запятой разделяют отдельные параметры, а за последним параметром следует точка. Использование такого макроса должно иметь тот же вид, что и шаблон, с тем отличием, что вместо формальных параметров могут использоваться произвольные строки.[4] Таким образом, мы можем записать
\JACM 17;4;715-728.
и получить при этом
J. АСМ 17:4, pp. 715-728.
Часть тела макроса { \ s1 J. АСМ} обеспечивает вывод текста J. АСМ наклонным (slanted[5]) шрифтом. Выражение {\bf #1} говорит о том, что первый фактический параметр должен быть выведен полужирным шрифтом (boldface). Этот параметр представляет собой номер тома журнала.
ТЕХ. позволяет использовать любые знаки пунктуации или строки текста для разделения тома, выпуска и номеров страниц в определении макроса \JACM. Можно обойтись и без разделителей — в этом случае ТЕХ будет считать фактическими параметрами отдельные символы или строки, взятые в фигурные скобки {}.
Ассемблеры
Некоторые компиляторы создают ассемблерный код, как в (1.5), который передается для дальнейшей обработки ассемблеру. Другие компиляторы самостоятельно выполняют работу ассемблера, производя перемещаемый машинный код, который непосредственно передается загрузчику/редактору связей. Читатель наверняка знает, как выглядит ассемблерный код и что такое ассемблер. Здесь же мы рассмотрим отношения между ассемблерным и машинным кодами.
Ассемблерный код представляет собой мнемоническую версию машинного кода, в которой вместо бинарных кодов операций используются их имена; кроме того, адресам памяти также могут присваиваться имена. Типичная последовательность инструкций выглядит как
MOV a, R1
ADD #2, R1 (1.6)
MOV R1, b
Этот код перемещает содержимое памяти по адресу а в регистр 1, затем добавляет к нему константу 2, рассматривая содержимое регистра 1 как число с фиксированной точкой, и сохраняет результат в именованной ячейке памяти b. Таким образом вычисляется b:= а+2.
Имеет ли язык ассемблера возможности работы с макросами, зависит от типа ассемблера.
Дата добавления: 2015-11-30; просмотров: 35 | Нарушение авторских прав