 
                          ГЛАВА 6
 
       Отладка программ, написанных на Турбо-Паскале
 
     Турбо-Паскаль, наряду с автоматизированной  разработкой
программ, высокой модульностью, быстрой компиляцией и легки-
ми в использовании  оверлеями  предлагает  вам  превосходный
инструмент отладки. Ведь даже располагая всеми этими средст-
вами вам не удастся избежать ошибок в программе, что  приво-
дит к ее неправильной работе.
     Чтобы помочь вам в этой ситуации, Турбо-Паскаль предла-
гает  инструмент,  необходимый  для отладки вашей программы.
Термин "отладка" означает исправление ошибок в  программе  и
обеспечение  ее  правильной  работы. Турбо-Паскаль позволяет
легко найти и исправить ошибки,  возникающие  как  во  время
компиляции,  так  и  во время выполнения. Он также позволяет
разрешить или запретить проверку ошибок в программе во время
ее работы (ошибк этапа выполнения).
     Но что более важно, Турбо-Паскаль поставляется с мощным
и  гибким  отладчиком,  работающим на уровне исходных кодов,
который позволяет вам построчно выполнять программу,  анали-
зируя  при этом выражения и модифицируя значения переменных.
Этот отладчик встроен в интегрированную интерактивную  среду
Турбо-Паскаля,  благодаря чему вы можете редактировать, ком-
пилировать и отлаживать программу, не выходя из Турбо-Паска-
ля.  Для больших комплексов программ, требующих полный набор
отладочных средств (от машинного языка до вычисления выраже-
ний Турбо-Паскаля) Турбо-Паскаль полностью обеспечивает так-
же поддержку автономного Турбо-отладчика фирмы Борланд.
     В программе могут быть разнообразные ошибки:  синтакси-
ческие,  семантические и логические. Давайте рассмотрим каж-
дый тип ошибок.
 
                  Ошибки этапа компиляции
 
     Ошибки на этапе компиляции (или синтаксические  ошибки)
возникают в том случае, если вы забудете описать переменную,
передатите неправильное количество пераметров процедуре  или
присвоите  вещественное  значение  целочисленной переменной.
Это означает, что написанные вами операторы Паскаля не удов-
летворяют требованиям Паскаля.
     Паскаль имеет строгие правила, особенно по сравнению  с
другими  языками, поэтому исправив синтаксические ошибки, вы
выполните основную часть отладки.
     Турбо-Паскаль не будет выполнять компиляции вашей прог-
раммы  (генерировать машинный код) до тех пор, пока не будут
устранены все синтаксические ошибки. Если Турбо-Паскаль  об-
наружит  синтаксическую  ошибку при компиляции программы, он
прекратит компиляцию, найдет расположение ошибки в  програм-
ме,  поместит там курсор и в окне редактирования выведет со-
общение об ошибке. Исправив  ошибку,  вы  можете  продолжить
компиляцию.
 
                  Ошибки этапа выполнения
 
     Другой возможный тип ошибок - это ошибки этапа выполне-
ния (или семантические ошибки). Это происходит в том случае,
если вы транслируете корректную программу, но затем  при  ее
выполнении  предпринимается  попытка  выполнить недопустимое
действие, например, открыть несуществующий  файл  для  ввода
или  разделить целое число на 0. В этом случае Турбо-Паскаль
печатает на экране сообщение  об  ошибке,  которое  выглядит
примерно так:
 
     Runtime error   at seg:ofs 
     (Ошибка этапа выполнения    в сегм:смещ)
 
и прекращает выполнение  программы.  Турбо-Паскаль,  выбирая
соответствующий  исходный  файл, автоматически находит место
возникновения ошибки.
     Если вы запустили программу из ДОС, то управление будет
передано  ДОС. При этом для определения места ошибки в вашем
исходном файле вы можете загрузить TURBO.EXE и для использо-
вать  команду  меню  "Компиляция/Поиск ошибки" (Compile/Find
Error) (при этом  нужно  убедиться  что  опция  "Назначение"
(Destination) установлена в значение Disk).
     Вы можете также использовать компилятор,  работающий  в
режиме  командной строки. Если программа выполняется в среде
компилятора с командными строками (ТРС.ЕХЕ), то ошибку можно
найти, используя необязательный параметр /F. (См. Приложение
"Справочник по командным строкам", где дано полное  объясне-
ние  и способ нахождения ошибок, возникающих на этапе выпол-
нения, при использовании  ТРС.EXE  для  запуска  выполняемых
программ).
 
                     Логические ошибки
 
     Ваша программа  может  содержать,  наконец,  логические
ошибки  (если  предположить, что она выполняет то, что вы ей
задали, а не то, что хотели задать).  Переменная,  например,
может  быть неинициализирована. При этом вычисления оказыва-
ются неправильными, изображения на экране выглядят  неверно,
или  программа может просто пропускать некоторые места, счи-
тая, что так и должно быть.
     Этот тип ошибок наиболее труден для обнаружения, и поэ-
тому  он  может  быть одной из основных причин возникновения
необходимости использования интегрированного отладчика.
 
           Интегрированный отладчик Турбо-Паскаля
 
     Некоторые ошибки оказывается трудно отследить и обнару-
жить. Другие ошибки могут оказаться скрытыми многочисленными
связями между отдельными частями программы. В  этих  случаях
вы,  вероятно,  захотите выполнить вашу программу в интерак-
тивном режиме, наблюдая за  изменениями  значений  отдельных
переменных  или  выражений.  Вы,  наверное,  также хотели бы
иметь возможность останавливаться в определенном месте прог-
раммы и смотреть, что там происходит. Желательно также оста-
навливаться и изменять значения некоторых переменных при вы-
полнении  программы. Это позволит повлиять на ее поведение и
увидеть, в какую сторону оно изменилось. Все это хотелось бы
делать в режиме, позволяющим вам быстро отредактировать, пе-
рекомпилировать и снова запустить программу.
     Все  эти  желательные  возможности  наряду  с   другими
средствами  может  вам предоставить интегрированный отладчик
Турбо-Паскаля. Он является составной частью  интегрированной
среды разработки программ Турбо-Паскаля и имеет три основных
меню ("Выполнение", "Отладка" и "Прерывание/Просмотр" - Run,
Debug  и  Break/Watch),  а  для работы с командами отладчика
можно использовать несколько оперативных клавишей.
     В Таблице 6.1 приведены все  команды  отледки,  включая
оперативные клавиши и соответствующие команды меню.
 
         Таблица 6.1 Команды отладчика и оперативные клавиши
------------------------------------------------------------
Опер. клавиша  Команда меню              Функция
------------------------------------------------------------
Ctrl-F9    "Выполнение/Выполнение" Запускает вашу программу,
                  (Run/Run)        выполняя, если это необ-
                                   ходимо, функцию Make.
 
Ctrl-F2      "Выполнение/Сброс     Завершает сеанс отладки,
                 программы"        освобождает выделенную 
               (Run/Program        память и закрывает файлы,
                  Reset)           подготавливаясь к новому
                                   сеансу отладки.
 
F4        "Выполнение/Выполнение   Запускает программу на
               до курсора"         выполнение, останавлива-
                (Run/Go to         ясь при достижении стро-
                  Cursor)          ки, на которой находится
                                   курсор. Будет инициали-
                                   зировать сеанс отладки.

F7            "Выполнение/Трас-    Выполняет текущую строку.
                 сировка"          Если на ней содержится 
               (Run/Trace Into)    вызов процедуры или функ-
                                   ции, выполняет трассиров-
                                   ку процедуры или функции
                                   (если это возможно). Бу-
                                   дет инициализировать се-
                                   анс редактирования.
 
F8            "Выполнение/Выпол-   Выполняет текущую строку.
               нение по шагам"     Трассировка процедуры или
                (Run/Step Over)    функции выполняться не 
                                   будет.  Будет инициализи-
                                   ровать сеанс отладки.

Alt-F5         "Выполнение/Экран   Переключается между ин-
                  пользователя"    тегрированной интерактив-
                (Run/User Screen)  ной средой и выводимой 
                                   программой информацией
                                   (экраном выполнения).

               "О/К/Отладочная     Позволяет выполнять от-
                  информация"      ладку на уровне исходных
                (O/C/Debug         кодов. Включает и выклю-
                 Information)      чает директиву $D. Однако
                                   использование директивы 
                                   $D в тексте программы от-
                                   меняет эти установки.
 
                "О/К/Локальные     Разрешает вычисление ло-
                  символы"         кальных символов. Включа-
                 (O/C/Local        ет и выключает директиву
                   Symbols)        $L. Если отладочная ин-
                                   формация не генерируется,
                                   то эта опция игнорирует-
                                   ся.

Ctrl-F4         "Отладка/Вычисле-  Выводит окно вычисления,
                  ние"             позволяющее вам вычислить
                 (Debug/Evaluate)  значения переменных и вы-
                                   ражений и модифицировать
                                   переменные.

Ctrl-F3         "Отладка/Стек      Показывает текущий стек 
                  вызова"          вызова. Позволяет выпол-
                 (Debug/Call       нить обратное отслежива-
                   Stack)          ние вызовов процедур и 
                                   фукнций. Допускается 
                                   только при отладке.

                "Отладка/Поск      Находит первую строку
                  процедуры"       в описании процедуры или
                 (Debug/Find       функции и выводит ее в 
                   Procedure)      окно редактора. Работает
                                   при команде "Компилиро-
                                   вать/Создать" (Compile/
                                   Make) и в режиме отладки.
 
                "Отладка/Интегри-  Разрешает отладку в ин-
                  рованная         тегрированной среде. Эту
                  отладка"         возможность нужно устано-
                 (Debug/Integra-   вить в значение Off (вык-
                   ted Debugging)  лючено), только когда у 
                                   вас не хватает памяти для
                                   компиляции программы.
                                   Если эта опция выключена,
                                   вы не сможете отлаживать 
                                   программу в интегрирован-
                                   ной среде.
 
                 "Отладка/Авто-    Разрешает выполнять от-
                   номная отлад-   ладку с использованием 
                   ка"             автономного Турбо-отлад-
                  (Debug/Stand-    чика путем добавления в 
                   alone Debug-    конец выполняемого файла
                   ging)           отладочной информации.
 
                 "Отладка/Переклю- Осуществляет выбор между
                  чение экранов"   установками переключения
                  (Debug/Display   экранов: эффективной, 
                   Swapping)       пошаговой и отсутствием
                                   переключения (smart,
                                   always, none). Обычной 
                                   позицией является эффек-
                                   тивная.
 
                  "Отладка/Обно-   Повторно выводит изобра-
                    вить экран"    жение на экран, стирая
                   (Denug/Refresh  при этом все, что могло
                    Display)       остаться на экране.

Ctrl-F7           "Прерывание/     Добавляет выражение в ок-
                   Просмотр/       не просмотра (Watch). Это
                   Добавление в    можно также сделать, вы-
                   окно просмотра" бирая окно просмотра и 
                   (Break/Watch/   нажимая клавиши Ins или
                    Add Watch)     Ctrl-N (если Display
                                   Swapping установлено в 
                                   None).
 
                  "Прерывание/     Удаляет текущее выбранное
                   Просмотр/       выражение из окна про-
                   Удалене из окна смотра. Это можно также
                   просмотра"      сделать, выбрав окно про-
                   (Break/Watch/   смотра, соответствующее
                    Delete Watch)  выражение и нажав Del или
                                   Ctrl-Y.
 
                  "Прерывание/     Удаляет текущие выбранные
                   Просмотр/       выражения из окна прос-
                   Удаление из     мотра (Watch). Это можно 
                   окна просмот-   также сделать, выбрав 
                   мотра"          окно просмотра, соответ-
                   (Break/Watch/   ветствующего выражения в 
                    Delete Watch)  нем и нажатия клавиш 
                                   Ctrl-Y.

                   "Прервать/      Редактирует текущее выб-
                    Просмотреть/   ранное выражение в окне 
                    Редактировать  просмотра (Watch). Это 
                    окно просмот-  можно также сделать, 
                    мотра"         выбрав окно просмотра, 
                    (Break/Watch   соответствующее выражение
                     Edit Watch)   в нем и нажав клавишу
                                   Enter.
 
                    "Прерывание/   Удаляет все выражения из
                     Очистка       окна просмотра (Watch).
                     окна просмот- 
                     ра"
                     (B/Remove All
                      Watches)
 
Ctrl-F8             "Прерывание/   Устанавливает или отменя-
                     Переключение  ет точку останова на те-
                     точки оста-   щей строке редактора.
                     нова"
                     (B/Toggle 
                      Breackpoint)
 
                     "Прерывание/  Отменяет все точки оста-
                      Отмена       нова.
                      точки оста-
                      нова"
                      (B/Clear All
                       Breackpoints)
 
                     "Прерывание/   Выводит на экран (но не 
                      Просмотр сле- выполняет) следующую 
                      дующей точки  останова.
                      останова"
                      (B/View Next
                       Breackpoint)
 
F5                   "Опции/Выполне- Позволяет переключить-
                      ние/Переключе- ся между многооконным и
                      ние окон"      не многооконным выводом
                      (O/E/Zoom      для текущего активного
                       Windows)      окна операционной сре-
                                     ды.

Alt-F5                               Позволяет переключать-
                                     ся между операционной 
                                     средой и окном выполне-
                                     ния (Execution).

F6                                   Позволяет переключать-
                                     ся в интегрированной 
                                     среду между окном ре-
                                     дактора и другим окном
                                     (например, окном прос-
                                     мотра или окном выво-
                                     да).

Alt-F6                               Переключает содержимое
                                     окон. Если выбрано окно
                                     редактирования (Edit),
                                     загружает ранее загру-
                                     женный файл в это окно.
                                     Если выбрано другое ок-
                                     но, позволяет переклю-
                                     читься между между ок-
                                     ном просмотра (Watch) и
                                     окном вывода (Output).
------------------------------------------------------------
 
                   Пример быстрой отладки
 
     Введем в Турбо-Паскале следующий пример программы:
 
  {$D+,$L+}  { Для генерации полной информации для отладки }
  {$R+}      { Для выключения проверки диапазона }

  program RangeTest;
  var
    List : array[1..10] of integer;
    Indx : integer;
  begin
    for Indx := 1 to 10 do
        List[Indx] := Indx;
    while (Indx < 11) do
    begin
      Indx := Indx + 1;
      if List[Indx] := -List[Indx];
    end;
    for Indx := 1 to 10 do
        Writeln(List[Indx]);
    end.
 
     После токо, как вы ввели эту программу, сохраните ее на
диске  с помощью клавиши F2. В ответ на запрос о новом имени
назовите ее RANGE.PAS. Теперь, чтобы начать отладку, нажмите
клавишу  F7. Это команда "пошагового выполнения", то есть вы
даете Турбо-Паскалю команду выполнить первую строку тела ос-
новной программы. Поскольку ваша программа еще не была ском-
пилирована, Турбо-Паскаль выполнит этот процесс автоматичес-
ки  и, тем самым, подготовит вашу программу к пошаговому вы-
полнению. Обратите внимание, что граница выполнения находит-
ся на операторе Begin (строка 7). Помните о том, что граница
выполнения показывает следующую выполняемую строку  програм-
мы. 
     Теперь еще несколько раз нажмите  клавишу  F7.  Граница
выполнения перемещается к оператору List[Indx] := Indx и ос-
тается на нем. Это означает, что данный оператор выполняется
в цикле. Давайте посмотрим, что при этом происходит.
     Выберите команду "Прервать/Просмотреть/Добавить в  окно
