stringtranslate.com

Переводчик (компьютерный)

Интерпретатор W3sDesign Шаблон проектирования UML

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

  1. Разобрать исходный код и напрямую выполнить его поведение;
  2. Перевести исходный код в какое-нибудь эффективное промежуточное представление или объектный код и немедленно выполнить его;
  3. Явно выполнить сохраненный предварительно скомпилированный байт-код [1] , созданный компилятором и сопоставленный с виртуальной машиной интерпретатора .

Ранние версии языка программирования Lisp и диалектов BASIC для мини- и микрокомпьютеров могут быть примерами первого типа. Perl , Raku , Python , MATLAB и Ruby являются примерами второго типа, а UCSD Pascal — примером третьего типа. Исходные программы компилируются заранее и сохраняются как машинно-независимый код, который затем компонуется во время выполнения и выполняется интерпретатором и/или компилятором (для систем JIT ). Некоторые системы, такие как Smalltalk и современные версии BASIC и Java , также могут сочетать два и три. [2] Интерпретаторы различных типов также были созданы для многих языков, традиционно связанных с компиляцией, таких как Algol , Fortran , Cobol , C и C++ .

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

История

Интерпретаторы использовались еще в 1952 году для облегчения программирования в рамках ограничений компьютеров того времени (например, нехватки места для хранения программ или отсутствия встроенной поддержки чисел с плавающей запятой). Интерпретаторы также использовались для перевода между машинными языками низкого уровня, что позволяло писать код для машин, которые все еще находились в стадии разработки, и тестироваться на уже существовавших компьютерах. [3] Первым интерпретируемым языком высокого уровня был Lisp . Lisp был впервые реализован Стивом Расселом на компьютере IBM 704 . Рассел прочитал статью Джона Маккарти «Рекурсивные функции символьных выражений и их машинное вычисление, часть I» и понял (к удивлению Маккарти), что функция eval в Лиспе может быть реализована в машинном коде. [4] Результатом стал работающий интерпретатор Лиспа, который можно было использовать для запуска программ на Лиспе или, точнее, «оценки выражений Лиспа».

Общая операция

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

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

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

Иллюстрация процесса связывания. Объектные файлы и статические библиотеки собираются в новую библиотеку или исполняемый файл.

Программы, написанные на языке высокого уровня, либо напрямую выполняются каким-либо интерпретатором, либо преобразуются в машинный код компилятором (а также ассемблером и компоновщиком ) для выполнения ЦП .

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

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

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

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

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

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

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

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

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

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

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

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

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

Основным недостатком интерпретаторов является то, что интерпретируемая программа обычно работает медленнее, чем если бы она была скомпилирована . Разница в скоростях могла быть крошечной или большой; часто на порядок, а иногда и больше. Обычно запуск программы под интерпретатором занимает больше времени, чем запуск скомпилированного кода, но ее интерпретация может занять меньше времени, чем общее время, необходимое для ее компиляции и запуска. Это особенно важно при прототипировании и тестировании кода, когда цикл редактирования-интерпретации-отладки часто может быть намного короче, чем цикл редактирования-компиляции-запуска-отладки. [6]

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

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

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

Регрессия

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

Вариации

Интерпретаторы байт-кода

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

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

Потоковые интерпретаторы кода

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

Интерпретаторы абстрактного синтаксического дерева

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

Однако для интерпретаторов AST вызывает больше накладных расходов, чем интерпретатор байт-кода, из-за узлов, связанных с синтаксисом, не выполняющих полезной работы, менее последовательного представления (требующего обхода большего количества указателей) и накладных расходов при посещении дерева. [13]

Компиляция точно в срок

Еще больше стирает различие между интерпретаторами, интерпретаторами байт-кода и компиляцией JIT-компиляция, метод, при котором промежуточное представление компилируется в собственный машинный код во время выполнения. Это обеспечивает эффективность выполнения собственного кода за счет времени запуска и увеличения использования памяти при первой компиляции байт-кода или AST. Самый ранний опубликованный JIT-компилятор обычно приписывают работе Джона Маккарти над LISP в 1960 году . [14] Адаптивная оптимизация — это дополнительный метод, при котором интерпретатор профилирует работающую программу и компилирует ее наиболее часто выполняемые части в собственный код. Последнему методу уже несколько десятилетий, и он появился в таких языках, как Smalltalk , в 1980-х годах. [15]

