LINUX.ORG.RU

Ответ на: комментарий от anonymous

может быть, он сначала переводит в машкод, а потом обратно «в себя»?

нет. Потом он отдаёт код процессору. А процессор его выполняет. Т.е. из x+=y; создаётся команда add %eax, %ebx.

emulek
()
Ответ на: комментарий от emulek

Ну, я условно. Все, в любом случае, процессором выполняется. После того, как код выполняется процессором (генерируется строка), выхлоп этого выполнения (строка) подается на вход интерпретатора.

anonymous
()
Ответ на: комментарий от anonymous

создаётся команда add %eax, %ebx

А почему в асм, а не сразу в двоичное представление?

понятно, что сразу в двоичное. Просто асм — взаимо-однозначная(во всяком случае теоретически) запись этого кода. Потому можно и так и так говорить.

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

emulek
()
Ответ на: комментарий от emulek

А компилятор эту «строку» пишет в файл.

Не эту строку, а текст программы (бинарь), генерирующий эту строку.

anonymous
()
Ответ на: комментарий от emulek

А я говорил, что на вход интерпретатора подается не этот бинарь, а результат его выполнения (строка, соответствующая синтаксису интерпретатора).

anonymous
()
Ответ на: комментарий от anonymous

А я говорил, что на вход интерпретатора подается не этот бинарь, а результат его выполнения (строка, соответствующая синтаксису интерпретатора).

«на вход» подаётся текст программы. А «выхода» в явном виде просто нет, т.к. выходной код сразу отсылается в CPU.

emulek
()
Ответ на: комментарий от emulek

код сразу отсылается в CPU.

Да это все фигня, не надо зацикливаться на железе. Допустим, у нас есть строка текста «foo» на языке X. Предположим, что X - компилируемый язык. Транслятор оттранслирует строку в язык Y и запишет в файл. Потом ты можешь исполнить этот файл, и он возвратит куда-нибудь результат своего выполнения [smth]. Предположим теперь, что X - интерпретируемый язык. Транслятор оттранслирует строку в язык Y, затем исполнит получившееся выражение в [smth], и этот [smth] возвратится сразу на вход интерпретатора, в цикл чтения-выполнения-печати. При этом, разумеется, [smth] должен быть синтаксически верным выражением языка X.

anonymous
()
Ответ на: комментарий от anonymous

Предположим теперь, что X - интерпретируемый язык. Транслятор оттранслирует строку в язык Y, затем исполнит получившееся выражение в [smth], и этот [smth] возвратится сразу на вход интерпретатора

не. выражение [smth] можно прямо так отдать исполнителю.

emulek
()
Ответ на: комментарий от emulek

Так оно и отдается исполнителю сразу, мы же абстрагированы от реализации, когда его рассматриваем. Язык X может быть тем же языком, что и Y, это ничего не меняет по сути. Важно, что результат выполнения выражения возвращается обратно.

anonymous
()
Ответ на: комментарий от emulek

«на вход» подаётся текст программы. А «выхода» в явном виде просто нет, т.к. выходной код сразу отсылается в CPU

То есть touch тоже транслятор — он транслирует имя файла в его открытие.

И mail тоже транслятор. Он транслирует текст письма в команды CPU по отправке этого текста.

И cp тоже транслятор. Транслирует имена файлов в команды CPU по их копированию.

Так?

monk ★★★★★
()
Ответ на: комментарий от emulek

Теоретически gcc может и интерпретировать, а не только компилировать, чуть подправить нужно, и взлетит.

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

Также и любой интерпретатор можно переделать в компилятор.

