Отладка программы

Это самый трудоемкий этап. Его цель – проверка синтаксической и логической правильности программы, а также определение того, что программа функционирует на всем диапазоне допустимых данных.

В процессе отладки программы выделяются этапы:

1. трансляция исходного текста программы;

2. компоновка программы;

3. выполнение программы с целью определения логических ошибок;

4. тестирование программы.

Трансляция

При трансляции выполняется перевод программы, понятной человеку, на язык, понятный компьютеру. Если цель трансляции – преобразование всего исходного текста на внутренний язык компьютера (т.е. получение некоторого нового кода) и только, то такая трансляция называется также компиляцией. Исходный текст называется также исходной программой или исходным модулем, а результат компиляции – объектным кодом или объектным модулем. Если же трансляции подвергаются отдельные операторы исходных текстов и при этом полученные коды сразу выполняются, такая трансляция называется интерпретацией. Поскольку трансляция выполняется специальными программными средствами, последние носят название компилятора или интерпретатора, соответственно.

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

Лексический анализ

Выявляются отельные составляющие текста программы, которые называются лексемами, и определяется их тип. К числу лексем относятся названия операторов, например, read или write; имена (переменных или констант), например, NABOR или CHISLO, различные разделители, такие как круглые скобки, знаки препинания и т.д. Одновременно типами указанных лексем являются названия операторов, имена переменных, разделители и т.д. Если программистом допущена ошибка и оператор ввода указан, например, rread, он будет распознан компилятором как имя. На этом этапе выявляется также использование недопустимых языком программирования символов, например, символа @. В результате лексического анализа исходная программа кодируется: каждая лексема заменяется кодом ее типа, что сокращает объем текста программы. Кроме того, из текста программы удаляются пробелы.

Пример 1. Лексический анализ фрагмента программы на Турбо-Паскале, содержащего только один правильно записанный оператор ввода:

read (NABOR,CHISLO);

дает цепочку

1 2 3 4 3 2 4,

где 1 – код названия оператора;

2 – код скобки;

3 – код имени;

4 – код знака препинания.

Пример 2. Лексический анализ фрагмента программы на Турбо-Паскале, содержащего только один неправильно записанный оператор ввода:

rread (NABOR,CHISLO);,

дает цепочку

3 2 3 4 3 2 4.

Синтаксический анализ

Определяется синтаксическая правильность закодированной в результате лексического анализа цепочки лексем. Например, определяется парность скобок, наличие в нужном месте требуемого знака препинания, соответствие исходного текста структурным правилам того или иного языка программирования, средствами которого была составлена программа. Для решения задачи в исходной (закодированной) цепочке выделяются подструктуры, соответствующие некоторым фрагментам оператора. Например, для оператора ввода в Турбо-Паскале можно определить структуру, представленную на рисунке 1 и соответствующую правилам из примера1 раздела Структурно-стилизованный способ описания алгоритма:

Рисунок 1

В то же время структура "правильного" оператора ввода определяется схемой:

Рисунок 2

Поскольку представленные структуры идентичны, оператор read (NABOR,CHISLO); при синтаксическом анализе определяется как правильный.

Именно на этом шаге выявляются ошибки в написании названий операторов: они ведут к некорректной структуре всего оператора. Так, примеру с "неправильным" оператором ввода соответствует структура, показанная на рисунке:

Рисунок 3

Поскольку структура этого рисунка не соответствует структуре рисунка 1, оператор rread (NABOR,CHISLO); расценивается как синтаксически некорректный: компилятор не найдет в анализируемом фрагменте требуемого действия, которое задается названием оператора, и сообщит об этом программисту.

Семантический анализ

На этом шаге выявляются ошибки, допущенные программистом в нарушение правил составления программ, например, следующего вида: все переменные и константы перед употреблением в операторах языка должны быть описаны; каждое имя (переменной или константы) должно быть описано только один раз; требуется согласование типов переменных с использующими их функциями и т.д. Так, если вся программа состоит только из оператора

