Содержание

Интерпретатор — Национальная библиотека им. Н. Э. Баумана

Материал из Национальной библиотеки им. Н. Э. Баумана
Последнее изменение этой страницы: 17:31, 18 января 2018.

Интерпретатор — программа (разновидность транслятора), выполняющая интерпретацию.

Интерпретация — построчный анализ, обработка и выполнение исходного кода программы или запроса (в отличие от компиляции, где весь текст программы, перед запуском, анализируется и транслируется в машинный или байт-код, без её выполнения) [Источник 1]

История

Первым интерпретатором языка высокого уровня был Lisp. Lisp был впервые реализован в 1958 году Стивом Расселом на компьютере IBM 704. Рассел читать бумаги Джона Маккарти, и понял (к удивлению Маккарти), что lisp-функция оценки может быть реализован в машинный код. В результате получился рабочий интерпретатор Lisp, который мог бы использоваться для запуска программ Lisp, или, более правильно, «оценивать выражения Lisp». [Источник 2]

Типы интерпретаторов

Простой интерпретатор анализирует и тут же выполняет (собственно интерпретация) программу покомандно (или построчно), по мере поступления её исходного кода на вход интерпретатора. Достоинством такого подхода является мгновенная реакция. Недостаток — такой интерпретатор обнаруживает ошибки в тексте программы только при попытке выполнения команды (или строки) с ошибкой. [1]

Интерпретатор компилирующего типа — это система из компилятора, переводящего исходный код программы в промежуточное представление, например, в байт-код или p-код, и собственно интерпретатора, который выполняет полученный промежуточный код (так называемая виртуальная машина). Достоинством таких систем является большее быстродействие выполнения программ (за счёт выноса анализа исходного кода в отдельный, разовый проход, и минимизации этого анализа в интерпретаторе). Недостатки — большее требование к ресурсам и требование на корректность исходного кода. Применяется в таких языках, как Java, PHP, Tcl, Perl, REXX (сохраняется результат парсинга исходного кода), а также в различных СУБД.

В случае разделения интерпретатора компилирующего типа на компоненты получаются компилятор языка и простой интерпретатор с минимизированным анализом исходного кода. Причём [Исходный код|исходного код]] для такого интерпретатора не обязательно должен иметь текстовый формат или быть байт-кодом, который понимает только данный интерпретатор, это может быть машинный код какой-то существующей аппаратной платформы. К примеру, виртуальные машины вроде QEMU, Bochs, VMware включают в себя интерпретаторы машинного кода процессоров семейства x86.

Некоторые интерпретаторы (например, для языков Лисп, Scheme, Python, Бейсик и других) могут работать в режиме диалога или так называемого цикла чтения-вычисления-печати (англ. read-eval-print loop, REPL). В таком режиме интерпретатор считывает законченную конструкцию языка (например, s-expression в языке Лисп), выполняет её, печатает результаты, после чего переходит к ожиданию ввода пользователем следующей конструкции.

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

Следует также отметить, что режимы интерпретации можно найти не только в программном, но и аппаратном обеспечении. Так, многие микропроцессоры интерпретируют машинный код с помощью встроенных микропрограмм, а процессоры семейства x86, начиная с Pentium (например, на архитектуре Intel P6), во время исполнения машинного кода предварительно транслируют его во внутренний формат (в последовательность микроопераций).

Компиляторы против интерпретаторов [2]

В то время как компиляторы (и ассемблеры) обычно производят машинный код, непосредственно исполняемый компьютерным оборудованием, они могут часто (дополнительно) производить промежуточную форму, названную объектным кодом. Это, в основном, тот же машинный определенный код, но с увеличенной таблицей символов с именами и тегами, чтобы сделать исполнимые блоки (или модули) идентифицируемыми и перемещаемыми. Скомпилированные программы обычно используют стандартные блоки (функции), сохраненные в библиотеке таких модулей объектного кода. Компоновщик используется для объединения предварительно сделанных файлов библиотеки с объектным файлом (файлами) приложения, чтобы сформировать единственный выполняемый файл. Объектные файлы, которые используются, чтобы генерировать исполняемый файл, часто создаются в разное время, и иногда даже различными языками (способный к генерации того же объектного формата).

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

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

Компилятор может, таким образом, сделать почти все преобразования от семантики исходного кода до уровня машины раз и навсегда (т.е. пока программа не была изменена), в то время как интерпретатор должен сделать часть этого преобразования каждый раз, когда оператор или функция выполняются. Однако в эффективном интерпретаторе, большая часть работы перевода (включая анализ типов, и подобное) факторизована и сделана только при первом запуске программы, модуля, функции, или даже оператора, выполнена, таким образом довольно сродни тому, как работает компилятор. Однако скомпилированная программа все еще работает намного быстрее при большинстве обстоятельств, частично потому что компиляторы разработаны, чтобы оптимизировать код и могут давать достаточно времени для этого. Это — особенно верно для более простых высокоуровневых языков без (многих) динамических структур данных, проверок или типовых проверок.
В традиционной компиляции, исполнимый вывод компоновщиков (.exe файлы или .dll файлы или библиотека, просмотр картинки) обычно перемещаем, когда выполнен под общей операционной системой, во многом как объектный код, в котором модули всего лишь с тем различием, что это перемещение сделано динамично во время выполнения, т.е. когда программа загружена для работы с ней. С другой стороны, скомпилированные и соединенные программы для маленьких встроенных систем обычно статически выделяются, часто трудно кодируются во флэш-памяти NOR, поскольку часто нет никакой внешней памяти и никакой операционной системы в этом смысле.

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

Цикл разработки

Во время цикла разработки программного обеспечения программисты вносят частые изменения в исходный код. При использовании компилятора, каждый раз, когда изменение было внесено в исходный код, они должны ожидать компилятор, чтобы перевести измененные исходные файлы и соединить все файлы двоичного кода, прежде чем программа может быть исполнена. Чем больше программа, тем дольше ожидание. В отличие от этого, программист, использующий интерпретатор, делает ждет намного меньше, поскольку интерпретатор обычно просто должен перевести код, работающий на промежуточном представлении (или не перевести его вообще), таким образом требуется намного меньшего количества времени, прежде чем изменения смогут быть протестированы. Эффекты заметны после сохранения исходного кода и перезагрузки программы. Скомпилированный код обычно с меньшей готовностью отлажен для редактирования, компиляции и соединения — последовательные процессы, которые должны быть проведены в надлежащей последовательности с надлежащим набором команд. Поэтому у многих компиляторов также есть исполнительное средство, известное как Make-файл и программа. Make-файл перечисляет командные строки компилятора и компоновщика и файлы исходного кода программы, но мог бы использовать простой ввод меню командной строки (например, «Make 3»), который выбирает третью группу (набор) инструкций, и тогда дает команды компилятору и компоновщику, которые подают указанные файлы исходного кода. [3]

Распределение

