И где же они там спрятаны? В ТП были вполне полноценные указатели, появилась арифметика указателей, были массивы для доступа в произвольное место памяти (Mem, MemW и MemL, синтаксис: Mem[segment:offset]), массивы для доступа к портам (Port, PortW) и даже директива inline для вставок машинного кода (не ассемблера, а именно машинного, в виде чисел).
В случае с прямым шитым кодом каждое «высокоуровневое» (то, которое определяется через двоеточие) слово компилируется в виде цепочки адресов подпрограмм в машинном коде, а в начале этой цепочки компилируется машинный код, который устанавливает указатель форт-инструкций на эту цепочку и сохраняет его предыдущее значение в стеке возвратов.
В случае с косвенным шитым кодом, компиляция происходит в цепочку адресов ячеек, содержащих адрес подпрограмм в машинном коде, в начале цепочки размешается адрес подпрограммы инициирующей запуск этого шитого кода (по аналогии с прямым шитым кодом).
Т.е. любом случае происходит трансляция с более высокоуровневого кода на форте в более низкоуровневый (т.е. компиляция) шитый код, либо байт-код, либо машинный код, а в случае с прямым без компиляции машинного кода даже никак не обойтись.
Большая разница с компиляторами большинства других языков в том, что этот код компилируется в оперативной памяти и часто там и остается, если в программе явно не было указано команды сохранения в файл. Чтобы было понятнее, можно считать, что это аналог запуска Си программы командой tcc -run program.c.
P.S. Да и, кстати, настоящих интерпретируемых языков осталось немного, почти всегда это компиляторы в байткод, которые (если явно не было указано другого) сразу запускают интерпретатор этого байткода, да и там тоже часто JIT-компилятор.
Там же вроде JIT, код компилируется прямо во время работы, и из-за оптимизаций может быть разным при различных запусках в разных условиях с разными данными.
Вроде есть проекты, которые позволяют сделать и бинарник в виде exe файла.
А какие конкретно? Скорее всего там тупая упаковка js-движка и исходного кода на js в один файл.
можно ли написать компилятор, например, JavaScript, не запихнув в итоговый бинарник целиком движок JavaScript?
Запихнуть движок (в данном случае компилятор, раз мы хотим его компилировать) просто придется при использовании eval или Function, они его просто требуют, по другому никак.
Это что, 100500-я попытка подогнать понятие низкоуровнего языка под Си? )))
Интерпретируемые языки, даже с промежуточным представлением кода, сразу мимо.
Промежуточное представление кода, и то, как исполняется программа на каком-то языке — это не часть языка, а деталь реализации. Для любого интерпретируемого языка можно написать компилятор, для любого компилируемого — интерпретатор. Просто для каких-то языков проще сделать первое, для других — второе.
Кстати, например система команд x86 тоже является промежуточным представлением, «ниже» идут микрокоды.
Тут в последнее время шарписты всячески извращаются, один добавил в язык асмовставки, другой генерирует ассемблерный код для AVR. Относить ли после этого C# к низкоуровневым?
Большинство реализаций Форта — интерпретаторы, а не компиляторы
Форт одновременно является и тем и другим.
Например
\ тут форт интерпретируемый
S" Hello from interpreting mode!" TYPE CR
: hello \ а тут уже компилируемый, : нас перевело в этот режим
S" Hello from compiling mode" \ но S" является immediate-словом и поэтому
\ не скомпилировалось, а было вызвано, оно
\ распарсило строковый литерал, где-то его
\ сохранило и скомпилировало код, который
\ заносит на стек адрес строки и ее длину
TYPE CR \ это обычные слова, они просто скомпилировались
; \ ; тоже immediate-слово, заканчивает определение и переводит нас обратно
\ в режим интерпретации
\ мы снова в интерпретаторе
hello \ зовем только что скомпилированное слово
BYE \ пока ;)
позволяет программисту создавать новые конструкции и абстрактные сущности
Это какие же? Новую функцию или структуру?
не забывайте про такое мощное средство как препроцессор!
Стандартный сишный препроцессор очень убог и примитивен. Тупая подстановка и пара операций. Сравните с m4 или макросами в лиспе, которые являются полноценными тьюринг-полными языками.
Заголовок спойлера
Единственные реально расширяемые языки — это форт и его потомки (например более высокоуровневый Factor или недавно представленный fift для TON). Форт одновременно является и препроцессором, и интерпретатором, и компилятором, и линкером, и операционной системой и вообще чем угодно. Например в форте нет никакого синтаксиса для описания классов, пишем небольшое расширение и тут же можем его использовать. Абсолютно любое слово можно переопределить как угодно прямо во время работы транслятора. Можно ввести в язык любую синтаксическую конструкцию, какая только взбредет в голову. В добавок механизм словарей (в других языках наиболее близким понятием является неймспейс) дает возможность иметь несколько лексиконов и переключатся между ними как угодно. К тому же есть возможность самому заниматься парсингом исходного кода, и можно отказатся от основного синтаксиса в виде слов разделяемых пробелами и перейти к любому другому.
Для AVR fasm не портировали. Но это совсем не обязательно, например на форуме fasma местные извращенцы пишут библиотеки макросов для программирования под множество различных архитектур. )))
Оптимизировать нужно алгоритмы, а не бесмысленно расставлять по коду заклинания, хороший компилятор сам разберется в какие инструкции лучше транслировать код. Часто даже бывают полезны подсказски, чтобы компилятор не применял оптимизаций (например volatile).
Я бы скорее Алгола ожидал, именно Алгол повлиял на синтаксис большинства современных структурных языков, много синтаксических конструкций и понятий идут из него, хоть на него и повлиял Фортран, сам Фортран изначально не был структурным.
Да, за это время PHP заметно облагородился, но большая часть статьи все еще актуальна. А кривой синтаксис и основы языка вообще навсегда останутся. Тем более PHP по-моему единственный шаблонизатор для которого пишут сторонние шаблонизаторы. :)
Но любить его точно не за что. Тем более тем кто-привык писать на нормальных языках.
Mem[segment:offset]
), массивы для доступа к портам (Port, PortW) и даже директива inline для вставок машинного кода (не ассемблера, а именно машинного, в виде чисел).В случае с косвенным шитым кодом, компиляция происходит в цепочку адресов ячеек, содержащих адрес подпрограмм в машинном коде, в начале цепочки размешается адрес подпрограммы инициирующей запуск этого шитого кода (по аналогии с прямым шитым кодом).
Т.е. любом случае происходит трансляция с более высокоуровневого кода на форте в более низкоуровневый (т.е. компиляция) шитый код, либо байт-код, либо машинный код, а в случае с прямым без компиляции машинного кода даже никак не обойтись.
Большая разница с компиляторами большинства других языков в том, что этот код компилируется в оперативной памяти и часто там и остается, если в программе явно не было указано команды сохранения в файл. Чтобы было понятнее, можно считать, что это аналог запуска Си программы командой
tcc -run program.c
.P.S. Да и, кстати, настоящих интерпретируемых языков осталось немного, почти всегда это компиляторы в байткод, которые (если явно не было указано другого) сразу запускают интерпретатор этого байткода, да и там тоже часто JIT-компилятор.
А какие конкретно? Скорее всего там тупая упаковка js-движка и исходного кода на js в один файл.
Запихнуть движок (в данном случае компилятор, раз мы хотим его компилировать) просто придется при использовании eval или Function, они его просто требуют, по другому никак.
И? Компиляция уже куда-то пропала, или что?
Промежуточное представление кода, и то, как исполняется программа на каком-то языке — это не часть языка, а деталь реализации. Для любого интерпретируемого языка можно написать компилятор, для любого компилируемого — интерпретатор. Просто для каких-то языков проще сделать первое, для других — второе.
Кстати, например система команд x86 тоже является промежуточным представлением, «ниже» идут микрокоды.
#pragma launch nuclear missiles
)))К тому же есть системы, компилирующиеся в нативный код: SP-Forth, SwiftForth
Форт одновременно является и тем и другим.
Например есть церновский CINT или пришедший к нему на замену Cling (но это уже вроде как C++).
Это какие же? Новую функцию или структуру?
Стандартный сишный препроцессор очень убог и примитивен. Тупая подстановка и пара операций. Сравните с m4 или макросами в лиспе, которые являются полноценными тьюринг-полными языками.
Так современный фортран вполне годный язык для матана и обработки массивов. У него даже в прошлом году новая версия стандарта вышла. ;)
Оптимизировать нужно алгоритмы, а не бесмысленно расставлять по коду заклинания, хороший компилятор сам разберется в какие инструкции лучше транслировать код. Часто даже бывают полезны подсказски, чтобы компилятор не применял оптимизаций (например volatile).
Но любить его точно не за что. Тем более тем кто-привык писать на нормальных языках.
Дык это простые подпрограммы, они могут быть переопределены и не являются частью синтаксиса. Все равно что назвать в Си ключевым словом printf.
Они не имеют какого-то специального значения как в других языках и могут быть включены в любое имя.
Пожалуй единственными спецсимволами в нем являются пробелы и переносы строки ;)