- •Тема 2. Основные принципы построения трансляторов
- •Трансляторы, компиляторы и интерпретаторы - общая схема работы
- •Формальное определение транслятора
- •Определение компилятора. Отличие компилятора от транслятора
- •Многопроходные и однопроходные компиляторы
- •Определение интерпретатора. Разница между интерпретаторами и трансляторами
- •Трансляция в ассемблер
- •Методики создания компилятора
- •Метод раскрутки
- •Кросс-транслятор
- •Виртуальная машина
- •Компиляция "на лету"
- •Этапы трансляции. Общая схема работы транслятора
- •Лексический анализ
- •Синтаксический анализ
- •Семантический анализ
- •Оптимизация кода
- •Генерация кода
- •Просмотры
Определение интерпретатора. Разница между интерпретаторами и трансляторами
Интерпретатор - это программа, которая воспринимает исходную программу на входном (исходном) языке и выполняет ее.
Интерпретатор, так же как и транслятор, анализирует текст исходной программы. Однако он не порождает результирующую программу, а сразу же выполняет исходную в соответствии с ее смыслом, заданным семантикой входного языка. Входными данными интерпретатора является не только исходная программа, но и входные данные самой исходной программы.
Рис. 2.3. Схема работы интерпретатора
Интерпретатор, так же, как и компилятор, анализирует программу на входном языке, создает промежуточное представление, а затем выполняет операции, содержащиеся в тексте этой программы. Например, интерпретатор может построить дерево разбора, а затем выполнить операции, которыми помечены узлы этого дерева.
В том случае, если исходный язык достаточно прост (например, если это язык ассемблера или Basic), то никакое промежуточное представление не нужно, и тогда интерпретатор – это простой цикл. Он выбирает очередную инструкцию языка из входного потока, анализирует и выполняет ее. Затем выбирается следующая инструкция. Этот процесс продолжается до тех пор, пока не будут выполнены все инструкции, либо пока не встретится инструкция, означающая окончание процесса интерпретации.
Рис. 2.4. Фазы интерпретатора в простейшем случае
При таком порядке работы интерпретатора проявляется существенная особенность, которая отличает его от компилятора, — если интерпретатор исполняет команды по мере их поступления, то он не может выполнять оптимизацию исходной программы. Следовательно, фаза оптимизации в общей структуре интерпретатора будет отсутствовать. В остальном же она будет мало отличаться от структуры аналогичного компилятора. Следует только учесть, что на последнем этапе — генерации кода — машинные команды не записываются в объектный файл, а выполняются по мере их порождения.
Отсутствие шага оптимизации определяет еще одну особенность, характерную для многих интерпретаторов: в качестве внутреннего представления программы в них очень часто используется обратная польская запись. Эта удобная форма представления операций обладает только одним существенным недостатком — она плохо поддается оптимизации. Но в интерпретаторах именно это как раз и не требуется.
Далеко не все языки программирования допускают построение интерпретаторов, которые могли бы выполнять исходную программу по мере поступления команд. Для этого язык должен допускать возможность существования компилятора, выполняющего разбор исходной программы за один проход. Кроме того, язык не может интерпретироваться по мере поступления команд, если он допускает появление обращений к функциям и структурам данных раньше их непосредственного описания. Поэтому данным методом не могут интерпретироваться такие языки, как С и Pascal.
Отсутствие шага оптимизации ведет к тому, что выполнение программы с помощью интерпретатора является менее эффективным, чем с помощью аналогичного компилятора. Кроме того, при интерпретации исходная программа должна заново разбираться всякий раз при ее выполнении, в то время как при компиляции она разбирается только один раз, а после этого всегда используется объектный файл. Таким образом, интерпретаторы всегда проигрывают компиляторам в производительности.
Преимуществом интерпретатора является независимость выполнения программы от архитектуры целевой вычислительной системы. В результате компиляции получается объектный код, который всегда ориентирован на определенную архитектуру. Для перехода на другую архитектуру целевой вычислительной системы программу требуется откомпилировать заново. А для интерпретации программы необходимо иметь только ее исходный текст и интерпретатор с соответствующего языка.
В современных системах программирования существуют реализации программного обеспечения, сочетающие в себе и функции компилятора, и функции интерпретатора — в зависимости от требований пользователя исходная программа либо компилируется, либо исполняется (интерпретируется). Кроме того, некоторые современные языки программирования предполагают две стадии разработки; сначала исходная программа компилируется в промежуточный код (некоторый язык низкого уровня), а затем этот результат компиляции выполняется с помощью интерпретатора данного промежуточного языка.
Например, языки Java и JavaScript — сочетают в себе функции компиляции и интерпретации. Текст исходной программы компилируется в некоторый промежуточный двоичный код, не зависящий от архитектуры целевой вычислительной системы, этот код распространяется по сети и выполняется на принимающей стороне — интерпретируется.
