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

Управление словарными статьями

Перейти вниз

Управление словарными статьями Empty Управление словарными статьями

Сообщение автор Gudleifr Вт Окт 03, 2017 11:41 am

Насколько просты и понятны слова, компилирующие шитый код, настолько неестественными кажутся слова, создающие заголовки словарных статей.
(Мур даже ввел для них специальное сложное кодовое слово ENTRY).

По Баранову и Ноздрунову - Управление словарными статьями Leaf10ТЕМА #120, АБЗАЦ #2029Управление словарными статьями Leaf10
***
Первая сложность: заголовок слова и шитый код слова могут лежать в разных областях памяти. Это может быть вызвано оптимизацией хранения или желанием сэкономить место при целевой компиляции (имена слов в исполняемом файле могут и не понадобится), или, даже, какими-нибудь свойствами ЭВМ.

Более того, даже разные части заголовков могут лежать в разных областях памяти. Из тех же соображений. (Например, Мур рассматривал возможность хранить отдельно части заголовков фиксированной и переменной длины).

Следствие таких разночтений - нечитабельность кода ENTRY. Начинающему может показаться, что там присутствует некий сокровенный смысл, а не просто код, создающий типовой набор полей наиболее простым способом.
***

Вторая сложность: количество и содержимое полей заголовка могут сильно варьироваться. Типовыми считаются:
- Поле признаков/флагов - содержит самый главный признак слова - признак немедленного исполнения (IMMEDIATE), часто добавляется признак SMUDGE - того, что слово еще недокомпилировалось. Обычно совмещают с байтом длины имени (входит в поле имени - NF), длину обычно ограничивают 32 байтами, т.о. остается место под три битовых флага/признака. Такое совмещение позволяет отдельно не проверять флаг SMUDGE - его установка портит длину слова и FIND его не найдет.
- Поле имени (NF) - в классическом случае - строка со счетчиком. Возможны самые разные "оптимизации" - хранение завершающего пробела/нулевого символа, отдельное/исключительное хранение части имени фиксированной длины (для удобства сравнения по-словно, а не по-байтово), упаковка символов, хеширование...
Так как главная функция СЛОВАРЯ - обеспечить главное свойство слов - связь "имя-код", имя обязано присутствовать, даже если оно совсем не похоже на имя в его классической, текстовой форме.
(Конечно, в FORTH, как в PostScript или SmallTalk можно создавать неименованные куски шитого кода, есть даже специальное слово - NONAME, и такие куски, скорее всего, будут храниться в СЛОВАРЕ, но называть их словарными статьями нельзя. Лучше называть их, по предложению Мура, псевдо-статьями).
- Поле связи (LF) - поле нужное FIND для перебора всего списка слов. Классически - содержит адрес предыдущей словарной статьи. Если FIND ищет другим способом, это поле может выглядеть совершенно иначе. Например, если словарные статьи имеют фиксированный размер, то можно перейти к предыдущему слову без всякой ссылки (предложение Мура). А, если имеет место хеширование списка слов, то надо будет привязать слово не просто к предыдущему, но к предыдущему в нужном списке (тоже Мур).
- Поле кода (CF) - самое главное в слове, оно всегда есть и оно всегда одно (чтобы гарантировать однозначность связи "имя-код"). Существует всего два варианта хранения кода: сам код (подпрограммный или прямой шитый код, внутреннее управление) и ссылка на код (косвенный шитый код, внешнее управление).
В общем смысле это вещи эквивалентные, поэтому оба варианта считаются FORTH-овскими, но поклонники разных шитых кодов готовы до последнего отстаивать именно свой вариант (иногда ЭВМ более приспособлена для одного вида кода, чем для других).
- Поле параметров (PF) - это универсальная затычка, позволяющая хранить все, что угодно. Самое главное назначение - хранить сам шитый код (в CF только его запускатель или ссылка на его интерпретатор). Но возможны и другие варианты: дополнительные точки входа в слово, данные слова, даже, код (например в косвенном шитом коде, его и хранить-то больше негде). В пределах одной FORTH-системы обычно принимается пяток вариантов, который считается правильным/достаточным (кодовые слова, шитые слова, CREATE-слова, DOES>-слова, QUAN-слова...), а остальные объявляются избыточными.
***

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

