2. Среды программирования
2.1. Компоненты среды программирования
Редактор – это инструментальное средство для создания и
изменения исходных символьных файлов,
написанных на языке программирования.
Компилятор – транслирует символы из исходного файла в
объектный модуль, который содержит команды в
машинном коде для конкретного компьютера.
Библиотекарь – поддерживает совокупности объектных
файлов, называемые библиотеками.
Компоновщик, или редактор связи – собирает объектные
файлы программы и разрешает внешние ссылки
между компонентами программы, формируя
исполняемый файл.
Загрузчик – копирует исполняемый файл с диска в память и
инициализирует компьютер перед выполнением
программы.
Отладчик – инструментальное средство, которое
представляет возможность программисту
управлять выполнением программы по
диагностике ошибок.
Профилировщик – измеряет время, затрачиваемое на каждый
компонент программы.
Средства тестирования автоматизируют процесс
тестирования программ и анализируют результаты
тестирования.
Средства конфигурирования автоматизируют создание
программ и отслеживают изменения в них до
уровня исходных файлов.
Интерпретатор непосредственно выполняет исходный код
программы, без создания объектного файла.
2.2 Транслятор
Процесс преобразования исходного модуля в загрузочный и выполнение его на ЭВМ можно представить в виде схемы:
ИМ (исходный модуль) – исходный текст программы, написанный на конкретном языке программирования (ЯП).
Транслятор – программа, предназначенная для перевода исходного модуля (ИМ) в загрузочный (ЗМ).
ОМ (объектный модуль) – программа в машинных кодах, подготовленная для обработки блоком 4.
Компоновщик (редактор связи) – специальная программа, устанавливающая все внешние ссылки на другие модули и создающая ЗМ. Если ОМ содержит неразрешимые ссылки, то процесс образования ЗМ прекращается.
ЗМ (загрузочный модуль) – программа в машинных кодах, определяющая последовательность выполнения команд на ЭВМ, готовая к выполнению.
Загрузчик устанавливает абсолютные адреса в оперативной памяти (ОП) ЭВМ.
Загрузочный модуль (ЗМ) будет выполняться только после прохождения программ пользователя всех шести этапов (блоков) процесса трансляцию
Трансляторы бывают двух типов: компиляторы (англ.:compiler) и интеграторы.
2.3. Компиляторы
Структура компилятора показана на рис.
Во входной части компилятора анализируется синтаксис и семантика программы согласно правилам языка. Синтаксический анализатор преобразует последовательности символов в абстрактные синтаксические объекты, называемые лексемами. Например, символ '' = '' в языке С преобразуется в оператор присваивания. Если за ним следует еще символ '' = '', т.е. '' = = '', то оба символа '' = = '' преобразуются в операцию проверки равенства. Анализатор семантики придает смысл этим абстрактным объектам. Например, в фрагменте программы семантический анализатор выделит глобальный адрес для первого i и вычислит смещение для второго i:
static int i
void proc ( int i ) {…}
Завершается работа входной части компилятора формированием промежуточного представления программы. По нему можно восстановить исходный текст программы, за исключением имен идентификаторов и физического формата строк: пробелов, комментариев и т. д.
Входная часть компилятора принимает промежуточное представление программы и генерирует машинный код для конкретного компьютера. Таким образом, входная часть является языковозависимой, а выходная – машинозависимой.
Для улучшения эффективности кода выходная часть компилятора содержит два оптимизатора. Первый предназначен для оптимизации промежуточного представления программы до формирования, второй при генерации объектного кода. Рассмотрим три способа оптимизации:
1.Машинозависимую оптимизацию промежуточного представления продемонстрируем на примере оптимизации выражения:
a= b (x+y)+c (x+y)
Сумма (x+y) вычисляется один раз и сохраняется во временной переменной или регистре. Подобная оптимизация не зависит от конкретного компьютера и может быть выполнена до генерации кода.
2.Машинно-ориентированная компиляция основана на специфике архитектуры компьютера. Например, для хранения промежуточных результатов в регистрах, а не в памяти, следует знать их число и тип, которые различны в различных компьютерах, точнее, процессорах.
3.Локальная оптимизация обычно выполняется как до, так и при генерации объектного кода. Ее основная функция – это замена коротких последовательностей команд на одну. Например в С выражение n++ может быть скомпилировано в последовательность команд:
load R1,n - Загрузить содержимое n в R1
add R1,# 1 - Прибавить к содержимому R1, 1 (ед.)
store R1,n - Сохранить содержимое R1 в n
Локальный оптимизатор мог бы заменить эти три команды одной: inter n.
Использование оптимизатора требует осторожности.
Ошибку оптимизатора трудно обнаружить, потому что отладчик создан для работы с исходным текстом, а не с оптимизированным объектным кодом, в котором изменен порядок выполнения команд. Для избежания ошибки необходимо проводить тестирование программы до и после работы оптимизатора. Например, в фрагменте программы для устройства ввода-вывода с регистрами, отображенными на память,
transmit_ register = 0x70
/* Ждать 1 секунду */
transmit_ register = 0x70
оптимизатор может удалить второе присваивание, предположив, что оно лишнее.
Так как конечным результатом работы компилятора является объектный модуль, то целесообразно, чтобы он был составлен в кодах конкретной машины. Однако такой подход имеет существенный недостаток – объектный модуль становится машинно-зависимым, и для каждого типа ЭВМ требуется свой компилятор. Чтобы не выполнять большую рутинную работу по преобразованию старого компилятора, было принято решение о разделении процесса компиляции на две части: команды для абстрактной (виртуальной) и конкретной ЭВМ. В этом случае схема компиляции выглядит так:
Рис. Схема двухуровневой компиляции
На первом уровне (блок 2) ИМ обрабатывается компилятором, транслирующим исходный текст на ЯВУ в объектный модуль в кодах некоторой виртуальной (абстрактной ) ЗВМ, учитывающей архитектуру конкретных классов процессоров (блок 3 ).
На втором этапе (блок 4 ) производится перевод ОМ в командах абстрактной ЭВМ (блок 3) в ОМ для конкретной ЭВМ (блок 5). Команды абстрактной машины (блок 3) машино - независимые и могут быть использованы на ЭВМ различных типов. Как правило, выходной ОМ (блок 5) формируется простым компилятором на языке ассемблера (англ. assembler – собирать) конкретной ЭВМ.
2.4. Библиотекарь
Библиотека – это структурированная совокупность типов и подпрограмм, не содержащая новых языковых конструкций.
Многие конструкции языка программирования реализуются не с помощью откомпилированного кода, выполняемого внутри программы, а через обращения к процедурам, которые хранятся в библиотеке, предусмотренной поставщиком компилятора. Из-за увеличения объема языков программирования библиотеки становятся их неотъемлемой частью.
Пр. Использование библиотеки ввода-вывода, которая в С++
находится в файле iostream.h или iostream.
# include < iostream.h>
include – директива препроцессора, которая выполняется в
первую очередь.
2.5. Компоновщик
При написании больших программных систем в несколько тысяч строк используется модульный подход. Вся программа разбивается на модули, связь между которыми осуществляется через обращения к заранее оговоренным процедурам. Если обращение делается к процедуре, находящейся вне текущего модуля, то компилятор вместо адреса этой процедуры записывает внешнюю ссылку. Когда все модули откомпилированы, компоновщик разрешает эти ссылки, разыскивая описания процедур и нелокальных переменных.
В современной практике модульное программирование используется для декомпиляции программы. Применение такого подхода имеет как и медаль две стороны. Положительный эффект (лицевая сторона) – быстрая и короткая компиляция. Обратная сторона медали – связь компоновщиком сотни модулей с тысячами ссылок. В этом случае даже незначительное изменение одного исходного модуля потребует продолжительной компоновки.