просмотра"  (Break/Watch/Add  Watch) или используйте клавиши
Ctrl-F7. В середине экрана появляется рамка с  надписью  Add
Watch (добавить в окно просмотра). Если курсор установлен на
слове List, то List появится в окне просмотра в режиме подс-
ветки.
     (Та информация, которая в действительности будет  появ-
ляться  в окне Add Watch зависит от того, где позиционирован
курсор при нажатии клавиш Ctrl-F7. Если курсор у вас позици-
онирован  на  первую  букву буквенно-цифровой строки, внутри
нее или непосредственно за ней, то эта строка будет скопиро-
вана  в  окно Add Watch. Поэтому, если курсор был, например,
позиционирован на Indx, то  Indx  появится  в  данном  окне.
(Если  вы  хотите что-либо изменить в окне, то начните ввод.
При этом исходное выражение и подсветка исчезнут.)
     Когда выведено окно "Добавить  просмотр"  (Add  Watch),
то,  с  помощью  клавиши "->" (правая стрелка) независимо от
его содержимого вы можете включить в него дополнительную ин-
формацию  (при  этом из редактора скопируется дополнительный
текст). Убедитесь в том, что List - это единственный появив-
шийся  в  рамке  текст,  и нажмите клавишу Enter. При этом в
окне просмотра (Watch) в нижней части экрана появится следу-
ющая строка:
 
     List: (1,2,0,0,0,0,0,0,0,0)
 
     Теперь снова нажмите F7. Когда появится  рамка  с  над-
писью  Add  Watch, наберите Indx и нажмите клавишу Enrter. В
окне просмотра появится List и оно примет следующий вид:
 
     Indx: 3
     List: (1,2,0,0,0,0,0,0,0,0)
 
     После этого снова нажмите F7 и вы увидите в окне  прос-
мотра (Watch) изменение значений переменных Indx и List, за-
висящих от тех действий, которые выполняет ваша программа.
     Когда вы войдете в цикл While, вы снова увидите пошаго-
вое  изменение значений переменны Indx и List. Обратите вни-
мание на то, что при нажатии клавиши  F7  изменения  в  окне
просмотра  отражают реальные действия, выполянемые на каждой
строке.
     Продолжайте нажимать F7, пока вы не окажетесь в  начале
выполнения  цикла  while    со значением Indx, равным 10. На
этот раз пройдите цикл нажимая F7 и не торопясь наблюдая  за
изменениями  в  окне  просмотра (Watch). Когда вы выполянете
оператор:

     List[Indx] := -List[Indx]
 
значения Indx изменяются до -11. Если вы  продолжаете  нажи-
мать F7, то обнаружите, что находитесь в бесконечном цикле. 
     Если вы введете и скомпилируете эту программу, она  бу-
дет  работать. Но работать бесконечно. Она попадает в беско-
нечный цикл, так как оператор while выполняется не 10 раз, а
11,  и при последнем проходе цикла переменная Indx также по-
лучает значение 11. Поскольку массив List содержит только 10
элементов,  List[11] будет указывать на некоторую ячейку па-
мяти за пределами массива List. В связи со способом хранения
переменных  может оказаться так, что List[11] занимает то же
самое место в памяти, что и переменная Indx.  Это  означает,
что когда Indx = 11, оператор
 
     List[Indx] := -List[Indx]
 
эквивалентен оператору 
 
     Indx := -Indx
 
Так как Indx равно 11, то этот оператор устанавливает Indx в
значение  -11.  При  этом программа снова начинает выполнять
цикл. При этом цикле будут изменяться  дополнительный  байты
где-то в ячейках, соответствующих List[-11..0].
     Другими словами, программа сама себя сбивает. При этом,
поскольку Indx никогда не достигает конца цикла (не принима-
ет значений больших или равных 11), то цикл будет выполнять-
ся бесконечно.
     Важно отметить, что всего за несколько минут  и  с  по-
мощью только нескольких клавиш (F7 и Ctrl-F7) вы можете выя-
вить и устранить трудноуловимую и скрытую ошибку.
 
              Для чего используется отладчик?
 
     Вероятно приведенный пример дал вам достаточно  хорошее
представление  о  том,  зачем нужен отладчик и как его можно
использовать для быстрого и легкого выявления  и  устранения
ошибок.  Но  благодаря  чему  отладчик  имеет такие полезные
свойства? Приведем краткий обзор.
 
     1.  Предположим, вы трассируете  выполнение  программы.
         Иногда простой просмотр того, как работает програм-
         ма (строка за строкой) и в каком порядке выполняют-
         ся  ее строки может значительно облегчить понимание
         того, что она делает. Фактически это может  оказать
         значительную  помощь в изучении Паскаля (и програм-
         маровании), поскольку вы можете, написав программу,
         сразу  посмотреть,  как она работает (проанализиро-
         вать ее "изнутри").
     2.  Допустим вы выполняете построчную трассировку прог-
         раммы.  При  этом вы можете переключаться от одного
         экрана к другому (или использовать  два  монитора),
         или  получить часть окна вывода под окном редактора
         (при этом укран будет разделен на две части).
     3.  Предположим, вы просматриваете значения  переменных
         и  выражений,  отсеживая их значения при выполнении
         программы. Как уже было показано  выше,  это  может
         очень  помочь при быстром выявлении ошибок, о также
         оказать помощь в понимании сложных ситуаций, позво-
         ляя  увидеть значения всех участвующих переменных и
         подвыражений.
     4.  Положим, вы изменяете значения переменных или  эле-
         ментов структур данных. При этом вы получаете прос-
         той механизм  проверки  того,  как  реагирует  ваша
         программа  на определенное множество значений пере-
         менных или условий. Предположим также, что во время
         отладки вы выполняете программу по шагам, корректи-
         руя отдельные значения. При этом, чтобы  продолжить
         сеанс  отладки,  вам  не  нужно возвращаться назад,
         исправлять ошибки и перекомпилировать программу.
     5.  Отладчик позволяет вам проверить работу тех  проце-
         дур и частей программы, которые во время ее обычной
         работы, как правило, не выполняются (например, раз-
         личные процедуры обработки ошибок). Вы можете также
         проверить условие соблюдения границ, посмотрев, как
         программа  реагирует на значения, находящиеся в до-
         пустимых пределах, и на значения, выходящие за тре-
         буемые границы.
              И что удивительно, отладчик позволяет это  де-
         лать  в очень простом режиме. При этом не требуется
         включения в  текст  программы  никаких  специальных
         инструкций  или увеличивать объем выполняемого фай-
         ла, а при завершении отладки для создания  автоном-
         ного  выполняемого  файла (.ЕХЕ) не требуется пере-
         компиляции.
              Как быть в том  случае,  если  ваша  программа
         разделена  на  отдельные  модули  или блоки?. Здесь
         также нет никаких проблем. При трассировке выполне-
         ния программы исходный код каждого модуля автомати-
         чески загружается в редактор.
              При использовании оверлеев  проблем  также  не
         возникает.   Отладчик   автоматически  обрабатывает
         оверлеи без какого-либо вмешательства с вашей  сто-
         роны.  Все это он делает в интегрированной интерак-
         тивной среде программирования, позволяя  легко  пе-
         реключаться между компилятором, редактором и отлад-
         чиком.
 
     Теперь, когда вы увидели, что  может  делать  отладчик,
давайте рассмотрим какими средствами он располагает.
 
     Трассировка
     Вы можете выполнить одну строку вашей программы,  оста-
новиться  и  посмотреть  результаты. Когда в вашей программе
вызываются процедуры или функции, имеется возможность выпол-
нить  этот  вызов, как один шаг, или трассировать вызываемую
процедуру построчно.
 
     Переход к курсору
     Вы модете перевести  курсор  к  заданной  строке  вашей
программы,  а  затем  указать  отладчику,  чтобы он выполнил
программу до данной строки. Это позволяет пропустить  выпол-
нение циклов и других малоинтересных частей программы и сра-
зу перейти к той точке, где вы хотите начать отладку.
 
     Прерывание выполнения программы
     Отдельные строки программы можно  пометить,  как  точки
останова.  Когда  вы  запускаете  программу и она попадает в
точку останова, ее выполнение приостанавливается и на  экран
исходный код в точке останова (граница выполнения). При этом
вы можете проверить значения переменных, начать  трассировку
или  запустить программу, пока она не достигнет другой точки
останова. Выполнение программы можно также прерывать в любой
точке,  нажав  клавиши  Ctrl-Break. Это приводит к такому же
эффекту, как остановка на следующей выполняемой  строке  ис-
ходного кода (как будто там находится точка останова).
 
     Просмотр
     В окне просмотра (Watch) вы можете устанавливать  число
просматриваемых  значений.  Каждое  из  этих  значений может
представлять собой переменную, структуру данных или  выраже-
ние.  По  мере  выполнения программы по шагам эти значения в
окне просмотра изменяются.
 
     Вычисление
     На экран можно  выводить  окно  вычислений  (Evaluate),
позволяющее   интерактивно  проверять  значения  переменных,
структур данных и выражений.
 
     Модификация
     С помощью окна  вычислений  (Evaluate)  можно  изменить
значение  любой  переменной, включая строки, указатели, эле-
менты массива, структуры данных и выражения.
 
     Перемещение
     Имеется возможность быстрого поиска описания  процедуры
или  фукнции,  даже если ваша программа разбита на множество
модулей. При трассировке программы вы можете  выполнять  об-
ратную трассировку вызовов процедуры и функции, которые при-
водят вас в ту точку, где вы в данный момент  находитесь,  и
проверять параметры каждого вызова.
 
            Подготовка к использованию отладчика
 
     Перед тем, как начать отладку конкретной программы,  вы
должны проинструктировать компилятор Турбо-Паскаля, чтобы он
сгенерировал для данной программы необходимую таблицу симво-
лов и информацию о номерах строк. Таблица символов представ-
ляет собой маленькую базу данных, в которую включены все ис-
пользуемые  идентификаторы  -  константы,  типы, переменные,
процедуры и информация о номерах строк.
     Наиболее простой способ сделать это состоит в  указании
директив  компилятора {$D+} и {$I+}. По первой директиве ге-
нерируется общая отладочная информация, касающаяся  глобаль-
ных  идентификаторов.  Она использовалась также в предыдущих
версиях Турбо-Паскаля для генерации  информации,  использую-
щейся автономными отладчиками. Ее также необходимо использо-
вать для работы с интегрированным отладчиком.  Другой  метод
задания  этой директивы состоит в использовании в интегриро-
ванной   среде   меню   команды   "Опции/Компилятор/Отладка"
(Options/Compiler/Debug),  которую нужно установить в значе-
ние On (включено). Директива {$D} позволяет сгенерировать  в
объектном коде информацию о номерах строк, благодаря которой
объектному коду ставятся  в  соответствие  строки  исходного
текста прогораммы.
     По директиве {$L} генерируется локальная отладочная ин-
формация.  Это означает создание списка идентификаторов, яв-
ляющихся для каждой процедуры или функции локальными. Благо-
даря  этому во время отладки отладчик может "помнить" о них.
Вы можете также установить эту возможность с помощью команды
меню           "Опции/Компилятор/Локальные          символы"
(Options/Compiler/Local Symbols). (Вы увидите, что все  при-
меры  этого  раздела на первой строке программы содержат ди-
рективы {$D+,L+}. Если вы пользуетесь  соответствующими  ко-
мандами меню, то это не является необходимым.)
     Если ваша программа включает  в  себя  модули,  которые
также нуждаются в отладке, то в начало исходного кода каждо-
го модуля вам также следует  поместить  директивы  {$D+,L+}.
Чтобы указать Турбо-Паскалю, в каком именной файле содержит-
ся ваша программа, вы, возможно, захотите  использовать  ко-
манду   меню  "Компилятор/Основной  файл"  (Compiler/Primary
File). (Заметим, что по умолчанию обе эти директивы установ-
лены  в  значение On (включены). В некоторых случаях опытные
программисты возможно захотят выключить эти возможности, сэ-
кономив  тем самым при компиляции место на диске или в памя-
ти.) Более подробная информация содержится  в  Приложении  С
"Справочного руководства ("Директивы компилятора").
     Наконец, нужно убедиться в том, что  переключатель  от-
ладки  в  интерактивной среде "Отладчик/Отладка в интегриро-
ванной среде" (Debug/Integrated Debugging) установлен в зна-
чение On (включено).
     Перед тем, как начать отладку, вы должны понимать,  что
основной  единицей выполнения при отладке является строка, а
не оператор. Если говорить более точно, строка является  ми-
нимальной  единицей  выполнения.  Если на одной строке у вас
содержится несколько операторов Паскаля, то они будут выпол-
нены все вместе при одном нажатии на клавишу F7. Если же на-
оборот один оператор у вас содержится не нескольких строках,
то  весь  он будет выполнен при одном нажатии на F7. Все ко-
манды выполнения, включая пошаговый режим и точки  останова,
основаны  на  построчной работе, и в качестве следующей гра-
ницы выполнения указывается следующая выполняемая строка.
 
                   Экран вашего терминала
 
     В интегрированной среде разработки программ  Турбо-Пас-
каля  обычно  выводится  на  экран  основное меню и два окна
(окно редактирования и окно просмотра -  Edit  и  Watch  или
окно редактирования и окно вывода - Edit и Output). Вы може-
те перейти к экрану выполнения (Execution), увеличить размер
каждого  из окон до полного экрана, переходить от одного эк-
рана к другому и т.д. Приведем перечень экранов,  к  которым
вы можете получить доступ:
 
     1.  Экран выполнения (Execution). Когда вы попадаете  в
         Турбо-Паскаль  этот экран исчезает, но он выводится
         на экран при обычном  выполнении  вашей  программы.
         При выходе из Турбо-Паскаля он появляется вновь.

     2.  Окно редактирования (Edit). В этом окне при отладке
         программы  выводится  ее исходный код. Во время от-
         ладки можно без  ограничений  использовать  команды
         редактирования  и команды работы с файлом для пере-
         мещения по исходному коду программы или для загруз-
         ки других файлов. Это позволяет вам установить точ-
         ки останова в различных частях исходного кода,  вы-
         полнять  обратную  трассировку  вызовов подпрограмм
         или выполнять  участок  программы  до  определенной
         точки.
     3.  Окно просмотра (Watch). В этом окне выводятся пере-
         менные,  структуры  данных  и выражения, которые вы
         включаете в окно просмотра.  В  начале  работы  это
         окно  пустое, но по мере того, как в него будут до-
         бавляться выражения (или удаляться  из  него),  оно
         будет увеличиваться в размере (или сжиматься). Наж-
         мите F6 и перейдите в окно  просмотра.  Теперь  для
         "прокрутки"  изображения в окне вы можете использо-
         вать клавиши управления курсором. Для  редактирова-
         ния подсвеченного текста можно использовать клавишу
         Enter, а для добавления и удаления - клавиши Ins  и
         Del.  Функционируют  также  клавиши, которые обычно
         используются в системе редактирования WordStar.
     4.  Окно вывода (Output). В этом окне  выводится  копия
         экрана  выполняния (только в текстовом режиме). При
         использовании Турбо-Паскаля  оно  не  изменяется  в
         размере, но его можно увеличить или уменьшить с по-
         мощью утилиты TINST. При выборе этого окна  изобра-
         жение  на нем можно "прокручивать" с помощью допол-
         нительной клавиатуры. Окно вывода можно также  уве-
         личить до размеров полного экрана.
 
     Когда вы находитесь в Турбо-Паскале,  можно  перейти  с
помощью    выбора   меню   "Выполнение/Экран   пользователя"
(Run/User Screen) в интегрированную  среду  Турбо-Паскаля  и
обратно  (для  этой  цели  можно  также использовать клавиши
Alt-F5). Эта возможность реализуется также, когда вы находи-
тесь в режиме отладки. Если ваша программа использует графи-
ческие средства, то нужно быть готовым к тому, что на экране
при  переключении между текстовым и графическим режимом воз-
никают кратковременные искажения. 
     В режиме неполного экрана (два окна выводятся на  экран
одновременно)  окно редактирования размещается над окном вы-
вода или окном просмотра. При этом клавиша F6 позволяет  пе-
реключаться  между  окном  редактирвания и вторым окном, что
позволяет вам выбрать то окно, с которым вы хотите  работать
(в  режиме  полного  экрана, когда окно занимает весь экран,
можно также переходить от одного окна к  дургому  с  помощью
клавиши F6).
     Когда вы в первый раз  входите  в  Турбо-Паскаль,  окно
операционной  среды  состоит из окна редактирования (Edit) и
окна просмотра (Watch). При продвижении  по  программе  Тур-
бо-Паскаль   будет   иногда  переходить  в  окно  выполнения
(Execution), выполнять ваш код, а затем переходить обратно в
интергированную среду и ожидать вашей команды. С помощью ко-
манды    "Отладка/Переключение    экранов"    (Debud/display
Swapping)  вы можете управлять переключением экранов. Данная
команда имеет три устанавливаемых значения:
 
     1.  Эффективное (Smart). Это обычное значение.  Переход
         в  окно  выполнения из интегрированной среды осуще-
         ствляется, когда программа выполняет прямой  доступ
         к  памяти  или когда подпрограмма оказывается прой-
         денной (выполненной).
     2.  Пошаговое (Always).  Переход  к  экрану  выполнения
         осуществляется на каждом шаге.
     3.  Отсутствует (None). Переключения экранов не  проис-
         ходит. Интегрированная среда остается все время ви-
         димой. Программа будет выполнять вывод на экран,  а
         в  тех  случаях,  когда  требуется  ввод информации
         пользователем, экран  интегрированной  среды  будет
         "затираться". Вы можете запросить, чтобы Турбо-Пас-
         каль заново вывел информацию на экран,  выбрав  ко-
         манду  "Отладка/Обновление  экрана"  (Debug/Refresh
         Display).

                   Начало сеанса отладки
 
     Самый быстрый способ начать отладку состоит в  загрузке
программы  и  выбора команды "Запуск/Трассировка" (Run/Trace
Into) или нажатии клавиши F7. При этом будет выполнена  ком-
пиляция  вашей программы. После завершения компиляции редак-
тор выведет основное тело программы, причем граница выполне-
ния  будет  установлена на начальный оператор begin. С этого
момента вы можете, используя клавиши  F7  и  F8,  продолжить
трассировку или использовать другие описанные здесь методы.
     Если вы знаете, в каком месте программы вы  хотите  на-
чать  отладку, то вы можете выполнить вашу программу до того
момента, пока она не достигнет этой точки и сделает там пау-
зу.  Чтобы  сделать  это, вам нужно просто выбрать эту часть
кода редактором и поместить курсор на ту строку, где вы  хо-
тите остановиться. Затем вы можете выполнить одно из следую-
щих действий:
 
     1.  Выбрать команду меню "Выполнение/Выполнение до кур-
         сора"  (Run/Go  to  Cursor) или нажать F4. При этом
         ваша программа будет выполнена до указанной точки и
         наступит пауза.
     2.  В данной  точке  можно  установить  точку  останова
         (выбрать команду меню "Прерывание/Просмотр/Переклю-
         чение точки останова" (Break/Watch/Toggle Breackpo-
         int) или нажать клавишу Ctrl-F8), а затем запустить
         программу, выбрав  команду  "Выполнение/Выполнение"
         (Run/Run)  или нажав Ctrl-F9. После этого программа
         будет останавливаться каждый раз, когда  дойдет  до
         данной строки. Можно установить несколько точек ос-
         танова. При этом программа будет останавливать  вы-
         полнение, когда дойдет до любой из них.
 
                Возобновление сеанса отладки
 
     Если вы, находясь в режиме отладки, захотите начать все