Иногда же авторам просто нравится рассматривать лексиконы, как некие объектно-ориентированные сущности, в которых можно инкапсулировать не только нестандартные словарные статьи (притягивая, например, к стандартно-словарному виду внешние источники кода/данных), но и позволять каждому лексикону СЛОВАРЯ иметь свою собственную копию процедуры СИМВОЛ.


Последний раз редактировалось: Gudleifr (Сб Мар 20, 2021 1:22 pm), всего редактировалось 1 раз(а)
Gudleifr
Gudleifr
Admin

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

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

Управление словарными статьями Empty Re: Управление словарными статьями

Сообщение автор Gudleifr Вт Окт 03, 2017 11:50 am

КАК ЭТО СДЕЛАНО В FOBOS

Самым простым из вожможных способов. На этапе 0 было принята такое начало статьи (NF-LF):

Код:
   Link = 0
   Header MACRO length, name, WordLabel
   Link2 = $
      DB length
      DB name
      DD Link
   Link = Link2
   WordLabel:
   ENDM

Некоторые предлагают размещать первым полем LF (туда пишется Link), якобы так быстрее перебирать слова, но т.к. в FIND-перебор входит проверка соответствия имен слов, то ставить впереди NF (строка name) или LF было бы делом исключительно вкуса, но... Ведь, проще всего разместить буфер WORD именно на вершине словаря, и т.о. при чтении имени создаваемой статьи мы автоматически получаем там готовое поле NF. Остается только дописать к нему остальные поля.

Признаки стандартно запихиваю в байт длины (length).

Поле кода (CF) начинается сразу за эаголовком - и метка WordLabel автоматически на него указывает.
Очевидно, можно было бы что-то выиграть, добавив выравнивание слов и/или введением завершающего имя символа, но в моем проекте это без надобности, т.к. основной источник торможения здесь - Windows, я в принципе не смогу написать что-то столь же тормозное.

Слово, создающее этот заголовок у меня получилось таким:
Код:
      WordCode 8, '(CREATE)', @28CRE
      DD @LATES, @3ER, @HERE
      DD @CURRE, @40, @21
      DD @BL, @WORD, @DUP, @COUNT, @TOUPP
      DD @C40, @312B, @ALLOT
      DD @R3E, @2C, @EXIT

Т.е., если перевести с языка ассемблера на FORTH:

Код:
: (CREATE)  LATEST >R
     HERE CURRENT @ !
     BL WORD DUP COUNT TOUPPER C@ 1+ ALLOT
     R> , ;

Т.е. сначала находим Link, затем регистрируем в текущем лексиконе адрес начала статьи (Link = Link2), потом, очевидно, WORD, перевод имени в верхний регистр и перенос указателя вершины словаря, наконец, запись в LF Link.
***

Как устроено CF. Я исторически использую прямой шитый код, поэтому, здесь просто код (а не ссылка на него). В кодовых словах т.о. можно лепить все, что угодно, надо лишь сохранять FORTH-регистры и в конце ставить макрос Next (СЛЕДУЮЩИЙ).

В случае шитого слова код стандартен:

Код:
   Called MACRO
      LOCAL Start
      mov [ebp], esi
      add ebp, 4
      mov esi, Start
      Next
   Start:
   ENDM

Кто читал Баранова и Ноздрунова без труда узнает, обычную процедуру CALL.

Шитый код (PF) начинается с метки Start и, очевидно, должен заканчиваться прошивкой адреса кода слова EXIT:

