Исполняем?

Перейти вниз

Исполняем?

Сообщение автор Gudleifr в Пт Сен 15, 2017 6:02 pm

Итак, откуда бы не было получено слово, мы получили его код (адрес поля кода)...
А, нет...

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

- Идея о том, что слово можно "не только исполнять/компилировать" восходит к Муру. Он изначально предлагал находить самое начало словарной статьи, чтобы Цикл Управления имел доступ ко всем ее полям.

- Есть две основные современные разновидности шитого кода: когда код слова хранится в словарной статье (подпрограммный, прямой коды) и когда он хранится "где-то рядом" (косвенный, свернутый коды).
Вторая разновидность не только позволяет писать эмуляторы FORTH на языках высокого уровня, но и легко изменять "способ исполнения" конкретного слова - надо всего лишь переставить ссылку с одного кода на другой.
avatar
Gudleifr
Admin

Сообщения : 908
Дата регистрации : 2017-03-29

Посмотреть профиль

Вернуться к началу Перейти вниз

Re: Исполняем?

Сообщение автор Gudleifr в Пт Сен 15, 2017 6:07 pm

ИСПОЛНЕНИЕ

В нормальной FORTH-системе используется два вида слов: кодовые и шитые. Первые что-то делают, вторые - это программы, состоящие из других слов. Т.е. существует два вида исполнения слов: просто исполнение и миниинтерпретация слов-программ.
Однако, FORTH-система этого не знает. Она просто передает адрес кода слова процессору для исполнения.
Она даже не знает, что выполняемое в данный момент слово может оказаться вторичной FORTH-машиной...
В этом прелесть внутреннего управления - я передаю слову управление, а оно само вернет управление куда надо.
Причем, создается впечатление, что слова "работают одинаково", будучи вызванными и из ПОТОКА, и из шитого кода СЛОВАРЯ... И это впечатление правильное... но сам ПОТОК и шитый код работаю по-разному, поэтому слово действующее и там, и там одинаково, на самом деле делает разное! Это, к счастью, случается только при использовании оборотов.
***

С точки зрения оборотов: слова, выполняемые после того, как их ввели из ПОТОКА, могут сами читать следующие за ними слова, а слова, выполняемые из шитого кода могут читать следующие за ними коды.
Это совсем не рушит самый главный FORTH-постулат - слово работает независимо от того, откуда его вызвали - из ПОТОКА или из кода. Однако, от этого не легче - путаница все равно остается, программист должен помнить, что слово, начинающее потоковый оборот, даже будучи "откомпилированным", все равно при исполнении "полезет" в ПОТОК...
Например, в привычных мне версиях FORTH, слово "апостроф" ищет следующее за ним слово в ПОТОКЕ и получает адрес его кода. Это может пригодиться, например, для хранения где-то "указателя на функцию" (в стиле языка C):

: ЗВЕЗДОЧКА 42 EMIT ;
VARIABLE ЗНАЧОК
' ЗВЕЗДОЧКА ЗНАЧОК !

Попробуем откомпилировать:

