KRIEGSSPIELE!
Вы хотите отреагировать на этот пост ? Создайте аккаунт всего в несколько кликов или войдите на форум.

Исполняем?

Перейти вниз

Исполняем? Empty Исполняем?

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

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

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

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

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

Однако, нужно понимать, что большая вольность в трактовке слова косвенного шитого кода обусловлено применением внешнего управления. Имея специальную программу перебирающую слова, трудно удержаться от искушения сделать ее еще чуть-чуть умнее. Поэтому, можно констатировать наличие избыточности - две умные программы разбора слов в одной FORTH-машине. По сути, возможно использовать в FORTH два экземпляра ЗНАЧЕНИЯ - для процедур ВЫПОЛНИТЬ и СЛЕДУЮЩИЙ. (Можно даже захотеть вернуться к первоначальной идее Мура - читать слова из ПОТОКА и шитого кода в одном Цикле Управления).

Если в прямом шитом коде единственное, что есть у нас при чтении из него - адрес кода слова, то при чтении из ПОТОКА мы имеем структуру данных ЗНАЧЕНИЕ, состоящую (обычно) из:
- адреса кода слова/числового значения;
- типа - слово/слово немедленного исполнения/число/длинное число/вещественное;
- значения переменной STATE - флага компиляции/интерпретации;
- значения переменной DPL - положения десятичной точки в длинном числе;
- строки со счетчиком - считанного слова.
И, хотя, традиционно эта структура не рассматривается (она по большей части реализуется путем условных программных конструкций), понятно, что программа может захотеть над этими значениями "сильно подумать". Мур для этого именно для этого лазейку оставил - предлагал в шитом коде хранить не адрес кода, а адрес словарной статьи.


Последний раз редактировалось: Gudleifr (Чт Дек 22, 2022 12:35 am), всего редактировалось 1 раз(а)
Gudleifr
Gudleifr
Admin

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

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

Исполняем? Empty 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-машины начинает казаться, по сравнению с этими хитростями, не таким уж и сложным.


Последний раз редактировалось: Gudleifr (Пт Фев 14, 2020 11:27 am), всего редактировалось 1 раз(а)
Gudleifr
Gudleifr
Admin

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

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

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

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

КОМПИЛЯЦИЯ

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Исполняем? Empty 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-машина из коробков:

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

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

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

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

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

ДРУГОЕ

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

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

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

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

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

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


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