Кстати, как раз в википедии есть понятие «Простой интерпретатор анализирует и тут же выполняет (собственно интерпретация) программу покомандно». И почему ты считаешь, что он является транслятором? Для примера возьмём sh.
Как-то читал, что согласно теории множеств, количество чисел натурального ряда равно количеству, например, четных, так как оба множества бесконечны. И вот, подумалось, в развитие этой интересной мысли, что вообще говоря, любые 2 произвольно взятых числа равны, поскольку количество чисел, которые идут после любого из них — равно. Из этого следует, что например, 1 = 2 или 1 = 100. Более строго, может быть, это можно выразить так. Например, берем числа 1 и 2. Какое количество чисел идет после 1 до бесконечности? Бесконечность. После 2-х? Тоже бесконечность. Бесконечность минус бесконечность равно 0. Следовательно, 1 и 2 равны нулю. Доказано. Правильно ли я рассуждаю?
Ну так ты ж его перенаправил, это не значит, что его нет, а значит, что он пошел в «другую струю». С другой стороны, можно считать отсутствие выхлопа тоже вариантом выхлопа, концептуально, так сказать. ИМХО, это сути не меняет. Разве компилятор не может выплюнуть «пустой файл программы»?
Лучше просто cat — выходным является ввод пользователя, так что если интерпретатор и «транслирует» код в конечные значения, то вместе с пользователем и всем остальным окружением :)
А на лекции надо было ходить и писать их, да (а на экзамене или зачёте тебя это спрашивать будут, такие вот дела, да ещё увидят, что ты ничего не знаешь и пойдут дополнительные вопросы). Но ты не бойся, тебе может даже автомат выдадут вместе с сапогами и формой.
Ну так ты ж его перенаправил, это не значит, что его нет, а значит, что он пошел в «другую струю». С другой стороны, можно считать отсутствие выхлопа тоже вариантом выхлопа, концептуально, так сказать. ИМХО, это сути не меняет. Разве компилятор не может выплюнуть «пустой файл программы»?
Ладно, пусть будет входной текст «cp -r a b». А если считать отсутствие вывода полностью эквивалентным пустой программе, то хочу заметить, что пустая программа не выполняет необходимых побочных эффектов «создание файла».
Шелл не создаёт «выходную программу». Он просто выполняет команды, которые являются входной программой, а потому транслятором не является.
Чего во что? Если в компилятор/декомпилятор/ассемблер/дизассемблер кинуть программу, то заведомо известно (с незначительными оговорками — сколько там рандомизации) что будет в результате. Если в интерпретатор кинуть программу, то выхлоп совсем не известен, так как она будет произвольным образом взаимодействовать с произвольным окружением.
Или трансляции не обязана соответствовать функция и она может делать просто что угодно?
Мне вот так видится:
interpretation : SourceLanguage * Environment -> Values * Environment — эффекты во все поля, наличие окружения в общем случае не позволяет говорить о соответствии между программами и конкретными значениями.
compilation : SourceLanguage -> TargetLanguage — чистая функция, есть соответствие.
Или трансляции не обязана соответствовать функция и она может делать просто что угодно?
Функцией, в данном случае, является сам транслятор. Он определенно соответствует «какой-то ф-ции». Кроме всего прочего, Вы путаете функцию с представлением ф-ции. Когда Вы пишите на бумаге «f(x)-->smth», ваша запись не есть функция, это лишь ее выражение.
Я не про конкретно программу cat без аргументов (которая принимает строки и их же печатает, то есть вполне является транслятором/циклом над ним), а про программу sh которая принимает cat без аргументов и возвращает... Что? Канал через который можно вести буфферезированное общение между stdin и stdout? Состояние памяти в котором работает /bin/cat? Наверно она просто _выполняет_ её и тем осуществляет это общение без всякой промежуточной трансляции и возвращает в итоге 0.
Если подходить к вопросу без заезженых стереотипов, любой побочный эффект в ходе выполнения, и их совокупность можно считать выводом. Почему транслятор обязан писать все в «одно место»? И кто сказал, что читать их может только одна программа, один объект и из одного, строго определенного места? Это все штампы ФП и структурщины, к реальным вычислениям это не имеет отношения.
Нужна не какая-то, а отношение между тем из чего происходит трансляция и тем во что, желательно близко к предметной области и без софистики, как в случае
компилятор/декомпилятор/ассемблер/дизассемблер
и т.п.
Равно как с наличием самого факта трансляции (во временных рамках).
А то так у интерпретатора есть функциональная спецификация — функция из программ и окружения (из которого можно доставать ввод) в результат и окружение (куда можно отправлять вывод). Но зачем...
Если подходить к вопросу без заезженых стереотипов, любой побочный эффект в ходе выполнения, и их совокупность можно считать выводом. Почему транслятор обязан писать все в «одно место»?
Наверное потому, что в определении транслятора указано, что его результатом должна быть программа на другом языке равносильная исходной. А набор побочных эффектов и состояние памяти считать «программой» затруднительно.
чем ты недоволен? «выходной текст» интерпретатора == бинарный код, который выполняет CPU. Точнее бинарный код это «буквы», а интерпретатор выдаёт определённые «слова».
Разница между компилятором и интерпретатором в том, что первый делает перевод кода из одного представление в другое предварительно. Ну а интерпретатор делает это в рантайме.
Правда сегодня довольно редко используются «чистые» интерпретаторы, разве что GNU bash...
другие синхронно переводят живую речь (интерпретаторы).
Но sh (а также старый бейсик) никуда входной файл не переводят, а исполняют по мере чтения.
А если мы считаем, что выполнение — подвид «перевода», тогда вопрос про команду touch (а также ftp, mail, cp) остаётся открытым. Входные данные есть, действия есть.
«выходной текст» интерпретатора == бинарный код, который выполняет CPU.
Это называется компилятор в машинный код а не интерпретатор!
Можешь написать себе интерпретатор AST/байткода на C++ (только exec* не трогай) — он их обходит, с системой взаимодействует, никакого кода CPU на выход не даёт (хотя сам может быть скомпилирован в такой), только эффекты.
Выдавал бы — был бы JIT (родного рантайма, LLVM, для бедных — dlopen/exec*).
Но sh (а также старый бейсик) никуда входной файл не переводят, а исполняют по мере чтения.
процессор не умеет исполнять бэйсик и sh, потому его надо переводить в ассемблер. А уже потом исполнять.
А если мы считаем, что выполнение — подвид «перевода», тогда вопрос про команду touch (а также ftp, mail, cp) остаётся открытым. Входные данные есть, действия есть.
есть действие. Это выполнение кода из файла /usr/bin/touch.
Оболочка парсит входной текст, видит там непонятное(ей) слово «touch», и потому ищет в путях $PATH такой файл. Если-бы это было «echo», а оболочкой /bin/bash, то она-бы сама «перевела» echo в код.
Тогда код чего возвращает sh на текст «df > ~/test» ?
sh возвращает код, который запускает файл /bin/df.
так как в коде ещё запись в файл теперь должна быть...
Кто сказал «нужна запись»? Запись не нужна. Ещё раз: переводчик-синхронист ничего не пишет, а просто слушает и говорит. Слушает речь на одном языке, и повторяет на другом. Понятным реципиенту. А уже реципиент _выполняет_ нужное действие.
Ну а jit/llvm это такой переводчик речи с карточками, на одной стороне «stop», на другой «стоять». Или на одной стороне «run», на другой «бежать».
В случае такого интерпретатора — из какого в какой? Так и представляю, как элементы Cmd «соответствуют» кускам машинного кода полученного после компиляции функции interpret.
может быть, он сначала переводит в машкод, а потом обратно «в себя»? затем, он при желании может еще раз повторить этот цикл, и может воспользоваться выводом исполнения скомпилированной программы, как данными? Т.е. разница в том, что компилятор может только туда, а интерпретатор «и туда и сюда». Он компилирует, исполняет и возвращает результат как данные, которые может вновь прочитать и скомпилировать?
Теоретически ты можешь сохранить «выхлоп» оболочки в виде машинных команд.
Не можешь, потому что никакого выхлопа машинных команд нет (и не надо про «оболочку» — речь про интерпретаторы вообще).
почем «нет»? Он просто не сохраняется негде.
В случае такого интерпретатора — из какого в какой?
из C в ассемблер. Просто этот асмовый код не сохраняется в файл, а прямо так и выполняется. Можешь его сохранить в файл, а выполнять потом. Получится компилятор. Правда хреновый, такие компиляторы в 70х годах прошлого века были. И вот в них надо было упароваться, например вместо деления на 3 умножать на 0x5555, а то компилятор так ведь и переводит в mov ax,3; div Сейчас это уже не нужно.
Потому что компилятор достаточно умный, что-бы умножить на 0x5555