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

Содержание:

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

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

Компилятор

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

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

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

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

Переводчик

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

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

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

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

• Перед выполнением вся программа выполняется компилятором, тогда как после перевода первой строки ее выполняет интерпретатор и так далее.

• Список ошибок создается компилятором после процесса компиляции, а интерпретатор прекращает перевод после первой ошибки.

• Независимый исполняемый файл создается компилятором, тогда как интерпретатор требуется интерпретируемой программе каждый раз.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Часто задаваемые вопросы

Лучше учить C++ вместо Python?

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

Если вас интересует системное или низкоуровневое программирование, то обратите внимание на C++

Если же ближе машинное обучение, то Python подойдет больше. Также можно познакомиться с веб-программированием на примере Ruby, JavaScript, Angular и так далее.

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

Python лучше чем C++

Да. Если говорить о простоте синтаксиса и легкости освоения. Python можно взять просто для того, чтобы познакомиться с программированием. Там нет точек с запятой, указателей, шаблонов, STL, типов и так далее.

Если вы хотите познакомиться с основами программирования, то Python явно лучше C++. Однако последний выигрывает в плане производительности, скорости работы, широты применения и так далее.

Может ли Python заменить C++

Нет. C и C++ образуют основу программирования. По сути, даже Python построен на базе C. Поэтому не может быть такого, что Python заменит один из этих языков.

Он может оказаться впереди в тех сферах, где нет взаимодействия с устройствами, производительности, серьезного управления ресурсами и так далее.

Что лучше, если выбирать из C++, Python и Java

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

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

Почему C++ быстрее Python

По следующим причинам:

  • Хороший C++ код исполняется в CPU быстрее, чем Python
  • Нет этапа интерпретации, когда каждое выражение построчно оценивается
  • Нет постоянно работающего сборщика мусора
  • Есть больше контроля над системными вызовами
  • Можно запросто писать машинный код

Это все и влияет на более высокую производительность кода C++. Вот что влияет на более медленную работу Python:

  • Язык интерпретируется, а не компилируется
  • В Python нет примитивов. Все представлено в виде объектов встроенных типов
  • Списки содержат объекты разных типов. Это требует дополнительного места для определения будущих элементов в списке

За и против

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

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

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

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

Другим преимуществом интерпретаторов является то, что их проще переписать или перекомпилировать для новых платформ.

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

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

Это проблема для конкретных real-time приложений, таких как игры с высоким разрешением и симуляцией. Некоторые интерпретаторы содержат компоненты, которые называются just-in-time компиляторами (JIT). Они компилируют программу непосредственно перед ее исполнением. Это специальные программы, вынесенные за рамки интерпретатора. Но поскольку процессоры становятся все более мощными, данная проблема становится менее актуальной.

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

Достоинства

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

Недостатки

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

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

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

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

Как и в случае с машинным кодом, не все компьютеры понимают байт-код. Чтобы интерпретировать его на машиночитаемый язык, необходимо промежуточное ПО, такое как виртуальная машина, или движок (например, 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

Введите 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 # используют методы ускорения, поэтому эффективная скорость почти такая же, как у скомпилированного языка.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Мы дошли одновременно до практически самой простой и самой муторной части. Простая она, потому что всего лишь описывает превращение слов языка в наши токены. А муторная, потому что лексеры (а может, только окамловский лексер) плохо рассчитаны на работу с русским языком, поэтому работать с русскими символами можно только как со строками. Так как я хотел сделать ключевые слова языка регистро-независимыми, это добавило кучу геморроя — вместо простого написания «дай» надо было расписывать вариант написания каждой буквы. В общем, смотрите сами, файл 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 }
Добавить комментарий

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

Adblock
detector