DAY17 (1114707), страница 2
Текст из файла (страница 2)
В эту же схему также часто добавляется этап оптимизации программы, причем оптимизация может происходить до этапа трансляции (т.е. в терминах исходного языка) или/и после трансляции (в терминах машинного кода). Например, до трансляции можно вычислить все константные подвыражения и т.д. Для машин типа PC этап оптимизации может быть не столь важен, потому что этот вопрос обычно разрешается покупкой какого-нибудь более быстрого компонента, но есть класс машин (mainframe), для которых этот этап необходим.
Поговорим теперь о средствах трансляции, о видах трансляторов и об общей схеме обработки программы.
Средства трансляции
Как известно транслятор - программа, которая переводит текст, написанный на одном формальном языке, в текст, написанный на другом формальном языке. Транслятор может быть компилятором: в этом случае выходной текст есть текст в формате машинного кода. Кроме того, компилятор может транслировать текст в ассемблер какой-либо машины. В результате работы другого типа транслятора - транслятора-интерпретатора не образуется объектный код в формате машинного языка (или близкого к машинному языку). Интерпретатор либо совмещает процесс перевода и выполнения программы, т. е., грубо говоря, step by step выполняет каждую строчку и при этом машинный код не генерируется, а происходит обращение к некоторой стандартной библиотеке (пример - MS Basic) , либо формирует программу на некотором другом языке, которая впоследствии может быть проинтерпретирована (классический пример - язык Fort).
Интересный пример интерпретатора, созданный Microsoft - Visual Java++. Когда Вы просите скомпилировать вашу программу Visual J++ не создает привычный Вам исполняемый модуль для компьютера с процессором 80x86. Вместо этого компилятор Visual J++ формирует так называемый Java byte code - набор инструкций, написанных для некоторой виртуальной машины Java, которой в действительности не существует. Для выполнения программы Вам необходимо иметь интерпретатор байтового кода, другими словами, Вы используете эмуляцию виртуальной машины Java (JVM - Java virtual machine), на каком компьютере и с какой операционной системой Вы не работали. Виртуальная машина Java убивает сразу трех зайцев: машинная (и системная) независимость, безопасность ( JVM производит контроль за ходом выполнения программы) и уменьшение размера Java-приложения (что позволяет активно использовать Java-разработки в Internet).
Этап трансляции
Давайте посмотрим на проблему кодирования с другой стороны. Мы посмотрим, как устроена трансляция.
Каждый транслятор при обработке программы выполняет следующие действия.
-
Лексический анализ.
-
Синтаксический анализ.
-
Семантический анализ и генерация кода.
Лексический анализ
Лексический анализатор производит анализ исходного текста на предмет правильности записи лексических единиц входного языка. Затем он переводит программу из нотации исходного текста в нотацию лексем.
Лексические единицы - это минимальные конструкции, которые могут быть продекларированы языком. К лексическим единицам относятся:
-
идентификаторы
-
ключевые слова
-
код операции
-
разделители
-
константы
Вещественные константы в некоторых трансляторах могут представляться в виде группы лексических единиц, каждая из которых является целочисленной константой.
После этого исходная программа переводится в вид лексем. Лексема - это некоторая конструкция, содержащая два значения - тип лексемы и номер лексемы.
Тип лексемы | № лексемы |
Тип лексемы - это код, который говорит о том, что данная лексема принадлежит одной из обозначенных нами групп, к примеру, лексема может быть ключевым словом, тогда в поле типа будет стоять соответствующий номер. Номер лексемы уточняет конкретное значение этой лексемы. Если, к примеру, было ключевое слово begin, то номер лексемы будет содержать число, соответствующее ключевому слову begin. Если тип лексемы - идентификатор, то номер лексемы будет номером идентификатора в таблице имен, которую создаст лексический анализатор. Если тип лексемы - константа, то номер лексемы тоже будет ссылкой на таблицу с константами.
После лексического анализатора мы получаем компактную программу, в которой нет уже ничего лишнего (пробелов, комментариев, и т.д.). Вся программа составлена в виде таких лексем, и поэтому она более компактна и проста.
Синтаксический анализ
Программа в виде лексем поступает на вход синтаксическому анализатору, который осуществляет проверку программы на предмет правильности с точки зрения синтаксических правил. Результатом работы синтаксического анализатора является либо информация о том, что в программе имеются синтаксические ошибки и указание координат этих ошибок и их диагностика, либо представление программы в некотором промежуточном виде. Этим промежуточным видом может быть, предположим, бесскобочная запись, либо запись в виде деревьев (хотя одно однозначно сводится к другому). Это промежуточное представление, которое является синтаксически и лексически правильной программой, поступает на вход семантическому анализатору.
Семантический анализ
Семантика - это все то, что не описывается синтаксисом и лексикой языка. К примеру, лексикой и синтаксисом языка сложно описать то, что нехорошо передавать управление в тело цикла не через начало цикла. Выявление таких ошибок - одна из функций семантического анализа, при этом семантический анализатор ставит в соответствие синтаксически и семантически правильным конструкциям объектный код, т.е. происходит генерация кода.
Система программирования и трансляции - очень наукоемкая область программного обеспечения. Организация трансляторов - это было первое применение теоретических достижений науки, которые заключались в следующем. За счет возможности использования тех или иных грамматик (наборов формальных правил построения лексических конструкций и синтаксических правил), можно разделить программную реализацию лексических и синтаксических анализаторов на два компонента. Первый компонент - это программа, которая в общем случае ничего не знает о том языке, который она будет анализировать. Второй компонент - это набор данных, представляющий из себя формальное описание свойств языка, который мы анализируем. Совмещение этих двух компонентов, позволяет автоматизировать процесс построения лексических и синтаксических анализаторов, а также генераторов кода, для различных языков программирования. Современные системы программирования в своем составе имеют средства автоматизации построения компиляторов. Для ОС UNIX есть пакет LEX - пакет генерации лексических анализаторов, и есть пакет YACC - для генерации синтаксических анализаторов. Это все достигается за счет возможности формализации свойств языка и использования этого формального описания, как параметров для тех или иных инструментальных средств.
Проходы трансляторов
Мы с вами посмотрели на транслятор с точки зрения функциональных этапов. Но очень часто мы слышим об однопроходных трансляторах, двухпроходных, трехпроходных, и т.д. С проблемой трансляции связано понятие "проход". Проход - это полный просмотр некоторого представления исходного текста программы.
Есть трансляторы однопроходные. Это означает, что транслятор просматривает исходный текст от начала и до конца, и к концу просмотра (в случае правильности программы) он получает объектный модуль.
Если мы посмотрим Си-компилятор, с которым вы работаете, то скорее всего он двухпроходный. Первый проход - это работа препроцессора. После первого прохода появляется чистая Си-программа без всяких препроцессорных команд. На втором проходе происходит лексический, синтаксический и семантический анализ, и в итоге вы получаете объектную программу в виде ассемблера.
Количество проходов в некоторых трансляторах связано с количеством этапов, т. е. бывают реализации, для которых удобно сделать отдельный проход для лексического анализа, отдельный проход для синтаксического анализа и отдельный проход для семантического анализа. Если транслятор многопроходный, то возникает проблема сохранения промежуточной нотации программы между проходами.
Этапы тестирования и отладки
Тестирование - это поиск ситуации, в которой программный продукт не работает. При этом используются наборы тестов, определяющих внешнюю нагрузку на программный продукт. Можно сказать, что программа оттестирована на определенном наборе тестов. Утверждение, что программа оттестирована вообще в общем случае некорректно.
Отладка - это процесс поиска, локализации и исправления ошибки. Отладка осуществляется, когда мы имеем программную систему, и знаем, что она не работает на каком-то из тестов.
Проблемы тестирования и отладки - это есть проблемы крайней важности. По оценкам, на тестирование и отладку затрачивается порядка 30% времени разработки проекта. Сложность тестирования и отладки зависит от качества проектирования и кодирования. Тестирования зачастую выполнить сложно и часто для тестирования используются модельные нагрузки, например, мы тестируем бортовую сеть самолета, что-то мы сможем сделать на земле, а что-то так или иначе делается уже на реальном полете, когда собираются данные и фиксируется: работает система или нет.