Компилятор преобразовывает исходный код в двоичную инструкцию для архитектуры определенного процессора, таким образом делая его менее портативным. Это преобразование сделано только один раз на стадии разработки, и после этого тот же двоичный файл может быть распространен машинам пользователя, где это может быть выполнено без дальнейшего перевода. Кросс-компилятор может генерировать двоичный код для пользовательской машины, даже если у нее есть другой процессор, отличный от машины, где код был скомпилирован. [4]

Интерпретируемая программа может быть записана как исходный код. Она должна быть переведена в каждой конечной машине, что занимает больше времени, но делает распределение программы независимым от архитектуры машины. Однако мобильность интерпретируемого исходного кода зависит от целевой машины, на самом деле имеющей подходящий интерпретатор. Если интерпретатор должен быть предоставлен вместе с источником, полный процесс установки сложнее, чем доставка монолитной исполнимой программы, так как сам интерпретатор — часть того, что должно быть установлено.

Факт, который интерпретировал код, может легко быть считан и скопирован людьми, может представить интерес с точки зрения авторского права. Однако существуют различные системы шифрования. Доставка промежуточного кода, такого как байт-код, имеет подобный эффект к шифрованию, но байт-код может декодироваться при помощи декомпилятора или дизассемблера.
Эффективность
Основной недостаток интерпретаторов — то, что интерпретируемая программа обычно работает медленнее, чем если бы она была скомпилирована. Различие в скоростях могло быть крошечным или большим; часто на порядок, иногда больше. Обычно для запуска программы под интерпретатором требуется больше времени, чем для запуска скомпилированного кода, но для его интерпретации может потребоваться меньше времени, чем общее время, необходимое для его компиляции и запуска. Это особенно важно при анализе прототипа и тестировании кода, когда цикл «редактирования-интерпретации-отладки», может часто быть намного короче цикла редактирования-компиляции-отладки.

Интерпретация кода медленнее, чем выполнение скомпилированного кода, потому что интерпретатор должен проанализировать каждый оператор в программе каждый раз, когда это выполняется, и затем выполнить желаемое действие, тогда как скомпилированный код просто выполняет действие в фиксированном контексте, определенном компиляцией. Этот анализ во время выполнения известен как «интерпретирующие издержки». Доступ к переменным также медленнее в интерпретаторе, потому что отображение идентификаторов в места хранения должно выполняться повторно во время выполнения, а не во время компиляции. [5]

Есть различные компромиссы между скоростью разработки при использовании интерпретатора и скоростью выполнения при использовании компилятора. Некоторые системы (такие как Lisp) позволяют интерпретируемому и скомпилированному коду вызывать друг друга и совместно использовать переменные. Это означает, что, как только подпрограмма была протестирована и отлажена под интерпретатором, она может быть скомпилирована и таким образом извлечь выгоду из более быстрого выполнения, в то время как другие подпрограммы разрабатываются. Много интерпретаторов не выполняют исходный код как есть но преобразуют его в некоторую более компактную внутреннюю форму. Многие интерпретаторы BASIC заменяют ключевые слова единственными маркерами байта, которые могут использоваться, чтобы найти инструкцию в таблице переходов. Несколько интерпретаторов, таких как интерпретатор PBASIC, достигают еще более высоких уровней уплотнения программы при помощи бит-ориентированной, а не байтовой структуры памяти программы, где маркеры команд занимают, возможно, 5 битов, номинально «16-разрядные» константы сохранены в неравномерном коде, требующем 3, 6, 10, или 18 битов, и операнды адреса включают «разрядное смещение». Многие BASIC интерпретаторов могут сохранить и считать назад свое собственное маркируемое внутреннее представление.

Регрессия

Интерпретация не может использоваться в качестве единственного метода выполнения: даже при том, что интерпретатор может самостоятельно быть интерпретирован и т.д., непосредственно выполняемая программа необходима где-нибудь у основания стека, потому что интерпретируемый код не является, по определению, тем же машинным кодом, который может выполнить ЦП. [6]

Алгоритм работы

  • прочитать инструкцию;
  • проанализировать инструкцию и определить соответствующие действия;
  • выполнить соответствующие действия;

Достоинства и недостатки интерпретаторов

Достоинства

  • Бо́льшая переносимость интерпретируемых программ — программа будет работать на любой платформе, на которой есть соответствующий интерпретатор.
  • Как правило, более совершенные и наглядные средства диагностики ошибок в исходных кодах.
  • Меньшие размеры кода по сравнению с машинным кодом, полученным после обычных компиляторов.

Недостатки

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

Изменения

Байткод переводчиков

Существует спектр возможностей интерпретации и компиляции, в зависимости от объема анализа, выполненного до выполнения программы. Например, Emacs Lisp компилируется в байт-код, который является сильно сжатым и оптимизированным представлением источника Lisp, но не машинный код (и поэтому не привязан к какому-либо конкретному оборудованию). Этот» скомпилированный » код затем интерпретируется интерпретатором байт-кода (сам написан на языке C). Скомпилированный код в этом случае представляет собой машинный код для виртуальной машины, который реализуется не в аппаратном обеспечении, а в интерпретаторе байт-кода. Такие компилирующие переводчики иногда называют компиляторами. В интерпретаторе байт-кода каждая инструкция начинается с байта, и поэтому интерпретаторы байт-кода имеют до 256 инструкций, хотя не все могут быть использованы. Некоторые байт-коды могут принимать несколько байт и могут быть произвольно сложными. [7]

Управляющие таблицы — это не обязательно когда-нибудь понадобится, чтобы пройти через составление поэтапного диктуют соответствующие алгоритмические поток управления через индивидуальные переводчики в аналогично байт-кода переводчиков.

Переводчики с резьбовым кодом

Потоковые интерпретаторы кода похожи на интерпретаторы байт-кода, но вместо байтов используются указатели. Каждая» инструкция » — это слово, указывающее на функцию или последовательность инструкций, за которой, возможно, следует параметр. Интерпретатор продетого нитку кода либо выполняет циклическую выборку инструкций и вызывает функции, на которые они указывают, либо выбирает первую инструкцию и прыгает к ней, и каждая последовательность инструкций заканчивается выборкой и переходом к следующей инструкции. В отличие от байткода нет эффективного ограничения на количество различных инструкций, кроме доступной памяти и адресного пространства. Классический пример многопоточности-четвертый код, используемый в открытых системах Прошивка: язык исходный код компилируется в код «Ф» (байт-код), который затем интерпретируется виртуальной машиной. [8]

Абстрактные синтаксические интерпретаторы

В спектре между интерпретацией и компиляцией другой подход заключается в преобразовании исходного кода в оптимизированное абстрактное дерево синтаксиса (AST), а затем выполнении программы, следующей за этой древовидной структурой, или использовании его для генерации собственного кода просто в срок. При таком подходе каждое предложение должно быть проанализировано только один раз. Как преимущество над байт-код, АСТ сохраняет глобальную структуру программы и отношения между утверждениями (которые теряются в представлении байт-код), а при сжатии обеспечивает более компактное представление. Таким образом, использование AST было предложено в качестве лучшего промежуточного формата для компиляторов just-in-time, чем байткод. Кроме того, это позволяет системе выполнять лучший анализ во время выполнения. [9]