сначала,  выберите  в меню "Выполнение" (Run) команду "Сброс
программы" (Progran Reset). Это приведет к повторной инициа-

лизации  системы отладки, и следующая команда пошагового вы-
полнения поместит вас на первую строку основного тела  прог-
раммы.  В то же время эта команда закрывает все открытые ва-
шей программой файлы, очищает  стек  всех  вложенных  вызвов
подпрограмм и освобождает использованную в динамически расп-
ределяемой области память. Переменные при этом повторно ини-
циализированы  и  модифицированы  не будут (Турбо-Паскаль не
выполняет автоматическую инициализацию  переменных),  однако
для  типизованных  констант  будут восстановлены их первона-
чальные значения.
     Турбо-Паскаль предлагает также способ перезапуска в том
случае, если вы при отладке внесли изменения в саму програм-
му. Например, если вы модифицировали какую-либо часть  прог-
раммы,  нажмите одну из клавиш выполнения (И7, И8, Ехун-И9 и
т.д.). При этом вы получите сообщение: "Source modified, re-
build?   (Y/N)"   ("Исходный   код   изменен,   сформировать
заново?"). Если вы нажмете Y (да), то Турбо-Паскаль выполнит
повторное создание вашей программы и начнет отладку сначала.
Если вы нажмете N (нет), Турбо-Паскаль, предполагая, что  вы
знаете,  что делаете, продолжает сеанс отладки. (Любые изме-
нения исходного кода не будут влиять на выполнение  програм-
мы,  пока  вы  ее  не перекомпилируете. Если вы добавили или
удалили строки, граница выполнения не будет  скомпенсирована
этими  изменениями и может оказаться, что теперь граница вы-
полнения находится в неверном месте.)
 
                 Завершение сеанса отладки
 
     Во время отладки программы Турбо-Паскаль отслеживает то
место, где вы находитесь, и следит за вашими действиями. При
этом поскольку во время отладки вы можете загружать и редак-
тировать различные файлы, Турбо-Паскаль не будет интерпрети-
ровать загрузку другого файла в редактор, как завершение се-
анса отладки. Поэтому, если вы хотите запустить или отладить
другую программу, необходимо сообщить об этом  Турбо-Паскалю
с   помощью   команды   меню   "Выполнение/Сброс  программы"
(Run/Program Reset) или клавиш Ctrl-F2.
     Другая причина использования  этой  команды  состоит  в
том,  что во время работы ваша программа могла израсходовать
всю имеющуюся память  и  команда  "Файл/Командный  процессор
ДОС"  (File/OS Shell) работать не сможет. Чтобы вновь разре-
шить использование этой команды, нужно  использовать  "Сброс
программы".  Однока  при этом нужно помнить о том, что нужно
будет начать отладку  заново.  Поскольку  команда  "Выполне-
ние/Сброс  программы" позволяет вам вновь начать отладку ва-
шей текущей программы, для очистки  последней  программы  от
вас  могут  потребоваться дополнительные шаги. Если вы уста-
навливали точки останова, их следует отменить с помощью  ко-
манды   "Прерывание/Просмотр/Отмена   всех  точек  останова"
(Break/Watch/Clear All Breakpoints). Если вы их не отмените,
то  они  будут мешать вам при отладке другой программы. Если
это произошло, перед отладкой текущей программы у вас имеет-
ся возможность отменить старые точки останова.
 
               Выполнение программы по шагам
 
     Давайте теперь рассмотрим реальную работу отладчика. 
     Простейшим методом отладки является  пошаговая  тресси-
ровка. Вы уже могли видеть его работу на предыдущем примере.
Если вы видите текст своей программы в окне  редактирования,
перед  началом  отладки  нужно эту программу скомпилировать.
Это можно сделать с  помощью  команды  "Компиляция/Создание"
(Compile/Make)  (клавиша F9) или команды "Выполнение/Трасси-
ровка" (Run/Trace Into) (клавиша F7). По  клавише  F9  будет
выполнено  создание программы, по клавише F7 программы будет
создана и граница выполнения будет помещена на первую строку
программы.  После  этого программу можно выполнить с помощью
команд "Выполнение/Трассировка" (Run/Trace Into) или "Выпол-
нение/Выполнение по шагам" (Run/Step Over) (клавиша F8). 
     Различия между командами "Выполнение/Трассировка"  (F7)
и  "Выполнение/Выполнение  по шагам" (F8) состоит в том, что
по клавише F7 будет выполняться трассировка фукнций и проце-
дур, а по F8 вызовы процедур и функций выполняются, как один
шаг. Если в коде инициализации программы используются  моду-
ли, то при выполнении оператора begin тела основной програм-
мы эти команды дакже имеют специальное значение. В этом слу-
чае  F7  будет  выполнять по шагам код инициализации каждого
модуля, что позволит вам увидеть, как инициализируется  каж-
дый  модуль. По клавише F8 код инициализации будет пропущен,
и граница выполнения переместится на  следующий  выполняемый
оператор после оператора begin. 
     При выполнении программы по шагам с помощью  клавиш  F7
или   F8   на   экране   может  появляться  окно  выполнения
(Execution), но обычно оно появляется ненадолго (пока  прог-
рамма ожидает ввода), после чего текст программы будет выве-
ден снова и граница выполнения будет установлена на  следую-
щий выполняемый оператор.
     При выполнении по шагам (с  помощью  команды  "Выполне-
ние/Трассировка" (Run/Trace Into) или клавиши F7) вызываемой
процедуры или фукнции, скомпилированной с опцией "Опции/Ком-
пилятор/Отладка"   (Option/Compiler/Debug)  установленной  в
значение On (включена), Турбо-Паскаль будет загружать исход-
ный код процедуры и граница выполнения будет устанавливаться
на начало процедуры или фукнции.
     Если в процедуре вам встретится другой вызов  процедуры
или  функции,  вы также можете выполнить его трассировку (до
тех пор, пока вам будет это необходимо). При достижении кон-
ца процедуры или фукнции вы вернетесь в вызывающую процедуру
или функцию.
     Рассмотрим следующий пример программы TEST.PAS:
 
  {$D+,$L+}
  program Test;
  var
    X, Y : integer;
  procedure Swap(var A,B : integer);
  var
    T : integer;
  begin
    T := A;
    A := B;
    B := T
  end;
  begin  { тело основной программы }
    Write('Введите два значения: ');
    Readln(X,Y);
    Swap(X,Y);
    Writeln('X = ',X,' Y = ',Y)
  end.  { конец программы }
 
     Если вы начнете отладку этой программы с помощью клави-
ши  F7,  программа будет скомпилирована и граница выполнения
высветит второй оператор begin (строка 16).
     При продолжении нажатий клавиши F7, программа будет вы-
полняться  по  шагам, пока вы не достигните вызова процедуры
Swap. При следующем нажатии клавиши  F7  граница  выполнения
переместится  на  оператор  begin  процедуры Swap. Начиная с
этого момента вы будете проходить по шагам  процедуру  Swap,
пока не будет обнаружен завершающий end. При следующем нажа-
тии F7 вы вернетесь обратно в тело основной программы Test и
подсвечен  будет  оператор Writeln. Следующее нажатие F7 вы-
полняет эту строку и вы оказываетесь на завершающем операто-
ре end программы Test. Еще одно нажатие клавиши F7 - и прог-
рамма будет выполнена. Обратите внимание, что граница выпол-
нения при этом исчезнет.
     Вы можете удивиться, зачем  нужно  выполнять  операторы
begin  и  end  основной программы. Объяснение состоит в том,
что граница выполнения только подсвечивает  строки,  которые
генерируют код. Выполнение оператора begin приводит в вызову
кода инициализации, включая код инициализации модулей, кото-
рые  ваша программа может использовать. Это означает, что (с
помощью клавиши F7) вы можете  действительно  выполнить  ваш
код инициализации (по клавише F8 выполнение кода инициализа-
ции будет опущено). Аналогично, выполнение завершающего опе-
ратора  end  приводит к тому, что ваша программа вызовет це-
почку процедур выхода. Если вы установили  свою  собственную
процедуру  (процедуры)  выхода, они также будут вызваны (для
их отладки вы можете установить в этих процедурах точки  ос-
танова).
     Давайте рассмотрим программу TEST.PAS.  Почему  нажатие
клавиши  F7  приводит  к  трассировке  процедуры Swap, но не
трассирует Write и Read?. Это  происходит  из-за  того,  что
Турбо-Паскаль  может  найти  исходный  код процедуры Swap, а
Read и Write являются частью библиотеки исполняющей  системы
Паскаля,  и их исходные коды недоступны (по этой причине они
скомпилированы с выключенной опцией "Информация  для  отлад-
ки").  Предположим, вы хотите выполнить трассировку тела ос-
новной программы Test, но не хотите  трассировать  процедуру
Swap.  Имеется ли способ заставить отладчик интерпретировать
процедуру Swap  таким  же  образом,  как  он  интерпретирует
Write, Writeln и Readln?. 
     Такой способ есть, и он состоит в использовании команды
"Выполнение/Выполнение  по  шагам"  (Run/Step Over) (клавиша
F8). Она работает также, как команда  "Выполнение/Трассиров-
ка" (Run/Trace Into) (клавиша F7), но с одним важным отличи-
ем: если строка содержит вызов процедуры или функции, то  их
трассировка  не  производится,  и они выполняются просто как
системные вызовы. Это позволяет  вам  избежать  утомительной
трассировки  подпрограмм,  которые и так прекрасно работают.
Конечно, если в этой подпрограмме у вас содержится точка ос-
танова, отладчик на ней остановится.
     Если при выполнении программы TEST.PAS,  когда  граница
выполнения находится на процедуре Swap, вы нажимаете клавишу
F8, то эта процедура вызывается, а граница выполнения  пере-
мещается на следующую выполняемую строку (вызов Writeln).
     Рассмотрим теперь следующий (неполный) пример  програм-
мы:
 
  {$D+,$L+}
  program TestSort;
  const
    NLMax = 100;
  type
    NumList = array[1..NLMax] of integer;
  var
    List : NumList;
    I,Count : word;
  procedure Sort(var L : NumList; Cnt : integer);
  begin
    { сортировка списка }
  end; { конец процедура }
  begin
    Randomize;
    Count := NLMax;
    for I := 1 to Count do
      List[I] := Random(1000);
    Sort(List,Count);
    for I := 1 to Count do
      Writeln(List[I]:8);
    Readln
    end. { конец программы TestSort }

     Предположим, вы отлаживаете процедуру Sort.  Вы  хотите
трассировать  обращение  к  процедуре Sort, включая проверку
значений в массиве List перед вызовом процедуры. Однако  при
этом  нужно будет выполнить утомительную трассировку первого
цикла for (100 раз), в котором инициализируется массив List.
Имеется  ли какой-либо способ выполнения цикла без необходи-
мости проходить по шагам каждую строку?
     Такой способ есть. Фактически, имеется  даже  несколько
методов.  Во-первых,  вы  можете  поместить цикл в отдельную
процедуру и при достижении цикла нажать клавишу F8,  но  это
не  совсем  красиво. Во-вторых, в программе можно установить
точку останова. Мы поясним, что такое точки останова, и  как
они работают несколько позднее.
     Наконец, вы можете использовать команду "Выполнение/Вы-
полнение до курсора" (Run/Go to Cursor) (оперативная клавиша
F4). Ваша программа будет выполняться до тех  пор,  пока  не
будет достигнута строка, содержащая курсор. Граница выполне-
ния переместится на эту строку, после чего вы можете  начать
трассировку  с  данного места (на этот раз с помощью клавиши
F7) и выполнить трассировку процедуры Sort.
     Команда "Выполнение/Выполнение до  курсора  (Run/Go  to
Cursor) (F4) позволяет пройти несколько уровней вызовов под-
программ, даже если исходный код содержится в другом  файле.
Например, вы можете поместить курсор где-то внутри процедуры
Sort и нажать F4. При этом программа начала бы  выполняться,
пока  она не достигнет строки внутри процедуры Sort. Поэтому
данная процедура может содержаться даже в отдельном  модуле.
При  этом отладчик будет знать, где ему нужно остановиться и
что нужно вывести на экран.
     Имеется три случая, когда данная команда (F4) не приве-
дет  к  выполнению  до строки, на которой содержится курсор.
Первый случай - это когда курсор позиционирован между  двумя
выполняемыми  строками  (например,  на  пустой строке или на
комментарии, содержащемся между двумя строками программы). В
этом случае программа будет выполняться до следующей строки,
содержащей выполняемый оператор. Другой случай -  это  когда
вы позиционируете курсор вне области действия данного проце-
дурного блока (например, на операторе program  или  описании
переменной). Отладчик сообщит вам, что "на данной строке нет
сгенерированного кода" ("no code generated on  this  line").
Третий  случай  возникает,  когда вы позицилнируте курсор на
строке, которой никогда не будет передано управление (напри-
мер,  на строке, содержащейся выше границы выполнения (пред-
полагается отсутствие циклов) или в части else оператора if,
условие которого никогда не принимает значение True). Отлад-
чик ведет себя при этом также, как если бы вы выбрали коман-
ду  "Выполнение/Выполнение"  (Run/Run) (клавиши Ctrl-F9), то
есть программа будет работать до тех пор, пока она не завер-
шит выполение, или пока не будет достигнута точка останова.
     Предположим, что вы хотите  некоторое  время  выполнять
трассировку процедуры Sort, а затем затем завершить выполне-
ние программы и посмотреть на выходные результаты.  Как  это
можно сделать? Во-первых, вы можете переместить курсор к за-
вершающему оператору end тела основной  программы,  а  зетем
выбрать  команду  "Выполнение/Выполнение до курсора" (Run/Go
error in text........ F4).
            При этом вы можете проверять и изменять значения
переменных, добавлять или удалять выражения из окна просмот-
ра (Watch), устанавливать или отменять тоски останова. С по-
мощью  команды  "Выполнение/Экран  пользователя"   (Run/User
Screen)  (клавиши  Alt-F5) можно просмотреть выводимую прог-
раммой информацию. Программу можно запустить  на  выполнение
сначала   (с  помощью  команды  "Выполнение/Сброс  программы
(Run/Program Reset) и команды выполнения  программы  по  ша-
гам). Можно также продолжить ее выполнение до следующей точ-
ки останова (или до конца программы) с помощью команды  "Вы-
полнение/Выполнение" (Run/Run) (клавиши Ctrl-F9).
     Чтобы отменить на строке программы точку останова, нуж-
но  переместить  туда  курсор  и  снова использовать команду
"Прерывание/Просмотр/Переключение      точки       останова"
(Break/Watch/Toggle  Breackpoint)  или  клавиши Ctrl-F8. Эта
команда переключает (устанавливает или отменяет)  на  данной
строке точку останова. Если вы используете ее на той строке,
где установлена точка останова, то эта точка останова  отме-
няется.
     Для отмены всех точек останова  можно  выбрать  команду
