В информатике , переводчик это компьютерная программа , которая непосредственно выполняет инструкции , написанные в программировании или сценариев языка , не требуя от них ранее были составлены на машинном языке программы. Интерпретатор обычно использует одну из следующих стратегий для выполнения программы:
- Разбираем в исходный код и выполнить его поведение непосредственно;
- Преобразуйте исходный код в какое-нибудь эффективное промежуточное представление и немедленно выполните его;
- Явно выполнить сохраненный предварительно скомпилированный код [1], созданный компилятором, который является частью системы интерпретатора.
Ранние версии языка программирования Lisp и диалекты BASIC для мини-компьютеров и микрокомпьютеров будут примерами первого типа. Perl , Python , MATLAB и Ruby являются примерами второго типа, а UCSD Pascal - примером третьего типа. Исходные программы компилируются заранее и сохраняются как машинно-независимый код, который затем связывается во время выполнения и выполняется интерпретатором и / или компилятором (для систем JIT ). Некоторые системы, такие как Smalltalk и современные версии BASIC и Java, также могут сочетать два и три. [2] Интерпретаторы различных типов также были созданы для многих языков, традиционно связанных с компиляцией, таких как Algol , Fortran , Cobol , C и C ++ .
Хотя интерпретация и компиляция являются двумя основными средствами, с помощью которых реализуются языки программирования, они не исключают друг друга, поскольку большинство систем интерпретации также выполняют некоторую работу по переводу, как и компиляторы. Термины «интерпретируемый язык» или « компилируемый язык » означают, что канонической реализацией этого языка является интерпретатор или компилятор, соответственно. В идеале язык высокого уровня - это абстракция, независимая от конкретных реализаций.
История
Интерпретаторы использовались еще в 1952 году, чтобы упростить программирование в рамках ограничений компьютеров того времени (например, нехватка места для хранения программ или отсутствие встроенной поддержки чисел с плавающей запятой). Интерпретаторы также использовались для перевода между низкоуровневыми машинными языками, что позволяло писать код для машин, которые все еще находились в стадии разработки, и тестировать на уже существующих компьютерах. [3] Первым интерпретируемым языком высокого уровня был Lisp . Лисп был впервые реализован в 1958 году Стивом Расселом на компьютере IBM 704 . Рассел прочитал статью Джона Маккарти и понял (к удивлению Маккарти), что функция eval Лиспа может быть реализована в машинном коде. [4] Результатом стал работающий интерпретатор Лиспа, который можно было использовать для запуска программ на Лиспе или, точнее, «оценки выражений Лиспа».
Компиляторы против интерпретаторов
Программы, написанные на языке высокого уровня , либо напрямую выполняются каким-либо интерпретатором, либо преобразуются в машинный код компилятором (а также ассемблером и компоновщиком ) для выполнения ЦП .
Хотя компиляторы (и ассемблеры) обычно создают машинный код, непосредственно исполняемый аппаратным обеспечением компьютера, они часто (необязательно) могут создавать промежуточную форму, называемую объектным кодом . Это в основном тот же машинно-зависимый код, но дополненный таблицей символов с именами и тегами, чтобы сделать исполняемые блоки (или модули) идентифицируемыми и перемещаемыми. Скомпилированные программы обычно используют строительные блоки (функции), хранящиеся в библиотеке таких модулей объектного кода. Линкер используется для объединения (готовый) файлы библиотек с объектным файлом (ы) приложений , чтобы сформировать единый исполняемый файл. Таким образом, объектные файлы, которые используются для создания исполняемого файла, часто создаются в разное время, а иногда даже на разных языках (способных генерировать один и тот же формат объекта).
Простой интерпретатор, написанный на языке низкого уровня (например, ассемблере ), может иметь аналогичные блоки машинного кода, реализующие функции языка высокого уровня, которые хранятся и выполняются, когда запись функции в таблице поиска указывает на этот код. Однако интерпретатор, написанный на языке высокого уровня, обычно использует другой подход, такой как создание и последующий обход дерева синтаксического анализа , или создание и выполнение промежуточных программно определяемых инструкций, или и то, и другое.
Таким образом, и компиляторы, и интерпретаторы обычно превращают исходный код (текстовые файлы) в токены, оба могут (или не могут) генерировать дерево синтаксического анализа, и оба могут генерировать немедленные инструкции (для стековой машины , учетверенного кода или другими способами). Основное отличие состоит в том, что система компилятора, включая (встроенный или отдельный) компоновщик, генерирует автономную программу машинного кода , а система интерпретатора вместо этого выполняет действия, описанные программой высокого уровня.
Таким образом, компилятор может выполнить почти все преобразования семантики исходного кода на машинный уровень раз и навсегда (т.е. до тех пор, пока программа не будет изменена), в то время как интерпретатор должен выполнять часть этой работы по преобразованию каждый раз, когда выполняется инструкция или функция. . Однако в эффективном интерпретаторе большая часть работы по переводу (включая анализ типов и т. Д.) Выносится за скобки и выполняется только при первом запуске программы, модуля, функции или даже оператора, что очень похоже на то, как компилятор работает. Однако скомпилированная программа по-прежнему работает намного быстрее, в большинстве случаев, отчасти потому, что компиляторы предназначены для оптимизации кода, и для этого может быть предоставлено достаточно времени. Это особенно верно для более простых языков высокого уровня без (многих) динамических структур данных, проверок или проверки типов .
При традиционной компиляции исполняемый вывод компоновщиков (файлы .exe, файлы .dll или библиотеки, см. Рисунок) обычно можно перемещать при запуске в общей операционной системе, как и модули объектного кода, но с той разницей, что это перемещение выполняется динамически во время выполнения, то есть когда программа загружается для выполнения. С другой стороны, скомпилированные и связанные программы для небольших встроенных систем обычно размещаются статически, часто жестко запрограммированы во флэш- памяти NOR , поскольку в этом смысле часто нет вторичного хранилища и операционной системы.
Исторически сложилось так, что большинство систем интерпретаторов имели встроенный автономный редактор. Это становится все более распространенным также для компиляторов (тогда часто называемых IDE ), хотя некоторые программисты предпочитают использовать редактор по своему выбору и запускать компилятор, компоновщик и другие инструменты вручную. Исторически компиляторы предшествовали интерпретаторам, потому что оборудование в то время не могло поддерживать и интерпретатор, и интерпретируемый код, а типичная пакетная среда того времени ограничивала преимущества интерпретации. [5]
Цикл разработки
Во время цикла разработки программного обеспечения программисты часто вносят изменения в исходный код. При использовании компилятора каждый раз, когда в исходный код вносятся изменения, они должны ждать, пока компилятор переведет измененные исходные файлы и свяжет все файлы двоичного кода вместе, прежде чем программа сможет быть выполнена. Чем больше программа, тем дольше ожидание. Напротив, программист, использующий интерпретатор, ожидает намного меньше, поскольку интерпретатору обычно просто нужно перевести код, над которым выполняется работа, в промежуточное представление (или не переводить его вообще), что требует гораздо меньше времени, прежде чем изменения могут быть проверено. Эффекты очевидны при сохранении исходного кода и перезагрузке программы. Скомпилированный код, как правило, труднее отлаживать, поскольку редактирование, компиляция и компоновка - это последовательные процессы, которые должны выполняться в правильной последовательности с правильным набором команд. По этой причине многие компиляторы также имеют вспомогательное средство управления, известное как файл и программа Make . В файле Make file перечислены командные строки компилятора и компоновщика и файлы исходного кода программы, но он может принимать простой ввод в меню командной строки (например, «Make 3»), который выбирает третью группу (набор) инструкций, затем выдает команды компилятору и компоновщик, загружающий указанные файлы исходного кода.
Распределение
Компилятор преобразует исходный код в двоичные инструкции для архитектуры конкретного процессора, что делает его менее портативным . Это преобразование выполняется только один раз в среде разработчика, и после этого тот же двоичный файл может быть распространен на компьютеры пользователя, где он может быть выполнен без дальнейшего преобразования. Кросс - компилятор может генерировать двоичный код для машины пользователя , даже если он имеет другой процессор , чем машины , на которой скомпилированный код.
Интерпретируемая программа может распространяться как исходный код. Его необходимо транслировать на каждой конечной машине, что занимает больше времени, но делает распространение программы независимым от архитектуры машины. Однако переносимость интерпретируемого исходного кода зависит от того, действительно ли целевая машина имеет подходящий интерпретатор. Если интерпретатор должен поставляться вместе с исходным кодом, общий процесс установки более сложен, чем доставка монолитного исполняемого файла, поскольку сам интерпретатор является частью того, что необходимо установить.
Тот факт, что интерпретируемый код может быть легко прочитан и скопирован людьми, может вызывать озабоченность с точки зрения авторского права . Однако существуют различные системы шифрования и обфускации . Доставка промежуточного кода, такого как байт-код, имеет тот же эффект, что и обфускация, но байт-код может быть декодирован с помощью декомпилятора или дизассемблера . [ необходима цитата ]
Эффективность
Основным недостатком интерпретаторов является то, что интерпретируемая программа обычно работает медленнее, чем если бы она была скомпилирована . Разница в скоростях может быть крошечной или большой; часто на порядок, а иногда и больше. Обычно для запуска программы под интерпретатором требуется больше времени, чем для запуска скомпилированного кода, но для ее интерпретации может потребоваться меньше времени, чем общее время, необходимое для ее компиляции и запуска. Это особенно важно при прототипировании и тестировании кода, когда цикл редактирования-интерпретации-отладки часто может быть намного короче, чем цикл редактирования-компиляции-запуска-отладки. [ необходима цитата ]
Интерпретация кода медленнее, чем запуск скомпилированного кода, потому что интерпретатор должен анализировать каждый оператор в программе каждый раз, когда он выполняется, а затем выполнять желаемое действие, тогда как скомпилированный код просто выполняет действие в фиксированном контексте, определяемом компиляцией. Такой анализ во время выполнения известен как «интерпретационные издержки». Доступ к переменным также медленнее в интерпретаторе, потому что отображение идентификаторов в места хранения должно выполняться многократно во время выполнения, а не во время компиляции . [ необходима цитата ]
Существуют различные компромиссы между скоростью разработки при использовании интерпретатора и скоростью выполнения при использовании компилятора. Некоторые системы (например, некоторые Lisps ) позволяют интерпретируемому и скомпилированному коду вызывать друг друга и совместно использовать переменные. Это означает, что после того, как подпрограмма была протестирована и отлажена в интерпретаторе, она может быть скомпилирована и, таким образом, получит выгоду от более быстрого выполнения, пока другие подпрограммы разрабатываются. [ необходима цитата ] Многие интерпретаторы не выполняют исходный код в его нынешнем виде, а преобразуют его в более компактную внутреннюю форму. Многие BASIC переводчики заменяют ключевые слова с одиночными байтовых лексем , которые могут быть использованы , чтобы найти инструкции в таблице переходов . Некоторые интерпретаторы, такие как интерпретатор PBASIC , достигают еще более высоких уровней сжатия программ за счет использования побитно-ориентированной, а не побайтовой структуры памяти программ, где токены команд занимают, возможно, 5 бит, номинально сохраняются «16-битные» константы. в коде переменной длины, требующем 3, 6, 10 или 18 битов, и операнды адреса включают «битовое смещение». Многие интерпретаторы BASIC могут сохранять и считывать собственное токенизированное внутреннее представление.
Интерпретатор выражений Toy C |
---|
// типы данных для абстрактного синтаксического дерева enum _kind { kVar , kConst , kSum , kDiff , kMult , kDiv , kPlus , kMinus , kNot }; struct _variable { int * память ; }; struct _constant { значение int ; }; struct _unaryOperation { struct _node * right ; }; struct _binaryOperation { struct _node * left , * right ; }; struct _node { enum _kind kind ; объединение _expression { STRUCT _variable переменного ; struct _constant constant ; struct _binaryOperation binary ; struct _unaryOperation unary ; } e ; }; // процедура интерпретатора int executeIntExpression ( const struct _node * n ) { int leftValue , rightValue ; switch ( n -> kind ) { case kVar : return * n -> e . переменная . память ; case kConst : вернуть n -> e . постоянный . значение ; case kSum : case kDiff : case kMult : case kDiv : leftValue = executeIntExpression ( n -> e . двоичный . left ); rightValue = executeIntExpression ( n -> e . двоичное . право ); переключатель ( n -> вид ) { case kSum : return leftValue + rightValue ; case kDiff : return leftValue - rightValue ; case kMult : return leftValue * rightValue ; case kDiv : if ( rightValue == 0 ) исключение ( «деление на ноль» ); // не возвращает return leftValue / rightValue ; } case kPlus : case kMinus : case kNot : rightValue = executeIntExpression ( n -> e . unary . right ); переключатель ( n -> вид ) { case kPlus : return + rightValue ; case kMinus : return - rightValue ; case kNot : return ! rightValue ; } по умолчанию : исключение ( «внутренняя ошибка: недопустимый вид выражения» ); } } |
Интерпретатор вполне может использовать тот же лексический анализатор и синтаксический анализатор, что и компилятор, а затем интерпретировать результирующее абстрактное синтаксическое дерево . Примеры определений типов данных для последнего и игрушечный интерпретатор для синтаксических деревьев, полученных из выражений C , показаны в поле.
Регресс
Интерпретация не может использоваться как единственный метод выполнения: хотя интерпретатор сам может быть интерпретирован и т. Д., Непосредственно выполняемая программа необходима где-то в нижней части стека, потому что интерпретируемый код по определению не совпадает с машинный код, который может выполнять ЦП. [6] [7]
Вариации
Интерпретаторы байт-кода
Существует целый спектр возможностей между интерпретацией и компиляцией, в зависимости от объема анализа, выполненного перед выполнением программы. Например, Emacs Lisp компилируется в байт-код , который представляет собой сильно сжатое и оптимизированное представление исходного кода Lisp, но не является машинным кодом (и поэтому не привязан к какому-либо конкретному оборудованию). Этот "скомпилированный" код затем интерпретируется интерпретатором байт-кода (сам написан на C ). Скомпилированный код в данном случае представляет собой машинный код для виртуальной машины , который реализован не аппаратно, а в интерпретаторе байт-кода. Такие компилирующие интерпретаторы иногда также называют компиляторами . [8] [9] В интерпретаторе байт-кода каждая инструкция начинается с байта, и поэтому интерпретаторы байт-кода имеют до 256 инструкций, хотя не все могут использоваться. Некоторые байт-коды могут занимать несколько байтов и могут быть произвольно сложными.
Таблицы управления, которым не обязательно когда-либо проходить этап компиляции, диктуют соответствующий алгоритм алгоритмического управления через настраиваемые интерпретаторы аналогично интерпретаторам байт-кода.
Потоковые интерпретаторы кода
Интерпретаторы потокового кода похожи на интерпретаторы байт-кода, но вместо байтов они используют указатели. Каждая «инструкция» - это слово, указывающее на функцию или последовательность инструкций, за которым, возможно, следует параметр. Интерпретатор многопоточного кода либо зацикливает выборку инструкций и вызов функций, на которые они указывают, либо выбирает первую инструкцию и переходит к ней, и каждая последовательность инструкций заканчивается выборкой и переходом к следующей инструкции. В отличие от байт-кода нет эффективного ограничения на количество различных инструкций, кроме доступной памяти и адресного пространства. Классическим примером многопоточного кода является код Forth, используемый в системах Open Firmware : исходный язык компилируется в «F-код» (байт-код), который затем интерпретируется виртуальной машиной . [ необходима цитата ]
Интерпретаторы абстрактного синтаксического дерева
В диапазоне между интерпретацией и компиляцией существует другой подход: преобразовать исходный код в оптимизированное абстрактное синтаксическое дерево (AST), затем выполнить программу, следуя этой древовидной структуре, или использовать ее для генерации собственного кода точно в срок . [10] При таком подходе каждое предложение нужно анализировать только один раз. В качестве преимущества перед байт-кодом AST сохраняет глобальную структуру программы и отношения между операторами (которые теряются в представлении байт-кода), а при сжатии обеспечивает более компактное представление. [11] Таким образом, использование AST было предложено как лучший промежуточный формат для оперативных компиляторов, чем байт-код. Кроме того, это позволяет системе выполнять лучший анализ во время выполнения.
Однако для интерпретаторов AST вызывает больше накладных расходов, чем интерпретатор байт-кода, из-за узлов, связанных с синтаксисом, не выполняющих полезной работы, менее последовательного представления (требующего обхода большего количества указателей) и накладных расходов на посещение дерева. [12]
Своевременная компиляция
Еще больше стирает различие между интерпретаторами, интерпретаторами байт-кода и компиляцией - это JIT-компиляция, метод, при котором промежуточное представление компилируется в собственный машинный код во время выполнения. Это обеспечивает эффективность выполнения собственного кода за счет времени запуска и увеличения использования памяти при первой компиляции байт-кода или AST. Самый ранний опубликованные JIT компилятор , как правило , связан с работой на LISP от Джона Маккарти в 1960 г. [13] оптимизаций адаптивных является дополнительной техникой , в которой интерпретатор профилей в выполняемой программе и компилирует его наиболее часто выполняемые части в машинный код. Последнему методу несколько десятилетий, и он появился в таких языках, как Smalltalk, в 1980-х годах. [14]
Компиляция «точно в срок» в последние годы привлекла к себе всеобщее внимание разработчиков языков: Java , .NET Framework , большинство современных реализаций JavaScript и Matlab теперь включают JIT-компиляторы. [ необходима цитата ]
Интерпретатор шаблонов
Еще более расплывчатое различие между компиляторами и интерпретаторами делает особая конструкция интерпретатора, известная как интерпретатор шаблонов. Вместо того, чтобы реализовывать выполнение кода с помощью большого оператора switch, содержащего все возможные байт-коды, при работе с программным стеком или обходом дерева, интерпретатор шаблона поддерживает большой массив байт-кода (или любое эффективное промежуточное представление), отображаемый непосредственно на соответствующие машинные инструкции, которые могут быть выполнены на аппаратном обеспечении хоста как пары ключ-значение [15] [16], известные как «Шаблон». Когда выполняется конкретный сегмент кода, интерпретатор просто загружает отображение кода операции в шаблоне и напрямую запускает его на оборудовании. [17] [18] Из-за своей конструкции интерпретатор шаблонов очень сильно напоминает Just-in Time Compiler, а не традиционный интерпретатор, однако технически это не так из-за того, что он просто переводит код с языка в собственные вызовы. один код операции за раз, а не создание оптимизированных последовательностей исполняемых инструкций ЦП из всего сегмента кода. Из-за простой конструкции интерпретатора, заключающейся в простой передаче вызовов непосредственно на оборудование, а не к их непосредственной реализации, он намного быстрее, чем любой другой тип, даже интерпретаторы байт-кода, и в некоторой степени менее подвержен ошибкам, но в качестве компромисса труднее поддерживать из-за того, что интерпретатор должен поддерживать перевод на несколько разных архитектур вместо независимой от платформы виртуальной машины / стека. На сегодняшний день единственная существующая реализация Template Interpreter языка - это Interpreter в эталонной реализации виртуальной машины Java HotSpot / OpenJDK. [15]
Самостоятельный переводчик
Самоинтерпретатор - это интерпретатор языка программирования, написанный на языке программирования, который может интерпретировать сам себя; пример - интерпретатор BASIC, написанный на BASIC. Самоинтерпретаторы относятся к компиляторам, размещающим на собственном хостинге .
Если для интерпретируемого языка не существует компилятора , создание самоинтерпретатора требует реализации языка на основном языке (который может быть другим языком программирования или ассемблером ). При наличии первого интерпретатора, такого как этот, система загружается, и новые версии интерпретатора могут быть разработаны на самом языке. Таким образом, Дональд Кнут разработал интерпретатор TANGLE для языка WEB промышленной стандартной системы набора текста TeX .
Определение компьютерного языка обычно выполняется в отношении абстрактной машины (так называемая операционная семантика ) или как математическая функция ( денотационная семантика ). Язык также может быть определен интерпретатором, в котором задана семантика основного языка. Определение языка самоинтерпретатором не является обоснованным (он не может определять язык), но самоинтерпретатор рассказывает читателю о выразительности и элегантности языка. Это также позволяет интерпретатору интерпретировать его исходный код, что является первым шагом к рефлексивной интерпретации.
Важным аспектом проектирования при реализации самоинтерпретатора является то, реализована ли функция интерпретируемого языка с той же функцией на основном языке интерпретатора. Примером может быть реализация замыкания на языке, подобном Lisp, с использованием замыканий на языке интерпретатора или реализация «вручную» с помощью структуры данных, явно хранящей среду. Чем больше возможностей реализовано одной и той же функцией на основном языке, тем меньше возможностей у программиста интерпретатора; другое поведение при работе с переполнением чисел не может быть реализовано, если арифметические операции делегированы соответствующим операциям на главном языке.
Некоторые языки, такие как Lisp и Prolog, имеют элегантные самоинтерпретаторы. [19] Многие исследования самоинтерпретаторов (особенно рефлексивных интерпретаторов) проводились на языке программирования Scheme , диалекте Lisp. В целом, однако, любой полный по Тьюрингу язык позволяет писать собственный интерпретатор. Лисп является таким языком, потому что программы на Лиспе представляют собой списки символов и другие списки. XSLT является таким языком, потому что программы XSLT написаны на XML. Суб-домен метапрограммированием является написание предметно-ориентированных языков (DSL).
Клайв Гиффорд ввел [20] критерий качества самоинтерпретатора (собственное отношение), предел отношения между компьютерным временем, затраченным на выполнение стека из N самоинтерпретаторов, и временем, затраченным на запуск стека из N - 1 самоинтерпретаторов, как N уходит в бесконечность. Это значение не зависит от запущенной программы.
В книге « Структура и интерпретация компьютерных программ» представлены примеры мета-круговой интерпретации схемы и ее диалектов. Другими примерами языков с самоинтерпретатором являются Forth и Pascal .
Микрокод
Микрокод - это очень часто используемый метод, «который устанавливает интерпретатор между аппаратным обеспечением и архитектурным уровнем компьютера». [21] Таким образом, микрокод является слоем инструкций аппаратного уровня, которые реализуют инструкции машинного кода более высокого уровня или внутреннее автоматическое упорядочение во многих элементах цифровой обработки . Микрокода используется в универсальных центральных процессоров , а также в более специализированных процессоров , таких как микроконтроллеров , цифровых сигнальных процессоров , контроллеров каналов , дисковых контроллеров , интерфейсных контроллеров сети , сетевых процессоров , графических процессоров , а в другом оборудовании.
Микрокод обычно находится в специальной высокоскоростной памяти и преобразует машинные инструкции, данные конечного автомата или другие входные данные в последовательности подробных операций на уровне схемы. Он отделяет машинные инструкции от базовой электроники, так что инструкции могут быть разработаны и изменены более свободно. Это также облегчает построение сложных многоступенчатых инструкций, уменьшая при этом сложность компьютерных схем. Запись микрокода часто называется микропрограммированием, а микрокод в конкретной реализации процессора иногда называют микропрограммой .
Более обширный microcoding позволяет маленькие и простые микроархитектуры для эмуляции более мощных архитектур с широкой разрядностью , больше исполнительных блоками и так далее, что является относительно простым способом для достижения совместимости программного обеспечения между различными продуктами в семействе процессоров.
Компьютерный процессор
Даже компьютерный процессор без микрокодирования может рассматриваться как интерпретатор немедленного выполнения синтаксического анализа, написанный на языке описания оборудования общего назначения, таком как VHDL, для создания системы, которая анализирует инструкции машинного кода и немедленно их выполняет.
Приложения
- Интерпретаторы часто используются для выполнения командных языков и склеивания языков, поскольку каждый оператор, выполняемый на командном языке, обычно является вызовом сложной процедуры, такой как редактор или компилятор. [ необходима цитата ]
- Самомодифицирующийся код можно легко реализовать на интерпретируемом языке. Это относится к истокам интерпретации в Lisp и исследованиях искусственного интеллекта . [ необходима цитата ]
- Виртуализация . Машинный код, предназначенный для аппаратной архитектуры, можно запускать с помощью виртуальной машины . Это часто используется, когда предполагаемая архитектура недоступна, или, среди прочего, для запуска нескольких копий.
- Песочница : хотя некоторые типы песочниц полагаются на защиту операционной системы, часто используется интерпретатор или виртуальная машина. Фактическая архитектура оборудования и изначально предполагаемая архитектура оборудования могут совпадать, а могут и не совпадать. Это может показаться бессмысленным, за исключением того, что песочницы не обязаны фактически выполнять все инструкции исходного кода, которые они обрабатывают. В частности, он может отказаться выполнять код, нарушающий любые ограничения безопасности, с которыми он работает. [ необходима цитата ]
- Эмуляторы для запуска компьютерного программного обеспечения, написанного для устаревшего и недоступного оборудования на более современном оборудовании.
Смотрите также
- БЕЙСИК-интерпретатор
- Интерпретатор командной строки
- Скомпилированный язык
- Динамическая компиляция
- Мета-круговой оценщик
- Частичная оценка
- Гомоиконность
Рекомендации
- ^ В этом смысле ЦП также является интерпретатором машинных инструкций.
- ^ Хотя эта схема (объединение стратегии 2 и 3) использовалась для реализации некоторых интерпретаторов BASIC уже в 1970-х, таких как, например, эффективный интерпретатор BASIC ABC 80 .
- ^ Беннетт, JM; Prinz, DG; Вудс, ML (1952). «Интерпретативные подпрограммы». Материалы Национальной конференции ACM, Торонто .
- ↑ Согласно сообщениям Пола Грэма в Hackers & Painters , стр. 185, Маккарти сказал: «Стив Рассел сказал:« Послушайте, почему бы мне не запрограммировать этот eval ... », и я сказал ему, хо-хо, вы путаете теорию с практикой, этот eval предназначен для чтения, а не для вычислений. Но он пошел дальше и сделал это. То есть он скомпилировал eval в моей статье вмашинный код IBM 704 , исправив ошибку , а затем объявил это как интерпретатор Лиспа, что, безусловно, так и было. по сути та форма, которую она имеет сегодня ... "
- ^ «Почему первый компилятор был написан до первого интерпретатора?» . Ars Technica . Проверено 9 ноября 2014 .
- ^ Теодор Х. Ромер, Деннис Ли, Джеффри М. Фолькер, Алек Вольман, Уэйн А. Вонг, Жан-Лу Бэр, Брайан Н. Бершад и Генри М. Леви, Структура и работа переводчиков
- ^ Terence Парр, Johannes Luber, разница между компиляторами и интерпретаторами Архивированными 2014-01-06 в Wayback Machine
- ^ Кюнель, Клаус (1987) [1986]. «4. Kleincomputer - Eigenschaften und Möglichkeiten» [4. Микрокомпьютер - Свойства и возможности. В Эрлекампфе, Райнер; Мёнк, Ханс-Иоахим (ред.). Mikroelektronik in der Amateurpraxis [ Микроэлектроника для практического любителя ] (на немецком языке) (3-е изд.). Берлин: Militärverlag der Deutschen Demokratischen Republik , Лейпциг. п. 222. ISBN. 3-327-00357-2. 7469332.
- ^ Хейн, Р. (1984). "Basic-Compreter für U880" [BASIC compreter for U880 (Z80)]. радио-fernsehn-elektronik (на немецком языке). 1984 (3): 150–152.
- ^ Промежуточные представления AST , форум Lambda The Ultimate
- ^ Кистлер, Томас; Франц, Майкл (февраль 1999 г.). «Древовидная альтернатива байт-кодам Java» (PDF) . Международный журнал параллельного программирования . 27 (1): 21–33. CiteSeerX 10.1.1.87.2257 . DOI : 10,1023 / A: 1018740018601 . ISSN 0885-7458 . S2CID 14330985 . Проверено 20 декабря 2020 .
- ^ Surfin 'Safari - Архив блога »Объявление о SquirrelFish . Webkit.org (02.06.2008). Проверено 10 августа 2013.
- ^ Эйкок 2003 , 2. JIT ГААП, 2,1 Genesis, стр. 98.
- ^ Л. Дойч, А. Шиффман, Эффективная реализация системы Smalltalk-80 , Труды 11-го симпозиума POPL, 1984.
- ^ а б "openjdk / jdk" . GitHub .
- ^ https://openjdk.java.net/groups/hotspot/docs/RuntimeOverview.html#Interpreter
- ^ «Демистификация JVM: варианты JVM, Cppinterpreter и TemplateInterpreter» . metebalci.com .
- ^ «Интерпретатор шаблонов JVM» . Программист искал .
- ^ Бондорф, Андерс. « Logimix: самоприменимый частичный оценщик для Prolog ». Синтез и преобразование логических программ. Springer, London, 1993. 214-227.
- ^ Гиффорд, Клайв. «Собственные отношения самоинтерпретаторов» . Блогер . Проверено 10 ноября 2019 .
- ^ Кент, Аллен; Уильямс, Джеймс Г. (5 апреля 1993 г.). Энциклопедия компьютерных наук и технологий: Том 28 - Приложение 13 . Нью-Йорк: ISBN Marcel Dekker, Inc. 0-8247-2281-7. Проверено 17 января, 2016 .
Внешние ссылки
- Страница IBM Card Interpreters в Колумбийском университете
- Теоретические основы практического «полностью функционального программирования» (особенно глава 7). Докторская диссертация, посвященная проблеме формализации того, что такое интерпретатор.
- Короткая анимация, объясняющая основные концептуальные различия между интерпретаторами и компиляторами.