read (NABOR,CHISLO);,

она будет определена как семантически некорректная, поскольку в ней отсутствуют описания вводимых переменных.

Пример 3. Программа

var NABOR, CHISLO: integer;

read (NABOR, CHISLO);

расценивается семантическим анализатором как семантически корректная.

Пример 4. Программа

var CHISLO: integer;

CHISLO:=CHISLO + 1;

расценивается семантическим анализатором как семантически корректная.

Генерация промежуточного кода

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

Пример 5. Программа из примера 4 преобразуется в промежуточный код на условном ассемблере:

$1 DD?; операторы DD описывают переменные: каждый из них

$2 DD?; отводит под переменную 2 байта памяти;

$3 DD?; переменные $1 - $3 вводятся генератором кода как

CHISLO DD?; вспомогательные переменные;

MOVE 1, $1; в операторах MOVE константы или содержимое

MOVE CHISLO, $2; переменных слева от запятой помещаются в переменные и

MOVE $1, AX; регистры процессора (АХ и СХ), указанные справа;

MOVE $2, CX;

ADD AX, CX; выполняется сложение содержимого регистров АХ и СХ,

; результат остается в регистре АХ

MOVE AX, $3; выполняются перемещения значений, находящихся в

MOVE $3, CHISLO; регистре и переменной, в соответствующие переменные

Полученный код избыточен: в самом деле, выполняется бессмысленная пересылка константы 1 и значения переменной CHISLO сначала в дополнительные переменные $1 и $2, а затем уже в регистры АХ и СХ, которые и используются при сложении. Аналогичные бессмысленные действия выполняются и с результатом сложения. Однако уменьшение размеров кода осуществляется на следующем этапе.

Оптимизация промежуточного кода

Из программы, полученной на предыдущем шаге, устраняются «лишние» операторы, переменные и константы, использование которых не влияет на корректность выполняемых действий.

Пример 6. Оптимизация промежуточного кода для программы из примера 5 приводит ее к виду:

CHISLO DD?

MOVE 1, AX

MOVE CHISLO, CX

ADD AX, CX

MOVE AX, CHISLO

Такой результат связан с тем, что ряд операторов выполняли лишние перемещения данных из одного места хранения в другое. Удаление этих операторов повлекло удаление вспомогательных переменных.

Генерация объектного кода

Программа, полученная в результате оптимизации, преобразуется в машинный код (так называемый объектный модуль), в котором использованы относительные, а не абсолютные адреса основной памяти. Как правило, для получения объектного модуля применяется условная память с начальным адресом 1. Каждый оператор программы преобразуется в машинную команду и размещается, начиная с начального адреса, в той последовательности, в которой он следует в программе. При этом учитывается размер каждого оператора. Пусть командам программы из примера 6 соответствуют машинные команды:

код объем действие

операции

124 1 б сложить содержимое регистров АХ и СХ, результат – в регистре АХ,

125 3 б поместить содержимое регистра АХ по адресу,

126 2 б поместить константу в регистр АХ,

127 3 б поместить содержимое адреса в регистр СХ.

Оператор DD выделяет объем памяти в 2 байта для описываемой переменной. Тогда схема размещения объектного кода имеет вид, представленный в таблице:

Адрес (байт) Команда Комментарий
внутреннее представление объем (байт)
  -   Память для переменной CHISLO – результат действия команды DD
  126 1   В регистр АХ помещается 1
  127 1   Содержимое адреса 1 помещается в регистр СХ
      Соответствует действию CHISLO + 1
  125 1   Содержимое регистра АХ помещается по адресу 1, т.е. выполняется действие CHISLO = CHISLO+1

Этот код еще не готов к выполнению: для этого требуется его «ориентация» на те адреса основной памяти, где он будет выполняться.

Следует отметить, что при интерпретации анализу подвергается не вся программа, а отдельные операторы. При этом из названных шагов выполняются лишь первые четыре.


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: