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

Примечания

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

Как это работает?

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

Интерпретатор создает программу. Он не связывает файлы и не генерирует машинный код. Происходит построчное выполнение исходных операторов во время исполнения программы.

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

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

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

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

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

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

Рабочий цикл программы

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

Когда пишете программу, вы хотите, чтобы ее инструкции работали на компьютере. Компьютер обрабатывает информацию с помощью процессора, который поэтапно выполняет инструкции, закодированные в двоичном формате. Как из выражения «a = 3;» получить закодированные инструкции, которые процессор может понять?

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

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

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

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

Не все языки программирования учитывают это в своей концепции. Например, Java предназначался для запуска в «интерпретирующей» среде, а Python всегда должен интерпретироваться.

Работа с памятью

Почти все знают, что языки типа Java/Python очень удобные, т.к. автоматизируют сборку мусора. Это значит, что если вы выделите память под объект (например, массив), а затем этот объект станет вам не нужен — то виртуальная машина сама освободит память. Например, в следующей программе при вызове функции создается новый объект , который после завершения работы функции становится недоступен — это и есть мусор. В языке C++ такие объекты уничтожаются в момент выхода из функции, а в Java, Python и многих других интерпретируемых языках — они живут до тех пор, пока свободная память не кончится:

public class Main {
    public static void say(String name) {
        String text = "hello " + name;
        System.out.println(text);  
    }
 
    public static void main(String[] args) {
        say("Bob");
    }
}

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

Система управления памятью занимается не только сборкой мусора, но также:

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

Вся эта дополнительная работа выполняется неявно в момент выполнения вашей программы и, естественно, тормозит. Обычно для сборки памяти необходима полная остановка вашей программы (всех потоков), поэтому когда память кончится — программа «зависнет» пока не закончит сборку. Память требуется не только для объектов в вашей программе, но и для работы самой JVM, в частности, объектами являются и потребляют память: загруженные классы; код, скомпилированный с помощью JIT; оптимизированный код.

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

Как и все остальные темы, работу с памятью в виртуальных машинах мы рассмотрим более подробно в следующих статьях. На текущем этапе должно быть понятно, что:

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

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

String bad = new String("Slower");
String good = "Faster";

Дополнительная литература по теме:

  1. Тюнинг JVM на примере одного проекта. URL: https://habr.com/en/company/luxoft/blog/174231/
  2. Java Bytecode Fundamentals. URL: https://habr.com/ru/post/111456/
  3. PGO: уход и кормление. URL: https://vk.com/for_programmer?w=wall-105242702_801
  4. Как работает JS: о внутреннем устройстве V8 и оптимизации кода. URL: https://habr.com/ru/company/ruvds/blog/337460/
  5. Martinsen, J. K., Grahn, H. (2010). An alternative optimization technique for JavaScript engines. Presented at the Third Swedish Workshop on Multi-Core Computing (MCC-10), Göteborg: Chalmers University of Technology. Retrieved from http://urn.kb.se/resolve?urn=urn:nbn:se:bth-7688
  6. Введение в технологии виртуализации.

Разница между компилятором и интерпретатором

Основание различия
Компилятор
Устный переводчик
Шаги программирования
Создайте программу.
Compile проанализирует или проанализирует все операторы языка на предмет их правильности. Если неверно, выдает ошибку
Если ошибок нет, компилятор преобразует исходный код в машинный код.
Он связывает разные файлы кода в исполняемую программу (известную как exe).
Запустить программу

Создать программу
Без связывания файлов или генерации машинного кода
Исходные операторы выполняются построчно ВО ВРЕМЯ выполнения

Преимущество Программный код уже переведен в машинный код. Таким образом, время выполнения кода меньше. Переводчиками проще пользоваться, особенно новичкам.
Недостаток Вы не можете изменить программу, не вернувшись к исходному коду. Интерпретируемые программы могут работать на компьютерах с соответствующим интерпретатором.
Машинный код Хранить машинный язык как машинный код на диске Никакого сохранения машинного кода.
Продолжительность Скомпилированный код работает быстрее Интерпретируемый код работает медленнее
Модель Он основан на языковой модели перевода ссылок-загрузки. Он основан на методе интерпретации.
Генерация программы Создает программу вывода (в виде exe), которую можно запускать независимо от исходной программы. Не генерировать программу вывода. Таким образом, они оценивают исходную программу каждый раз во время выполнения.
Исполнение Выполнение программы отделено от компиляции. Он выполняется только после того, как вся программа вывода скомпилирована. Выполнение программы является частью процесса интерпретации, поэтому оно выполняется построчно.
Требования к памяти Целевая программа выполняется независимо и не требует наличия компилятора в памяти. Во время устного перевода переводчик существует в памяти.
Лучше всего подходит для Ограничено конкретной целевой машиной и не может быть перенесено. C и C ++ — самые популярные языки программирования, использующие модель компиляции

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

В таких случаях лучше переводчики.
Оптимизация кода Компилятор видит весь код заранее. Следовательно, они выполняют множество оптимизаций, которые ускоряют работу кода. Интерпретаторы видят код построчно, поэтому оптимизации не так надежны, как компиляторы.
Динамический набор текста Сложно реализовать, поскольку компиляторы не могут предсказать, что произойдет во время очереди. Переводимые языки поддерживают динамический ввод
использование Лучше всего подходит для производственной среды. Он лучше всего подходит для программы и среды разработки.
Выполнение ошибки Компилятор отображает все ошибки и предупреждения во время компиляции. Следовательно, вы не можете запустить программу без исправления ошибок. Интерпретатор читает один оператор и показывает ошибку, если таковая имеется. Вы должны исправить ошибку, чтобы интерпретировать следующую строку.
Вход Требуется целая программа Требуется всего одна строчка кода.
Выход Compliers генерирует промежуточный код machnie. Интерпретатор никогда не генерирует какой-либо промежуточный мачный код.
Ошибки Отображать все ошибки после компиляции одновременно. Отображает все ошибки каждой строки одну за другой.
Соответствующие языки программирования C, C ++, C #, Scala, Java используют компилятор. PHP, Perl, Ruby используют интерпретатор.

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

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

Определение переводчика

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

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

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

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

AMD x86 Open64 Compiler Suite

Это версия набора компиляторов Open64 (описанного ниже), которая была настроена для процессоров AMD и имеет дополнительные исправления ошибок. Компилятор C / C++ соответствует стандартам ANSI C99 и ISO C++ 98, поддерживает межъязыковые вызовы (так как он включает в себя компилятор Fortran), 32-битный и 64-битный код x86, векторную и скалярную генерацию кода SSE / SSE2 / SSE3, OpenMP 2.5 для моделей с разделяемой памятью, MPICH2 для моделей с распределенной и разделяемой памятью; содержит оптимизатор, поддерживающий огромное количество оптимизаций (глобальную, цикл-узел, межпроцедурный анализ, обратную связь) и многое другое. Набор поставляется с оптимизированной AMD Core Math Library и документацией. Для этого набора компиляторов требуется Linux.

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

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

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

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

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

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

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

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

Достоинства

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

Недостатки

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

Эффективность

Обычно программисту не нужно разбираться в байт-коде, да и с загрузчиком проблем особых не возникает. Однако надо знать, что интерпретатор Java очень медленный, имеет стековую архитектуру (сильно отличается от вашего центрального процессора) и это сильно ослабляет эффект от распараллеливания ваших программ. Почему при этом Java-программы работают достаточно быстро? — Эффективность обеспечивают компилятор времени исполнения (Just-In-Time, JIT) и динамический профилировщик.

JIT-компилятор принимает байт-код и генерирует машинный код, который исполняется не виртуальным процессором, а реальным. За счет JIT ваши программы на Java/Python могут (теоретически) выполняться также быстро, как написанные на С++. По сути, JIT выполняет ту же работу что и компилятор C++, но делает это прямо во время выполнения программы и не для всей программы, а для так называемого Common path (основного пути исполнения). Отсюда растут ноги многих статей, показывающих, что Java-программа работает также быстро как на С++.

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

В языках типа C++ профилирование кода тоже выполняется перед компиляцией, но делают это не все программисты. Для этого программа запускается на некоторых эталонных наборах данных и собирается статистика ее выполнения. Затем, эта статистика передается оптимизатору кода. Например, если небольшая функция вызывается внутри цикла — то ее есть смысл инлайнить (подставить тело функции вместо ее вызова), если же она почти никогда не вызывается — то смысла в этом нет.

В современных интерпретаторах также встроен оптимизатор кода. Оптимизация — очень трудоемкий процесс, который в Java выполняется прямо при выполнении программы — это тормозит работу. Однако, при оптимизации учитываются результаты профилирования — за счет этого, программа на Java может оказаться более эффективной по сравнению с С++ если:

  • программа на С++ не оптимизировалась вообще или не выполнялось профилирование. Так, например, инлайнить обычно надо не более 5% функций, однако чтобы найти эти функции — нужно выполнить профилирование. Многие из читающих эту статью программистов выполняют профилирование своего кода? — Думаю не более 1%.
  • программа на С++ профилировалась на одних данных, а работает — на совершенно других. В видео рассказывается как с этим столкнулась и боролась команда Яндекс.Браузер (оказалось, что пользователи работают с браузером не так как планировали разработчики);
  • программа оптимизирована под одно железо, а запущена на совершенно другом.

По приведенным выше причинам, программы на интерпретируемых языках могут иметь сносную (на фоне компилируемых) производительность. Если на этом этапе вам уже кажется что ничего такого в вашем любимом JavaScript/Python нету — посмотрите вот эту статью , также можно найти научные изыскания вплоть до автоматического распараллеливания программ на JS .

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

Преимущества и недостатки

Преимущества компилятора

  • Программный код уже переведен в машинный, и, следовательно, требуется меньше времени на его исполнение.
  • Файлы .exe выполняются быстрее, чем исходный код. Объектные программы сохраняются и могут быть запущены в любое время.
  • Объектные программы пользователю сложнее изменить, чем исходный код.
  • Компилятор проверяет исходный код на наличие синтаксических ошибок во время компиляции.

Недостатки компилятора

  • Поскольку переводится вся программа, она использует гораздо больше памяти компьютера.
  • При работе с компилятором невозможно изменить программу, не вернувшись к исходному коду.
  • Необходимо создавать объектную программу перед окончательным исполняемым файлом. Это может занять много времени.
  • Исходный код должен быть на 100% верным для создания исполняемого файла.

Преимущества интерпретатора

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

Недостатки интерпретатора

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

Интерпретатор C / C++ Ch Embeddable (стандартная версия)

Интерпретатор C / C++, поддерживающий стандарт ISO 1990 C (C90), основные функции C99, классы C++, а также расширения к языку С, такие как вложенные функции, строковый тип и т. д. Он может быть встроен в другие приложения и аппаратные средства, использоваться в качестве языка сценариев. Код C / C++ интерпретируется напрямую без компиляции промежуточного кода. Поскольку этот интерпретатор поддерживает Linux, Windows, MacOS X, Solaris и HP-UX, созданный вами код можно перенести на любую из этих платформ. Стандартная версия бесплатна для личного, академического и коммерческого использования. Для загрузки пакета необходимо зарегистрироваться.

Природа интерпретатора

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

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

Такой код быстрее обрабатывается, и его проще написать для исполнителя (части интерпретатора, которая исполняет), который считывает байтовый код, а не код источника.

Есть интерпретаторы, для которых этот вид байтового кода имеет более важное значение. Например, язык программирования Java «запускается» на так называемой виртуальной машине

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

У меня есть эмулятор для игровой приставки NIntendo. Когда я загружаю ROM-файл Dragon Warrior, он форматируется в машинный код, который понимает только процессор NES. Но если я создаю виртуальный процессор, который интерпретирует байтовый код во время работы на другом процессоре, я могу запустить Dragon Warrior на любой машине с эмулятором.

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

Историческая справка

На заре компьютерных технологий на дизайн языка сильно повлияло решение использовать компиляцию или интерпретацию в качестве способа выполнения. Например, Smalltalk (1980), который был разработан для интерпретации во время выполнения, позволяет универсальным объектам динамически взаимодействовать друг с другом.

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

Примеры включают:

  • JavaScript
  • Perl
  • Python
  • БАЗОВЫЙ
  • Четвертый
  • Lua

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

Лакмусовые тесты

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

  • Если подпрограмма может быть вызвана до того, как она определена в исходном коде, весь исходный код, вероятно, компилируется в промежуточное представление перед выполнением. Примеры: Perl , Java
  • Если промежуточное представление (например, байт-код) обычно создается и вызывается непосредственно как отдельный шаг при выполнении кода, язык, скорее всего, будет считаться скомпилированным. Примеры: Java , C
  • Если синтаксическая ошибка в исходном коде не препятствует выполнению предыдущих операторов, скорее всего, это интерпретированная парадигма. Примеры: языки оболочки Unix

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

составление

Для написания программы необходимо выполнить следующие действия:

  1. Редактировать программу
  2. Скомпилируйте программу в файлы машинного кода.
  3. Свяжите файлы машинного кода в работающую программу (также известную как exe).
  4. Отладка или запуск программы

Для некоторых языков, таких как Turbo Pascal и Delphi, шаги 2 и 3 объединены.

Файлы машинного кода — это автономные модули машинного кода, которые требуют связывания вместе для создания окончательной программы. Причиной наличия отдельных файлов машинного кода является эффективность; компиляторы должны только перекомпилировать исходный код, который изменился. Файлы машинного кода из неизмененных модулей используются повторно. Это известно как создание приложения. Если вы хотите перекомпилировать и пересобрать весь исходный код, это называется сборкой.

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

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

Примечание по байт-коду

Как и в случае с машинным кодом, не все компьютеры понимают байт-код. Чтобы интерпретировать его на машиночитаемый язык, необходимо промежуточное ПО, такое как виртуальная машина, или движок (например, Javascript V8). По этой причине браузеры могут выполнять этот байт-код из интерпретатора во время вышеупомянутых 5-ти стадий с помощью движков JavaScript.

В результате возникает следующий вопрос:

Является ли JavaScript интерпретируемым языком?

Да, но не совсем. На ранних этапах JavaScript Брендан Айк создал движок JavaScript ‘SpiderMonkey’. У движка был интерпретатор, который говорил браузеру, что нужно делать. Сейчас есть не только интерпретаторы, но и компиляторы, а код не только интерпретируется, но и компилируется для оптимизации. Технически все зависит от реализации.

  • Прототипирование для Vue(Opens in a new browser tab)
  • Как не лажать с JavaScript. Часть 1
  • JavaScript async/await: что хорошего, в чём опасность и как применять?

Перевод статьи Mano lingam: JavaScript: Under the Hood

Ключевые различия между компилятором и интерпретатором

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

  1. Компилятор берет программу в целом и переводит ее, а интерпретатор переводит оператор программы за оператором.
  2. Промежуточный код или целевой код создается в случае компилятора. В отличие от интерпретатора, не создает промежуточный код.
  3. Компилятор сравнительно быстрее, чем интерпретатор, поскольку компилятор берет всю программу за один раз, тогда как интерпретаторы компилируют каждую строку кода за другой.
  4. Компилятору требуется больше памяти, чем интерпретатору, из-за генерации объектного кода.
  5. Компилятор представляет все ошибки одновременно, и трудно обнаружить ошибки в контрастных ошибках отображения интерпретатора каждого оператора по очереди, и легче обнаружить ошибки.
  6. В компиляторе при возникновении ошибки в программе он останавливает ее перевод, и после устранения ошибки вся программа переводится заново. Напротив, когда в интерпретаторе возникает ошибка, он предотвращает его перевод, и после устранения ошибки перевод возобновляется.
  7. В компиляторе процесс требует двух шагов, на которых сначала исходный код транслируется в целевую программу, а затем выполняется. В интерпретаторе Это одноэтапный процесс, в котором исходный код компилируется и выполняется одновременно.
  8. Компилятор используется в таких языках программирования, как C, C ++, C #, Scala и т. Д. С другой стороны, интерпретатор используется в таких языках, как PHP, Ruby, Python и т. Д.

Введите Java и C #

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

Java при компиляции создает байт-код, который интерпретируется во время выполнения виртуальной машиной Java (JVM). Многие JVM используют компилятор Just-In-Time, который преобразует байт-код в машинный код, а затем запускает этот код для увеличения скорости интерпретации. Фактически исходный код Java компилируется в два этапа.

C # скомпилирован в Common Intermediate Language (CIL, который ранее был известен как Microsoft Intermediate Language MSIL). Он запускается в Common Language Runtime (CLR), части .NET Framework, среды, которая предоставляет службы поддержки, такие как сборка мусора и Just -Временная компиляция.

И Java, и C # используют методы ускорения, поэтому эффективная скорость почти такая же, как у скомпилированного языка.

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

Вывод

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

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

Заключение

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

Для меня не имеет значения, скомпилировано что-то или интерпретировано, если оно может выполнить задачу эффективно.

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

Сообщите мне, что бы вы предпочли: интерпретацию или компиляцию? Спасибо за уделенное время!

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Adblock
detector