Однако, для устных переводчиков, АСТ вызывает больше накладных расходов, чем байт-код интерпретатора, из-за узлов, связанных с синтаксисом, выполняющих никакой полезной работы, менее последовательное представление (требуется прохождение нескольких указателей) и накладных осмотреть дерево.

Сборник «точно в срок»

Дальнейшим размыванием различия между интерпретаторами, интерпретаторами байт-кода и компиляцией является компиляция just-in-time (JIT), метод, в котором промежуточное представление компилируется в машинный код машинного кода во время выполнения. Это повышает эффективность выполнения собственного кода за счет времени запуска и увеличения использования памяти при первой компиляции байт-кода или AST. Адаптивная оптимизация-это дополнительный метод, при котором интерпретатор профилирует запущенную программу и компилирует ее наиболее часто выполняемые части в машинный код. Оба метода несколько десятилетий, появляются в языках, таких как Smalltalk в 1980-х.

Просто в момент компиляции завоевала всеобщее внимание среди разработчиков языков в последние годы, с Java, на Framework, у большинства современных реализациях JavaScript, MATLAB, которые сейчас в том числе JITs.

Self-переводчик

Само-переводчика интерпретатора языка программирования, написанный на языке программирования, который может интерпретировать себя; пример-базовый интерпретатор написан на Basic. Собственн-переводчики, связанные с самообслуживанием таких компиляторов.

Если компилятор существует для языка, для интерпретации, создания собственного переводчика требует внедрения языка в принимающем языке (которым может быть другой язык программирования или ассемблер). При наличии первого переводчика, такого как этот, система загрузится и новые версии переводчика могут быть разработаны на самом языке. Это было таким образом, что Дональд Кнут разработал клубок переводчик для языка веб-промышленного стандартная система набирания Текс.

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

Важную дизайна аспект в реализации собственной переводчика является ли особенностью интерпретируемый язык реализуется с той же функцией, принимающей в переводчик язык. Пример является ли закрытие в lisp-подобного языка реализуется с помощью замыканий в языке переводчика или реализован «вручную» с помощью структуры данных, явно сохраняя окружающую среду. Чем больше функций реализовано той же функцией на языке хоста, тем меньше контроля программист имеет; разное поведение для борьбы с переполнением числа не может быть реализовано, если арифметические операции делегированы соответствующим операциям на языке хоста.

Некоторые языки имеют элегантный само-переводчик, таких как Лисп или Пролог.[править] много исследований по собственной переводчиков (в частности, отражательная переводчиков) был проведен в схеме язык программирования, диалект Лиспа. В целом, однако, любой Тьюринг-полный язык позволяет писать собственные переводчика. Lisp-это такой язык, потому что программы Lisp являются списками символов и другими списками. XSLT-это такой язык, потому что язык XSLT программы пишутся в XML. Суб-домен Мета-программирование-это написание проблемно-ориентированные языки (DSL-языки).

Клайв Гиффорд представил[править] измерение качества собственн-переводчик (в eigenratio), предел соотношения между компьютерами время, потраченное на работу стека N собственн-переводчики и времени, потраченных на проведение стек из N − 1 самовыдвижение-переводчиков при N стремящемся к бесконечности. Это значение не зависит от программы.

Книга Структура и интерпретация компьютерных программ представлены примеры Мета-круговой перевод схема и его диалектах. Другие примеры языков с собственной переводчика вперед и Паскаль.

Микрокод

Микрокод — это очень часто используемый метод, который накладывает интерпретатор между аппаратным и архитектурным уровнем компьютера ». Таким образом, микрокод является слоем аппаратных инструкций, которые реализуют инструкции машинного кода более высокого уровня или секвенсирование внутреннего состояния во многих элементах цифровой обработки. Микрокод используется в центральных процессорах общего назначения, а также в более специализированных процессорах, таких как микроконтроллеры, цифровые сигнальные процессоры, контроллеры каналов, контроллеры дисков, контроллеры сетевых интерфейсов, сетевые процессоры, графические процессоры и другие аппаратные средства. [10]

Микрокод обычно находится в специальной высокоскоростной памяти и преобразует машинные инструкции, данные конечных автоматов или другой вход в последовательности подробных операций на уровне цепей. Он отделяет машинные инструкции от базовой электроники, так что инструкции могут быть спроектированы и изменены более свободно. Это также облегчает создание сложных многоступенчатых инструкций, одновременно уменьшая сложность компьютерных схем. Написание микрокода часто называют микропрограммированием, а микрокод в конкретной реализации процессора иногда называют микропрограммой.

Более обширное микрокодирование позволяет малым и простым микроархитексам эмулировать более мощные архитектуры с более широкой длиной слова, большим количеством исполнительных блоков и т. Д., Что является относительно простым способом обеспечения совместимости программного обеспечения между различными продуктами семейства процессоров. [11]

Приложения [12]

  • Интерпретаторы часто используются для выполнения языков команд, и языки клея, так как каждый оператор, выполняемый на языке команд, обычно является вызовом сложной подпрограммы, такой как редактор или компилятор.
  • Самомодифицирующийся код может быть легко реализован на интерпретируемом языке. Это относится к истокам интерпретации в Lisp и исследований искусственного интеллекта.
  • Виртуализация. Машинный код, предназначенный для аппаратной архитектуры можно запустить с помощью виртуальной машины. Это часто используется, когда предполагаемая архитектура недоступна или используется для выполнения нескольких копий.
  • Песочница: в то время как некоторые типы песочницы полагаются на защиту операционной системы, интерпретатор или виртуальная машина часто используется. Фактическая аппаратная архитектура и первоначально предназначенная аппаратная архитектура могут быть одинаковыми или не совпадать. Это может показаться бессмысленным, за исключением того, что песочницы не вынуждены фактически выполнять все инструкции, которые они обрабатывают. В частности, он может отказаться выполнить код, который нарушает какие-либо ограничения, связанные с безопасностью его эксплуатации в соответствии.
  • Эмуляторы для запуска компьютерного программного обеспечения, написанного для устаревшего и недоступного оборудования на более современном оборудовании

Типы языка

Первый наш файл, yobaType.ml, который описывает все возможные виды инструкций, устроен максимально просто: [Источник 3]

type action =
        DoNothing
      | AddFunction of string * action list
      | CallFunction of string
      | Stats
      | Create of string
      | Conditional of int * string * action * action
      | Decrement of int * string
      | Increment of int * string;;

Каждая конструкция языка будет приводиться к одному из этих типов. DoNothing — это просто оператор NOP, он не делает ровным счётом ничего. Create создаёт переменную (у нас они всегда целочисленны), Decrement и Increment соответственно уменьшают и увеличивают заданную переменную на какое-то число. Кроме этого есть Stats для вывода статистики по всем созданным переменным и Conditional — наша реализация if, которая умеет проверять, есть ли в заданной переменной требуемая величина (или большая). В самом конце я добавил AddFunction и CallFunction — возможность создавать и вызывать собственные функции, которые на самом деле очень даже процедуры.

Грамматика языка

Любая конструкция, кроме запроса статистики (это у нас как бы служебная команда) и создания функции начинается и заканчивается ключевыми словами. Благодаря этому мы можем смело расставлять как угодно переносы строк и отступы. Кроме этого (мы же работаем с русским языком) я специально создал по паре инструкций для случаев, когда надо передавать и переменную, и значение. Позже увидите, зачем это было нужно. Итак, наш файл yobaParser.mly:

%{
        open YobaType
%}

%token <string> ID
%token <int> INT

%token RULEZ
%token GIVE TAKE
%token WASSUP DAMN
%token CONTAINS THEN ELSE
%token FUCKOFF
%token STATS
%token MEMORIZE IS
%token CALL

%start main
%type <YobaType.action> main

%%

main:
        expr                                          { $1 }
expr:
        fullcommand                                   { $1 }
      | MEMORIZE ID IS fullcommandlist DAMN           { AddFunction($2, $4) }
fullcommandlist:
        fullcommand                                   { $1 :: [] }
      | fullcommand fullcommandlist                   { $1 :: $2 }
fullcommand:
        WASSUP command DAMN                           { $2 }
      | STATS                                         { Stats }
command:
        FUCKOFF                                       { DoNothing }
      | GIVE ID INT                                   { Increment($3, $2) }
      | GIVE INT ID                                   { Increment($2, $3) }
      | TAKE ID INT                                   { Decrement($3, $2) }
      | TAKE INT ID                                   { Decrement($2, $3) }
      | RULEZ ID                                      { Create($2) }
      | CALL ID                                       { CallFunction($2) }
      | CONTAINS ID INT THEN command ELSE command     { Conditional($3, $2, $5, $7) }
      | CONTAINS INT ID THEN command ELSE command     { Conditional($2, $3, $5, $7) }
%%

Первым делом мы вставляем заголовок — открытие модуля YobaType, который содержит наш тип action, описанный в самом начале. Для чисел и строк, не являющихся ключевыми словами языка (переменных) мы объявляем два специальных типа, которым указываем, что именно они в себе содержат. Для каждого из ключевых слов с помощью директивы %token мы создаём тоже свой тип, который будет идентифицировать это слово в грамматике. Можно было бы указать их все хоть в одну строчку, просто такая запись группирует всё по видам инструкций. Имейте в виду, что все созданные нами токены — это именно подстановочные типы, по которым парсер грамматики определяет, что ему делать. Обозвать их можно как угодно, то, как они будут выглядеть в самом языке, мы опишем позже. Указываем, что входной точкой для грамматики является main, и что возвращать он всегда должен объект типа action — инструкцию для интерпретатора. Наконец, после двух знаков %% мы описываем саму грамматику:

  • Инструкция состоит либо из команды (fullcommand), либо из создания функции.
  • Функция, в свою очередь, состоит из списка команд (fullcommandlist).
  • Команда бывает либо служебной (STATS), либо обычной (command), в таком случае она должна быть обёрнута в ключевые слова.
  • С обычной командой всё просто, даже расписывать не буду.

В фигурных скобках мы указываем, что делать при совпадении строки с данным вариантом, при этом $N обозначает N-ный член конструкции. Например, если мы встречаем «CALL ID» (ID — это строка, не забываем), то мы создаём инструкцию CallFunction, которой в качестве параметра передаём $2 (как раз ID) — имя вызываемой функции.

Лексер — превращаем язык в ключевые слова

Мы дошли одновременно до практически самой простой и самой муторной части. Простая она, потому что всего лишь описывает превращение слов языка в наши токены. А муторная, потому что лексеры (а может, только окамловский лексер) плохо рассчитаны на работу с русским языком, поэтому работать с русскими символами можно только как со строками. Так как я хотел сделать ключевые слова языка регистро-независимыми, это добавило кучу геморроя — вместо простого написания «дай» надо было расписывать вариант написания каждой буквы. В общем, смотрите сами, файл yobaLexer.mll:

{
        open YobaParser
        exception Eof
}
rule token = parse
        ("и"|"И") ("д"|"Д") ("и"|"И") (' ')+
        ("н"|"Н") ("а"|"А") ("х"|"Х") ("у"|"У") ("й"|"Й") { FUCKOFF }
      | ("б"|"Б") ("а"|"А") ("л"|"Л") ("а"|"А")
        ("н"|"Н") ("с"|"С") (' ')+
        ("н"|"Н") ("а"|"А") ("х"|"Х")                     { STATS }
      | [' ' '\t' '\n' '\r']                              { token lexbuf }
      | ['0'-'9']+                                        { INT(int_of_string(Lexing.lexeme lexbuf)) }
      | ("д"|"Д") ("а"|"А") ("й"|"Й")                     { GIVE }
      | ("н"|"Н") ("а"|"А")                               { TAKE }
      | ("ч"|"Ч") ("о"|"О")                               { WASSUP }
      | ("й"|"Й") ("о"|"О") ("б"|"Б") ("а"|"А")           { DAMN }
      | ("л"|"Л") ("ю"|"Ю") ("б"|"Б") ("л"|"Л") ("ю"|"Ю") { RULEZ }
      | ("е"|"Е") ("с"|"С") ("т"|"Т") ("ь"|"Ь")           { CONTAINS }
      | ("т"|"Т") ("а"|"А") ("д"|"Д") ("а"|"А")           { THEN }
      | ("и"|"И") ("л"|"Л") ("и"|"И")                     { ELSE }
      | ("у"|"У") ("с"|"С") ("е"|"Е") ("к"|"К") ("и"|"И") { MEMORIZE }
      | ("э"|"Э") ("т"|"Т") ("о"|"О")                     { IS }
      | ("х"|"Х") ("у"|"У") ("й"|"Й") ("н"|"Н") ("и"|"И") { CALL }
      |
      ("а"|"б"|"в"|"г"|"д"|"е"|"ё"|"ж"
       |"з"|"и"|"й"|"к"|"л"|"м"|"н"|"о"
       |"п"|"р"|"с"|"т"|"у"|"ф"|"х"|"ц"
       |"ч"|"ш"|"щ"|"ъ"|"ы"|"ь"|"э"|"ю"|"я")+             { ID(Lexing.lexeme lexbuf) }
      | eof                                               { raise Eof }

Интерпретатор

Осталась последняя часть — сам интерпретатор, который обрабатывает наши конструкции языка.

open YobaType
 
let identifiers = Hashtbl.create 10;;
let funcs = Hashtbl.create 10;;
 
let print_stats () =
        let print_item id amount =
                Printf.printf ">> Йо! У тебя есть %s: %d" id amount;
                print_newline ();
                flush stdout in
        Hashtbl.iter print_item identifiers;;
 