Код:
      Header 4, 'EXIT', @EXIT
      sub ebp, 4
      mov esi, [ebp]
      Next

***

Неприятности начинаются только тогда, когда PF начинает "плавать" в зависимости от длины CF.

Например, слова, созданные CREATE, и слова, созданные CREATE ... DOES> должны иметь разный код, но место-то под CF резервируется в CREATE. Ранее даже использовалось дополнительное слово: вместо CREATE ... DOES> писали <BUILDS ... DOES> . Пришлось резервировать сразу максималную длину:

Код:
   : CREATE  (CREATE) 053 C, 0BB C, >MARK NEXT,
     4 ALLOT 0 , NEXT, >RESOLVE ;

Т.е. компилируем код "push ebx; mov ebx, OFFSET Data; lodsd; jmp eax" и резервируем 4 байта под будующий DOES> (и даже заранее для него ставим второй NEXT,).

Код:
   : (DOES)  LATEST >CFA 6 + 83007589 OVER ! 4 + 0BE04C5 OVER ! 3 +
     R@ 4 + SWAP ! ;
   : DOES> COMPILE (DOES) COMPILE EXIT ; IMMEDIATE

Т.к. DOES> должен, как всякий уважающий себя IMMEDIATE работать и на этапе компиляции слова и при его исполнении, то естественно разделить его на две части - что исполнять, а что компилировать.
Исполняющаяся часть завершает компиляцию слова и переходит к компиляции того, что будет компилироваться в создаваемые словом слова (т.е. того, что после DOES>).
Компилирующаяся же часть как раз заменяет код, созданный CREATE начиная с 6-го байта (т.е. затирая первый NEXT,) на "mov [ebp], esi; add ebp, 4; mov esi, Start; lodsd; jmp eax", где метка Start обозначает то, что будет после DOES> - "R@ 4 +".
***

Также плавающий размер CF приводит к тому, что для доступа к PF нужно использовать разные слова:

Код:
   : >PFA  ( cfa -- pfa)  14 + ;  ( ТОЛЬКО ДЛЯ СЛОВ, СОЗДАННЫХ CREATE)
   : >BODY  ( cfa -- wa)  0E + ;  ( ТОЛЬКО ДЛЯ СЛОВ, СОЗДАННЫХ ":" )

Может показаться, что в косвенном шитом коде, где вместо кода имеем дело с ссылками на него, все намного проще, но запутаться в косвенных адресациях тоже можно запросто.
***

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

Код:
   "создать слово,
      создающее заголовок слова и зафигачивающее туда кусок кода,
         обеспечивающий выкладывание на стек адреса данных;
      затем размещающее данные, снимая их со стека;
      затем изменяющее первоначально зафигаченный кусок кода так,
         чтобы он после после выкладывания на стек адреса данных, перепрыгнул к нужному коду;
   дописать в конец слова нужный код."

а потом, всего лишь, найти способ разрешения всех связанных с этим процессом ссылок.
Gudleifr
Gudleifr
Admin

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

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

Управление словарными статьями Empty Re: Управление словарными статьями

Сообщение автор Gudleifr Вт Окт 03, 2017 4:14 pm

КРАМОЛА

По сути, СЛОВАРЬ - это тоже СТЕК. Причем, его "шитая" часть практически повторяет то, что копится в СТЕКЕ (особенно в модели Дейкстры). Так, может, их совместить?
Правда, возникнут некоторые  сложности с прошивкой оборотов, но ничего непреодолимого, вроде не наблюдается. Наоборот, некоторые вещи станут проще - не придется, например, дважды проверять тип литералов (при формировании ЗНАЧЕНИЯ и при прошивке нужного для его извлечения оборота).

Управление словарными статьями Leaf10ТЕМА #45, АБЗАЦ #450Управление словарными статьями Leaf10
Gudleifr
Gudleifr
Admin

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

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

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

- Похожие темы

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