"Прерывание/Просмотр/Отмена     всех     точек     останова"
(Break/Watch/Clear All Breakpoints).
     Если вы хотите просмотреть те точки  останова,  которые
заданы  в  вашей  программе,  то  выберите команду "Прерыва-
ние/Просмотр  следующей  точки  останова"  (Break/Watch/View
Next Breakpoint). При этом вы будете циклически перемещаться
по точкам останова программы.
     Давайте вернемся к рассмотренному ранее примеру:
 
  begin  { пело основной программы }
    Randomize;
    Count := NLMax;
    for I := 1 to Count do
      List[I] := Random(1000);
    Sort(List,Count);
    for I := 1 to Count do
      Writeln(List[I]:8);
    Readln
    end. { конец программы TestSort }

     Если вы вспомните, идея состояла в том,  чтобы  пропус-
тить  начальный цикл и начать трассировку с вызова процедуры
Sort. Новое решение состоит в том, чтобы переместить  курсор
на  эту строку и выбрать команду "Прерывание/Просмотр/Перек-
лючение  точки  останова"  (Break/Watch/Toggle   Breakpoint)
(клавиши  Ctrl-F8),  задав  точку останова. Теперь с помощью
команды "Выполнение/Выполнение" (Run/Run) (клавиши  Ctrl-F9)
выполните  программу до точки останова, после чего программа
остановится и вы сможете начать отладку.
 
              Использование клавиш Ctrl-Break
 
     В добавление к использования в программе точек останова
в  процессе ее выполнения в вашем распоряжении имеется "пос-
тоянная" точка останова - клавиши Ctrl-Break.  Это  означает
что  для  предотвращения сбоя вы можете в любой момент прер-
вать  выполнение  вашей  программы.   При   нажатии   клавиш
Ctrl-Break  вы перейдете из вашей программы в среду редакто-
ра, а причем граница выполнения будет установлена на следую-
щей строке и программа будет готова к пошаговому выполнению.
     При этом отладчик сам следит за ДОС,  базовой  системой
ввода-вывода  и  другими средствами. Таким образом, он "зна-
ет", является ли выполняемый в данный момент код  программой
ДОС, программой базовой системы ввода-вывода или вашей прог-
раммой. Когда вы нажимаете клавиши Ctrl-Break, отладчик ожи-
дает, пока не начнет выполняться сама программа. При этом он
проходит по шагам каждую машинную инструкцию, пока следующей
инструкцией не окажется строка с началом исходного кода Пас-
каля. В этой точке он прерывает работу и перемещает  на  эту
строку  границу выполнения, после чего выводит вам подсказку
нажать клавишу Esc.
     Если до того, как отладчик найдет и  выведет  на  экран
строку исходного кода будет обнаружено второе нажатие клавиш
Ctrl-Break, то отладчик прерывает работу программы и не  пы-
тается  найти строку исходного кода. В этом случае процедуры
выхода не выполняются. Это означает, что файлы,  видеорежим,
и выделение памяти ДОС будут отменены не полностью.
 
                     Просмотр значений
 
     Ход выполнения программы может сказать вам о многом, но
не  так много, как вы бы того хотели. Ведь вы вероятно захо-
тите посмотреть, как при выполнении вашей программы  изменя-
ются  значения  переменных.  Рассмотрим, например, программу
сортировки из предыдущего  примера.  Предположим,  процедура
Sort для этой программы выглядит следующим образом:
 
  procedure Sort(var L : NumList; C : word);
  var
    Top,Min,K : word;
    Temp : integer;
  begin
    for Top := 1 to C-1 do
    begin
    Min := Top;
    for K := Top+1 to C do
      if L[K] < L[Min] then
         L[Min] := L[K];
      if Min <> Top then
    begin
      Temp := L[Top];
      L[Top] := L[Min];
      L[Min] := Temp;
    end. { конец процедуры Sort }

     В этой программе имеется ошибка, поэтому пройдем ее  по
шагам  с помощью команды "Выполнение/Трассировка" (Run/Trace
Into) или клавиши F7, наблюдая  за  изменением  значений  L,
Top,  Min  и K. (Чтобы облегчить задачу, вам, вероятно, сле-
дует изменить значение MLMax (в примере программы,  рассмот-
ренном выше) на 10, благодаря чему вы будете работать с мас-
сивом меньшего размера.)
     Отладчик позволяет вам отслуживать изменение значений в
программе  по  мере ее выполнения. Как вы можете догадаться,
наблюдаемыми значениями при этом являются значения  перемен-
ных,  структур данных или выражений, помещенных в окно прос-
мотра (Watch). В этом окне показывается  каждое  наблюдаемое
значение и то, как оно изменяется при выполнении строки.
     Вернемся к предыдущему  примеру.  Наблюдаемые  значения
можно  легко задать. Для этого нужно просто переместить кур-
сор к каждому из таких  идентификаторов  и  выбрать  команду
"Прерывание/Просмотр/Добавление     в     окно    просмотра"
(Break/Watch/Add Watch) (Ctrl-F7). С  помощью  этой  команды
выражение  можно дабавить идентификатор, на котором позицио-
нирован курсор, в окно просмотра. Для того, чтобы  выражение
было воспринято, нужно нажать клавишу Enter.
 
  K: 21341
  Min: 51
  Top: 21381
  L: (163,143,454,622,476,161,850,402,375,34)
 
     При этом предполагается, что  вы  перешли  в  процедуру
