ГЛАВА 21. ДИРЕКТИВЫ КОМПИЛЯТОРА. Некоторые свойства компилятора Turbo Pascal управляются с помощью директив. Директива компиляции является комментарием со специальным синтаксисом. Turbo Pascal допускает указание директив компилятора в любом месте, где допустимы комментарии. Директива компилятора начинается с символа $, который является первым символом после открывающего комментарий разделителя, а за ним сразу указывается имя (одна или больше букв), обозначающие определенную директиву. Есть три типа директив: - Директивы переключения. Эти директивы включают определенные свойства компилятора или выключают эти свойства с помощью + или -, указанных сразу же после имени директивы. - Параметрические директивы. Эти директивы задают параметры, которые влияют на компиляцию, например: имена файлов и размеры памяти. - Условные директивы. Эти директивы управляют условной компиляцией частей исходного текста в зависимости от условных символов, определенных пользователем. Все директивы, за исключением директив переключения, должны иметь по крайней мере один пробел между именем директивы и параметром. Ниже приведено несколько примеров директив компилятора: {$B+} {$R- Выключение проверки допустимого диапазона} {$I TYPES.INC} {$O EdFormat} {$M 65520, 8192, 655360} {$ DEFINE Debug} {$ IFDEF Debug} {$ ENDIF} Можно помещать директивы компилятора непосредственно в исходный код. Можно также изменить, определенные по умолчанию директивы и для компилятора командной строки (TPC.EXE) и для компилятора IDE (TURBO.EXE). Меню Options/Compiler (опция/компилятор) содержит все директивы компилятора; любые изменения в установках этих директив будут влиять на все последующие компиляции. Когда используется компилятор командной строки, можно задать директивы компилятора в командной строке (например, TPC / $R+ MYPROG), или можно поместить директивы в файл конфигурации (TPC.CFG - более подробная информация содержится в главе 9 Руководства пользователя). Директивы компилятора в исходном коде всегда отменяют определенные по умолчанию значения и в компиляторе командной строки, и в компиляторе IDE. Директивы переключения. Директивы переключения являются или локальными, или глобальными. Глобальные директивы влияют на всю компиляцию, в то время как локальные директивы влияют только на часть компиляции, которая выполняется от этой директивы до следующего появления этой же директивы. Глобальные директивы должны появляться перед декларативной частью программы или модуля, который будет компилироваться, т.е. перед первыми ключевыми словами: uses, label, const, type, procedure, function или begin. С другой стороны локальные директивы могут появиться в любом месте программы или модуля. Несколько директив переключения можно группировать в одном комментарии, разделив их с помощью запятых, например: {$B+,R-,S-} В этом случае между директивами не должно быть пробелов. Выравнивание данных. Синтаксис: {$A+} или {$A-} По умолчанию: {$A+} Тип : глобальный. Эквивалент меню : Options/Compiler/Word Align Data. Командная строка : /$A Эта директива переключает выравнивание переменных и типированных констант на границу байта или на границу слова. Выравнивание на границу слова не имеет эффекта в центральном процессоре 8088. Однако, для всех процессоров 80х86 выравнивание на границу слова означает более быстрое выполнение, т. к. к элементам размером в слово с четными адресами доступ осуществляется за один цикл памяти по сравнению с двумя циклами памяти для слов с нечетными адресами. В состоянии {$A+} все переменные и типированные константы размером больше одного байта выравниваются на границу машинного слова (адреса с четными номерами). Если требуется, то вставляются дополнительные неиспользованные байты между переменными, для того, чтобы обеспечить выравнивание на границу слова. Директива {$A+} не влияет на переменные размером в байт, также она не влияет на поле структур записи и элементы массива. Поле в записи будет выравниваться на границу слова только, если общий размер всех полей перед ним является четным. Аналогично, элемент массива будет выравниваться на границу слова, если размер элементов массива является четным. В состоянии {$A-} выравнивание не производится. Переменные и типированные константы просто размещаются по следующему доступному адресу, независимо от их размера. Если Вы перекомпилируете программу, использующую Turbo Pascal Editor Toolbox, убедитесь, что все программы в Toolbox компилируются с {$A-}. Примечание: Независимо от директивы $A каждая секция объявлений глобальных переменных и констант всегда начинается на границе слова. Аналогично, компилятор всегда стремится выравнивать указатель стека (SP) на границе слова, размещая дополнительный неиспользуемый байт в кадре стека процедуры, если это необходимо. Вычисление булевских выражений. Синтаксис : {$B+} или {$B-} По умолчанию : {$B-} Тип : локальный. Эквивалент меню : Options/Compiler/Complete Boolean Eval Эта опция переключает две различных модели генерации кода для булевских операторов and или or. В состоянии {$B+} компилятор генерирует код для полного вычисления булевского выражения. Это означает, что каждый операнд булевского выражения, построенный из операторов and или or, будет вычисляться, даже когда результат всего выражения уже известен. В состоянии {$B-} компилятор генерирует код для короткого вычисления булевского выражения, это означает, что вычисление прекращается как только результат всего выражения становится очевидным. Более подробная информация по данному вопросу содержится в разделе "Логические операторы" в гл.6 "Выражения". Отладочная информация. Синтаксис : {$D+} или {$D-} По умолчанию : {$D+} Тип : глобальный Эквивалент меню : Options/Compiler/Debug information Эта опция разрешает или отменяет генерацию отладочной информации. Эта информация состоит из таблицы с номерами строк для каждой процедуры, которая отображает адреса объектного кода в номера строк исходного текста. Когда отладочная информация для данной программы или модуля включена, встроенный отладчик Turbo Pascal предоставляет возможность пошагового выполнения и установки точек прерывания в этом модуле. Белее того, когда в программе или в модуле, откомпилированном с директивой {$D+} появляется ошибка выполнения, Turbo Pascal может автоматически указать оператор, который вызвал ошибку. Переключатели Debugging (Options/Debugger) и Options/ Linker/ Map File формируют информацию о номерах строк для данного модуля, только если этот модуль компилируется при заданной директиве {$D+}. Для модулей отладочная информация записывается в файл .TPU вместе с объектным кодом модуля. Отладочная информация увеличивает размер .TPU файлов и занимает дополнительное место при компиляции программ, использующих этот модуль, но она не влияет на размер и скорость выполнимой программы. Переключатель отладочной информации обычно используется вместе с переключателем $L, который включает или выключает генерацию информации о локальных символах для отладки. Примечание: Если нужно использовать для отладки программы Турбо Debugger, то установите Compile/destination (назначение) на Disk (диск) и включите Standаlone в Options/Debugger/Debugging. Эмуляция. Синтаксис : {$E+} или {$E-} По умолчанию : {$E+} Тип : глобальный Эквивалент меню : Options/Compiler/Emulation Эта опция разрешает или отменяет редактирование связей с библиотекой времени выполнения, которая будет эмулировать числовой сопроцессор 8087, если он отсутствует. При компиляции программы в состоянии {$N+,E+} Turbo Pascal редактирует связи с полным эмулятором 8087. Результирующий .EXE файл можно использовать на любой машине, независимо от наличия сопроцессора 8087. Если он есть, то он используется; в противном случае он эмулируется библиотекой времени выполнения. В состоянии {$N+,E-} Turbo Pascal редактирует связи с значительно меньшей библиотекой с плавающей точкой, которая может использоваться только, если сопроцессор 8087 есть в наличии. Переключатель эмуляции 8087 не оказывает никакого действия, если используется в модуле; он применяется только при компиляции программы. Более того, если программа компилируется в состоянии {$N -} и если все модули, используемые программой, были откомпилированы с {$N-}, то библиотека времени выполнения 8087 не требуется и переключатель эмуляции 8087 игнорируется. Выбор модели дальнего вызова. Синтаксис : {$F+} или {$F-} По умолчанию : {$F-} Тип : локальный Эквивалент меню : Options/Compiler/Force Far Calls Эта опция управляет выбором модели вызова, используемой для последовательно откомпилированных процедур и функций. Процедуры и функции, откомпилированные в состоянии {$F+}, всегда используют модель вызова FAR (дальний). В состоянии {$F-} Turbo Pascal автоматически выбирает соответствующую модель: Far (дальний), если процедура или функция объявляются в части interface модуля; в противном случае NEAR (ближний). NEAR и FAR модели вызовов описаны подробно в главе 18 "Вопросы управления". Примечание: Для программ, которые используют оверлеи, предполагается, что в начале каждой программы и каждого модуля помещается директива {$F+} для того, чтобы выполнялось требование FAR вызова. Более подробная информация по данному вопросу приведена в главе 13 "Оверлеи". Для программ, которые используют процедурные переменные, все такие процедуры должны использовать модель вызова FAR. Более подробная информация приведена в разделе "Процедурные переменные" главы 8. Генерация кода 80286. Синтаксис : {$G+} или {$G-} По умолчанию : {$G-} Тип : локакальный Эквивалент меню : Options/Compiler/286 instructions Директива $G включает или выключает генерацию кода 80286. В состоянии {$G-} генерируются только инструкции 80286 и программа, откомпилированная в этом состоянии может работать на любом процессоре 80х86. В состоянии {$G+} компилятор использует дополнительные инструкции 80286 для улучшения генерации кода, но программы, откомпилированные в этом состоянии, не могут работать на процессорах 8088 и 8086. Дополнительные инструкции, используемые в состоянии {$G+} включают ENTER, LEAVE, PUSH, IMUL, SHL, SHR. Проверка ввода/вывода. Синтаксис : {$I+} или {$I-} По умолчанию : {$I+} Тип : локальный Эквивалент меню : Options/Compiler/I/O Checking Переключатель проверки ввода/вывода задает или отменяет автоматическую генерацию кода, который проверяет результат вызова процедур ввода/вывода. Процедуры ввода/вывода описываются в главе 19 "Ввод и вывод". Если процедура ввода/вывода возвращает ненулевой результат ввода/вывода, когда этот переключатель включен, то программа завершается и на дисплей выводится сообщение об ошибке выполнения. Когда этот переключатель выключен, нужно проверять ошибки ввода/вывода с помощью функции IOResult. Информация о локальных символах. Синтаксис : {$L+} или {$L-} По умолчанию : {$L+} Тип : глобальный Эквивалент меню : Options/Compiler/Local Symbols. Переключатель локальных символов задает или отменяет генерацию информации о локальных символах. Информация о локальных символах состоит из имен и типов всех локальных переменных и констант в модуле, т.е. из символов, расположенных в части реализации модуля и символов, расположенных внутри процедур и функций модуля. Когда этот переключатель включен для данной программы или модуля, интегрированный отладчик Turbo Pascal позволяет просматривать и модифицировать локальные переменные модуля. Более того, вызовы процедур и функций данного модуля могут быть просмотрены через окно Window/Call Stack. Реализация методов объектов, написанных на Ассемблере, могут быть включены в программу на Turbo Pascal, используя директиву компилятора $L и ключевое слово external. Переключатели Map File (Options/Linker) и Debugging (Options/ Debugger) формируют информацию о локальных символах для данного модуля, только если этот модуль был откомпилирован в состоянии {$L+}. Для модулей информация о локальных символах записывается в .TPU файл вместе с объектным кодом модуля. Информация о локальных символах увеличивает размер .TPU файлов и занимает дополнительную память при компиляции программ, которые используют этот модуль, но это не влияет на размер и скорость выполнимой программы. Переключатель информации о локальных символах обычно используется вместе с переключателем отладочной информации $D, который включает или выключает генерацию таблицы номеров строк для отладки. Заметим, что директива $L игнорируется, если переключатель отладочной информации выключен {$D-}. Числовая обработка. Синтаксис : {$N+} или {$N-} По умолчанию : {$N-} Тип : глобальный Эквивалент меню : Options/Compiler/8087|80287 Переключатель числовой обработки определяет одну из двух различных моделей генерации кода с плавающей точкой, поддерживаемых Turbo Pascal. В состоянии {$N-} код для выполнения всех вычислений вещественного типа генерируется с помощью вызова программ библиотеки времени выполнения. В состоянии {$N+} код для выполнения всех вычислений вещественного типа генерируется с помощью использования числового сопроцессора 8087. Заметим, что можно использовать для эмуляции 8087 директиву {$ E+}. Это даст доступ к IEEE типам с плавающей точкой без необходимости инсталляции типа 8087. Генерация оверлейного кода. Синтаксис : {$O+} или {$O-} По умолчанию : {$O-} Тип : глобальный Эквивалент меню : Options/Compiler/Overlays Allowed Директива $O задает или отменяет генерацию оверлейного кода. Turbo Pascal позволяет сделать модуль оверлейным, только если он был откомпилирован с директивой {$O+}. В этом случае генератор кода принимает специальные меры предосторожности при передаче строки и устанавливает постоянные параметры при передаче из одной оверлейной процедуры или функции в другую. Использование директивы {$O+} в модуле не заставляет делать этот модуль оверлейным. Эта директива только инструктирует Turbo Pascal гарантировать, что этот модуль может быть оверлейным, если это потребуется. Если разрабатываются модули, которые планируется использовать в оверлейных и неоверлейных прикладных программах, тогда их компиляция с опцией {$O+} обеспечивает эту возможность при наличии только одной версии модуля. Примечание: Директива компилятора {$O+} почти всегда используется с директивой {$F+} для того, чтобы удовлетворить требование монитора оверлеев об использовании дальней модели вызова процедур или функций. Более подробная информация о генерации оверлейного кода приведена в главе 13 "Оверлеи". Проверка диапазона. Синтаксис : {$R+} или {$R-} По умолчанию : {$R-} Тип : локальный Эквивалент меню : Options/Compiler/Range checking Переключатель проверки диапазона задает или отменяет код проверки диапазона. В состоянии {$R+} во всех выражениях проверяется, находятся ли индексы массивов и строк в заданных границах, а также проверяется принадлежность допустимому диапазону всех присваиваемых скалярных и поддиапазонных переменных. Если эта проверка дала отрицательные результаты, то программа завершается и на дисплей выводится сообщение об ошибке выполнения. Проверка диапазона замедляет выполнение программы и увеличивает ее размер. Используйте эту опцию при отладке, когда же в программе будут отсутствовать ошибки, эту опцию нужно выключить. Проверка переполнения стека. Синтаксис : {$S+} или {$S-} По умолчанию : {$S+} Тип : локальный Эквивалент меню : Options/Compiler/Stack checking Этот переключатель задает или отменяет генерацию проверки переполнения стека. В состоянии {$S+} компилятор генерирует код в начале каждой процедуры и функции, который проверяет имеется ли достаточно места в стеке для локальных переменных и другой временной памяти. Когда места в стеке недостаточно, вызов процедуры или функции, откомпилированной с опцией {$S+}, вызывает завершение программы и на дисплей выдается сообщение об ошибке. В состоянии {$ S-} такой вызов наиболее вероятно приведет к аварийному отказу системы. Проверка переменной строки. Синтаксис : {$V+} или {$V-} По умолчанию : {$V+} Тип : локальный Эквивалент меню : Options/Compiler/Strict Var-String Этот переключатель управляет проверкой типа для строк, передаваемых как переменные параметры. В состоянии {$V+} выполняется строгая проверка типов, при которой требуется, чтобы формальные и фактические параметры имели одинаковый строковый тип. В состоянии {$V-} в качестве фактического параметра может быть любая переменная строкового типа, даже если объявленная максимальная длина не совпадает с длиной формального параметра. Расширенный синтаксис. Синтаксис : {$X+} или {$X-} По умолчанию : {$X+} Тип : глобальный Эквивалент меню : Options/Compiler/Extended Syntax Директива компилятора $X включает и выключает расширенный синтаксис Turbo Pascal. В режиме {$X+} вызов функции может использоваться как оператор; т.е. результат вызова функции может быть отброшен. В общем случае вычисления, производимые функцией представлены через ее результат. Так, что отбрасывание результата имеет мало смысла. Однако, в некоторых случаях функция может выполнять операции, основанные на ее параметрах, и в некоторых случаях может не создавать осмысленного результата - в этих случаях {$X+} позволяет интерпретировать функцию как процедуру. Примечание: Директива {$X+} неприменима к встроенным функциям (т.е. функциям, определенным в модуле System). В состоянии по умолчанию {$X-} - это расширение запрещено и попытка использовать его приведет к ошибке. Параметрические директивы. Включенный файл. Синтаксис : {$I имя файла} Тип : локальный Эквивалент меню : Options/Directоries/Include Directories Директива $I сообщает компилятору о включении названного файла в компиляцию. Фактически файл вставляется в компилируемый текст сразу после директивы {$I имя файла}. По умолчанию для имени файла определено расширение .PAS. Если в имени файла не задан справочник, тогда в дополнении к поиску файла в текущем справочнике Turbo Pascal ищет этот файл в справочниках, заданных в меню Options/Directories/Include Directories (или в справочниках, заданных в опции /I в командной строке TPC). Вы можете вкладывать включаемые файлы на глубину до 15 уровней. Есть только одно ограничение на использование включенных файлов: включенный файл не может быть задан в середине операторной части исходного кода. Фактически, все операторы между begin и end операторной части должны быть в одном исходном файле. Подключение объектного файла. Синтаксис : {$L имя файла} Тип : локальный Эквивалент меню : Options/Directories/Object Directories Директива $L инструктирует компилятор о редактировании указанного файла с компилируемой программой или модулем. Директива $L используется для редактирования с кодом, написанном на ассемблере для подпрограмм, объявленных как external. Названный файл должен быть объектным файлом (.OBJ файлом). Для имени файла по умолчанию определено расширение .OBJ. Если в имени файла не задан справочник, то в дополнении к поиску файла в текущем справочнике Turbo Pascal ищет заданный файл в справочниках, указанных в меню Options/Directories/Object Directories (или в справочниках, заданных в опции /O в командной строке TPC). Более подробная информация о редактировании с ассемблером содержится в главе 23 "Включение ассемблерного кода". Размеры распределения памяти. Синтаксис : {$M stacksize (размер стека), heapmin (минимальный адрес кучи), heapmax (максимальный адрес кучи)} По умолчанию : {$M 16384, 0, 655360} Тип : глобальный Эквивалент меню : Options/Memory Sizes Эта опция задает параметры распределения памяти программ. Stacksize должен быть целым числом в диапазоне от 1024 до 65520, которое задает размер сегмента стека. heapmin должен быть в диапазоне от 0 до 655360, а heapmaх должен быть в диапазоне от heapmin до 655360. Heapmin и heapmax задают минимальный и максимальный размер кучи соответственно. Более подробно сегмент стека и куча описаны в главе 4 "Переменные" и в главе 16 "Память". Примечание: Директива $M не имеет действия, когда используется в модуле. Имя оверлейного модуля. Синтаксис : {$O имя модуля} Тип : локальный Эквивалент меню : нет Эта директива вкючает модуль в оверлей. Директива {$O имя модуля} не имеет действия, если используется в модуле; при компиляции программы она задает какой из модулей, используемых программой, должен быть помещен в файл .OVR вместо .EXE. Директива {$O имя_модуля} должна помещаться после использования предложения uses в программе. Turbo Pascal выдает ошибку, если Вы пытаетесь сделать оверлейным модуль, который не был откомпилирован в состоянии {$O+}. Любой модуль, названный в директиве {$O имя модуля}, должен быть откомпилирован с включенным переключателем Overlays Allowed в IDE (эквивалент директивы компилятора {$O+}). Более подробная информация об оверлеях приведена в главе 13 "Оверлеи". Условная компиляция. Директивы условной компиляции Turbo Pascal позволяют получать различный код из одного и того же исходного текста в зависимости от условных символов. Есть две основных конструкции условной компиляции, которые очень напоминают оператор if Паскаля. Первая конструкция {$IFxxx}...{$ENDIF} приводит к тому, что исходный код между {$IFxxx} и {$ENDIF} будет компилироваться только, если условие, заданное в {$IFxxx}, имеет значение True; если условие имеет значение False, то исходный код между двумя этими директивами игнорируется. Вторая конструкция исходной компиляции : {$IFxxx}...{$ELSE}...{$ENDIF} приводит к тому, что исходный текст между {$IFxxx} и {$ELSE}, или исходный текст между {$ELSE} и {$ENDIF} будут компилироваться в зависимости от условия, заданного {$IFxxx}. Ниже приведено несколько примеров конструкций условной компиляции: {$IFDEF Debug} Writeln ('X=', X); {$ENDIF} {$IFDEF CPU87} {$N+} type Real = Double; {$ELSE} {$N-} type Single = Real; Double = Real; Extended = Real; Comp = Real; {$ENDIF} Конструкции условной компиляции могут иметь уровень вложенности до 16. Для каждой директивы {$IFxxx} соответствующая директива {$ENDIF} должна быть найдена внутри того же исходного файла - это означает, что должно быть одинаковое количество {$IFxxx} и {$ENDIF} в каждом исходном файле. Условные символы. Условная компиляция основана на оценке условных символов. Условные символы определяются и отменяются (забываются) с помощью директив {$DEFINE имя} {$UNDEF имя} Можно также использовать переключатель /D в компиляторе командной строки (или команду меню Options/Compiler/Conditional Defines внутри интегрированной среды). Условные символы лучше всего сравнимы с булевскими переменными: они или имеют значение True (определен) или False (неопределен). Директива {$DEFINE} устанавливает для заданного символа значение True, а директива {$UNDEF} устанавливает значение False. Условные символы следуют точно таким же правилам, как идентификаторы Паскаля: они должны начинаться с буквы, за которой следует любая комбинация букв, цифр и подчеркиваний. Они могут быть любой длины, но только первые 63 символа являются значащими. Примечание: Условные символы и идентификаторы Паскаля не имеют никакого соотношения. Условные символы нельзя использовать в активной программе, а идентификаторы программы нельзя использовать в условных директивах. Например, конструкция const Debug = True; begin {$IFDEF Debug} Writeln('Oтладка включена'); {$ENDIF} end; не будет компилировать предложение Writeln. Аналогично, конструкция {$DEFINE Debug} begin if Debug then Writeln('Oтладка включена'); end; будет приводить к ошибке "неизвестный идентификатор" в операторе if. Turbo Pascal определяет следующие стандартные условные символы: VER60 всегда определен, указывает, что это версия 6.0 Turbo Pascal. Другие версии (начиная с 4.0) определяют соответствующие символы версии; например, VER40 для версии 4.0 и т.д. MSDOS всегда определен, указывает, что это операционная система - MS DOS или PC DOS. Версии Turbo Pascal для других операционных систем будут вместо этого символа определять символическое имя для определенной операционной системы. CPU86 всегда определен, указывает, что центральный процессор принадлежит к семейству процессоров 80х86. Версии Turbo Pascal для других центральных процессоров будут определять соответствующее символическое имя для определенного центрального процессора. CPU87 определен, если числовой сопроцессор 8087 имеется в наличии во время компиляции. Если конструкция {$IFDEF CPU87} {$N+} {$ELSE} {$N-} {$ENDIF} появляется в начале компиляции, то Турбо Паскаль будет автоматически выбирать для данного компилятора соответствующую модель генерации кода для чисел с плавающей точкой. Другие условные символы могут быть определены перед компиляцией с помощью меню Options/Compiler/Conditional Defines или опции /D командной строки при использовании TPC. Директива Define (определить). Синтаксис : {$DEFINE имя} Определяет условный символ заданного имени. Символ распознается до конца компиляции в текущем модуле, в котором объявлен этот символ или до появления директивы {$UNDEF имя}. Директива {$DEFINE имя} не имеет эффекта, если имя уже определено. Директива UNDEF. Синтаксис : {$UNDEF имя} Отменяет определение предварительно определенного условного символа. Этот символ становится неопределенным до конца компиляции или до тех пор, пока он опять не появится в директиве {$DEFINE имя}. Директива {$UNDEF имя} не имеет эффекта, если имя уже неопределено. Директива IFDEF. Синтаксис : {$IFDEF имя} Компилирует исходный текст, который следует за директивой, если указанное имя определено. Директива IFNDEF. Синтаксис : {$IFNDEF имя} Компилирует исходный текст, который следует за директивой, если указанное имя неопределено. Директива IFOPT. Синтаксис : {$IFOPT переключатель} Компилирует исходный текст, который следует за директивой, если переключатель в данный момент находится в заданном состоянии. Переключатель состоит из имени опции переключателя, за которым следует + или -. Например, конструкция {$IFOPT N+} type Real = Extended; {$ENDIF} будет компилировать объявление типа, если опция $N в данный момент времени активна. Директива ELSE. Синтаксис : {$ELSE} Переключает между компилированием и игнорированием исходного текста, выделенного с помощью последней директивы {$IFxxx} и следующей директивы {$ENDIF}. Директива ENDIF. Синтаксис : {$ENDIF} Завершает условную компиляцию, инициированную последней директивой {$IFxxx}.