Попробуй сделать компилятор picolisp, в котором eval должен получать весь контекст выполнения (потому как вместо макросов fexpr'ы).

monk ★★★★★
()
Ответ на: комментарий от monk

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

1. очевидно ты путаешь с C++.

2. какая разница, что файл надо читать целиком? Это тут вообще не при чём, как оно файл читает роли не играет.

emulek
()
Ответ на: комментарий от monk

Попробуй сделать компилятор picolisp, в котором eval должен получать весь контекст выполнения (потому как вместо макросов fexpr'ы).

не вижу проблемы.

emulek
()
Ответ на: комментарий от emulek

не вижу проблемы.

Ну так сделай. Так, чтобы

(de (test x y)
   (eval (read))
   (x y))
компилировалось в ассемблерный код и работало как в picolisp. Можешь хотя бы просто привести эквивалентный ассемблерный код (ну или C-подобный, если ассемблер не знаешь)

Намекну: (eval ...) в picolisp имеет доступ к полному контексту в исходном коде, аналогично #include в C

monk ★★★★★
()
Последнее исправление: monk (всего исправлений: 1)
Ответ на: комментарий от emulek

1. очевидно ты путаешь с C++.

Нет

$ cat test.c
#include <stdio.h>
int main()
{
   printf("%i\n", foo());
}

int foo() { return 5; }
$ gcc test.c
$ ./a.out

какая разница, что файл надо читать целиком

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

monk ★★★★★
()
Последнее исправление: monk (всего исправлений: 1)
Ответ на: комментарий от emulek

угу. «Транслятор одной команды».

Ну тогда все программы, получающие ввод по твоему определению являются трансляторами.

Не-трансляторами являются только команды без входных данных: whoami, yes, true, false, ...

Так?

monk ★★★★★
()
Последнее исправление: monk (всего исправлений: 1)
Ответ на: комментарий от monk

Что является выходным текстом?

Машкод.

Транслятор — переводчик, переводит текст программы с одного языка (у тебя sh) на другой (машкод). Таким образом, и тот и другой — трансляторы.

anonymous
()

Компилятор компилирует, интерпретатор интерпретирует.

CYB3R ★★★★★
()
Ответ на: комментарий от anonymous

Входной текст «df > ~/test». Что является выходным текстом?

Машкод.

Транслятор — переводчик, переводит текст программы с одного языка (у тебя sh) на другой (машкод).

Машкода, эквивалентного алгоритму «прочитать свободное место и записатьв файл ~/test» sh не создаёт. Он при чтении входного текста сразу выполняет поиск файла, перенаправление вывода и запуск в новом процессе команды df. И, опять же, машкод для алгоритма «поиск файла, перенаправление вывода и запуск в новом процессе команды df» не создаётся. В sh вообще нет генерации машкода.

monk ★★★★★
()
Ответ на: комментарий от monk

компилировалось в ассемблерный код и работало как в picolisp. Можешь хотя бы просто привести эквивалентный ассемблерный код (ну или C-подобный, если ассемблер не знаешь)

мне лениво. Как-то процессор ведь выполняет этот код? Значит это возможно, да? А если код есть, то почему его нельзя сохранить? Что тебе мешает?

Намекну: (eval ...) в picolisp имеет доступ к полному контексту в исходном коде, аналогично #include в C

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

emulek
()
Ответ на: комментарий от monk

Интерпретатор, согласно определению, выполняет команду сразу после чтения.

бред. С какого перепугу он _должен_?

Да, bash например функции и объявления переменных НЕ выполняет сразу после чтения.

Например:

$ foo() { echo "execute function"; }

как видишь, ничего не выполнилось. Только запомнилось.

В твоём примере тоже можно просто запомнить main(), а выполнить её после определения foo. Где ты узрел проблему?

emulek
()
Ответ на: комментарий от monk

Ну тогда все программы, получающие ввод по твоему определению являются трансляторами.

«транслятором» является sh, команды получают уже готовый массив с разобранными параметрами. Например rm -rf /* получит массив с именами всех каталогов в корне.

emulek
()

Лор сегодня в ударе.

Deleted
()

Компилятор компилирует код в некое промежуточное состояние, которое потом выполняется процессором, интерпретируемый код выполняется интерпретатором, и то и то трансляторы

rikimaru
()
Ответ на: комментарий от monk

ЮМашкода, эквивалентного алгоритму «прочитать свободное место и записатьв файл ~/test» sh не создаёт. этот код создавать не нужно, он уже создан, и записан в файле /bin/df, оболочка его просто запускает.

В sh вообще нет генерации машкода.

есть. Там есть сам маш код. Если ты написал (( X = 2+2 )), то будет создан машкод для вычисления 2+2. (скорее всего этот код уже там есть, и записан где-то в switch для всех арифм. операторов).

emulek
()
Ответ на: комментарий от emulek

этот код создавать не нужно, он уже создан, и записан в файле /bin/df

Там нет части алгоритма «записать в файл ~/test»

monk ★★★★★
()
Ответ на: комментарий от emulek

Например rm -rf /* получит массив с именами всех каталогов в корне

А дальше считаем этот массив с именами входной программой на языке «rm», а выходной программой считаем удаление каталогов. Значит, транслятор.

monk ★★★★★
()
Ответ на: комментарий от emulek

В твоём примере тоже можно просто запомнить main(), а выполнить её после определения foo.

Убедил. Интерпретатор можно сделать для всего, для чего существует компилятор.

monk ★★★★★
()
Ответ на: комментарий от monk

А дальше считаем этот массив с именами входной программой на языке «rm»

да. Дальше rm работает как транслятор, и транслирует этот массив во множество системных вызовов unlink(2). А их уже транслирует ядро, а точнее модуль ФС в машкод.

emulek
()
Ответ на: комментарий от emulek

Как-то процессор ведь выполняет этот код?

Во время выполнения кода модифицируется исходный код программы командой (eval (read)). Потом выполняется то, что получилось.

Всё равно, что в С можно было бы в качестве параметра #include подставлять значение переменной, полученное от пользователя. Тогда тоже компилятор был бы невозможен. Например, не компилировалось бы такое.

int main()
{
    char[1024] code;
    scanf("%s", &code);
    #include code
    print("%s\n", res);
}
monk ★★★★★
()
Ответ на: комментарий от monk

Интерпретатор можно сделать для всего, для чего существует компилятор.

в принципе это одно и то же. Просто детали реализации и использования.

emulek
()
Ответ на: комментарий от emulek

Дальше rm работает как транслятор ... их уже транслирует ядро ...

Я и говорю, что в таком определении транслятором является любая программа с входными данными

monk ★★★★★
()
Ответ на: комментарий от monk

Во время выполнения кода модифицируется исходный код программы командой

это возможно в любом Тьюринг-полном ЯП, ассемблер не исключение.

Всё равно, что в С можно было бы в качестве параметра #include подставлять значение переменной

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

И не трогай препроцессор, он вообще говоря — отдельная сущность. Это что-то вроде предварительной обработки исходного текста, которая делает из двух строк /bin/true Over9000 строчек, которые и компилируются.

Т.е. препроцессор к предмету обсуждения не относится.

emulek
()
Ответ на: комментарий от monk

Я и говорю, что в таком определении транслятором является любая программа с входными данными

да. формально — да. И даже без данных. /bin/true тоже транслирует себя в код, всегда один и тот же, return 0;

emulek
()
Ответ на: комментарий от emulek

Т.е. препроцессор к предмету обсуждения не относится

Относится. Я утверждаю, что нельзя сделать интерпретатор для языка, где eval имеет мощность не меньше, чем у препроцессора.

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

monk ★★★★★
()
Ответ на: комментарий от monk

что нельзя сделать интерпретатор для языка

может s/интерпретатор/компилятор? Согласно Вашему определению?

anonymous
()
Ответ на: комментарий от anonymous

может s/интерпретатор/компилятор?

Да. Следует читать «Я утверждаю, что нельзя сделать компилятор для языка, где eval имеет мощность не меньше, чем у препроцессора»

monk ★★★★★
()
Ответ на: комментарий от monk

а для компилятора появляется необходимость перекомпилировать новый исходный код

зачем? А если в программе есть цикл, который выполняется uint16_t раз, то ты тоже предлагаешь для каждого из 65536и чисел компилировать свой код? Нет, ты сделаешь один цикл.

Открой K&R, там ЕМНИП был пример калькулятора, который вычисляет любые выражения. Без всяких перекомпиляций. Хоть 2+2, хоть (1+4-(8*(4/5)))%6.

Т.ч. eval не нужен. Ну и он вовсе не обязан eval'ить именно тот ЯП, на котором он написан. Вот например eval в sed/perl eval'ит bash'ем. Пример с rm -rf на ЛОРе есть.

emulek
()
Ответ на: комментарий от emulek

Т.ч. eval не нужен.

Существуют языки с таким eval. Picolisp я уже упоминал. Еще в sh можно делать

read a
source $a
ну и eval в нём тоже полнофункциональный. Поэтому сделать компилятор из *.sh в бинарник тоже невозможно

monk ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.