Sort  и  граница выполнения находится на начальном операторе
begin. (Если вы еще не находитесь в процедуре  Sort,  то  на
экран после каждого выбираемого идентификатора будет выведе-
но сообщение "unknown identifier" ("неизвестный  идентифика-
тор")).  Заметим, что K, Min и Top имеют случайные значения,
поскольку они еще не инициализированы.  Предполагается,  что
значения в массиве L также случайны, но при работе программы
элементы массива примут неотрицательные  значения  от  1  до
999.
     Если нажать четыре раза клавишу F7, то вы переместитесь
к строке:
 
     if L[K] < L[Min] then
 
     Теперь вы можете заметить, что K, Min и Top имеют,  со-
ответственно,  значения  2,  1 и 1. Продолжайте нажимать F7,
пока вы не выйдите из внутреннего цикла и не перейдете,  вы-
полнив строку:
 
     if Min <> Top then
 
в начало внешнего цикла и не начнете снова выполнять строку:
 
     if L[K] < L[Min] then
 
     В этой точке окно просмотра будет  выглядеть  следующим
образом:
 
  K: 3
  Min: 2
  Top: 2
  L: (34,143,454,622,476,161,850,402,375,34)
 
     Теперь вы можете  обратить  внимание  на  два  момента.
Во-первых, последнее значение L (34), которое может оказать-
ся наименьшим, скопировалось в первую ячейку  массива  L,  а
значение,  которое  там  было  записано ранее (163) исчезло.
Во-вторых, Min и Top все время имели одни и те же  значения.
Фактически, при более внимательном анализе, вы обратите так-
же внимание на следующее: Min получило значение Top, но  оно
больше нигде не изменяется. А в конце цикла имеется проверка
if Min <> Top then. Это означает, что либо вы делаете не  ту
проверку, либо между этими двумя строками в программе что-то
неверно.
     Как оказалось, ошибка содержится в пятой строке  исход-
ного  кода: ее следует читать, как Min := K; а не как L[Min]
:= L[K];. Исправьте ее, поместив курсор на начальный  опера-
тор begin  в процедуре Sort и выбрав команду "Выполнение/Вы-
полнение до курсора" (Run/Go to Cursor)  (клавиша  F4).  Как
только  вы  измените  программу,  появится  рамка с вопросом
"Source code modified, rebuld? (Y/N)" ("Исходный  код  изме-
нен,  выполнить  повторное построение+ (Да/Нет)). Нажмите Y.
Ваша программа будет заново скомпилирована, начнет  выполне-
ние, а затем остановится на начальном операторе begin в про-
цедуре Sort. На этот раз она будет работать правильно: вмес-
то перезаписи первой ячейки массива наименьшим значением она
выполнит обмен значений, переместив значение из первой ячей-
ки в то место, где ранее находилось наименьшее значение. За-
тем она продолжит этот процесс для  второй  ячейки,  третьей
ячейки и т.д., пока список не будет полностью отсортирован.
 
               Область действия и ограничения
 
     Будем продолжать выполнение по  шагам  процедуры  Sort,
пока  она  не  завершит работу. Если у вас не хватает на это
терпения, можно воспользоваться командой  "Выполнение/Выпол-
нение" (Run/Run) (клавиша F9) или поместить курсор на конеч-
ный оператор end в процедуре Sort, а затем нажать F4.  Обра-
тите  внимание,  что  массив L полностью отсортирован, и его
значения упорядочены в возрастающем порядке. Окно  просмотра
(Watch)  может выглядеть следующим образом (значения элемен-
тов массива L будут, конечно, меняться по ходу выполнения):
 
  K: 10
  Min: 9
  Top: 9
  L: (19,43,66,202,262,285,396,473,803,936)
 
 Теперь снова нажмите F7. При этом вы вернетесь в тело
 основной программы 
DoSort. Окно просмотра теперь выглядит у вас так:
 
  K: Unknown identifier
  Min: Unknown identifier
  Top: Unknown identifier
  L: Unknown identifier
 
     Что же случилось? Только что эти выражения имели значе-
ния,  а теперь они совсем исчезли. Почему это произошло? Это
случилось потому, что, как мы уже упоминали ранее,  все  эти
величины  являются локальными по отношению к процедуре Sort,
то есть они являются "видимыми" и могут использоваться толь-
ко во время работы процедуры Sort.
     Та область, в которой  идентификатор  (константа,  тип,
переменная, процедура или функция) являются "выдимыми" и мо-
гут использоваться, называется областью действия этого иден-
тификатора. Формальное определение и правила, касающиеся об-
ласти действия, приведены в Главе 1 "Справочного  руководст-
ва"  ("Смиволы и константы"). Дадим, однако, простое поясне-
ние: область действия идентификатора начинается от его опре-
деления  и  завершается  оператором end программы, процедуры
или фукнции, в которой он был определен. (Очевидным исключе-
нием является идентификатор, объявленный в интерфейсной сек-
ции модуля. При использовании модуля идентификаторы  из  ин-
терфейсной секции "перемещаются" в локальную область.)
     Теперь то, что произошло, становится понятным.  Область
действия переменных Top, K, Min, а также "пустого" параметра
L ограничена процедурой Sort. При выходе из Sort эти иденти-
фикаторы  не  могут быть больше видимыми, и это отражается в
окне просмотра.
     Имеется также  следующее  пояснение  области  действия.
Рассмотрим следующий пример программы:
 
  {$D+,L+}
  program TestScope;
  var
    W,X,Y,Z : integer;
  procedure Swap(var X,Y : integer);
  var
    Z : integer;
  begin
    Z := X;
    X := Y;
    Y := Z
  end; { конец процедуры Swap }
   
  begin { тело основной программы TestScope }
    W := 10; X := 20; Y := 30; Z := 40;
    Swap(X,W);
    Swap(X,Y);
    Swap(Z,Y);
    Writeln(W:8,X:8,Y:8,Z:8)
  end. { конец программы TestScope }
 
     Наберите эту программу, сохраните ее в файле SCOPE.PAS,
скомпилируйте   с   помощью   команды  "Компиляция/Создание"
(Compile/Make) (клавиша F9), а затем нажмите F7. Когда будет
выведено  окно просмотра (Watch), добавьте в него переменные
W, X, Y и Z с помощью команды  "Прерывание/Просмотр/Добавле-
ние  в  окно  просмотра"  (Break/Watch/Add  Watch)  (клавиши
Ctrl-F7). После этого еще два раза нажмите F7. При этом гра-
ница  выполнения  должна  переместиться  на  вызов процедуры
Swap(X,W), а окно просмотра будет выглядеть следующим  обра-
зом:
 
     W: 10
     X: 20
     Y: 30
     Z: 40
 
     Теперь еще раз нажмите F7. При этом вы начнете  трасси-
ровку  процедуры Swap. Окно просмотра (Watch) примет следую-
щий вид (переменная Z будет инициализирована, поэтому ее те-
кущее значение изменится):
 
     W: 10
     X: 10
     Y: 20
     Z: 21326
 
     Выполняйте процедуру Swap по шагам, пока вы не  достиг-
ните  ее  завершающего  оператора end. Окно просмотра теперь
будет следующим:
 
     W: 10
     X: 10
     Y: 20
     Z: 10
 
     Чтобы вернуться в тело  основной  программы  TestScope,
еще  раз нажмите F7. При этом окно просмотра будет содержать
следующую информацию:
 
     W: 10
     X: 10
     Y: 20
     Z: 40
 
     Что здесь происходит? Похоже, что значения переменых W,
X, Y и Z будут сильно отличаться, хотя для этого нет причин.
Это показывает, насколько хорошо вы поняли  правило  области
действия:  когда  два идентификатора (с различными областями
действия) являются идентичными, преимущество имеет идентифи-
катор "наиболее локальный" или "наиболее вложенный".
     В нашем примере процедура Swap переопределяет три иден-
тификатора  X, Y и Z. Когда вы проходите через тело основной
программы, в окне просмотра видны "глобальные версии"  иден-
тификаторов X, Y и Z. Однако, когда вы выполняете трассиров-
ку процедуры Swap, то рассматириваются локальные по  отноше-
нию к данной процедуре переменные X, Y и Z и выводятся имен-
но их значения. При выходе из процедуры Swap снова  начинают
использоваться глобальные версии этих переменных.
     Если какой-либо способ избежать этой путаницы? Один  из
способов,  конечно,  состоит в том, чтобы избегать использо-
вать локальные идентификаторы,  переопределяющие  глобальные
идентификаторы.  Например,  процедуру  Swap можно переписать
следующим образом:
 
  procedure Swap(var A,B : integer);
  var
    T : integer;
  begin
    T := A;
    A := B;
    B := T
  end; { конец процедуры Swap }
 
     Теперь при трассировке этой процедуры в окне  просмотра
все  время будут показываться правильные значения глобальных
переменных X, Y и Z, поскольку локальные версии  этих  пере-
менных в процедуре Swap отсутствуют.
     Однако есть случаи, когда такое переименование неудобно
или  нежелательно. Можно ли избежать путаници в этом случае?
Предположим, у вас есть исходная версия программы TestScope,
и вы во время выполнения трассировки все время хотите отсле-
живать значения глобальных переменных. Можно ли это сделать?
     Да, и делается это с помощью квалификации идентификато-
ров.  Вы  можете  явным  образом  квалифицировать глобальный
идентификатор, указав перед его именем имя программы или мо-
дуля. При этом используется следующий формат:
 
     модуль.идентификатор
 
где "модуль" - это имя программы или модуля, а  "идентифика-
тор" - имя идентификатора. Например, вы можете задать, чтобы
окно просмотра выглядело следующим образом:
 
     W: 10
     X: 10
     Y: 20
     Z: 40
     TestScope.W:
     TestScope.X:
     TestScope.Y:
     TestScope.Z:
 
     Это позволит вам на  протяжении  всего  времени  работы
программы  отслеживать  значения переменных и "пустых" пара-
метров. На самом деле вы можете даже пойти дальше и  сделать
так, чтобы окно просмотра (Watch) приняло следующий вид:

 X: 
 @X=@TestScope.X:
 Y:
 @Y=@TestScope.Y:
 Z:
 @Z=@TestScope.Z:
 TestScope.W:
 TestScope.X:
 TestScope.Y:
 TestScope.Z:
 
     В первом добавленном вами выражении сравнивается  адрес
Х  с адресом TestScope.Х. Когда это выражение принимает зна-
чение True  (истинно), вы знаете, что Х обозначает глобальную
переменную Х, когда оно имеет значение False (ложно), то Х -
это какая-то локальная переменная  или  параметр.  Остальные
два выражения выполняют те же функции для переменных Y и Z.
     Можно также квалифицировать локальные идентификаторы  с
помощью специального синтаксиса, задающего для данного имени
полный "процедурный путь". В программе TestScope  вы  можете
отслеживать  параметр  процедуры  Swap X путем наблюдения за
значением TestScope.Swap.X.
 
                 Типы наблюдаемых выражений
 
     Единственный тип выражений, которые вы можете видеть  в
окне  просмотра (Watch) - это константы, массивы и целые пе-
ременные. На самом деле в выражение (как выражение  Паскаля)
вы  можете  поместить  любой  вид  константы, переменной или
структуру данных. Отметим конкретно, что вы можете добавлять
в окно просмотра и что будет при этом выводиться на экран:
 
     1.  Целые: Целые числа выводятся, как десытичные значе-
         ния.  Их  можно  также выводить в шестнадцатиричном
         виде, например:
 
              -23 $10
 
     2.  Вещественные: Вещественные значения, если это  воз-
         можно, выводятся без экспоненты. Например:
            38328б27    6.28е23    0.004709025032

     3.  Символьные:  Печатаемые  символы  (включая  символы
         расширенной граыики) выводятся так, как они есть (в
         одиночных кавычках). При выводе управляющих  симво-
         лоа  (коды ASCII от 0 до 31) выводятся в виде кодов
         ASCII. Например:
           'b'    '0'    #4
     4.  Вы можете задать  режим,  при  котором  управляющие
         символы  будет  интерпретироваться,  как печатаемые
         символы.
     5.  Булевские:  Булевские  значения  отображаются,  как
         True или False.
     6.  Перечислимые типы данных: Типы данных  выводятся  в
         виде  их действительных значений имен (при этом ис-
         пользуются только прописные буквы). Например:
            RED    JAN    WEDNESDAY
     7.  Указатели: Текущее  значение  указателя  выводится,
         как указатель. Примеры:
            PRT($3632,$106)    PTR(DSEG,$AB)  
          PRT(CSEG,$220)
     8.  Строки: Текущее содержимое строки выводится в  оди-
         ночных кавычках. Например:
            'Droid'
     9.  Массивы: Текущее  содержимое  массива  выводится  в
         скобках.  При этом элементы массива разделяются за-
         пятыми. Многомерные массивы выводятся в  виде  сло-
         женных списков. Примеры:
            (-42,23,2292,0,648)   ((10,20)   (20,40)  
          (40,60))
     10. Записи:Текущее содержимое записи выводится в  скоб-
         ках,  при этом поля разделяются запятыми. Вложенные
         записи выводятся в виде вложенных списков. Примеры:
             (5,20'Borland',RED,TRUE)   
          (5.6,7.8(TRUE,'0',9),TUES)
     11. Множества: Текущие элементы множества  выводятся  в
         квадратных  скобках. При этом выражения разделяются
         запятыми, и там, где возможно используются  отрезки
         множеств (поддиапазоны). Примеры:
            [MON.WED,FRI]    ['0'..'9','A'..'F']

     12. Файлы: Текущий статус  файла  выводится  в  формате
         (статус,имя_файла), где "статус" может иметь значе-
         ния CLOSED (закрыт), OPEN  (открыт),  INPUT  (ввод)
         или  OUTPUT  (вывод), а "имя_файла" - это имя файла
         на диске, присвоенное файловой переменной. Пример:
            (OPEN,'BUDGET.DTA')    (INPUT,'INPUT.TXT')
 
                   Спецификаторы формата
 
     Для управления выводом информации на экран в окно прос-
мотра Турбо-Паскаль позволяет включать в выражения просмотра
спецификаторы формата. В  случае  его  наличия  спецификатор
формата следует за выражением просмотра и отделяется от него
запятой.
     Спецификатор формата состоит из необязательного счетчи-
ка  повторений  (целого),  за которым следует ноль или более
символов формата. В Таблице 6.2 приводится список специфика-
торов формата и описывается, как они действуют.
     Счетчик повторений используется  для  вывода  на  экран
последовательности переменных (например, элементов массива).
Предположим, что List представляет собой  массив,  состоящий
из  10  целых значений. В окне просмотра (Watch) массив List
будет выглядеть следующим образом:
 
     List: (10,20,30,40,50,60,70,80,90,100)
 
     Если вы ходите наблюдать за  какой-то  частью  массива,
можно  определить  индекс  первого элемента и задать счетчик
повторений:
 
     List[6],3: 60,70,80
 
     Указанный метод особенно полезен, когда вы имеете  дело
с  очень  большими  массивами,  которые  не могут при выводе
уместиться на одной строке.
     Использование счетчиков  повторений  не  ограничивается
массивами: счетчик повторения может указываться за любой пе-
ременной. При задании "переменная,x" будет просто выведено x
последовательных перменных того же типа, что и "переменная",
начинающихся по адресу "переменная".  Отметим,  однако,  что
если  выражение просмотра не обозначает переменную, то счет-
чик посторений будет игнорироваться.  При  этом  справедливо
следующее  правило:  конструкция является допустимой, если в
ней используется переменная, которая может содержаться в ле-
вой  части  оператора присваивания или быть параметром-паре-
менной процедуры или функции.
 
                                                 Таблица 6.2
                    Символы управления форматом, 
              использующиеся при работе с отладчиком
------------------------------------------------------------
Символ       Функция
------------------------------------------------------------
  $          Шестнадцатиричное значение. Имеет такое же дей-
             ствие, как спецификатор H.
  С          Символ. Задает специальный символ для управля-
             ющих символов (значения кода ASCII от 0 до 31).
             По умолчанию такие символы выводятся в виде 
             значений кода ASCII в виде #xx. Влияет на все 
             символы и строки.
  D          Десятичное значение. Все целые значения выводят-
             ся на экран в десятичном виде. Влияет на прос-
             тые выражения целого типа, а также на структуры
             (массивы и записи), содержащие целые значения.
  Н          Шестнадцатиричное значение. Все целые значения
             будут выводиться в шестнадцатиричном виде с 
             предшествующим символом '$'. Влияет на простые 
             целые выражения, а также на структуры (массивы
             и записи), содержащие целые значения.
  Fn         Выражение с плавающей запятой. n - это целое
             значение от 2 до 18, задающее число выводимых
             на экран значащих цифр. По умолчанию это значе-
             ние равно 11. Оказывает влияние только на зна-
             чения в формате с плавающей запятой.
  M          Память. Выводит на экран дамп памяти перемен-
             ной. Выражение должно представлять собой кон-
             струкцию, которую допускается использовать в
             левой части оператора присваивания (то есть 
             конструкцией, обозначающей адрес памяти). В 
             противном случае спецификатор М игноритуется.
             По умолчанию каждый байт переменной показывает-
             ся в виде двух шестнадцатиричных цифр. Добавле-
             ние спецификатора D приводит к тому, что байты
             будут выводиться в десятичном представлении, а
             добавление спецификаторов H, $ и X задает вы-
             вод байтов в шестнадцатиричном виде с предшест-
             вующим символом '$'. Спецификаторы С или S при-
             водят к тому, что переменная будет выводится в 
             виде строки (со специальными символами или без
             них). По умолчанию число выводимых байтов соот-
             ветствует размеру переменной, но для точного 
             задания числа выводимых байтов можно использо-
             вать счетчик повторения.
   Р         Указатель. Выводит указатели в формате "сегмент:
             смещение", а не в принятом по умолчанию формате
             Ptr(seg,ofs). Например, на экран выводится 
             3ЕА0:0020 вместо Ptr($3EA0,$20). Влияет только 
             на значения типа указатель.
   R         Запись. Выводит на экран имена полей записи, 
             например (X:1;Y:10;Z:5) вместо (1,10,5). Влияет
             только на переменные типа запись.
   S         Строки. Показывает управляющие символы кода 
             ASCII (коды от 0 до 31) в виде значений кода 
             ASCII. При этом используется синтаксис #xx. 
             Поскольку этот формат принят по умолчанию, ис-
             пользовать спецификатор S полезно только в со-
             четании со спецификатором М.
   Х         Шестнадцатиричное значение. Действует также, 
             как спецификатор Н.
------------------------------------------------------------
 
     Чтобы продемонстрировать  использование  спецификаторов
формата,  предположим, что описаны следующие типы и перемен-
ные:
 
  type
    NamePtr = ^NameRec;
    NameRec = record
                Next: NamePtr;
                Count: integer;
                Name: string[31];
              end;
  var
    List: array[1..10] of integer;
    P: NamePtr;
 
     С учетом этих описаний можно построить следующие  выра-
жения просмотра:
 
  List: (10,20,30,40,50,60,70,80,90,100)
  List[6],3H,$3C,$46,$50
  P: PTR($EA0,3C)
  P,P: 3EA0:000C
  P^:(PTR($EF2,$2),412,'John')
  P^,R$: (NEXT:PTR($3EF,$2):COUNT:$19C;NAME:'John')
  P^.Next^,R: (NEXT:NIL;COUNT:377;NAME:'Joe')
  Mem[$40:0],10M: F8 03 F8 02 00 00 00 BC 03
  Mem[$40:0],10MD: 248 3 248 2 0 0 0 0 188 3
 
                      Приведение типов
 
     Приведение (преобразование) типов - это еще одно мощное
средство,  которое можно использовать для изменения вида вы-
водимых на экран в окне просмотра (Watch) выражений и  кото-
рое  позволяет  интерпретировать  данные  с одним типом, как
данные с другим типом (который  отличается  от  их  обычного
типа).  Это  может  оказаться особенно полезным при работе с
адресом или с общим указателем, который вы хотите рассматри-
вать, как ссылающийся на конкретный тип данных.
     Предположим, в вашей программе имеется переменная DFile
файлового типа MyRec, и вы хотите выполнить следующую после-
довательность операторов:
 
     Assign(DFile, 'INPUT.REC');
     Reset(DFile);
 
     Если вы включите DFile в список просматриваемых выраже-
ний,  то  соответствующая  строка  в  окне просмотра (Watch)
будет выглядеть следующим образом:
 
     DFile: (OPEN, 'INPUT.REC')
 
     Однако о самой записи файлового типа вы, возможно,  за-
хотите  получить  больше  информации.  Если вы измените свою
программу таким образом, что она будет  использовать  модуль
Dos, то вы сможете также изменить просматриваемый файл DFile
на FileRec(DFile),rh. Это означает, что файл DFile нужно вы-
вести, как запись типа FileRec(DFile) (которая описана в мо-
дуле Dos), все поля которой помечены,  как  целые  значения,
выводимые  на  экран  в  шестнадцатиричном виде. Выводимый в
окне просмотра результат может выглядеть следующим образом:
 
     FileRec(DFile),rh:
(HANDLE:$6;$D7B3;RECSIAE:$14;PRIVATE($0,$0,...)
 
     Эта запись имеет слишком большую длину и ее нельзя уви-
деть сразу. Однако с этой целью вы можете использовать пере-
мещение курсора и просматривать данные, не видимые в  данный
момент на экране (см. раздел "Редактирование в окне просмот-
ра").
     С помощью такого  приведения  типов  вы  теперь  можете
просматривать отдельные поля DFile. Можно, например, добавив
в   окно   просмотра   выражение    FileRec(DFile).UserData,
просматривать поле UserData:
 
     FileRec(DFile).UserData:
(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
 
     Тот же метод можно  использовать  для  вывода  структур
данных и для ваших собственных типов. Если эти типы описыва-
ются в вашей программе или модуле,  вы  можете  использовать
для  них в окне просмотра приведение типов. Правила приведе-
ния типов поясняются в  Главе  6  "Справочного  руководства"
("Выражения").
 
                         Выражения
 
     Как уже упоминалось ранее, выражения вы можете  исполь-
зовать  в  качестве выражений просмотра (наблюдаемых выраже-
ний) - тех выражений, информация о которых при отладке прог-
раммы будет выводиться в окне просмотра (Watch). При этом вы
можете использовать вычисляемые выражения, сравнения, адреса
и смещения, а также другие выражения. В Таблице 6.3 приведен
список средств, которыми можно воспользоваться при работе  с
окном просмотра, и воспринимаемые значения.
 
          Значения выражений в окне просмотра
                                                Таблица 6.3
-----------------------------------------------------------
Допускается использовать            Воспринимаемые значения
в выражениях просмотра
-----------------------------------------------------------
Константы и литералы            Все обычные типы: булев-
                                ский, байтовый, символьный,
                                перечислимый, целый, длин-
                                ный целый, вещественный,
                                короткий целый, строковый,
                                слово.
 
Переменные:                     Все типы, включая типы, оп-
  целочисленные                 ределяемые пользователем и
                                элементы структур данных.
 
  с плавающей запятой           Любое выражение с плавающей
                                запятой (или целое) в гра-
                                ницах представления порядка
                                переменной. Лишние значащие
                                цифры отбрасываются.
 
  символьные                    Любое символьное выражение,
                                включая любой печатаемый
                                символ, заключенный в оди-
                                ночные кавычки. С помощью
                                функций Chr или Char() мож-
                                но воспользоваться преобра-
                                зованием целого типа в сим-
                                вольный. При этом исполь-
                                зуются констаны кода ASCII
                                (символ #, за которым сле-
                                дует число от 0 до 255).
 
  булевские                     True или False, а также лю-
                                бое выражение булевского
                                типа.
 
  данные перечислимого типа     Любые совместимые перечис-
                                лимые константы. Выполняю-
                                щиеся в рамках допустимых
                                границ приведение целочис-
                                ленных выражений к совмес-
                                тимому перечислимому типу.
 
  указатель                     Любой совместимый указа-
                                тель, любое совместимое вы-
                                ражение с приведением типа,
                                Функция Ptr с соответству-
                                ющими параметрами.
 
  строковая                     Любая строковая константа
                                (текст заключается в оди-
                                ночные кавычки). Переменные
                                строкового типа, строковые
                                выражения, состоящие из
                                строковых констант и пере-
                                менных, связынных операто-
                                ром "+".
 
  множественного типа           Любая константа множествен-
                                ного типа (элементы совмес-
                                тимого типа, заключенные в
                                квадратные скобки). Любое
                                совместимое выражение мно-
                                жественного типа, включая
                                выражения, в которых исполь-
                                зуются операции над множест-
                                вами +,-,*.

Приведение типа                 Соответствует правилам стан-
                                дартного Паскаля.
 
Операторы                       Все обычные операторы Паска-
                                ля, плюс расширения Турбо-
                                Паскаля (такие, как xor, @ и
                                т.д.).
 
Встроенные функции              Abs, Addr, Chr, Hi,
 IOResult,
                                Length, Lo, MaxAvail, Mem,
                                MemAvail, MemL, MemW, Ofs,
                                Ord, Ptr, Pred, Ptr, Round,
                                Seg, SizeOf, SPtr, SSeg,
                                Succ, Swap и Trunc.
------------------------------------------------------------
 
     Другими словами, выражение  должно  представлять  собой
обычное,  допустимое в Паскале выражение, и использовать лю-
бое из средств, описанных в Таблице 6.3. О  том,  как  можно
изменять  выводимые в окне просмотра (Watch) выражения, рас-
сказывается в разделе "Модификация выражений просмотра".

              Редактирование в окне просмотра
 
     Теперь вы  знаете,  как  с  помощью  команды  "Прерыва-
ние/Просмотр/Добавление  в  окно просмотра" (Break/Watch/Add
Watch) (клавиша F7) добавлять выражения просмотра. Выражения
в  окне  просмотра  (Watch) можно также удалять и редактиро-
вать.
     Наиболее развитым  подходом  является  использование  в
окне просмотра команд редактирования. Выберите с помощью на-
жатия клавиши F6 окно просмотра (Watch). Верхняя часть этого
окна  ограничена двойной линией в выведено подсвеченное наз-
вание окна (Watch). (Если  выведено  окно  вывода  (Output),
нажмите Alt-F6.)
     Теперь вы находитесь в окне просмотра и для перемещения
курсора  от  одного  выражения к другому можете использовать
клавиши "Стрелка вверх" и "Стрелка  вниз".  Можно  заметить,
что  использование этих клавиш изменяет схему подсветки окна
просмотра. Подсвечиваемое выражение - это то выражение,  ко-
торое  вы  можете  отредактировать или удалить. Над границей
подсветки вы всегда можете добавить новое выражение просмот-
ра.  Если все выражения в окне просмотра (Watch) не умещают-
ся, то для вывода невидимых в данный момент выражений  можно
использовать "прокрутку" изображения.
     Если выражение просмотра по длине превышает размер окна
(то  есть  содержит более 77 символов), то нужно переместить
подсветку к этому выражению  и  для  горизонтального  сдвига
изображения использовать клавиши "Стрелка вправо" и "Стрелка
влево". Для перемещения в начало и в конец строки можно  ис-
пользовать клавиши Home и End.
     Для того, чтобы находясь в окне  просмотра  добавить  в
него  новое  выражение  просмотра,  нажмите калвишу Ins (или
Ctrl-N). При этом будет выведена рамка добавляемых выражений
просмотра (Add Watch) (как и при нажатии F7). Когда вы набе-
рете новое выражение, оно будет включено над текущим выбран-
ным выражением просмотра.
     Для выражения текущего выражения просмотра нажмите кла-
вишу  Enter.  При  этом  будет выведена рамка редактирования
окна просмотра (Edit Watch). Если вы хотите полностью  изме-
нить выведенное в ней выражение, то просто начните ввод (при
этом подсветка исчезнет). Для редактирования  выражения  ис-
пользуйте  клавиши "Стрелка вправо", "Стрелка влево", Home и
End. Если вы хотите заменить исходное выражение его отредак-
тированной версией, нажмите клавишу Enter. Если вы не хотите
изменять старое выражение, нажмите клавишу Esc, а если хоти-
те снова восстановить прежнюю версию - клавиши Ctrl-R.
     Для удаления выражения из окна просмотра выберите его с
помощью  клавиш  перемешения  курсора  и нажмите клавишу Del
(вместо клавиши Del можно использовать Ctrl-Y  или  Ctrl-R).
Можно использовать также команду "Прерывание/Просмотр/Очист-
ка окна просмотра"  (Break/Watch/Remove  All  Watches).  При
этом окно просмотра будет полностью очищено.
     Когда вы переходите по клавише F6 в  окно  редактирова-
ния, выражения в окне просмотра больше подсвечиваться не бу-
дет и вместо этого перед выражением  указывается  знак  ".".
Любые операции, выполняемые из текущего меню, будут ссылать-
ся на текущее выражение в окне просмотра (Watch).
     Обратите внимание, что границы окна просмотра  настраи-
ваются  автоматически:  если вы добавите или удалите выраже-
ние, оно будет автоматически увеличиваться или уменьшаться в
размере.  Благодаря  этому пустые строки не занимают место в
окне просмотра и пространство экрана используется для вывода
исходного кода программы.
 
                  Вычисление и модификация
 
     Окно просмотра (Watch) хорошо использовать для  трасси-
ровки  значений  при  выполнении  программы по шагам. Однако
имеются случаи, когда это не соответствует вашим  потребнос-
тям. Часто приходится имеють дело с переменными и выражения-
ми, которые требуется проверять только  в  отдельных  точках
программы.  Допустим,  вы  не хотите, чтобы они выводились в
окне просмотра все время, но находите  слишком  утомительной
необходимость  включать  их периодически в окно просмотра, а
затем удалять (особенно если требуется проверять сразу  нес-
колько  таких  выражений).  Наконец,  вы  можете захотеть не
только наблюдать за изменением значения переменной, но и из-
менять его.
     Для этого в  отладчике  предусмотрено  окно  вычислений
(Evaluate),  показанное  на  Рис. 6.1. Для вывода этого окна
нужно    воспользоваться    командой    "Отладка/Вычисление"
(Debug/Evaluate)  или  оперативными  калвишами  Ctrl-F4. Это
окно содержит три поля с именами "Вычисление"  (Evaluation),
"Результат" (Result) и "Новое значение" (New Value).
     Как и в случае рамки "Добавление выражений" (Add Watch)
поле "Вычисление" уже содержит слово, найденное в месте рас-
положения курсора. Оно выводится  в  режиме  подсветки.  Его
можно  отредактировать (как и в случае рамки "Добавление вы-
ражений"). Когда вы захотите вычислить его значение, нажмите
клавишу Enter. При этом текущее значение константы, перемен-
ной или выражения появится в поле результата (Result).
 
------------------------------------------------------------
    File  Edit  Run  Compile  Options  Debug  Break/Watch
   ---------------------------------------------------------
   !   Line 1  Col 1  Insert Indent   !Evaluation Ctrl/F4 !!
   !                                  ---------------------!
   !                 ---------------------------------------
   !                 !  ------------- Evaluate ----------  !
   !                 !  !                               !  !
   !                 !  ---------------------------------  !
   !                 !  -------------- Result -----------  !
   !                 !  !                               !  !
   !                 !  ---------------------------------  !
   !                 !  ------------- New Value ---------  !
   !                 !  !                               !  !
   !                 !  ---------------------------------  !
   !                 ---------------------------------------
   !                                                       !
   !                                                       !
   !                                                       !
   !------------------------ Watch ------------------------!
   !                                                       !
   ---------------------------------------------------------
    F1 - Help   Esc - Abort
------------------------------------------------------------
 
     Рис. 6.1 Окно вычислений
 
     Поле вычислений (Evaluale) позволяет работать с тем  же
множеством  констант, переменных и выражений, которые допус-
кается использовать в окне просмотра (Watch). При этом имеют
силу  те  же  ограничения и допускается использование тех же
средств, о которых мы уже рассказывали.  Можно  использовать
также  символы формата, применяемые при работе с окном прос-
мотра (Watch).
     Когда вы нажимаете Enter, идентификатор или выражение в
поле вычислений (Evaluate) снова подсвечиваются. Это означа-
ет (если начали набирать новое имя без  нажатия  клавиш  Ins
или "Стрелка влево"), что оно заместит старое. Это позволяет
вам быстро вводить ряд переменных или выражений.
     Поле "Новое значение" (New  Value)  позволяет  изменить
значения   переменных,   названных   в   поле   "Вычисление"
(Evalute). Вы можете ввести имя другой переменной,  значения
константы или даже выражение. Результирующее значение должно
иметь тип, совместимый с типом перекменной в поле  "Вычисле-
ние".  Таким  образом, если в поле "Вычисление" у вас содер-
жится выражение, в результате вычисления которого не получа-
ется ячейка памяти, то любое значение, введенное в поле "Но-
вое значение" (New Value) приведет к выводу сообщения Cannot
be modified" (изменить нельзя).
     В поле результата (Evaluate) выводится текущее значение
или  то,  что содержалось в этом поле. При этом используется
тот же формат, что и при работе с окном  просмотра  (Watch).
Аналогично  тому, как это бывает при работе с окном просмот-
ра, размер выводимых данных может превысить  длину  поля.  В
этом  случае для смещения изображения вы можете использовать
клавиши Tab, BackTab ("Табуляция" и  "Обратная  табуляция"),
"Стрелка влево", "Стрелка вправо", Home и End.
     Во всех случаях для перемещения между этими тремя поля-
ми вы можете использовать клавиши "Стрелка вверх" и "Стрелка
вниз" (или обычные команды редактирования с помощью  клавиа-
туры). Когда вы модифицировали поле, для получения результа-
та нажмите клавишу Enter.
 
                   Модификация переменных
 
     Возможность модифицировать переменную во время выполне-
ния программы может оказать при отладке существенную помощь.
Но она может привести также к ошибкам, поэтому вы должны хо-
рошо разбираться в том, как можно это средство использовать.
     Простейшим способом модификации является, конечно, ввод
имени  переменной  в  поле "Вычисление" (Evaluate) и соотве-
тстсвующее значение в поле  "Новое  значение"  (New  Value).
После того, как вслед за набором нового значения вы нажимае-
те клавишу Enter, значения переменной изменяется и это отра-
жается в поле результата (Result).
     При этом, конечно, допускается использовать  не  только
значения-константы.  В  поле "Новое значение" (New Value) вы
можете вводить любую переменную или  выражение,  которые  вы
вогли вводить в поле "Вычисление" (Evaluate), однако с одним
главным ограничением: оно должно быть совместимо по присваи-
ванию  с  переменной  или  выражением  в  поле  "Вычисление"
(Evaluate). Другими словами, "выраж" - это то, что содержит-
ся  в  поле  вычисления, то не допускается вводить выражение
"выраж" в поле "Новое значение" (New Value), если оператор:
 
     выраж := выраж
 
вызовет ошибку во время компиляции.
     Заметим, что обратное верно  не  всегда:  есть  случаи,
когда оператор:
 
     выраж := выраж
 
допустим, однако "выраж" нельзя использовать в  поле  "Новое
значение" (New Value).
     Если вводимое выражение имеет несовместимый тип (напри-
мер, для целочисленной переменной вводится значение с плава-
ющей запятой), то в поле результата (Result) вместо  резуль-
тата    будет    выведено    сообщение    "Type    mismatch"
("Несоответствие типов"). Для того, чтобы в поле  результата
было  вновь  выведено текущее значение переменной, вернитесь
назад в поле вычислений и нажмите клавишу Enter.
     Если вводимое значение приводит к выходу за  допустимые
границы (например, ввод значения 50000 для переменной целого
типа), то в поле результата  выведется  сообщение  "Constant
out of range" (константа выходит за границы допуcтимого диа-
пазона). То же самое произойдет,  если  вы  введете  элемент
массива, индексы которого выходят за границу массива.
     Если  выражение,  вводимое  в  поле  "Новое  значение",
представляет собой такое значение, которое нельзя присвоить,
то в поле результата будет выведено сообщение "Cannot evalu-
ate  this expression" ("Данное выражение нельзя вычислить").
Такие выражения могут включать в себя массивы, записи,  мно-
жества и файлы.
     Аналогично, если переменная или выражение в поле вычис-
ления  (Evaluate)  является  таким,  которое  модифицировать
нельзя (весь массив, файл или множество), то попытка присва-
ивания нового значения приведет к сообщению "Cannot be modi-
fied" ("Нельзя модифицировать").
     Что же вы можете изменять? Список того, что  можно  ис-
пользовать  в выражениях просмотра, наряду с воспринимаемыми
значениями, содежится в Таблице 6.3. Обратите внимание,  что
в  выражениях  можно использовать только встроенные функции,
перечисленные для выражений просмотра в Таблице 6.3.
     Нужно также учитывать следующее:
 
     1.  Нельзя модифицировать весь массив, всю  запись  или
         весь файл. Однако, как уже упоминалось, можно изме-
         нять отдельные элементы массива или записи,  своди-
         мые  к одному из типов, перечисленных в Таблице 6.3
         (если они сами не являются массивами или записями).
     2.  Вы не можете непосредственно модифицировать нетипи-
         зованные   параметры,  передаваемые  процедуре  или
         функции. Можно, однако, свести их  к  определенному
         типу, а затем изменить в соответствии с перечислен-
         ными выше ограничениями.
     3.  Необходимо помнить о том, что изменять значения пе-
         ременных нужно очень внимательно. Например, если вы
         изменяете указатель, это может привести к изменению
         содержимого  тех  ячеек памяти, изменять которые вы
         вовсе не собирались, даже изменяя  значения  других
         переменных и структур данных.
 
                        Перемещения
 
     При отладке большой программы, особенно такой,  которая
содержит несколько модулей, можно "заблудиться" в ее дебрях.
Чтобы помочь вам в этом, в отладчике предусмотрено два меха-
низма  -  команды "Отладка/Стек вызова" (Debug/Call Stack) и
"Поиск процедуры" (Find Procedure).
 
                        Стек вызова
 
     При каждом вызове процедуры или  функции  Турбо-Паскаль
запоминает вызов и передаваемые ей параметры. Когда вы выхо-
дите из этой процедуры или функции, по Паскаль про этот  вы-
зов "забывает". Это называется стеком вызова.
     Каждый раз, когда ваша программа, достигнув точки оста-
нова (или при пошаговом выполнении), делает паузу, с помощью
команды "Отладка/Стек вызова" (Debug/Call Stack)  вы  можете
запросить текущий стек вызова. При этом выводится список вы-
зовов процедур и фукнций, содержащихся  в  данный  момент  в
стеке вызова (активных).
     Предположим, у вас имеется программа для работы с  поч-
товыми  адресами,  которая считывает список имен и адресов и
выводит их на печать в две колонки. Сама программа при  этом
называется Adress, процедура, которая выводит на печать спи-
сок имен, носит название PrintList, и последняя процедура  в
свою  очередь вызывает процедуры PutLeft и PutRight, которые
печатают данные в два столбца. Если вы п процедуре  PutLeft,
установите  точку останова, запустите программу, а когда она
выйден  на  паузу  выберите  команду  "Отладка/Стек  вызова"
(Debug/Call  Stack),  то  окно  стека вызова будет выглядеть
следующим образом:
 
      +------------------- Call Stack ------------------+
      ! PUTLEFT('Allan Jones')                          !
      ! PRINTLIST((...),36)                             !
      ! ADDRESS                                         !
      +-------------------------------------------------+
 
     Это говорит о том, что в данный момент вы находитесь  в
процедуре PutLeft, которой в качестве параметра была переда-
на строка 'Allan Jones'. Процедура PutLeft была  вызвана  из
процедуры PrintList, которой был передан массив (из-за огра-
ниченного места массив не показывается) и значение 36.  Сама
процедура  PrintList была вызвана из тела основной программы
Address (если программа имени не имеет, то эта запись  будет
содержать PROGRAM).
     При этом можно говорить о стеке вызова, поскольку  под-
держивается     именно     стек     с    дисциплиной    LIFO
("последний-пришел-первый-ушел"), то есть структура  данных,
которая моделирует обработку вызовов подпрограмм. При каждом
вызове процедуры или функции этот вызов появляется (заносит-
ся)  в  вершине  стека, а когда вы выходите из процедуры или
функции, то соответствующий вызов исчезает  (извлекается  из
вершины стека).
     Стек вызова несет также другую важную функцию: он  поз-
валяет  вам  выполнять  обратный просмотр последовательности
вызовов. Когда на экране появляется стек вызова, самый верх-
ний  вызов  подсвечивается.  Для перемещения вверх и вниз по
стеку вы можете использовать  клавиши  управления  курсором.
Если  вы нажмете клавиши Enter, то переместитесь к последней
активной точке в программе или подпрограмме.
     Рассмотрим, например, описанный выше стек. Если вы  вы-
берите  запись с PrintList и нажмете клавишу Enter, то пере-
меститесь в ту точку процедуры PrintList, где  была  вызвана
процедура  PutLeft.  Аналогично,  если  вы выберите запись с
Address и нажмете Enter, то вам будет показана точка  в  ос-
новной  программе,  где  была  вызвана  процедура PrintList.
Наконец, если вы выберите самую  верхнюю  запись  и  нажмете
Enter, то всегда сможете вернуться к границе выполнения.
     Такого рода перемещения не влияют на  выполнение  прог-
раммы.  Если  вы нажмете клавишу F7 (выполняете программу по
шагам), то при этом вернетесь в процедуру PutLeft, а граница
выполнения  переместится  на  следующую  строку  в процедуре
PutLeft (как будто вы ее не покидали).  Однако  предусмотрен
также  быстрый механизм для выхода из последовательности вы-
зовов процедур и функций. Для этого нужно выйти в то  место,
куда вы хотите попасть, переместить курсор на строку, следу-
ющую за вызовом процедуры и функции и нажать клавишу F4.
     В качестве второго примера рассмотрим следующую неболь-
шую программу:
 
  program TestPower;
  function Power(Base,Exp : word) : longint;
  begin
    if Exp <= 0 then
      Power := 1;
    else
      Power := Base * Power(Base,Exp-1);
  end;  { конец функции Power }
  begin { тело основной программы }
    Writeln('2^14 = ',Power(2,14))
  end. { конец программы TestPower }
 
     Введите эту программу, скомпилируйте  ее  и  установите
точку  останова  на  второй строке процедуры Power (Power :=
1). Теперь запустите программу. Когда она выйдет  на  паузу,
выберите  команду  "Отдалка/Стек вызова" (Debug/Call Stack).
     Обратите внимание, что в нижней части окна не  показана
процедура TestPower. Это вызвано тем, что в окне стека вызо-
ва (Call Stack) одновременно выводится только девять вызовов
процедур  и  функций.  Однаковсе  вызовы на месте - чтобы их
увидеть, нужно воспользоваться клавишами перемещения курсора
("Cтрелкa  вверх" и "Стрелка вниз"). В стеке вызова отслежи-
вается до 128 вложенных вызовов.
     Окно стека вызова будет выглядеть следующим образом:

------------------------------------------------------------
    File  Edit  Run  Compile  Options  Debug  Break/Watch
   ---------------------------------------------------------
   !   Line 1  Col 1  Insert Indent   !Evaluate   Ctrl-F4 !!
   !program TestPower;                !Call Stack Ctrl-F3 !!
   !function Power(Base,Exp:word):long!Find Procedure     !!
   !  begin                           !Integrated Debug On!!
   !     if Exp <= 0 then             !Stand --Call Stack--!
   !#######Power := 1;################!Displa! Power(2,0) !!
   !     else                         !Refres! Power(2,1) !!
   !Power := Base * Power(Base,Exp-1);-------! Power(2,2) !!
   !  end;  { конец функции Power }          ! Power(2,3) !!
   !  begin { тело основной программы }      ! Power(2,4) !!
   !    Writeln('2^14 = ',Power(2,14))       ! Power(2,5) !!
   !end. { конец программы TestPower }       ! Power(2,6) !!
   !                                         ! Power(2,7) !!
   !                                         ! Power(2,8) !!
   !                                         --------------!
   !                                                       !
   !                                                       !
   !                                                       !
   !------------------------ Watch ------------------------!
   !                                                       !
   ---------------------------------------------------------
    F1 - Help     -><- Scroll   <-! View Call
------------------------------------------------------------
 
     Рис. 6.1 Окно стека вызова
  
              Как найти процедуру или функцию
 
     Иногда в процессе отладки, чтобы установить точку оста-
нова,  выполнить  программу  до этой точки, проверить список
параметров, просмотреть переменные или для какой-либо другой
цели желательно найти конкретную процедуру или функцию.
     Если ваш исходный код разбит на несколько  файлов,  вам
понравится   работа  с  командой  "Отладка/Поиск  процедуры"
(Debug/Find Procedure). Когда вы используете эту команду, на
экране  появляется  маленькое окно и у вас запрашивается имя
процедуры или функции. После того, как вы набираете  иденти-
фикатор  и  нажимаете клавишу Enter, Турбо-Паскаль проверяет
внутренние таблицы и ищет, где находится  эта  подпрограмма,
затем  загружает соответствующий исходный файл (если это не-
обходимо) и выводит на экран окно редактирования (Edit), по-
зиционируя курсор на начало процедуры или функции. 
     При  использовании  команды  "Отладка/Поисск  процедуры"
(Debug/Find  Procedure)  нужно помнить о трех важных особен-
ностях:
 
     1.  Данная команда не влияет на текущее  состояние  от-
         ладки.  Другими словами, если вы находитесь в паузе
         в какой-либо точке программы, то вы  и  будете  там
         находиться,  и выбор команды "Выполнение/Трассиров-
         ка" (Run/Trace Into) (клавиша F7)  выполнит  данную
         строку  в  вашей  программе,  а не ту процедуру или
         функцию, в которой вы только что нашли.
     2.  Команда "Отладка/Поиск процедуры"  помещает  курсор
         на первую выполняемую строку процедуры или функции,
         а не на ее заголовок. Это означает, что  для  того,
         чтобы выполнить программу до текущего места в нача-
         ле процедуры или функции, можно воспользоваться ко-
         мандой  "Выполнение/Выполнение  до курсора" (Run/Go
         to Cursor).
     3.  Вы использовать эту команду только  в  том  случае,
         если  ваша программа уже скомпилирована и отладчику
         доступна информация по процедуре или функции.
 
     При задании имени процедуры или  функции,  поскольку  в
разных  местах  программы  у вас могут содержаться процедуры
или функции с одинаковыми именами (в модулях, вложенные про-
цедуры  и т.д.), может возникнуть двусмысленность. Вы можете
квалифицировать имя подпрограммы, указав перед ее именем имя
модуля, в котором эта подпрограмма содержится, или имя любой
процедуры или функции, в которой эта подпрограмма  содержит-
ся,  например,  "модуль.процедура.процедура<...>.процедура".
Если вы модифицируете исходный код или позицию в файле  (или
даже его имя) процедуры или функции изменяется, команду "От-
ладка/Поиск процедуры" (Debug/Find Procedure)  не  будет  об
этом  известно, пока вы не выполните перекомпиляцию програм-
мы. Если вы сначала транслируете  программу  TestPower  (см.
раздел  "Стек вызова"), а затем удаляете пустую строку перед
описанием функции Power, то команда "Отладка/Поиск  процеду-
ры"   (Debug/Find   Procedure)  поместит  курсор  на  строке
if...then, а не на строке begin.
 
                       Общие вопросы
 
     Если вы уже изучили, как пользоваться  отладчиком,  да-
вайте  теперь осветим некоторые общие вопросы, которые могут
возникнуть при его использовании.
 
              Как писать программы для отладки
 
     Есть несколько простых приемов, благодаря которым  ваши
программы будет потом легче отлаживать. В большинстве случа-
ев не следует размещать более одного  оператора  на  строке.
Поскольку отладчик работает построчно, это позволяет обеспе-
чить, что при каждом нажатии клавиши F7 будет выполняться не
более одного оператора.
     В то же время есть случаи,  когда  вы  можете  захотеть
разместить  на  одной строке несколько операторов. Если есть
набор операторов, которые вы должны пройти по шагам, но  ко-
торые  в  отношении  отладки  весьма надежны и в проверке не
нуждаются, их можно свободно поместить на одной или несколь-
ких  строках и выполнять программу быстрее. Именно поэтому в
приведенных выше примерах мы записывали:
 
     W := 10; X := 20; Y := 30; Z := 40;
 
а не 
     W := 10; 
     X := 20; 
     Y := 30; 
     Z := 40;

     Вы можете также построить описания переменных таким об-
разом,  что  описание переменной, которая скорее всего будет
использоваться в окне просмотра, будет ближайшим к начально-
му оператору begin процедуры или функции. Когда вы попадаете
в эту процедуру или функцию, то можно быстро перемещать кур-
сор по списку, используя команду "Прерывание/Просмотр/Добав-
ление в окно  просмотра"  (Break/Watch/Add  Watch)  (клавиша
Ctrl-F7) для включения переменной в число выражений просмот-
ра.
     Аналогично, если у вас есть выражения, которые вы хоти-
те просматривать или вычислять в отдельных точках программы,
включите из в качестве комментариев. Когда вы попадете в эту
точку, то можно переместить курсор к началу выражения и ско-
пировать его в рамку "Добавить в окно просмотра" (Add Watch)
или  "Вычисление"  (Evaluate).  Это может оказаться особенно
полезным, если выражение является сложным и включает в  себя
преобразование  типов, символы формата, элементы массива или
поля записи.
     Наконец, лучшей отладкой является профилактическая  от-
ладка.  Хорошо  построенная  и четко написанная программа не
только будет содержать меньше ошибок, но и  значительно  об-
легчит  вам поиск исправление тех нескольких ошибок, которые
в ней имеются. Существует ряд основных моментов,  о  которых
всегда нужно помнить, когда вы пишете программу:
 
     1.  Используйте технику программирования  снизу  вверх.
         Там, где это возможно, пишите, проверяйте и отлажи-
         вайте программы небольшими частями. Добейтесь, что-
         бы  одна  такая часть правильно работала перед тем,
         как она будет использована в другой части.
     2.  Разбивайте свою программу на блоки: модули,  проце-
         дуры  и функции. Избегайте писать большие процедуры
         и функции (содержащие более 25 строк). Если  проце-
         дура  получается большой, лучше разбейте ее на нес-
         колько меньших процедур и функций.
     3.  Там, где это возможно, используйет передачу  инфор-
         мации только через параметры, не используя в проце-
         дурых или функциях ссылки на глобальные переменные.
         Это  позволит избежать побочных эффектов и облегчит
         отладку программы, поскольку вы легко сможете  наб-
         людать  всю входную и выходную информацию процедуры
         или функции.
     4.  Не вдавайтесь в  сложности.  Пусть  ваша  программа
         начнет работать правильно, а уж потом вы будете пы-
         таться заставить ее работать быстрее.
 
          Вопросы, касающиеся использования памяти
 
     При отладке большой программы можно исчерпать имеющийся
объем  памяти. Кроме всего прочего Турбо-Паскаль размещает в
памяти редактор текстов, компилятор, отладчик,  текущий  ис-
ходный  файл, выполняемый код, таблицу символов и другую ин-
формацию по отладке, и все это одновременно. Следить за объ-
емом  свободной  памяти  можно  с  помощью команды "Компиля-
ция/Получение информации" (Compile/Get Info). 
     Если вы превысили объем имеющейся памяти, можно  выпол-
нить  несколько  шагов,  которые могут помочь вам освободить
часть памяти и выполнить отладку:
 
     1.  Если у вас есть расширенная  память  (EMS),  убеди-
         тесь, что при запуске ТURBO.EXE доступно по крайней
         мере 64К. Таким образом Турбо-Паскаль может хранить
         буфер  редактирования  в расширенной памяти и вашей
         программе будет предоставлена дополнительная опера-
         тивная память.
     2.  Используйте вместо компиляции  программы  в  память
         компиляцию  на  диск (установите переключатель меню
         "Копиляция/Назначение" (Compile/Destination) в  по-
         ложение Disk.
     3.  Если в программе вы не используете динамические пе-
         ременные,  то  установите  с  помощью  команды "Оп-
         ции/Компилятор/Размеры                      памяти"
         (Options/Compiler/Memory  Sizes) или директивы ком-
         пилятора $M для  минимального  размера  динамически
         распределяемой области памяти значение 0. Уменьшите
         также (аналогичным образом) размер стека (если  вам
         требуется меньше выделяемых по умолчанию 16К).
     4.  Удалите все резидентные в  памяти  программы  (типа
         SideKick, Norton или SuperKey).
     5.  Удалите (с помощью утилиты TPUMOVER.EXE)  из  файла
         TURBO.TPL  редко  используемые модули. Такие модули
         занимают место в памяти даже в том случае, если они
         не  используются выполняющейся программой. При этом
         в файле TURBO.TPL  всегда  рекомендуется  оставлять
         модуль System, поскольку его использует любая прог-
         рамма.
     6.  Если у  вас  нет  расширенной  памяти,  используйте
         TINST  для задания меньшего размера буфера редакто-
         ра. По умолчанию буфер редактора занимает 64К памя-
         ти,  хотя наибольший файл в вашем программном комп-
         лексе может быть существенно меньше.
     7.  В тех модулях, где не требуются локальные  символы,
         поместите  директиву компилятора {$L-}. В таких мо-
         дулях вы сможете выполнять трассировку, но не  смо-
         жете проверять значения локальных переменных, конс-
         тант и параметров.
     8.  В тех модулях, где не требуется выполнять  отладку,
         поместите директиву компилятора {18-}. При этом для
         них будет подавляться генерирование всей отладочной
         информации. Процедуры и функции с директивами {$D-}
         будут интерпретироваться, как стандартные программы
         Турбо-Паскаля  и вы не сможете выполнять их трасси-
         ровку.
     9.  Выключите все директивы, которые генерируют  код  с
         проверкой  ошибок  (например,  {$S-}  и {60-}). Это
         позволит несколько уменьшить объем вашей программы.
     10. Используйте в своей программе  оверлеи  (с  помощью
         директивы  компилятора  $O и модуля Overlay). С по-
         мощью оверлеев вы сможете в среде Турбо-Паскаля от-
         лаживать  очень  большие  прикладные  задачи. Более
         подробная информация об оверлеях содержится в Главе
         13 "Справочного руководства" ("Оверлеи").
     11. Постарайтесь  отладить  некоторые  части  исходного
         кода (например, модули) отдельно от остальной прог-
         раммы. Другими словами, сделайте копию вашей  прог-
         раммы  и  сократите  те части, которые не нужны для
         отладки. Это не всегда можно сделать, но часто сама
         такая попытка позволит в результате пролучить прог-
         рамму с лучшей модульной структурой.
 
     Если после выполнения всех перечисленных операций  ваша
программа  все  еще  превышает допустимые размеры памяти, то
она просто слишком велика, чтобы ее можно  было  отладить  в
интерактивной  программной  среде.  Выключив с помощью ключа
"Отладка/Интегрированная     отладка"      (Debug/Integrated
Debugging) средства отладки, вы освободите еще больше памяти
и сможете запустить вашу программу. Чтобы отладить  ее,  вам
следует воспользоваться Турбо-отладчиком и установить перек-
лючатель меню "Отладка/Автономная отладка"  в  положение  On
(включено).
 
                   Рекурсивные программы
 
     Рекурсия - это метод программирования, при котором про-
цедура  прямо  или  косвенно  вызывает  сама себя. Например,
функция Power в приведенном ранее примере является рекурсив-
ной, поскольку для вычисления возвращаемого значения она вы-
зывает сама себя.
     Существуют некоторые соглашения, которые  нужно  учиты-
вать  при  отладке  рекурсивных программ. Во-первых, большой
уровень вложенности при рекурсии может  исчерпать  простран-
ство  стека  системы и иметь другие побочные эффекты (напри-
мер, остановке или сбою программы из-за переполения  стека).
В  любом случае это общая опасность при использовании рекур-
сии, и о ней просто нужно знать, если ваша программа во вре-
мя  отладки  аварийно  завершает работу, поскольку это может
быть вызвано переполнением стека а не тем, что что-то случи-
лось с отладчиком.
     При большой глубине вложенности рекурсии вы также може-
те  не иметь возможности использовать стек вызова. Это может
произойти потому, что стек  вызова  ограничен  128  вызовами
процедур  и функций. Однако вы можете перейти в нижнюю часть
стека, использовать хранящуюся там информацию для  получения
данных  о  самом  "старом" вызове, перейти в соответствующую
точку программы и вновь воспользоваться стеком вызова.
     Каждый раз при рекурсивном вызове функции создается но-
вое  множество  локальных переменных этой функции и парамет-
ров-значений (не переменных). Если вы включаете эти данные в
окно просмотра (Watch), но учтите, что они не являются абсо-
лютными и отражают активные в текущий момент локальные  дан-
ные.
 
                 Когда отладчик не работает
 
     Есть несколько случаев, когда вы не  сможете  выполнить
трассировку  данной  процедуры  или  фукнции.  Иногда (но не
всегда) это вызвано тем, что недоступен исходный  файл.  Эти
ситуации включают в себя следующие случаи:
 
     1.  Любая процедура или функция типа inline. Это связа-
         но с тем, что здесь вызов процедуры или функции во-
         обще отсутствует, а вместо "вызова" (call) подстав-
         ляется  соответствующий  машинный  код. Такой вызов
         интерпретируется, как один оператор.
              Заметим, что те процедуры или функции, к кото-
         рых  содержится оператор inline вы трассировать мо-
         жете. Однако в этом случае каждый  оператор  inline
         интерпретируется,  как  одна  строка, независимо от
         того, сколько строк он занимат. При этом справедли-
         вы  те  же правила, что и для других операторов, то
         есть если один оператор занимает  несколько  строк,
         он  интерпретируется  командами "Выполнение/Трасси-
         ровка" (Run/Trace Into) и "Выполнение/Выполнение по
         шагам" (Run/Step Over), как одна строка.
     2.  Любая процедура или функция одного  из  стандартных
         модулей (Crt, Dos, Graph, Graph3, Overlay, Printer,
         System, Turbo3).
     3.  Любая внешняя процедура или функция.
     4.  Любая процедура, функция или код инициализации, со-
         держащиеся в модуле, который не был скомпилирован с
         директивой {$D+} или с установленной в значение  On
         включено  опцией  меню "Опции/Компилятор/Отладочная
         информация" (Option/Compiler/Debug  Information)  в
         интерактивной среде.
     5.  Любая процедура, функция или код инициализации, со-
         держащиеся в модуле, исходный код которого оказыва-
         ется не найденным. Если он не содержится в  текущем
         каталоге  или  в каталоге модулей, или его исходный
         файл называется иначе,  чем  "имя_модуля.PAS"  (где
         "имя_модуля"  -  это  имя,  указанное в предложении
         uses), то интерактивная среда выведет вам подсказку
         и  запросит  правильное  имя файла. Если вы вводите
         нулевое имя файла или нажимаете калвишу Esc, то от-
         ладчик  будет вести себя так и в случае, когда ино-
         фрмация для отладки отсутствует.
     6.  Любая процедура, заданная,  как  процедура  выхода.
         Если  вы проходите программу с помощью команды "Вы-
         полнения/Трассировка"  (Run/Trace  Into)   (клавиша
         F7),  то вы никогда не начнете пошаговое выполнение
         процедуры Exit (процедура выхода). Однако, если  вы
         установите  в процедуре Exit точку останова, то от-
         ладчик остановится в соответствующем месте, и  гра-
         ница  выполнения  будет установлена на данной точке
         останова.
 
                      Другие проблемы
 
     Имеется целый ряд проблем, с которыми часто можно  сто-
лкнуться во время отладки. Перечислим некоторые из них:
 
     1.  Задавать генерацию локальной и глобальной  отладоч-
         ной  информации не требуется. По умолчанию оба этих
         переключателя установлены в значение On (включены).
         Если у вас возникают проблемы при выполнении по ша-
         гам программы или программного модуля, то поместите
         в  начале  каждой отлаживаемой программы или модуля
         директивы {$D+,$L+}.
     2.  Не следует начинать отладку другой программы,  если
         не  отменены  точки  останова и выражения просмотра
         предыдущей программы. Перед тем, как новая програм-
         ма  будет  загружена  для  отладки, нужно выполнить
         следующие  команды:  "Выполнение/Сброс   программы"
         (Run/Program  Reset)  (клавиша  Ctrl-F2), "Прерыва-
         ние/Просмотра/Очистить       окно        просмотра"
         (Break/Watch/Remove   All   Watches)   и  "Прерыва-
         ние/Просмотр/Отмена         точек         останова"
         (Break/Watches/Clear All Breakpoints).
     3.  Ошибкой является попытка компиляции и запуска  дру-
         гой  программы,  когда  предыдущая программа еще не
         сброшена и задана в качестве основного  файла.  Для
         отмены предыдущего имени файла и задания нового ис-
         пользуйте   команду   "Компиляция/Основной    файл"
         (Compile/Primary File).
     4.  В ответ на  подсказку  "Source  modified,  rebuild?
         (Y/N)  ("Исходный  код  изменен,  построить заново?
         (Да/Нет)) нажата клавиша N. Это  означает,  что  во
         время  отладки  вы изменили файл с исходным кодом и
         таблица с номерами строк могут теперь оказаться для
         отладчика недействительными. Это может исказить об-
         работку точек останова, пошаговое выполнение и  ра-
         боту  других  средств  отладки.  Если вы в исходном
         файле случайно набрали символ, а затем удалили его,
         то при нажатии N в ответ на подсказку ничего плохо-
         го не случится, однако при включении  или  удалении
         из  файла  строк  лучше  воспользоваться ответом Y,
         поскольку отлаживаемый вами машинный код теперь  не
         будет  совпадать с исходным кодом, который вы прос-
         матриваете.
 
     Безусловно, в программе могут быть разнообразные  ошиб-
ки: синтаксические, семантические и логические - и вы можете
обнаружить их с помощью интегрированного и  автономного  от-
ладчика. Однако, Турбо-Паскаль предусматривает также для об-
легчения отслеживания и выявления ошибок несколько  директив
компилятора и средств языка. В данном разделе кратко описаны
некоторые из этих средств.
     Один из возможных типов ошибок - это ошибки  этапа  вы-
полнения  (или  семантические  ошибки).  Можно  "включать" и
"выключать" ошибки этапа выполнения, разрешая  или  запрещая
генерацию кода с автоматической проверкой ошибок. При этом у
вас имеется возможность разрабатывать свои собственные прог-
раммы обработки ошибок.
 
                Проверка ошибок ввода/вывода
 
     Рассмотрим еще раз программу, указанную ранее:
 
program DoSum;
var
  A,B,Sum : Integer;
begin
  Write('Введите два числа: ');
  Readln(A,B);
  Sum := A + B;
  Writeln('Сумма равна ',Sum)
end.
 
Допутим, что вы запустили эту программу на выполнение и вве-
ли следующие значения:
 
 Введите два числа: 45 8х

а затем  нажали  клавишу  "Enter".  Что  произойдет  в  этом
случае? На этапе выполнения возникнет ошибка (а именно 106),
как это было описано в предыдущем разделе. Если при этом ис-
пользуется команда Find error, то Вам будет указано, что она
возникла в операторе:
 
     Readln(A,B);
 
Что произошло? Вы ввели  нечисловые  данные  8х,  тогда  как
программа  ожидала  целочисленное  значение, что и привело к
возникновению ошибки на этапе выполнения.
     В такой короткой программе подобная ошибка не  принесет
много беспокойства. А что если вводится большой список чисел
и вы большую часть его ввели правильно прежде,  чем  сделать
ошибку?  Вы  будете  вынуждены начать все сначала. Еще хуже,
если вы написали программу для других  пользователей  и  они
ошиблись при вводе.
     Турбо-Паскаль позволяет отменить автоматическую провер-
ку  ошибок  ввода/вывода,  тогда  Вы сами должны в программе
осуществлять такую проверку. Для того, чтобы выключить  про-
верку  ошибок ввода/вывода в некотором месте программы, ука-
жите в программе директиву компилятора {$I-} (или используй-
те  средство проверки ошибок "Опции/Копмилятор/Проверка оши-
бок ввода-вывода" (O/C/I/O-Checking)). Это является указани-
ем  компилятору не генерировать код для проверки ошибок вво-
да/вывода.
     Переделаем предыдущую программу так, чтобы  она  осуще-
ствляла собственную проверку ошибок ввода/вывода:
 
program DoSum; var
     A,B,Sum : Integer;
     IOCode : Integer; begin
     repeat
     Write('Введите два числа: ');
     {$I-} {Отменить автоматическую проверку ошибок}
     {ввода/вывода}
     Readln(A,B);
     {$I+} {Включить автоматическую проверку ошибок}
     {ввода/вывода}
     IOCode := IOResult;
     if IOCode <> 0
     then Writeln('Неправильные данные. Нажмите Enter')
     until IOCode = 0;
     Sum := A + B;
     Writeln('Сумма равна ',Sum) 
     end. 
 
     В начале программы отменяется  автоматическая  проверка 
ошибок ввода/вывода с помощью  директивы  компилятора {$I-}. 
Для ввода  данных  используется цикл  repeat..until, посколь-
ку ввод следует выполнять до тех пор, пока пользователь счи-
тает  это  необходимым. Операторы Write и Readln точно такие 
же, как и раньше, однако после них стоит оператор:
 
     IOCode := IOResult; 
 
     Переменная IOC0de описана как глобальная переменная,  а 
что такое IOResult? Это встроенная функция, возвращающая код 
ошибки, возникшей  при последней  операции  ввода/вывода,  в 
данном случае - Readln. Если никакой ошибки  ввода-вывода не
возникает, то возвращаемое значение равно 0. В обратном слу-
чае  возвращается ненулевое значение, указывающее, что прои-
зошло. Сразу после вызова IOResult она обнуляет  себя  и  до
появления  следующей ошибки будет возвращать 0. Поэтому зна-
чение IOResult присваивается IOCode с тем, чтобы можно  было
проверить результат в операторе if и в предложении until.
     Аналогичную структуру можно использовать  для  проверки
ошибок  при  открытии файлов для ввода. Рассмотрим следующий
пример программы:
 
var
  FileName  : string[40];
  F         : text;
begin
  Write('Введите имя файла: ');
  Readln(FileName);
  Assign(F,FileName);
  Reset(F);
  ...
 
     В этом фрагменте программы выдается запрос на ввод име-
ни  файла,  а затем осуществляется попытка открыть этот файл
для ввода. Если файл, имя которого вы указали, не  существу-
ет,  то  выполнение  программы будет прекращено из-за ошибки
этапа выполнения (02). Однако, вы можете переписать програм-
му следующим образом:
 
var
  FileName  : string[40];
  F         : text;
  IOCode    : integer;
begin
  {$I-}
  repeat
    Write('Введите имя файла: ');
    Readln(FileName);
    Assign(F,FileName);
    Reset(F);
    IOCode := IOResult;
    if IOCode <> 0
      then Writeln('Файл',Filename,'не существует')
    until IOCode = 0;
    {$I+}
    ...
 
Используя эти и аналогичные методы, можно создавать програм-
мы, не дающие фатальных сбоев, то есть возникающие ошибки не
будут вызывать прекращения работы программы.
 
                     Проверка диапазона
 
     Другим распространенным  классом  семантических  ошибок
является  превышение  диапазона или границ значений. К числу
примеров того, как возникают эти ошибки, относится  присвое-
ние  слишком  большого значения целочисленной переменной или
попытка указать индекс массива, превышающий его границы. При
желании можно указать Турбо-Паскалю генерировать код, прове-
ряющий диапазоны. Это увеличит программу и замедлит  ее  вы-
полнение,  однако может оказать неоценимую помощь при отсле-
живании ошибок диапазона в программе.
     Допустим, что имеется следующая программа:
 
program RangeTest;
var
  List : array[1..10] of integer;
  Indx : integer;
begin
  for Indx := 1 to 10 do
    List[Indx] := Indx;
  Indx := 0;
  while (Indx < 11) do begin
    Indx := Indx + 1;
    if List[Indx] > 0 then
      List[Indx] := -List[Indx]
  end;
  for Indx := 1 to 10 do
    Writeln(List[Indx])
end.
 
Если ввести эту программу, то ее можно оттранслировать и за-
пустить  на  выполнение.  Однако, она окажется в бесконечном
цикле. Просмотрим внимательно этот код. Цикл while  выполня-
ется  11 раз, не 10, и переменная indx имеет значение 11 при
последнем прохождении цикла. Поскольку массив List  содержит
10  элементов, List[11] указывает на некоторую ячейку памяти
вне List. При имеющемся  распределении  переменных  List[11]
занимает  то же самое место в памяти, что и переменная Indx.
Это означает, что когда Indx=11, оператор
 
     List[Indx] := -List[Indx]
 
эквивалентен оператору
 
     Indx := -Indx
 
Поскольку Indx равен 11,  последний  оператор  устанавливает
Indx  равным -11, что ведет к возобновлению выполнения цикла
в программе. Теперь при выполнении цикла изменятся  дополни-
тельные  байты  еще  где-нибудь - в ячейках, соответствующих
List[-11..0].
     Другими словами, эта программа может только внести бес-
порядок  в  самое себя. Поскольку цикл никогда не завершится
при значении Indx, большем или равном 11, то он будет выпол-
няться бесконечно.
     Как отслеживать или проверять такие ситуации? Вы можете
вставить  в начало программы директиву {$R+} для активизации
проверки диапазона. Теперь при запуске  указанной  программы
ее  выполнение  будет  прекращено из-за возникновения ошибки
201 на этапе выполнения (ошибка превышения  диапазона,  пос-
кольку  индекс  массива превышает его границы); это произой-
дет, как только будет достигнут оператор if List[Indx]>0 при
Indx=11.  При  выполнении  программы в интегрированной среде
программирования этот оператор будет указан на экране и  бу-
дет  распечатана  ошибка.  (Проверка  диапазона по умолчанию
выключена. При активизации проверки диапазона  увеличивается
размер программы и удлиняется время ее выполнения).
     В некоторых ситуациях, как правило, при  программирова-
нии  на  более  высоком уровне, бывает необходимым или жела-
тельным нарушение границ диапазона, чаще всего при работе  с
динамически  распределяемыми массивами или при использовании
Succ и Pred с перечислимыми типами данных.
     Вы можете выборочно  использовать  проверку  диапазона,
поместив  директиву  {$R-}  в  начале программы. Для каждого
раздела программы, требующего проверки диапазона, в его  на-
чале  следует  помещать  директиву {$R+}, а в конце - {$R-}.
Например, предыдущий цикл можно записать следующим образом:
 
while Indx < 11 do begin
  Indx := Indx + 1;
  {$R+}             {Активизировать проверку диапазона}
  if List[Indx] > 0 then
    List[Indx] := -List[Indx]
  {$R-}             {Отменить проверку диапазона}
end;
 
     В этом случае проверка диапазона  будет  осуществляться
только внутри оператора if..then и нигде более, если, конеч-
но, вы не укажете где-нибудь директиву {$R+}.
 
              Другие средства обработки ошибок
 
     Турбо-Паскаль предовтавляет вам возможность  воспользо-
ваться  другими методами обработки ошибок, но, поскольку эти
методы более полно описаны в  других  частях  данного  руко-
водства, в этом разделе мы только кратко их коснемся.
     Когда ваша программа завершает работу (нормальным обра-
зом  или  с  ошибкой этапа выполнения), вызывается процедура
выхода, с которой была  скомпонована  ваша  программа.  Тур-
бо-Паскаль  позволяет вам использовать собственные процедуры
выхода, которые вызываются перед  обращением  к  стандартным
процедурам  выхода.  Фактически,  каждый  модуль может иметь
свою собственную процедуру выхода. Благодаря этому наряду  с
автоматическим  кодом инициализации можно получить также ав-
томатический код очистки. Более  подробно  процедуры  выхода
описаны в Главе 15 "Справочного руководства".
     Если вы (с помощью вызова процедур New и GetMem) пытае-
тесь  выделить память, а памяти в динамически распределяемой
области недостаточно, то автоматически вызывается  процедура
обработки  ошибки динамически распределяемой области памяти,
которая просто приводит к тому, что программа завершает  ра-
боту с ошибкой этапа выполнения. Однако для обработки такого
рода ошибок по нужному вам алгоитму вы  можете  задать  свою
собственную  процедуру  обработки ошибки, которая, например,
будет освобождать память, занимаемую ненужными больше  дина-
мическими  структурами, или просто приведет к тому, что про-
цедуры New и GetMem будут возвращать указатель nil. Процеду-
ры обработки ошибки динамически распределяемой области более
подробно описаны в Главе 15 "Справочного руководства".
     Если вы используете модуль Graph, то у вас есть возмож-
ность выполнить такую же тщательную процерку ошибок, как и в
случае ошибок ввода-вывода. Одна  из  функций  этого  модуля
(функция GraphError) возвращает код ошибки, который устанав-
ливается многими графическими процедурами. Как  использовать
это  средство  и какие коды ошибок возвращает данная функция
подробно  описано  в  Главе  12  "Справочного   руководства"
("Стандартные модули"). 
     Модуль  Overlay   содержит   целочисленную   переменную
OvrResult, в которой хранится код результата выполнения пос-
ледней операции, выполненной подсистемой управления оверлея-
ми. Аналогично, модуль Dos сохраняет код ошибки в переменной
DosError.
 
                       Турбо-отладчик
 
     Турбо-Паскаль версии 5.0 включает в  себя  полную  под-
держку  Турбо-отладчика фирмы Борланд. Это мощный автономный
отладчик, который позволяет работать с выполняемыми  файлами
Турбо-Паскаля, Турбо-Си и Турбо-Ассемблера (.ЕХЕ). Турбо-От-
ладчик включает в себя отладку как на уровне  исходных  тек-
стов,  так и на уровне машинных кодов, расширенное использо-
вание точек останова (включая точки останова по условию  или
с  вычислением  заданных  выражений)  и позволяет отлаживать
большие программные комплексы с помощью отладки в среде вир-
туальных  машин на процессоре 80386 или выполнять отладку на
двухмашинном комплексе (в котором ЭВМ связаны через последо-
вательный порт).
     Турбо-отладчик является профессиональным  отладчиком  и
включает в себя целый ряд мощных средств. С большинством ихх
этих средств вы уже знакомы, поскольку они совпадают с соот-
вествующими средствами многооконной работы и интегрированной
интерактивной среды Турбо-Паскаля.
     Предположим, у вас есть написанная на Паскале  програм-
ма, которая называется MYPROG.PAS. С помощью Турбо-отладчика
ее можно отладить следующим образом:
 
     Если вы используете в интегрированную среду  разработки
программ:

     1.  Загрузите TURBO.EXE и введите файл MYPROG.PAS в ре-
         дактор  (нажмите  F3, наберите MYPROG.PAS и нажмите
         Enter).
     2.  Установите       меню       "Компиляция/Назначение"
         (Compile/Destination)  в  значение Disk (копсиляция
         на диск).
     3.  Установите   меню   "Отладка/Автономная    отладка"
         (Debug/Stand-alone Debuging) в значение On (включе-
         но).
     4.  Оттранслируйте вашу программу (нажав клавишу F9).
 
     Если вы используете компилятор, работающий в режиме ко-
мандной  строки,  наберите  следующую  команду ДОС и нажмите
Enter:
 
     TPC /V MYPROG
 
(Независимо от того, какой компилятор используется, директи-
вы {$D} и {$L} должны буть включены. Первая директива управ-
ляет генерацией отладочной информации и должна иметь  значе-
ние  {$D+} (в интерактивной среде можно использовать команду
"Опции/Компилятор/Информация для отладки", установив  его  в
значения On  (включено), а в командной строке ТРС используй-
те квалификатор /$D). Вторая директива {$L} управляет сохра-
нением  и  разрешением  информации о локальный символах (эта
информация разрешается по директиве {$L+}  в  исходном  коде
программы или путем установки меню "Опции/Компилятор/Локаль-
ные символы" (Options/Compiler/Local Symbols) в  интерактив-
ной среде в состояние On). При работе с компилятором ТРС для
этой цели можно использоваь квалификатор /$L+. По  умолчанию
обе эти директивы разрешены, но если вы изменили значения по
умолчанию и не поместили в исходном коде эти  директивы,  то
отладчик работать не сможет.
     Предположим, что компиляция вышей программы выполнена и
на  диске  имеется  файл MYPROG.EXE. Не удивляйтесь, если он
оказался несколько большим, чем вы ожидали, поскольку в  ко-
нец  файла .ЕХЕ добавлена информация о номерах строк и инор-
мация о символах для отладчка. Чтобы отладить этот выполняе-
мый файл с помощью отладчика, наберте следующую команду ДОС:
 
     td myprog
 
и  нажмите  клавишу   Enter.  TD  -  это  Турбо-отладчик,  а
myprog  - имя вашей программы. При этом вы должны находиться
в том же каталоге, что и файл TD.EXE, или должен быть  задан
путь доступа к этому файлу (или использован командный файл).
Если для вашей программы требуется указывать  параметры,  их
можно просто задать после имени программы:
 
     td myprog param1 param2
 
     Это все. Встроенные в Турбо-Паскаль средства,  интерак-
тивная  отладка  в интегрированной среде и мощный автономный
отладчик позволят вам устранить в программе все виды ошибок.
Желаем успеха!