let arithm id op value () =
        try
                Hashtbl.replace identifiers id (op (Hashtbl.find identifiers id) value);
                Printf.printf ">> Гавно вопрос\n"; flush stdout
        with Not_found -> Printf.printf ">> Х@#на, ты %s не любишь\n" id; flush stdout;;
 
let rec cond amount id act1 act2 () =
        try
                if Hashtbl.find identifiers id >= amount then process_action act1 () else process_action act2 ()
        with Not_found ->
                Printf.printf ">> Човаще?!\n";
                flush stdout
and process_action = function
        | Create(id) -> (function () -> Hashtbl.add identifiers id 0)
        | Decrement(amount, id) -> arithm id (-) amount
        | Increment(amount, id) -> arithm id (+) amount
        | Conditional(amount, id, act1, act2) -> cond amount id act1 act2
        | DoNothing -> (function () -> ())
        | Stats -> print_stats
        | AddFunction(id, funclist) -> (function () -> Hashtbl.add funcs id funclist)
        | CallFunction(id) -> callfun id
and callfun id () =
        let f: YobaType.action list = Hashtbl.find funcs id in
        List.iter (function x -> process_action x ()) f
;;
 
while true do
        try
                let lexbuf = Lexing.from_channel stdin in
                process_action (YobaParser.main YobaLexer.token lexbuf) ()
        with
                YobaLexer.Eof ->
                        print_stats ();
                        exit 0
              | Parsing.Parse_error ->
                        Printf.printf ">> Ни@#я не понял б@#!\n";
                        flush stdout
              | Failure(_) ->
                        Printf.printf ">> Ни@#я не понял б@#!\n";
                        flush stdout
done

Первым делом мы создадим две хэштаблицы — для переменных и для функций. Начальный размер 10 взят от фонаря, у нас же тренировочный язык, зачем нам сразу много функций.
Затем объявим две небольших функции: одна — для вывода статистики, вторая — для инкремента/декремента переменных.

Дальше идёт группа из сразу трёх функций: cond обрабатывает условные конструкции (наш if), callfun отвечает за вызов функций, а process_action отвечает за обработку пришедшей на вход инструкции как таковой. Надеюсь, почему все три функции зависят друг от друга, объяснять не надо.

Обратите внимание, все варианты в process_action не выполняют действие, а всего лишь возвращают функцию, которая его выполнит. Изначально это было не так, но именно это маленькое изменение позволило мне легко и непринужденно добавить в язык поддержку пользовательских функций.

Наконец, последняяя часть кода до посинения в цикле читает и обрабатывает результат работы парсера.

Добавим к этому Makefile:

all:
   ocamlc -c yobaType.ml
   ocamllex yobaLexer.mll
   ocamlyacc yobaParser.mly
   ocamlc -c yobaParser.mli
   ocamlc -c yobaLexer.ml
   ocamlc -c yobaParser.ml
   ocamlc -c yoba.ml
   ocamlc -o yoba yobaLexer.cmo yobaParser.cmo yoba.cmo

clean:
   rm -f *.cmo *.cmi *.mli yoba yobaLexer.ml yobaParser.ml

Источники

Примечание

  1. «Why was the first compiler written before the first interpreter?». Ars Technica. Retrieved 9 November 2014. 
  2. ↑ Short animation, explaining the key conceptual difference between interpreters and compilers
  3. ↑ Terence Parr, Johannes Luber, The Difference Between Compilers and Interpreters
  4. ↑ Theodore H. Romer, Dennis Lee, Geoffrey M. Voelker, Alec Wolman, Wayne A. Wong,
    Jean-Loup Baer, Brian N. Bershad, and Henry M. Levy, The Structure and Performance of Interpreters]
  5. Heyne, R. (1984). «Basic-Compreter für U880» [BASIC compreter for U880 (Z80)]. Шаблон:Ill (in German) 1984 (3): 150–152. 
  6. Kühnel, Claus (1987) [1986]. «4. Kleincomputer — Eigenschaften und Möglichkeiten» [4. Microcomputer — Properties and possibilities]. In Erlekampf, Rainer; Mönk, Hans-Joachim. Mikroelektronik in der Amateurpraxis [Micro-electronics for the practical amateur] (in German) (3 ed.). Berlin: Шаблон:Ill, Leipzig. p. 222. ISBN 3-327-00357-2. 7469332. 
  7. ↑ A Tree-Based Alternative to Java Byte-Codes, Thomas Kistler, Michael Franz
  8. ↑ Surfin’ Safari — Blog Archive » Announcing SquirrelFish. Webkit.org (2008-06-02). Retrieved on 2013-08-10.
  9. ↑ L. Deutsch, A. Schiffman, Efficient implementation of the Smalltalk-80 system, Proceedings of 11th POPL symposium, 1984.
  10. Kent, Allen; Williams, James G. (April 5, 1993). Encyclopedia of Computer Science and Technology: Volume 28 — Supplement 13. New York: Marcel Dekker, Inc. ISBN 0-8247-2281-7. Retrieved Jan 17, 2016. 
  11. ↑ IBM Card Interpreters, page at Columbia University
  12. ↑ Theoretical Foundations For Practical ‘Totally Functional Programming’, (Chapter 7 especially) Doctoral dissertation tackling the problem of formalising what is an interpreter

ru.bmstu.wiki

Интерпретатор — это… Что такое Интерпретатор?

Эта статья включает описание термина «Интерпретация»; см. также другие значения.

Интерпрета́тор — программа (разновидность транслятора) или аппаратное средство, выполняющее интерпретацию.[1]

Интерпрета́ция — пооператорный (покомандный, построчный) анализ, обработка и тут же выполнение исходной программы или запроса (в отличие от компиляции, при которой программа транслируется без её выполнения).[2][3][4]

Типы интерпретаторов

Простой интерпретатор анализирует и тут же выполняет (собственно интерпретация) программу покомандно (или построчно), по мере поступления её исходного кода на вход интерпретатора. Достоинством такого подхода является мгновенная реакция. Недостаток — такой интерпретатор обнаруживает ошибки в тексте программы только при попытке выполнения команды (или строки) с ошибкой.

Интерпретатор компилирующего типа — это система из компилятора, переводящего исходный код программы в промежуточное представление, например, в байт-код или p-код, и собственно интерпретатора, который выполняет полученный промежуточный код (так называемая виртуальная машина). Достоинством таких систем является большее быстродействие выполнения программ (за счёт выноса анализа исходного кода в отдельный, разовый проход, и минимизации этого анализа в интерпретаторе). Недостатки — большее требование к ресурсам и требование на корректность исходного кода. Применяется в таких языках, как Java, Tcl, Perl (используется байт-код[источник не указан 1309 дней]), REXX (сохраняется результат парсинга исходного кода[5]), а также в различных СУБД (используется p-код[источник не указан 1309 дней]).

