Автор:
mOleg
дата первой публикации на forthwiki 01-03-2002
Снятие ограничений на использование управляющих констукций.
Preface.
Предназначено для снятия ограничений с операторов управления, как то: Begin While Repeat, If Else Then и прочих - на использование вне ':' ';', то есть в состоянии исполнения.
Абстракт.
Довольно часто бывает так, что нужно, например в цикле, провести какой-нибудь тест, предвычисление или сделать тот или иной выбор, заполнить массив осмысленными данными при его создании, создать за ряз ряд "похожих" Does> слов. Обычно такая необходимость предполагает порождение лишних определений, которые в последствии засоряют словарь и к тому же совсем не нужны в самой программе. Методы избавления от таких слов существуют, но они неудобны и занимают много времени. Например можно сделать так:
<pre>
: Test ( --> n ) Begin .... While .... Repeat
Abort" Unit not available!" ;
Test
Forget Test
</pre>
Возможен и вариант с Marker-ами или с Noname: - ами. И если вариант с маркерами просто дольше выполняется, то вариант с Noname: засоряет память а в некоторых системах и словарь, что в свою очередь вызывает замедление поиска слов в словаре и тоже сказывается на скорости работы системы в целом и ее размере. Кроме того, если после такого ненужного слова будет определено уже нужное, то ни один из перечисленных методов не пройдет.
Реализация.
Механизм работает следующим образом: при выполнении одного из слов, начинающих управляющую структуру, в режиме интерпретации система переводится в состояние компиляции до тех пор, пока не встретится закрывающая часть конструкции, после чего собранная конструкция исполняется.
Данная библиотека предополагает решение за счет введения системы в режим компиляции после встречи слов: If, IfNot, Begin, Do, ?Do, Case, Switch и перевода системы в режим интерпретации (точнее переводя систему в предыдущее состояние) после слов Then, Again, Until, While, Loop, +Loop,EndCase, EndSwitch, закрывающих первые.
Для того, чтобы не мешать выполнению полученного таким путем слова, сборка должна быть проведена не на here, куда в последствии могут попасть результаты работы этого слова, а во временном буфере, который может быть безболезненно удален по завершении исполнения полученного таким оборазом участка кода.
Реализация не предполагает сильного изменения самого интерпретатора и более того переписывания всех слов, завязанных на State, а так же создания более сложных правил поведения привычных слов: снаружи все должно выглядеть, как раньше.
Область применимости.
Не следует путать поведение слов IF и [IF] - первое вызывает компиляцию кода, вплоть до завершающего THEN, то есть автоматически переводит компилятор в режим компиляции, а по-завершении THEN возвращает систему в режим интерпретации и вызывает выполнение скомпилированного кода, в то время как [IF] управляет потоком трансляции. Таким образом следующий текст не вызовет ошибки трансляции:
0 [IF] простой пример многострочного коментария [THEN]
а следующий текст:
0 IF недопустимый текст внутри конструкции ветвления THEN
вызовет ошибку, на первом же неопознанном слове, то есть на слове: 'недопустимый'.
текст решения для СПФ.
Код:
содержимое файла devel\~moleg\lib\util\run.f
\ 02-06-2007 ~mOleg
\ Copyright [C] 2007 mOleg mininoleg@yahoo.com
\ поддержка временного буфера для создания безымянных временных слов
REQUIRE ADDR devel\~moleg\lib\util\addr.f
REQUIRE ON-ERROR devel\~moleg\lib\util\on-error.f
REQUIRE IFNOT devel\~moleg\lib\util\ifnot.f
\ переменная для контроля парности открывающих и закрывающих слов
USER controls ( --> addr )
\ размер временного буфера для сборки слов мимо кодофайла
0x4000 CONSTANT #compbuf ( --> const )
\ адрес временного буфера
USER-VALUE CompBuf ( --> addr )
\ переменная для временного хранения адреса DP из CURRENT
USER save-dp ( --> addr )
\ восстановить системные переменные
: rest ( --> )
save-dp A@ DP A!
0 controls !
[COMPILE] [ ;
\ начать компиляцию во временный буфер
: init: ( --> )
0 controls A!
HERE save-dp A!
CompBuf IFNOT #compbuf ALLOCATE THROW TO CompBuf THEN
['] rest ON-ERROR
CompBuf DP A!
] ;
\ закончить компиляцию во временный буфер, выполнить его содержимое
\ восстановить состояние системных переменных
: ;stop ( --> )
RET,
EXIT-ERROR rest
CompBuf EXECUTE ;
\ пока так
\ при входе в определение переменная controls увеличивается на 1
\ при выходе из определения - уменьшается на 1
: : 1 controls ! : ;
: ; controls @ 1 = IFNOT -22 THROW THEN 0 controls ! [COMPILE] ; ; IMMEDIATE
содержимое файла devel\~moleg\lib\util\control.f
\ 19-04-2007 ~mOleg
\ Copyright [C] 2007 mOleg mininoleg@yahoo.com
\ структуры управления: ветвления и циклы
\ можно использовать даже во время исполнения.
REQUIRE ?DEFINED devel\~moleg\lib\util\ifdef.f
REQUIRE IFNOT devel\~moleg\lib\util\ifnot.f
REQUIRE ;stop devel\~moleg\lib\util\run.f
\ Начало ветвления. Код за словом IF выполняется в случае, если flag <> 0
: IF ( flag --> )
STATE @ IFNOT init: THEN
2 controls +!
HERE ?BRANCH, >MARK 1 ; IMMEDIATE
\ Альтернативное ветвление. Код за else выполняется в случае, если
\ пропущен код за основным: IF или IFNOT ветвлением.
: ELSE ( --> ) ?COMP HERE BRANCH, >RESOLVE >MARK 2 ; IMMEDIATE
\ Описатель начала цикла. На код за словом BEGIN передается управление
\ в случае повторений цикла
: BEGIN ( --> )
STATE @ IFNOT init: THEN
2 controls +!
<MARK 3 ; IMMEDIATE
\ возврат без условий на точку BEGIN. Отмечает конец кода бесконечного цикла.
: AGAIN ( --> )
?COMP -2 controls +!
3 = IFNOT -2006 THROW THEN BRANCH,
controls @ IFNOT ;stop THEN ; IMMEDIATE
\ Возврат на точку после BEGIN если flag <> 0 (цикл с постусловием)
: UNTIL ( flag --> )
?COMP -2 controls +!
3 = IFNOT -2004 THROW THEN ?BRANCH,
controls @ IFNOT ;stop THEN ; IMMEDIATE
\ условный выход из цикла, если flag = 0
\ используется между BEGIN и REPEAT, отмечающими начало и конец цикла
: WHILE ( flag --> )
?COMP 2 controls +!
HERE ?BRANCH, >MARK 1 2SWAP ; IMMEDIATE
\ условынй выход из цикла, если flag <> 0. Используется аналогично WHILE
: WHILENOT ( flag --> )
?COMP 2 controls +!
HERE N?BRANCH, >MARK 1 2SWAP ; IMMEDIATE
\ безусловный возврат на BEGIN. Используется вместе с BEGIN и WHILE
: REPEAT ( --> )
?COMP -4 controls +!
3 = IFNOT -2005 THROW THEN BRANCH, >RESOLVE
controls @ IFNOT ;stop THEN ; IMMEDIATE
\ Начало ветвления. Промежуточное имя.
: ifnot ( flag --> )
STATE @ IFNOT init: THEN
2 controls +!
HERE N?BRANCH, >MARK 1 ;
\ Конец ветвления. На точку за THEN переходит управление после выполнения
\ одной из альтернатив, то есть кода после IF IFNOT или ELSE
: THEN ( --> )
?COMP -2 controls +!
>RESOLVE
controls @ IFNOT ;stop THEN ; IMMEDIATE
\ Начало ветвления. Код за словом IFNOT выполняется в случае, если flag = 0
: IFNOT ifnot ; IMMEDIATE