: ПУСТЬ-ЗВЕЗДОЧКА ' ЗВЕЗДОЧКА ЗНАЧОК ! ; \ НЕПРАВИЛЬНО
: ПУСТЬ-ЗВЕЗДОЧКА ['] ЗВЕЗДОЧКА ЗНАЧОК ! ; \ ПРАВИЛЬНО

Скомпилированный "апостоф", все равно, полезет в ПОТОК, а не в шитый код. Приходится использовать "апостроф в квадратных скобках", чтобы "вылезти в ПОТОК" еще во время компиляции ПУСТЬ-ЗВЕЗДОЧКА и правильно скомпилировать словарный оборот.
Обычная техника "одинаково действующих оборотов" выглядит так:

: (ОБОРОТ) ВЗЯТЬ-ПАРАМЕТРЫ-ИЗ-ШИТОГО-КОДА ЧТО-ТО-СДЕЛАТЬ ;
: ОБОРОТ ВЗЯТЬ-ПАРАМЕТРЫ-ИЗ-ПОТОКА
STATE @ IF \ РЕЖИМ КОМПИЛЯЦИИ
COMPILE (ОБОРОТ) СКОМПИЛИРОВАТЬ-ПАРАМЕТРЫ
ELSE \ РЕЖИМ ИСПОЛНЕНИЯ
ЧТО-ТО-СДЕЛАТЬ THEN ; IMMEDIATE

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

Еще одна хитрость: слово "апостроф в кавычках", вроде бы, может не лазать в ПОТОК для чтения ЗВЕЗДОЧКА, то и так прочтется при компиляции. Но, в общем случае, вместо ЗВЕЗДОЧКИ может быть какое-то IMMEDIATE-слово, попытающееся не откомпилироваться, а выполниться - поэтому его приходится читать принудительно. А если это IMMEDIATE-слово само начинает новый оборот? В этих рекурсиях можно погрязнуть.
Рассмотрение каждого слова, порождающего оборот, в виде отдельной FORTH-машины начинает казаться, по сравнению с этими хитростями, не таким уж и сложным.
avatar
Gudleifr
Admin

Сообщения : 908
Дата регистрации : 2017-03-29

Посмотреть профиль

Вернуться к началу Перейти вниз

Re: Исполняем?

Сообщение автор Gudleifr в Пт Сен 15, 2017 6:09 pm

КОМПИЛЯЦИЯ

FORTH-стандарты находят естественным компиляцию слов сразу из ПОТОКА.
Исключение - только слова-монстры для создания заголовков статей в словарях: CREATE, VARIABLE, CONSTANT, наконец, "двоеточие". На мой взгляд, если не делать, то говорить об этом, нужно иначе.

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

Во-вторых, раз мы можем компилировать "на лету", т.е. писать в СЛОВАРЬ, то какой смысл говорить о "запоминании" и/или "присваивании"? Т.к. это тоже запись в СЛОВАРЬ, то это тоже компиляция! Да, да слово восклицательный знак" - компилирующее! Более того, практически любую "структуру данных" можно считать разновидностью шитого кода. А код, работающий с данными - специализированной FORTH-машиной.

Т.е. в писании программой кода (т.е. компиляцией не только при чтении ПОТОКА, но и в процессе вычислений) нет ничего зазорного. Где это может понадбиться?
avatar
Gudleifr
Admin

Сообщения : 908
Дата регистрации : 2017-03-29

Посмотреть профиль

Вернуться к началу Перейти вниз

Re: Исполняем?

Сообщение автор Gudleifr в Пт Сен 15, 2017 6:11 pm

ОТ УДАЛЕНИЯ ОБЪЕКТОВ - К РАН-ТАЙМ КОМПИЛЯЦИИ

Win-программисты наверняка помнят о достаточно неудобном свойстве объектов-ресурсов. Если удается и открытие, и работу, и закрытие ресурса запихнуть в одну транзакцию, все просто замечательно.
Но, вот, когда открытие, работа и закрытие это отдельные операции, возникает следующая неприятность: объект создается один раз, но уничтожается минимум дважды: либо по закрытии ресурса, либо по уничтожению охватывающего визуального объекта (в т.ч. приложения). Списки объектов, подлежащих уничтожению, проблемы не решают, как и вложенные деструкторы. Всегда есть вероятность, что одно закрытие будет отличаться от другого.
А если решать проблему FORTH-овски? Ввести слово "НЕ-ЗАБЫТЬ", связанное с сигналом "закончить работу", и докомпилировать туда/откомпилировать оттуда коды действий, которые необходимо совершить в этот момент... Развивая мысль: иметь развитый аппарат, способный откладывать действия "на потом", перекомпилируя "на лету" слова, связанные с какими-либо сигналами/состояниями...
***

Пример эмуляции этого явления в простейшей форме:

DOER ПОДГОТОВИТЬ-КОНЕЦ
: НАЧАТЬ ВЫДЕЛИТЬ IF MAKE ПОДГОТОВИТЬ_КОНЕЦ ОСВОБОДИТЬ ;AND THEN ;
: ОТКАЗАТЬСЯ ОСВОБОДИТЬ UNDO ПОДГОТОВИТЬ_КОНЕЦ ; \ ЕСЛИ РЕСУРС БОЛЬШЕ НЕ НУЖЕН
: ЗАКОНЧИТЬ ПОДГОТОВИТЬ-КОНЕЦ ; \ КОНЕЦ СЕАНСА

Понятно, в сложном случае, ни число конкретных отложенных действий, ни точный момент вызова (класс событий) могут быть неизвестны. Что-то вроде:

КОГДА-БУДЕТ-НЕЧЕГО-ДЕЛАТЬ СОБЕРИ-МУСОР
...
КОГДА-БУДЕТ-НЕЧЕГО-ДЕЛАТЬ ПРОГОНИ-ТЕСТ
...
МУСОР-СОБРАН \ Т.Е. УЖЕ НЕ НАДО БУДЕТ ЕГО СОБИРАТЬ
...
\ КОГДА БУДЕТ НЕЧЕГО ДЕЛАТЬ, ПОЙДЕТ ТЕСТ
avatar
Gudleifr
Admin

Сообщения : 908
Дата регистрации : 2017-03-29

Посмотреть профиль

Вернуться к началу Перейти вниз

Re: Исполняем?

Сообщение автор Gudleifr в Пт Сен 15, 2017 6:14 pm

КОД ВМЕСТО СТРУКТУР ДАННЫХ

Попробуем представить реализацию машины "из коробков" Д.Мичи.
FORTH-реализация вполне может состоять в создании слов-коробков. КОРОБОК создается автоматически при появлении в игре новой комбинации. При создании в каждый коробок прошивается столько слов-БУСИН, сколько возможно вариантов:

СТАРТ
LIT e1 LIT k1 БУСИНА
LIT e2 LIT k2 БУСИНА
...
LIT eN LIT kN БУСИНА
ФИНИШ EXIT

где

: СТАРТ R@ >ИГРОСТЕК 0 0 ;
: БУСИНА ( e k eI kI -- e' k+kI)
ROT OVER + ВЫПАЛО? IF ROT ELSE SWAP THEN DROP ;
: ФИНИШ DROP DUP >ИГРОСТЕК EXECUTE ;

ИГРОСТЕК используется для запоминания сыгравших вариантов.
R@ >ИГРОСТЕК - запоминает в в ИГРОСТЕКЕ адрес первого LIT в КОРОБКЕ.
kI - число бусин.
eI - адрес процедуры хода.
ВЫПАЛО? ( k1, k2 -- k2, f) выдает TRUE c вероятностью k1/k2 (в случае k2 == 0 - TRUE).
Обучение состоит в прохождении ИГРОСТЕКА, заполненного парами КОРОБОК-e1, и соответствующем измененении kI.
***

Можно, конечно, хранить КОРОБКИ в честных списках, вынеся за пределы шитого кода.
Получится гораздо короче (LIT-ы и БУСИНЫ уйдут, останутся только пары eI-kI).
По сути, это просто выбор между прямым и косвенным шитым кодом. Ведь список пар eI-kI - именно косвенный шитый код.
***

Обобщенная FORTH-машина из коробков:

ПОТОК команд игрока;
СЛОВАРЬ содержит набор КОРОБКОВ;
ЗНАЧЕНИЕ описывает позицию на момент хода машины и ее нормализации;
СТЕК содержит набор сыгравших КОРОБКОВ и выбранных ходов.
ОК - выдача позиции игроку;
СИМВОЛ - распознание/нормализация позиции;
ВЫПОЛНИТЬ - если необходимо, создание нового КОРОБКА и выбор хода;
КОМПИЛИРОВАТЬ - в конце игры провести обучение КОРОБКОВ, сохраненных в стеке;
СЛЕДУЮЩИЙ - зависит от реализации.
avatar
Gudleifr
Admin

Сообщения : 908
Дата регистрации : 2017-03-29

Посмотреть профиль

Вернуться к началу Перейти вниз

Re: Исполняем?

Сообщение автор Gudleifr в Пт Сен 15, 2017 6:15 pm

ДРУГОЕ

Простота и привлекательность FORTH, как раз, и базируется на том, что ничего "другого" быть не может. Слово либо компилируется, либо исполняется, причем, совершенно независимо от контекста.
***

Однако, выше мы видели, что при желании этот самый контекст можно без труда добавить, т.к. весь наш интерпретатор доступен программисту и в любой его точке можно перехватить управление и что-то проанализировать/переиначить.
С одной стороны, возникают опасения за "чистоту языка". Ведь, рано или поздно количество оборотов изменит само его качество. Например, многие фортеры так привыкли к стандартным "операторам управления" - IF, WHILE, DO... - что считают их частью FORTH-синтаксиса.
Это, наверное, главная FORTH-граница: пока СТЕК похож на стек, а не на дерево грамматического разбора, а всю грамматику обеспечивают сами слова, используя свои недокументированные свойства - все в порядке. (Например FORTH совершенно не в курсе, чем занимается слово IF, и, тем более, что за ним должно следовать THEN).
***

Можно ли как-то обойти это ограничение, сохранив FORTH-образность интерпретатора? Добавить на этапе конструирования в FORTH-систему средства, которые не сводятся к добавлению специальных слов? (Конечно, т.к. я могу при помощи "специальных слов" создать поверх первичной FORTH-машины совершенно на нее не похожий интерпретатор, то предыдущую фразу надо дополнить условием "не строя новую машину").
Можно ввести отложенное исполнение, запуск не именно последнего считанного слова, а наиболее активного (что бы это не значило) и еще кучу всего, но это будут уже не те слова, с которыми мы имели дело, строя FORTH-систему, а какие-то сверхвысокоуровневые слова-понятия, слова-абстракции... (Как бы получается, что FORTH-принципы работают не только на уровне простейшего интерпретатора, но и на уровне интерпретатора каких-то сложно-понятийных языков. Которые, поэтому, тоже оказываются простейшими...)
avatar
Gudleifr
Admin

Сообщения : 908
Дата регистрации : 2017-03-29

Посмотреть профиль

Вернуться к началу Перейти вниз

Re: Исполняем?

Сообщение автор Спонсируемый контент


Спонсируемый контент


Вернуться к началу Перейти вниз

Вернуться к началу


 
Права доступа к этому форуму:
Вы не можете отвечать на сообщения