Представьте, у вас есть слово с определенным функционалом.
Вот только в какой-то момент возникает необходимость этот функционал расширить и хуже того, возможно, делать это придется динамически.
Что-то такое было вроде?
Ах да, реализация в СПФ с не очень очевидным поведением (слово
... (три точки) должно всегда стоять вначале слова, иначе вылет).
Благо, это не единственный способ сделать доопределение.
Что же делать?
Можно такие проблемные слова переписать как векторы, а затем при необходимости брать из них указатель, вставлять его в новое слово и уже указатель на это слово прописывать в вектор.
Собственно реализация:
Код:
: ADD-VECT HERE [COMPILE] FROM DUP @ COMPILE, ! -1 STATE ! ;
Пример использования
Код:
VECT TEST. : X 10 . ;
' X TO TEST. ;
ADD-VECT TEST. 20 . ;
ADD-VECT TEST. 30 . ;
Преимущество: реализация достаточно тривиальна.
Недостатки: 2 лишние строчки кода в примере (а это напомню, придется повторять в реальном коде. Оно вам надо?), каждый новый вариант вызывает предыдущий (затраты на стек во всей красе).
Но можно реализовать и по другому, не в лоб.
Например, хранить указатели на доопределяемый код в списке.
Код:
: EXT:
CREATE
HERE 2 CELLS + ,
0 ,
-1 STATE !
DOES>
>R
BEGIN R@ WHILE R@ @ EXECUTE R> CELL+ @ >R REPEAT
RDROP
;
: ADD-EXT:
' >BODY >R
BEGIN R@ CELL+ @ WHILE R> CELL+ @ >R REPEAT \ находим последний элемент списка
HERE \ создаем новый элемент
HERE 2 CELLS + ,
0 ,
R> CELL+ !
-1 STATE ! \ начинаем доопределение слова
;
Пример
Код:
EXT: TEST 10 . ;
ADD-EXT: TEST 20 . ;
ADD-EXT: TEST 30 . ;
Но можно пойти еще дальше! Зачем нам хранить 2 ячейки для доопреляемого кода! Это слишком жирно! Мы фортеры или кто?! Обойдемся всего одной ячейкой на ВЕСЬ КОД.
ладно не на весьРеализация для Nova-forth
Код:
: EXT:
:
HERE >R
120 ALLOT
R@ , \ ссылка на пространство кода с текущими КОМПИЛИРУЕМЫМИ вызовами
HERE
R> DP KEEP! \ ненадолго используем старый указатель кодофайла
COMPILE,
RET,
;
: ADD-EXT:
'
120 + >R \ пропускаем компилируемый код
R@ @ DUP 2>R
BEGIN R@ GET-CALL WHILE DROP R> >param >R REPEAT \ находим последнее свободное место
DROP
2R@ - ABS 100 > \ если вызовов слишком много, выделяем еще кусочек кодофайла
IF
HERE 2 RPICK ! \ новая ссылка на пространство кода с указателями
HERE >R
1 RPICK DP ! \ тут и ниже мы компилируем безусловный переход на новый участок
POSTPONE AHEAD
R@ DP !
POSTPONE THEN
120 ALLOT
R>
RDROP RDROP RDROP
ELSE
R>
RDROP RDROP
THEN
:NONAME
SWAP DP KEEP!
COMPILE,
RET,
;