Блог программатора |
||||||||
| Главная | Последние правки | Поиcк | Все страницы | Редактор | Админ | Печать | ||||||||
Особенности реализации конструкции CREATE DOES>Разрабатывая свою "домашнюю" Форт-машину я столкнулся с необычным явлением (в Форте вообще мало обычного) - конструкцией CREATE/DOES>. Поиски детального объяснения работы этой конструкции (на примитивном уровне) привели к появлению этой статьи. Надеюсь она поможет тем, кто испытывает аналогичные затруднения.В статье используется ассемблер семейства x86 в диалекте NASM'а. Также следует отметить, что в своей Форт - машине я использовал Subroutine Threaded Code (STC) with inline expansion для микропроцессора Intel 80386 (это влияет на способ генерации и тип генерируемого кода). Также хочу отметить,что мои знания в Форте носят начальный уровень - терминология может не совпадать с общепринятой. Создание Форт-слова с помощью CREATEПриступая к исследованию необходимо обратиться к первоисточнику - ANSI X3.215-1994 ( далее приводиться перевод Сергея Кадочникова 2:4657/33.3):6.1.1000 CREATE CORE ( "<spaces>name" -- ) Пропускает ведущие разделители пробелы. Выделяет name, ограниченное пробелом. Создает определение для name с семантикой выполнения , определенной ниже. Если указатель области данных не выровнен , резервирует достаточно области данных для его выравнивания. Новый указатель области данных определяет поле данныхname. CREATE не распределяет область данных в поле данных name. name Выполнение: ( -- a-addr ) a-addr - адрес поля данных name. Семантика выполнения name можетбыть расширена использованием DOES>. См.: 3.3.3 Область данных, 6.1.1250 DOES>. Ну что же, достаточно туманно. Для начала - слова CREATE и DOES> не являются словами немедленного исполнения (т.е. не IMMEDIATE). А теперь попытаемся вчитаться в текст. Слово CREATE должно выполнять следующие шаги:
Пункты 1-2 более-менее понятны, а что же за код упоминается в 3? Например, это может быть следующий код: POP EDX
PUSH DWORD FREE_MEM ;занесение offset FREE_MEM в стек
PUSH EDX
RET
FREE_MEM:Пояснения:
Скажем,можно избавиться от пункта 2,применив захардкодив следующее: CALL .a1 ; думаю, знакомая конструкция ;)
.a1: POP EAX ; в EAX - смещение .a1
ADD EAX, .a2-.a1 ; прибавляем дельту
POP EDX
PUSH EAX
PUSH EDX
RET
.a2:Выполнив данные требования мы получим , полностью совместимое слово CREATE. Например уже будет работать конструкция вида: CREATE MASSIV 10 CELLS ALLOT После выполнения слова MASSIV на вершине стека окажется адрес 10 выделенных ячеек (Форт-ячеек) памяти Модификация поведения слова - DOES>Ну что же - с CREATE мы все выяснили теперь давайте рассмотрим DOES>.6.1.1250 DOES> CORE Интерпретация: Семантика интерпретации для этого слова не определена. Компиляция: ( C: colon-sys1 -- colon-sys2 ) Добавляет семантику времени-выполнения ниже к текущему определению. В любом случае текущее определение представленное находимым в словаре при компиляции DOES> - определенное реализацией. Потребляет colon-sys1 и производит colon-sys2.Добавляет семантику инициирования, данную ниже к текущему определению. Время-выполнения: ( -- ) ( R: nest-sys1 -- ) Заменяет семантику выполнения самого последнего определения,упоминаемого как name , семантикой выполнения имени данной ниже. Возвращает управление на вызывающее определение, определенное nest-sys1. Неопределенная ситуация существует если name не было определено CREATE, или определенным пользователем словом которое вызывает CREATE. Инициирование: ( i*x -- i*x a-addr ) ( R: -- nest-sys2 ) Сохраняет зависящую-от-реализации информацию nest-sys2 о вызывающем определении. Размещает адрес поля данных name на стеке. Состояние стека i*x представляет параметры name. name Выполнение: ( i*x -- j*x ) Выполняет часть определения , которая начинается с семантики инициирования добавленной изменившим name DOES>. Состояния стека i*x и j*x представляют параметры, и результаты name , соответственно. См.: 6.1.1000 CREATE. Слово DOES> должно выполнять:
Что это значит? Давайте рассмотрим действия по пунктам: 1. Модифицировать код уже сформированного слова плохо - мы можем получить проблемы при переносе Форт-машины на другую платформу. Поэтому создадим новый код. Делать он будет следующее:
После этого необходимо ассоциировать новый код с созданным словом. Все. 2. Тут все просто - надо сделать DROP из стека возвратов один адрес. И выйти. Это гарантирует что код, следующий за DOES> не выполниться. Дотошный читатель может задать вопрос: "а что же будет в действительности происходить при вызове модифицированного слова ?". Давайте посмотрим:
Теперь получится что заработает конструкция вида: : CONSTANT CREATE , DOES> @ ; Но это еще не все. Как "ассоциировать" новый код ? Ведь в угоду переносимости,мы великодушно отказались от модификации уже сформированного байт-кода. Для этого необходимо посмотреть на структуру словарной статьи. Как правило вхождение описывают макросом: %MACRO FRT 4 %2_lfa: dd %1_lfa ; предыдущий lfa %2_nfa: db %3,%4 %2: %ENDM После чего используют этот макрос в виде: FRT ??? , FRT_EMIT, 4, 'EMIT'
POP EDX
POP EAX
PUSH EDX
MOV DL,AL
MOV AH,2
INT 21h
RET
FRT FRT_EMIT, FRT_KEY, 3, 'KEY'
MOV AH,01h
INT 21H
XOR ECX,ECX
MOV CL,AL
POP EDX
PUSH ECX
PUSH EDX
RETКак видите, лучше завести в словарной статье поле %2_cfa, которое будет содержать адрес машинных команд слова. Тогда мы без трудностей ( связанных с модификацией кода созданного CREATE ) можем изменить функциональность нашим DOES> . Макрос FRT в моей версии: %MACRO FRT 4 %2_lfa: dd %1_lfa ; предыдущий lfa %2_nfa: db %3,%4 %2_cfa: dd %2 ; смещение кода статьи %2: %ENDM КоментарииОтслеживать новые комментарии![]() Прокоментируйте эту статью! |
Главная Софт Хард Политеги SimpleWiki ![]() Почта ![]() Мой номер ICQ 456824974 ![]() Архив: 01.2010 02.2010 03.2010 04.2010 05.2010 06.2010 07.2010 Радио «Анонимус» ![]()
Blog ![]() Add bookmark: |
|||||||
|
© Komenda Viacheslav |
||||||||