В случае разделения интерпретатора компилирующего типа на компоненты получаются компилятор языка и простой интерпретатор с минимизированным анализом исходного кода. Причём исходный код для такого интерпретатора не обязательно должен иметь текстовый формат или быть байт-кодом, который понимает только данный интерпретатор, это может быть машинный код какой-то существующей аппаратной платформы. К примеру, виртуальные машины вроде QEMU, Bochs, VMware включают в себя интерпретаторы машинного кода процессоров семейства x86.

Некоторые интерпретаторы (например, для языков Лисп, Scheme, Python, Бейсик и других) могут работать в режиме диалога или так называемого цикла чтения-вычисления-печати (англ. read-eval-print loop, REPL). В таком режиме интерпретатор считывает законченную конструкцию языка (например, s-expression в языке Лисп), выполняет её, печатает результаты, после чего переходит к ожиданию ввода пользователем следующей конструкции.

Уникальным является язык Forth, который способен работать как в режиме интерпретации, так и компиляции входных данных, позволяя переключаться между этими режимами в произвольный момент, как во время трансляции исходного кода, так и во время работы программ.[6]

Следует также отметить, что режимы интерпретации можно найти не только в программном, но и аппаратном обеспечении. Так, многие микропроцессоры интерпретируют машинный код с помощью встроенных микропрограмм, а процессоры семейства x86, начиная с Pentium (например, на архитектуре Intel P6), во время исполнения машинного кода предварительно транслируют его во внутренний формат (в последовательность микроопераций).

Алгоритм работы простого интерпретатора

  1. прочитать инструкцию;
  2. проанализировать инструкцию и определить соответствующие действия;
  3. выполнить соответствующие действия;
  4. если не достигнуто условие завершения программы, прочитать следующую инструкцию и перейти к пункту 2.

Достоинства и недостатки интерпретаторов

Достоинства

  • Бо́льшая переносимость интерпретируемых программ — программа будет работать на любой платформе, на которой есть соответствующий интерпретатор.
  • Как правило, более совершенные и наглядные средства диагностики ошибок в исходных кодах.
  • Упрощение отладки исходных кодов программ[источник не указан 573 дня].
  • Меньшие размеры кода по сравнению с машинным кодом, полученным после обычных компиляторов.

Недостатки

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

См. также

Примечания

  1. ГОСТ 19781-83; СТ ИСО 2382/7-77 // Вычислительная техника. Терминология: Справочное пособие. Выпуск 1 / Рецензент канд. техн. наук Ю. П. Селиванов. — М.: Издательство стандартов, 1989. — 168 с. — 55 000 экз. — ISBN 5-7050-0155-X
  2. Першиков В. И., Савинков В. М. Толковый словарь по информатике / Рецензенты: канд. физ.-мат. наук А. С. Марков и д-р физ.-мат. наук И. В. Поттосин. — М.: Финансы и статистика, 1991. — 543 с. — 50 000 экз. — ISBN 5-279-00367-0
  3. Борковский А. Б. Англо-русский словарь по программированию и информатике (с толкованиями). — М.: Русский язык, 1990. — 335 с. — 50 050 (доп,) экз. — ISBN 5-200-01169-3
  4. Толковый словарь по вычислительным системам = Dictionary of Computing / Под ред. В. Иллингуорта и др.: Пер. с англ. А. К. Белоцкого и др.; Под ред. Е. К. Масловского. — М.: Машиностроение, 1990. — 560 с. — 70 000 (доп,) экз. — ISBN 5-217-00617-X (СССР), ISBN 0-19-853913-4 (Великобритания)
  5. Dave Martin. Why does my OS/2 REXX program run more quickly the second time?. Rexx FAQs. Архивировано из первоисточника 22 августа 2011. Проверено 22 декабря 2009.
  6. Jeff Fox. Chapter 2. More Interpretation  (англ.). Thoughtful Programming and Forth. UltraTechnology. Архивировано из первоисточника 22 августа 2011. Проверено 25 января 2010.

dic.academic.ru

Интерпретатор

Интерпретатор

Интерпретатор
(interpreter) — программа или техническое
средство, выполняющее интерпретацию,
а также вид транслятора, осуществляющего
пооперационную (покомандную) обработку
и выполнение исходной программы или
запроса. В отличие от компилятора,
который осуществляет трансляцию всей
программы высокого уровня в машинные
коды один раз без ее выполнения (создает
объектную программу), интерпретатор
транслирует исходную программу команда
за командой каждый раз при выполнении
и не создает объектного модуля. За счет
такого режима выполнение программы
происходит медленнее, чем в случае ее
обработки транслятором, однако при
обработке интерпретатором программы
выполняются сразу, без промежуточной
стадии трансляции.

Интерпретаторы
— трансляторы языков программирования,
работают на отличающемся от компиляторов
принципе. Интерпретаторы не производят
исполняемого машинного кода. Они берут
исходный текст программы на языке
программирования и выполняют его сами
строка за строкой. При этом интерпретатор
извлекает из файла с исходным текстом
одну команду, распознает ее и вызывает
те или иные функции операционной системы.
Интерпретатор определяет команду и
переводит (интерпретирует) ее так, чтобы
операционная система поняла, что от нее
хотят. Скорость выполнения программ в
режиме интерпретации намного ниже, чем
у компилированного кода, за счет того,
что работа программы идет не напрямую
с центральным процессором на языке
машинных команд, а через программу-посредника,
которая и тратит большое количество
времени на распознавание исходного
текста. В отличие от интерпретаторов,
компиляторы «знакомятся» с исходными
текстами программы всего один раз, когда
делают из текста на языке программирования
машинный код.

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

Интерпретация
(в программировании)

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

studfiles.net

Что такое компилятор, интерпретатор, транслятор

Для реализации задач, описанных в программном коде, процессор компьютера должен произвести ряд операций. Но процессор, как и другие части компьютерного «железа», не понимает языки программирования высокого уровня. Поэтому для того, чтобы добиться исполнения описанных в программе действий, её переводят в понятный процессору объектный код. Конечный результат этого перевода называется объектным модулем или объектным файлом и содержит в себе набор единичек и нулей, понятных процессору компьютера.

Для проведения переводов исходного кода в объектный или промежуточный код используются специальные программы – трансляторы.

Что такое транслятор?

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

Помимо осуществления перевода, трансляторы могут выявлять в исходном коде ошибки, оптимизировать исходный код, добавлять в исходный код отладочные процедуры, формировать словари идентификаторов и другое.

Существуют также обратные трансляторы, осуществляющие перевод с машинного кода в понятный пользователю язык программирования.

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

Что такое компилятор?

Компилятор (от английского Compile – собирать, накапливать) – это вариант реализации транслятора, который создаётся для перевода программы, написанной на высокоуровневом языке программирования в машинный код, который в последствие будет исполняться процессором компьютера. Этот тип трансляции называется компиляцией.

В большинстве случаев компиляция программы происходит полностью (AOT-компиляция). Компилятор целиком считывает программу, проводит её пошаговый анализ (лексический, синтаксический, семантический), оптимизирует её, очищая от излишних конструкций, но сохраняя исходный смысл операций, и также целиком переводит её в машинный код.