В последние годы компиляция «точно в срок» привлекла всеобщее внимание разработчиков языков: Java , .NET Framework , большинство современных реализаций JavaScript и Matlab теперь включают JIT-компиляторы. [ нужна цитата ]

Интерпретатор шаблонов

Еще более размытым различие между компиляторами и интерпретаторами делает специальная конструкция интерпретатора, известная как интерпретатор шаблона. Вместо того, чтобы реализовывать выполнение кода с помощью большого оператора переключения, содержащего все возможные байт-коды, при работе со стеком программного обеспечения или обходом дерева, интерпретатор шаблонов поддерживает большой массив байт-кода (или любое эффективное промежуточное представление), сопоставленный непосредственно с соответствующим собственные машинные инструкции, которые могут выполняться на аппаратном обеспечении хоста как пары ключ-значение (или, в более эффективных конструкциях, прямые адреса к собственным инструкциям), [16] [17], известные как «Шаблон». Когда конкретный сегмент кода выполняется, интерпретатор просто загружает или переходит к отображению кода операции в шаблоне и напрямую запускает его на оборудовании. [18] [19] По своей конструкции интерпретатор шаблонов очень сильно напоминает JIT-компилятор, а не традиционный интерпретатор, однако технически он не является JIT, поскольку он просто переводит код с языка на Native вызывает один код операции за раз, а не создает оптимизированные последовательности исполняемых инструкций ЦП из всего сегмента кода. Благодаря простой конструкции интерпретатора, заключающейся в простой передаче вызовов непосредственно аппаратному обеспечению, а не их непосредственной реализации, он намного быстрее, чем любой другой тип, даже интерпретаторы байт-кода, и в некоторой степени менее подвержен ошибкам, но в качестве компромисса его труднее реализовать. поддерживаться из-за того, что интерпретатору приходится поддерживать перевод на несколько различных архитектур вместо независимой от платформы виртуальной машины/стека. На сегодняшний день единственными существующими реализациями интерпретатора шаблонов широко известных языков являются интерпретатор в официальной эталонной реализации Java, виртуальная машина Java Sun HotSpot [16] и интерпретатор Ignition в механизме выполнения javascript Google V8.

Самопереводчик

Самоинтерпретатор — это интерпретатор языка программирования , написанный на языке программирования, который может интерпретировать сам себя; примером является интерпретатор BASIC , написанный на BASIC. Самоинтерпретаторы связаны с самостоятельными компиляторами .

Если для интерпретируемого языка не существует компилятора , создание самоинтерпретатора требует реализации языка на основном языке (который может быть другим языком программирования или ассемблером ). Имея такой первый интерпретатор, система загружается , и новые версии интерпретатора могут быть разработаны на самом языке. Именно таким образом Дональд Кнут разработал интерпретатор TANGLE для языка WEB системы набора текста промышленного стандарта TeX .

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

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

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

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

В книге «Структура и интерпретация компьютерных программ» представлены примеры метациклической интерпретации схемы и ее диалектов. Другими примерами языков с самоинтерпретатором являются Форт и Паскаль .

Микрокод

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

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

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

Компьютерный процессор

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

Приложения

Смотрите также

Рекомендации

  1. ^ В этом смысле ЦП также является интерпретатором машинных инструкций.
  2. ^ Хотя эта схема (объединяющая стратегии 2 и 3) использовалась для реализации некоторых интерпретаторов BASIC уже в 1970-х годах, например, эффективного интерпретатора BASIC ABC 80 .
  3. ^ Беннетт, Дж. М.; Принц, Д.Г.; Вудс, МЛ (1952). «Интерпретационные подпрограммы». Материалы Национальной конференции ACM, Торонто .
  4. ^ Согласно сообщению Пола Грэма в Hackers & Painters , стр. 185, Маккарти сказал: «Стив Рассел сказал, послушай, почему бы мне не запрограммировать эту оценку ..., и я сказал ему: хо-хо, ты путаешь теорию с практикой, эта оценка предназначена для чтения, а не для чтения». для вычислений. Но он пошел дальше и сделал это. То есть он скомпилировал eval из моей статьи в машинный код IBM 704 , исправив ошибку , а затем рекламировал это как интерпретатор Лиспа, что, безусловно, и было. Итак, в тот момент Лисп имел по сути, в той форме, которую он имеет сегодня...»
  5. ^ «Почему первый компилятор был написан раньше первого интерпретатора?». Арс Техника . 8 ноября 2014 года . Проверено 9 ноября 2014 г.
  6. ^ «Компиляторы против интерпретаторов: объяснение и различия». Цифровой гид IONOS . Проверено 16 сентября 2022 г.
  7. ^ Теодор Х. Ромер, Деннис Ли, Джеффри М. Фолькер, Алек Вулман, Уэйн А. Вонг, Жан-Лу Баер, Брайан Н. Бершад и Генри М. Леви, Структура и деятельность переводчиков
  8. ^ Теренс Парр, Йоханнес Любер, Разница между компиляторами и интерпретаторами. Архивировано 6 января 2014 г. в Wayback Machine.
  9. ^ Кюнель, Клаус (1987) [1986]. «4. Кляйнкомпьютер — Eigenschaften und Möglichkeiten» [4. Микрокомпьютер - Свойства и возможности. В Эрлекампфе, Райнер; Монк, Ханс-Иоахим (ред.). Mikroelektronik in der любительской практики [ Микроэлектроника для практического любителя ] (на немецком языке) (3-е изд.). Берлин: Militärverlag der Deutschen Demokratischen Republik  [de] , Лейпциг. п. 222. ИСБН 3-327-00357-2. 7469332.
  10. ^ Хейн, Р. (1984). «Basic-Compreter für U880» [BASIC-компьютер для U880 (Z80)]. радио-фернсен-электроник  [ де ] (на немецком языке). 1984 (3): 150–152.
  11. ^ Промежуточные представления AST, форум Lambda the Ultimate
  12. ^ Кистлер, Томас; Франц, Майкл (февраль 1999 г.). «Древовидная альтернатива байт-кодам Java» (PDF) . Международный журнал параллельного программирования . 27 (1): 21–33. CiteSeerX 10.1.1.87.2257 . дои : 10.1023/А: 1018740018601. ISSN  0885-7458. S2CID  14330985 . Проверено 20 декабря 2020 г. 
  13. ^ Surfin' Safari — Архив блога»Анонсируем SquirrelFish. Вебкит.орг (02.06.2008). Проверено 10 августа 2013 г.
  14. ^ Эйкок 2003, 2. Методы JIT-компиляции, 2.1 Бытие, стр. 2. 98.
  15. ^ Л. Дойч, А. Шиффман, Эффективная реализация системы Smalltalk-80, Материалы 11-го симпозиума POPL, 1984.
  16. ^ ab "openjdk/jdk". Гитхаб . 18 ноября 2021 г.
  17. ^ «Обзор среды выполнения HotSpot» . Openjdk.java.net . Проверено 6 августа 2022 г.
  18. ^ «Демистификация JVM: варианты JVM, Cppinterpreter и TemplateInterpreter» . metebalci.com .
  19. ^ «Интерпретатор шаблонов JVM» . Программист Ищу .
  20. ^ Бондорф, Андерс. «Logimix: самостоятельный частичный оценщик Пролога». Синтез и преобразование логических программ. Спрингер, Лондон, 1993. 214–227.
  21. ^ Гиффорд, Клайв. «Собственные отношения самоинтерпретаторов». Блогер . Проверено 10 ноября 2019 г. .
  22. ^ Кент, Аллен; Уильямс, Джеймс Г. (5 апреля 1993 г.). Энциклопедия компьютерных наук и технологий: Том 28 - Приложение 13. Нью-Йорк: Marcel Dekker, Inc. ISBN. 0-8247-2281-7. Проверено 17 января 2016 г.

Источники

Внешние ссылки