Информатика 10 класса Системы программирования
1. Отметьте все языки программирования высокого уровня.
Паскаль
Си
Python
2. Отметьте языки программирования, которые используются для создания Web-сайтов в Интернете.
Javascript
PHP
Perl
3. Как называется программа, которая переводит в машинные
коды тексты программ, написанных на языке высокого уровня?
компилятор
4. Как называется программа, которая переводит в машинные
коды символьную запись машинных команд?
5. В чем преимущества трансляторов-интерпретаторов в сравнении с компиляторами?
программы легче отлаживать
программы переносимы на любую платформу, для которой есть интерпретатор
6. Назовите тип транслятора, который переводит в машинный код сразу всю программу и строит исполняемый файл.
однопроходный компилятор (??)
7. Как называется промежуточный исполняемый код, который выполняется виртуальной машиной?
байт-код
8. Как называется программа, которая собирает разные части (модули) создаваемой программы и функции из стандартных библиотек в единый исполняемый файл?
линковщик (linker)
9. Как называется программа для поиска ошибок в других программах?
отладчик
10. Как называется программа, позволяющая оценить время работы каждой процедуры и функции во время выполнения программы?
профайлер (profiler)
11. Каким термином называется набор стандартных структур данных и функций операционной системы или сервиса, которые программисты могут использовать в своих программах?
интерфейс программирования приложений
12. Отметьте все программы, которые обычно входят в состав интегрированной среды разработки программ (IDE).
текстовый редактор
компоновщик
отладчик
профилировщик (??)
13. Как называются среды программирования, нацеленные на высокую скорость и низкую стоимость разработки программ?
среды быстрой разработки приложений
14. Отметьте языки программирования, программа на которых может быть переведена в псевдокод, выполняемый в виртуальной машине.
Компиляция. 6: промежуточный код
Первый этап — разбор синтаксиса нашего джей-скрипа — пройден; подбираемся к генерации кода.
Далее в посте:
Выбор кода
Часто п-код делают стековым (например, MSIL): вообразим себе процессор, внутри которого нет пронумерованных регистров, а есть один большой стек, и все действия выполняются с верхними значениями на стеке. (Те, кому довелось программировать для х87, с такой моделью знакомы.) Стековый код действительно удобно генерировать и удобно выполнять, но не слишком удобно обрабатывать — например, в нём тяжело отслеживать зависимости между командами.
О выборе между стековым и регистровым промежуточным кодом выразительно отзывается создатель языка Beep:
Регистровый без вариантов:
Упрощение рантайма. Меньше манипуляций с указателями. Отсутствует понятие переполнения стека. Меньше кода, меньше работы с памятью — меньше места для критических ошибок.
Увеличивается сложность компиляции: появляется фаза выделения регистров. В случе исполнения на виртуальной машине нам не важно количество регистров, можем сделать их достаточное количество для того, что бы вообще не делать аллокацию, а просто маппить все параметры и переменные функции на регистры (см. Lua). Если количество параметров будет превышать количество регистров, то можно выделять часть activation record в хипе, но проще сделать так, что бы компилятор предлагал автору такого кода лечить голову.
В любом случае, если стоит вопрос упрощения рантайма ценой усложнения компилятора, так и следует поступать.
Возможность оптимизации: маппинг N регистров виртуальной машины на регистры процессора. На стековой машине это сделать значительно сложнее.
Работа с памятью для нас пока не актуальна: если не все переменные удастся разместить в регистрах, значит программисту не повезло. Операции, которых в джей-скрипе пока нет, вроде вызова функций, тем более не закладываем в п-код.
Упорядочим опкоды так, чтобы команды похожей структуры (в плане используемых регистров) шли подряд, и вынесем определение структуры команды в отдельный файл jsk.h : она потребуется и компилятору, и интерпретатору.
typedef unsigned char regnum;
struct command <
enum opcodes <
hlt,
store, // dst>
jz, // dst>
echo, // dst>
mov, // >dst
load, // >dst
input, // >dst
add, // src>dst
sub, // src>dst
mul, // src>dst
div, // src>dst
eq, // src>dst
ne, // src>dst
ge, // src>dst
le, // src>dst
gt, // src>dst
lt // src>dst
>;
opcodes opcode;
regnum dest;
union <
struct <
regnum src1, src2;
>;
short imm;
>;
command(opcodes opcode, regnum dest, regnum src1, regnum src2) :
opcode(opcode), dest(dest), src1(src1), src2(src2) <>
command(opcodes opcode, regnum dest, short imm) :
opcode(opcode), dest(dest), imm(imm) <>
>;
Чтобы под опкод действительно выделялся один байт, при компиляции придётся указывать ключ
Компиляция
Строки для echo будем хранить вместе с кодом программы, в самом конце; одинаковые строки объединим, чтобы хранилась только одна копия. Для этого будем хранить map всех строк, где значением будет «идентификатор» строки (её порядковый номер в программе).
Все переменные в джей-скрипе — глобальные. В отдельном map будем хранить по имени переменной номер выделенного ей регистра.
В общем, идея та же, что с форматированной распечаткой; только теперь в каждом узле дерева храним не текст, а список команд. Для элементов выражения также храним номер регистра, в котором результат вычисления.
(340 строк кода вынесены на http://tyomitch.net.ru/jsk.y.html, чтобы сохранить размер поста в пределах допустимого.)
Как видим, понадобилось «расщепить» узел value на три разных типа: литерал-число, литерал-строка, и ссылка на переменную. При форматировании кода различия между ними были несущественны, но при генерации уже понадобилось их различать.
Выполнение
#include
#include
#include
#include
#include
#include «jsk.h»
int pc = 0 ; // индекс команды (не смещение)
bool halted = false ;
int mem[ 1000 ]; // размер не важен: всё равно пока не пользуемся
typedef int (*op)( int src1, int src2, int dest, int imm); // все возможные входные значения
const char * fdata = NULL ; // весь прочитанный п-код
extern op ops[]; // объявлен ниже
int main( int argc, char ** argv) <
if (argc!= 2 ) <
printf( «Missing pcode file name. \n » );
exit( 1 );
>
const command* pcode = ( const command*) fdata;
int r[ 256 ] = < 0 >; // registers
while (!halted) <
command next = pcode[pc++];
r[next.dest] = ops[next.opcode](r[next.src1], r[next.src2], r[next.dest], next.imm);
>
munmap(( void *)fdata, finfo.st_size);
close(fd);
return 0 ;
>
Фанфары! Запускаем первую в мире программу на джей-скрипе:
]$ bison jsk.y
[tyomitch@home
]$ ./jskc pcode
[tyomitch@home
]$ ./jsk pcode
Задумай число от 0 до 1000, а я буду угадывать
Это 500? (1=меньше, 2=больше, 3=попал) 2
Это 750? (1=меньше, 2=больше, 3=попал) 2
Это 875? (1=меньше, 2=больше, 3=попал) 2
Это 938? (1=меньше, 2=больше, 3=попал) 1
Это 906? (1=меньше, 2=больше, 3=попал) 1
Это 890? (1=меньше, 2=больше, 3=попал) 2
Это 898? (1=меньше, 2=больше, 3=попал) 2
Это 902? (1=меньше, 2=больше, 3=попал) 1
Это 900? (1=меньше, 2=больше, 3=попал) 1
Это 899? (1=меньше, 2=больше, 3=попал) 1
Врёшь, так не бывает!
Если приглядеться к дампу, то можно заметить, что первые 0xa0 байт занимает п-код (четвёрки байтов), а остаток файла — строки в UTF-8.
Backpatching
Сейчас в каждом узле дерева хранится список всех соответствующих ему команд, и каждая реализация emit включает в себя объединение команд из дочерних узлов — в том самом порядке (слева направо), в котором эти узлы создавались во время парсинга. Можно сэкономить и память на хранение команд, и код на их объединение, если все генерируемые команды сразу же сваливать в результат, а в символах хранить только «метаинформацию» типа номеров регистров.
Самая резкая разница — что теперь нам вообще не потребуется дерево: для каждого символа оказывается достаточно хранить один скаляр. Более того: у символов операторов теперь вовсе нет значения — весь результат их разбора немедленно сваливается в вектор готового п-кода; поэтому свёртках, где не генерируется код, даже наследовать ничего не нужно.
Дополнительное преимущество новой системы — что для каждой генерируемой команды сразу известен её адрес, так что для строк сможем хранить не временные «идентификаторы», а списки всех ссылок. Это упростит подстановку адресов строк на заключительном этапе генерации п-кода.
std::vector command > pcode;
std::map vars;
std::map int > > strings;
regnum lastreg = 0 ;
inline regnum newreg() <
if (!++lastreg)
yyerror( «Too many registers used.» );
return lastreg;
>
inline int emit( const command& cmd) <
pcode.push_back(cmd);
return pcode.size()- 1 ;
>
inline int emit(command::opcodes opcode, regnum dest, regnum src1, regnum src2) <
return emit(command(opcode, dest, src1, src2));
>
inline int emit(command::opcodes opcode, regnum dest, short imm) <
return emit(command(opcode, dest, imm));
>
inline void fix( int index, command::opcodes opcode, regnum dest, short imm) <
pcode[index] = command(opcode, dest, imm);
>
%>
%token IF ELSE WHILE EXIT
%token EQ LE GE NE
%token STRING NUM ID
%type str > ID NUM STRING
%type dest > EXPR EXPR1 EXPR2 TERM VAL
%type arg > ARG
%type args > ARGS
%type null > OPS OP1 OP2 OP
%type addr > M N
OPS: OP // no action
| OPS OP // no action
;
OP: OP1 | OP2 ; // no action
>
Код компилятора сократился почти вдвое, а компилирует он точно так же, как и прежде.
Если нет разницы, зачем писать больше?
Байт-код
Байт-код или байтко́д (англ. byte-code ), иногда также используется термин псевдоко́д — машинно-независимый код низкого уровня, генерируемый транслятором и исполняемый интерпретатором. Большинство инструкций байт-кода эквивалентны одной или нескольким командам ассемблера. Трансляция в байт-код занимает промежуточное положение между компиляцией в машинный код и интерпретацией.
Байт-код называется так, потому что длина каждого кода операции — один байт, но длина кода команды различна. Каждая инструкция представляет собой однобайтовый код операции от 0 до 255, за которым следуют такие параметры, как регистры или адреса памяти. Это в типичном случае, но спецификация байт-кода значительно различается в разных языках.
Программа на байт-коде обычно выполняется интерпретатором байт-кода (обычно он называется виртуальной машиной, поскольку подобен компьютеру). Преимущество — в портируемости, т. е. один и тот же байт-код может исполняться на разных платформах и архитектурах. То же самое преимущество дают интерпретируемые языки. Однако, поскольку байт-код обычно менее абстрактный, более компактный и более «компьютерный», чем исходный код, эффективность байт-кода обычно выше, чем чистая интерпретация исходного кода, предназначенного для правки человеком. По этой причине многие современные интерпретируемые языки на самом деле транслируют в байт-код и запускают интерпретатор байт-кода. К таким языкам относятся Perl, PHP, Ruby (начиная с версии 1.9) и Python. Программы на Java обычно передаются на целевую машину в виде байт-кода, который перед исполнением транслируется в машинный код «на лету» — с помощью JIT-компиляции. В стандарте открытых загрузчиков Open Firmware фирмы Sun Microsystems байт-код представляет операторы языка Forth.
В то же время возможно создание процессоров, для которых данный байт-код является непосредственно машинным кодом (такие процессоры существуют, например, для Java и Forth).
Также некоторый интерес представляет p-код (p-code), который похож на байт-код, но физически может быть менее лаконичным и сильно варьироваться по длине инструкции. Он работает на очень высоком уровне, например «напечатать строку» или «очистить экран». P-код повсеместно используется в СУБД и некоторых реализациях BASIC и Паскаля.
Языки и среды программирования, использующие байткод
См. также
Полезное
Смотреть что такое «Байт-код» в других словарях:
БАЙТ-КОД — Иногда используется термин псевдокод машинно независимый код низкого уровня, генерируемый транслятором и исполняемый интерпретатором (англ. byte code) Словарь бизнес терминов. Академик.ру. 2001 … Словарь бизнес-терминов
байт-код — Машинно независимый код, генерируемый Java компилятором. [ГОСТ Р 54456 2011] Тематики телевидение, радиовещание, видео EN byte codeJava byte code … Справочник технического переводчика
Байт-код Java — Байт код Java набор инструкций, исполняемых виртуальной машиной Java. Каждый код операции байт кода один байт. Используются не все 256 возможных значений кодов операций. 51 из них зарезервированы для использования в будущем.… … Википедия
Код (значения) — Код (фр. code, от лат. codex): В Викисловаре есть статья «код» … Википедия
Код операции — Эта статья об инструкциях; о системе команд в целом см.: Машинный код. Код операции, операционный код, опкод часть машинного языка, называемая инструкцией и определяющая операцию, которая должна быть выполнена. Определение и формат кодов… … Википедия
Байт — в запоминающих устройствах наименьшая адресуемая единица данных в памяти ЭВМ, обрабатываемая как единое целое. По умолчанию байт считается равным 8 битам. Обычно в системах кодирования данных байт представляет собой код одного печатного или… … Финансовый словарь
БАЙТ — (англ. byte) набор из стандартного числа (обычно 8) битов (двоичных единиц), используемый как единица количества информации при её передаче, хранении и обработке на ЭВМ. В международных системах кодирования данных (ASCII, EBCDIC) Б. представляет… … Юридическая энциклопедия
Байт — У этого термина существуют и другие значения, см. Byte. Байт (англ. byte) единица хранения и обработки цифровой информации; совокупность битов, обрабатываемая компьютером одномоментно. В современных вычислительных системах байт… … Википедия
Код операции (информатика) — Эта статья об инструкциях; о системе команд в целом см.: Машинный код. В комьютерной отрасли под кодом операции (также операционный код, опкод англ. operation code) понимают часть машинного языка, называемую инструкцией, определяющую операцию,… … Википедия
Промежуточный код — Байт код или байткод (англ. byte code), иногда также используется термин псевдокод машинно независимый код низкого уровня, генерируемый транслятором и исполняемый интерпретатором. Большинство инструкций байт кода эквивалентны одной или нескольким … Википедия
Как объяснить, что такое байткод? [закрыт]
Хотите улучшить этот вопрос? Переформулируйте вопрос так, чтобы на него можно было дать ответ, основанный на фактах и цитатах.
7 ответов 7
Легко будет объяснить и переносимость. Если человек (секретарша) выучит все коды операций, то она сможет выполнить любую работу, главное, что бы была последовательность кодов. А инженеры могут попробовать спаять-сконструировать устройство, которое будет это исполнять.
@vanyamelikov по-моему вы сами не понимаете что такое байткод Java 🙂
Байткод Java это машинные инструкции для несуществующей Java машины, которую часто называют Java Virtual Machine.
В чем сила брат? А сила брат в том, что вы пишете для некоей Java машины (когда-нибудь кто-нибудь сделает таки физическую Java машину). Что такое портабельность Java кода: это всего лишь вопрос реализации Java машины на какой-то реальной машине ну и т.д.
Я бы попытался объяснить как-то так:
Компьютеры «думают» простейшими инструкциями, и когда вы пишете программу допустим на С то она преобразуется в набор примитивных машинных инструкций. Например было выражение на языке программирования
Оно грубо говоря преобразуется в последовательность инструкций
Так как компьютеры бывают разные то и инструкции которые они используют тоже не всегда одни и те же.
Буду рад услашать критику по поводу подобного объяснения^_^
Я так понимаю, вопрос в том, как объяснить, что такое байт-код, не прибегая к объяснению остального контекста. Мне кажется, что не получится объяснить, что такое байт-код, не объяснив, что такое машинный язык и язык программирования, потому что он ведь не сам по себе, он прослойка между ними — т.е. чтобы понять, что делает прослойка, нужно понять, между чем она лежит.
Самый лучший способ практический:
Зачем придумали байт-код? В начале были интерпретаторы которые просто выполняли код из текста, но так как эффективность в постоянном разборе строк не есть хорошо, придумали работать с байтами, а не как с исходным кодом строк, то есть программа преобразует исходный синтаксис ЯП-а в байт-код где есть инструкции и метки и т.п. почти как в ASM, отсюда и происходит название виртуальная машина, а не интерпретатор, к примеру в Java это JVM. Так что тут всё просто, виртуальная машина при загрузке байт-кода исполняет его. Но это ещё не всё, для большей производительности ввели JIT, то есть компиляции байт-кода в нативный код на ходу исполнения, тем самым не много получаем конкурентоспособность программ к компилируемым ЯП-ам.
Всё ещё ищете ответ? Посмотрите другие вопросы с метками c# c java байткод c++ или задайте свой вопрос.
Похожие
дизайн сайта / логотип © 2021 Stack Exchange Inc; материалы пользователей предоставляются на условиях лицензии cc by-sa. rev 2021.10.12.40432
Нажимая «Принять все файлы cookie» вы соглашаетесь, что Stack Exchange может хранить файлы cookie на вашем устройстве и раскрывать информацию в соответствии с нашей Политикой в отношении файлов cookie.
Промежуточный код
Многие современные языки программирования, особенно интерпретируемые, используют байт-код для облегчения и ускорения работы интерпретатора. Трансляция в байт-код является методом, промежуточным по эффективности между прямой интерпретацией и компиляцией в машинный код.
Байт-код называется так, потому что длина каждого кода операции традиционно составляет один байт. Каждая инструкция обычно представляет собой однобайтовый код операции (от 0 до 255), за которым могут следовать различные параметры, например, номер регистра или адрес в памяти.
Содержание
Исполнение
Программа на байт-коде обычно выполняется интерпретатором байт-кода. Преимущество байт-кода в большей эффективности и портируемости, то есть один и тот же байт-код может исполняться на разных платформах и архитектурах, для которых реализован интерпретатор. То же самое преимущество дают непосредственно интерпретируемые языки, однако, поскольку байт-код обычно менее абстрактен и более компактен, чем исходный код, эффективность интерпретации байт-кода обычно выше, чем чистая интерпретация исходного кода или интерпретация АСД. Кроме того, интерпретатор байт-кода зачастую проще интерпретатора исходного кода и его проще перенести (портировать) на другую аппаратную платформу.
В высокопроизводительных реализациях виртуальных машин может применяться комбинация интерпретатора и JIT-компилятора, который во время исполнения программы транслирует часто используемые фрагменты байт-кода в машинный код, применяя при этом различные оптимизации. Вместо JIT-компиляции может применяться AOT-компилятор, транслирующий байт-код в машинный код предварительно, до исполнения.
В то же время возможно создание процессоров, для которых данный байт-код является непосредственно машинным кодом (такие экспериментальные процессоры создавались, например, для языков Java и Форт).
История
Варианты p-кода широко использовались в различных реализациях языка Pascal, например, в UCSD p-System (UCSD Pascal). [8]
Применение
К интерпретируемым языкам, использующим байт-код, относятся Perl, PHP (например Zend Engine), Ruby (начиная с версии 1.9), Python, Erlang и многие другие.
Широко распространённые платформы, использующие байт-код [9] :
Компилятор Clipper создает исполняемый файл, в который включен байт-код, транслированный из исходного текста программы, и виртуальная машина, исполняющая этот байт-код.
В ранних реализациях Visual Basic (до версии 6) использовался высокоуровневый Microsoft p-code [9]
Высокоуровневые p-коды и байт коды применялись в СУБД, некоторых реализациях Бейсика и Паскаля.
В стандарте открытых загрузчиков Open Firmware фирмы Sun Microsystems байт-код представляет операторы языка Форт.
Примеры
Python
Критика
Ошибки верификации байт-кода стековых машин приводили к появлению множества экстремально опасных уязвимостей, в частности десятков в виртуальной машине AVM2, используемой в Adobe Flash для исполнения скриптов ActionScript [14] [15] [16] и нескольких в ранних популярных системах исполнения Java (JVM) [17] [18]
В конце 2000-х — начале 2010-х авторы компиляторов V8 (для языка JavaScript, часто реализуемого через байт-код) [19] и Dart [20] усомнились в том, что промежуточные байткоды обязательны для быстрых и эффективных виртуальных машин. В этих проектах была реализована непосредственная JIT-компиляция (компиляция во время исполнения) из исходных кодов сразу в машинный код. [21]