Однако, иногда используется и построчная компиляция. В этом случае машинный код генерируется и исполняется для каждой полной грамматической конструкции исходного кода. От интерпретации такая компиляция отличается способом исполнения.

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

Компиляторы для C++

Так, например, для C++ можно использовать:

  • Microsoft Visual C++ 6.0
  • MS Visual Studio 2005 Professional
  • Intel C++ Compiler 4.5
  • Borland Builder 6.0
  • Borland C++ Compiler
  • g++
  • gcc
  • MinGW 3.2

Подходящий компилятор выбирается, исходя из особенностей программ, с которыми предстоит работать и, как уже говорилось выше, операционной системы.

Компилятор для Python

Необходимость самостоятельно компилировать исходный код с Питона в exe-файл для последующей интерпретации возникает нечасто. В тех случаях, когда на компьютер, на котором планируется выполнение программы, уже установлен интерпретатор Python, компиляция обычно не требуется.

Если программе всё же необходима компиляция, можно использовать cx_Freeze.

Компилятор для Java

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

Компиляторы в Java используются для того, чтобы преобразовать исходный код в байт-код, доступный пониманию виртуальной машины и пригодный для последующей интерпретации.

Чаще всего используются:

  • GNU Compiler for Java
  • Javac

Javac помимо анализа и трансляции, производит ещё и оптимизацию кода.

В целом, за счёт использования виртуальной машины, Java выполняет операции, описанные в исходном коде куда медленнее, чем, скажем, С++. При исполнении некоторых операций Java может уступать в скорости до 7 раз. Для ускорения работы программ на Java используется оптимизация библиотек (в них широко используется native-код), некоторые аппаратные решения для ускоренной обработки байт-кода и JIT-компиляция.

JIT-компиляция

JIT-компиляция – это трансляция байт-кода в машинный код непосредственно во время работы программы. JIT-компиляция может быть применена к любой части программы или ко всей программе в целом.

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

Что такое интерпретатор?

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

Проще говоря, в отличие от большинства компиляторов, интерпретатор обрабатывает, а затем исполняет не всю исходную программу, а отдельно каждую её строку, пока программа не будет закончена.

Интерпретаторы бывают двух типов:

  • Простые — осуществляющие исключительно интерпретацию введённого исходного кода.
  • Интерпретаторы компилирующего типа – это система, состоящая из компилятора, транслирующего исходный код в промежуточный, и виртуальной машины, реализующей операции, описанные в коде.

Виртуальная машина

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

Давайте рассмотрим алгоритм этого процесса на примере PVM (Python Virtual Machine).

По схожей схеме работают виртуальная машина Java, Common Language Runtime (инструмент для интерпретации С#) и некоторые другие интерпретаторы.

Интерпретатор для PHP

Интерпретатор PHP отличается от большей части виртуальных машин отсутствием создания выполняемого файла. То есть в отличие от, скажем, PVM (Python Virtual Machine) он не кеширует сгенерированный байт-код в памяти. Потому при запуске и отладке программы компиляция одного и того же фрагмента байт-кода происходит несколько раз. Это существенно замедляет работу программы.

Сравнение интерпретаторов и компиляторов

Плюсы интерпретаторов

  • Использование для реализации исходного кода виртуальной машины позволяет интерпретаторам эффективно работать на всех платформах.
  • С интерпретатором можно работать в интерактивном режиме.

Минусы интерпретаторов

  • Исходный код не может работать отдельно без наличия интерпретатора.

Плюсы компиляторов

  • Возможность эффективной оптимизации кода, сокращающей количество операций и итоговое время выполнения поставленных программе задач.
  • Быстродействие – перевод в машинный код и реализация операций процессором происходит в среднем в 1,5 раза быстрее, чем пошаговая трансляция программы в байт-код и последующая реализация её виртуальной машиной.
  • Производительность – исполнимый модуль, получившийся в результате компиляции, обладает оптимальными показателями скорости выполнения и задействует в работе минимум ресурсов компьютера.

Минусы компиляторов

  • И сами компиляторы, и генерируемый ими код рассчитаны на использование в определённой операционной системе и взаимодействие с определённым типом процессора. В других исходных условиях они работать не будут.

Выбор транслятора

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

Если Вы хотите разобраться в этой теме глубже, рекомендуем прочесть:

Альфред В. Ахо, Моника С. Лам, Рави Сети, Джеффри Д. Ульман. Компиляторы: принципы, технологии и инструментарий

Это учебник по теории написания компиляторов, в котором подробно описаны принципы работы разноуровневых компиляторов (начиная от простейших однопроходных, заканчивая современным компилятором на языке Java), уделяется повышенное внимание лексическому, синтаксическому и семантическому разбору программ в исходном коде, генерации машинного кода.

В.А.Серебряков, М.П.Галочкин. Основы конструирования компиляторов

Ещё один учебник по созданию компиляторов, только теперь отечественный. Глубоко раскрыты темы лексического и семантического анализа, рассмотрены темы автоматизации процесса разработки компиляторов, получения оптимального кода.

learn-code.ru

Интерпретатор — Мегаэнциклопедия Кирилла и Мефодия — статья

Интерпретатор (interpreter) — программа или техническое средство, выполняющее интерпретацию, а также вид транслятора, осуществляющего пооперационную (покомандную) обработку и выполнение исходной программы или запроса. В отличие от компилятора, который осуществляет трансляцию всей программы высокого уровня в машинные коды один раз без ее выполнения (создает объектную программу), интерпретатор транслирует исходную программу команда за командой каждый раз при выполнении и не создает объектного модуля. За счет такого режима выполнение программы происходит медленнее, чем в случае ее обработки транслятором, однако при обработке интерпретатором программы выполняются сразу, без промежуточной стадии трансляции.

Интерпретаторы — трансляторы языков программирования, работают на отличающемся от компиляторов принципе. Интерпретаторы не производят исполняемого машинного кода. Они берут исходный текст программы на языке программирования и выполняют его сами строка за строкой. При этом интерпретатор извлекает из файла с исходным текстом одну команду, распознает ее и вызывает те или иные функции операционной системы. Интерпретатор определяет команду и переводит (интерпретирует) ее так, чтобы операционная система поняла, что от нее хотят. Скорость выполнения программ в режиме интерпретации намного ниже, чем у компилированного кода, за счет того, что работа программы идет не напрямую с центральным процессором на языке машинных команд, а через программу-посредника, которая и тратит большое количество времени на распознавание исходного текста. В отличие от интерпретаторов, компиляторы «знакомятся» с исходными текстами программы всего один раз, когда делают из текста на языке программирования машинный код.

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

megabook.ru

Интерпретатор — WiKi

Эта статья включает описание термина «Интерпретация»; см. также другие значения.

Интерпретатор (англ. interpreter ıntə:’prıtə[1], от лат. interpretator — толкователь[2]) — программа (разновидность транслятора), выполняющая интерпретацию[3].

Интерпретация — построчный анализ, обработка и выполнение исходного кода программы или запроса (в отличие от компиляции, где весь текст программы, перед запуском, анализируется и транслируется в машинный или байт-код, без её выполнения) [4][5][6].

Простой интерпретатор анализирует и тут же выполняет (собственно интерпретация) программу покомандно (или построчно), по мере поступления её исходного кода на вход интерпретатора. Достоинством такого подхода является мгновенная реакция. Недостаток — такой интерпретатор обнаруживает ошибки в тексте программы только при попытке выполнения команды (или строки) с ошибкой.

Интерпретатор компилирующего типа — это система из компилятора, переводящего исходный код программы в промежуточное представление, например, в байт-код или p-код, и собственно интерпретатора, который выполняет полученный промежуточный код (так называемая виртуальная машина). Достоинством таких систем является большее быстродействие выполнения программ (за счёт выноса анализа исходного кода в отдельный, разовый проход, и минимизации этого анализа в интерпретаторе). Недостатки — большее требование к ресурсам и требование на корректность исходного кода. Применяется в таких языках, как Java, PHP, Tcl, Perl, REXX (сохраняется результат парсинга исходного кода[8]), а также в различных СУБД.

В случае разделения интерпретатора компилирующего типа на компоненты получаются компилятор языка и простой интерпретатор с минимизированным анализом исходного кода. Причём исходный код для такого интерпретатора не обязательно должен иметь текстовый формат или быть байт-кодом, который понимает только данный интерпретатор, это может быть машинный код какой-то существующей аппаратной платформы. К примеру, виртуальные машины вроде QEMU, Bochs, VMware включают в себя интерпретаторы машинного кода процессоров семейства x86.

Некоторые интерпретаторы (например, для языков Лисп, Scheme, Python, Бейсик и других) могут работать в режиме диалога или так называемого цикла чтения-вычисления-печати (англ. read-eval-print loop, REPL). В таком режиме интерпретатор считывает законченную конструкцию языка (например, s-expression в языке Лисп), выполняет её, печатает результаты, после чего переходит к ожиданию ввода пользователем следующей конструкции.

Уникальным является язык Forth, который способен работать как в режиме интерпретации, так и компиляции входных данных, позволяя переключаться между этими режимами в произвольный момент, как во время трансляции исходного кода, так и во время работы программ.[9]

Следует также отметить, что режимы интерпретации можно найти не только в программном, но и аппаратном обеспечении. Так, многие микропроцессоры интерпретируют машинный код с помощью встроенных микропрограмм, а процессоры семейства x86, начиная с Pentium (например, на архитектуре Intel P6), во время исполнения машинного кода предварительно транслируют его во внутренний формат (в последовательность микроопераций).

ru-wiki.org

Что это — интерпретатор, и где он используется? :: SYL.ru

Практически каждый пользователь компьютерных сетей встречался с такой областью науки, как программирование – это невероятная вещь, которая появилась в середине 20 века и полностью перевернула наш мир. Сложно представить не только повседневную жизнь каждого без компьютера, но и даже общемировую ситуацию. Возможно, что мы бы до сих пор не могли нормально общаться с родственниками, которые не так уж и близко, если бы не известный всем нам интернет и операционные системы, обслуживающие обе эти вещи. В данной статье будет подробно рассказано, что это – интерпретатор, где используется и для чего нужен. Статья особенно будет полезна начинающим программистам, ведь подобную информацию не везде рассказывают.

Что такое компиляторы и интерпретаторы?

Статья рассчитана на пользователей, которые хотя бы немного знают о том, как устроены сети, операционные системы и языки программирования. Если вы вообще не имеете никакого представления о перечисленном, то рекомендуем почитать, ибо информация будет выглядеть достаточно сумбурно.

Для начал стоит разобраться, что же такое компилятор, ведь он буквально является основой основ. После написания кода на каком-либо языке он обязательно должен пройти стадию компиляции, т. е. сборки всех частей кода воедино. Дело в том, что проект всегда и обязательно разделяется на множество частей, каждая из которых выполняет лишь определенную роль. Будь то работа с сетью, файлами, пользователем и т. д. Такие куски кода могут быть написаны самим пользователем или взяты из стандартной библиотеки STL.

При взятии какого-либо элемента есть два варианта компиляции: автоматический и динамический. При автоматическом берутся все необходимые (включенные) библиотеки, а при динамическом — лишь выбранные части эти библиотек. Это весьма большая тема, поэтому рекомендуем прочитать про каждый способ отдельно.

Итак, все библиотеки, части кода в форме исходных файлов собраны, а что дальше? Правильно, теперь самое время заставить компьютер понимать наш код. Делается это для того, чтоб компьютер мог вообще взаимодействовать с пользователем. Промежуточным звеном между аппаратной и программной частью является полумашинный язык программирования – ассемблер, именно в этот язык интерпретатор переводит вами написанный код.

Из сказанного выше можно сказать, что интерпретатор – это определенная программа для перекодировки в полумашинный язык ассемблер. В следующей части статьи мы поговорим подробнее про современные компиляторы и интерпретаторы.

Самые популярные программы интерпретатора

В современном стиле программирования принято при создании нового языка совмещать все в одной программе. Чтобы программисту не пришлось пропускать весь код через несколько программ, теперь все объединено в одно приложение – компилятор.

Современные функции компилятора:

  1. Компиляция. Сборка всех фрагментов кода.
  2. Интерпретация. Создание полумашинного кода.
  3. Линковка. Связывания частей интерпретированного кода в памяти.

Итак, из этого можно еще лучше понять, насколько интерпретатор — это мощное средство, поскольку без него программирование было бы таким же, как и в 60-х годах 20 века, то есть невероятно сложным. Теперь надо рассказать, какие же интерпретаторы (в составе компиляторов) на данный момент самые популярные:

  1. MVS. Популярный компилятор от «Майкрософт» для языка программирования С++.
  2. Xcode. Используется для создания приложений под технику Apple.
  3. MinGW. Один из самых распространенных компиляторов для языков программирования С и С++. Является прямым конкурентом MVS.

В каких языках используются интерпретаторы?

В современном мире программирования чаще всего используют только самые популярные языки программирования, ведь именно они развиваются наиболее быстро, что позволяет воплотить весь потенциал программистов. Примером таких языков могут стать Java и С\С++. Веб-языки не стоит относить сюда, потому что реализации их кода не требуются дополнительные приспособления, кроме рабочей станции и приложения, способного запустить код. Многие программисты считают лучшим интерпретатором Windows именно MVS, поскольку он разработан исключительно только для работы с операционной системной Windows.

Где можно найти объектные файлы?

После компиляции в папке с проектом создается специальный объектный файл – это и есть плод стараний компилятора. В операционной системе «Линукс» подобный файл использует расширение «*.о», т.е. от слова object. В операционной системе Windows этот процесс сразу перетекает в создание исполняемого файла, который можно дизассемблировать и получить тот же результат, что и при открытии файла с расширением «*.o».

В заключение

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

www.syl.ru