
\ Temporary variables
( 24.09.1997 Черезов А. )
\ April 12th, 2000 - 14:44 Mihail Maksimov
\ добавил конструкции !! ... !! и >| ... | , ликвидировал |DOES

\ оптимизированный вариант. переменные можно использовать и внутри DO LOOP
( 10.06.1999 Ruvim Pinka, idea - Mihail Maksimov )

( Простое расширение СП-Форта локальными переменными.
  Реализовано без использования LOCALS стандарта 94.

  Объявление временных переменных, видимых только внутри
  текущего слова и ограниченных временем вызова данного
  слова выполняется с помощью слова "|" аналогично
  Смолтолку: внутри определения слова используется
  конструкция
  | список локальных переменных через пробел |

  Это заставляет СП-Форт автоматически выделять место в
  стеке возвратов для этих переменных в момент вызова слова
  и автоматически освобождать место при выходе из него.

  Обращение к таким локальным переменным - как к обычным
  переменным по имени и следующими @ и !
  Имена локальных переменных существуют в динамическом
  словаре TEMP-NAMES только в момент компиляции слова, а
  после этого вычищаются и более недоступны.
)
\ Инициализация временных переменных значениями, лежащими на
\ стеке (например, входными параметрами), возможна "списком"
\ с помощью конструкции
\ (( имена инициализируемых локальных переменных ))
\ Имена должны быть ранее объявлены в слове с помощью | ... |

( Использование локальных переменных внутри циклов DO LOOP
  невозможно по причине, описанной в стандарте 94.

  При желании использовать локальные переменные в стиле VALUE-переменных
  можно использовать конструкцию
  || список локальных переменных через пробел ||
  Имена этих переменных будут давать не адрес, а свое значение.
  Соответственно присвоение значений будет осуществляться конструкцией
  -> имя
  по аналогии с присвоением значений VALUE-переменным словом TO.
)

VARIABLE TEMP-CNT
WORDLIST CONSTANT TEMP-NAMES

: INIT-TEMP-NAMES
  ALSO TEMP-NAMES CONTEXT !
  TEMP-CNT 0!
;
: DEL-NAMES ( A -- )
  DUP>R
  @
  BEGIN
    DUP 0<>
  WHILE
    DUP CDR SWAP 5 - FREE THROW
  REPEAT DROP
  R> 0!
;
: DEL-TEMP-NAMES
  TEMP-NAMES DEL-NAMES
;
HEX
: COMPIL, ( A -- )
  0E8 DOES>A @ C! DOES>A 1+!              \ машинная команда CALL
  DOES>A @ CELL+ - DOES>A @ !
  DOES>A @ 1- DOES>A !
;
DECIMAL
C" LAST-HERE" FIND NIP
[IF] 
  : TEMP-DOES ( N -- ) ( -- ADDR )
    ['] DUP MACRO,
    0x8D C, 0x44 C, 0x24 C, C,  \  LEA     EAX , X [ESP]
    HERE TO LAST-HERE  \  разрешено оптимизировать
    ;
[ELSE]
  : TEMP-DOES ( N -- ) ( -- ADDR )
     POSTPONE RP@ LIT, POSTPONE +  ;
[THEN]

: |TEMP-DOES ( N -- ) ( -- VALUE )
  TEMP-DOES ['] @ COMPILE,
;
: |TEMP-DOES! ( N --  ) ( X -- )
  TEMP-DOES ['] ! COMPILE,
;

VARIABLE  add_depth   add_depth 0!   

\ глубина в стеке возвратов до начала переменных

: !TEMP-CREATE ( addr u -- )
  DUP 20 + ALLOCATE THROW >R
  R@ CELL+ CHAR+ 2DUP C!
  CHAR+ SWAP MOVE ( name )
  TEMP-NAMES @
  R@ CELL+ CHAR+ TEMP-NAMES ! ( latest )
  R@ CELL+ CHAR+ COUNT + DUP>R ! ( link )
  R> CELL+ DUP DOES>A ! R@ ! ( cfa )
  &IMMEDIATE R> CELL+ C! ( flags )
  ['] _CREATE-CODE COMPIL,
  TEMP-CNT @ DOES>A @ 5 + !
  TEMP-CNT 1+!
  POSTPONE >R   DOES> @  2 +  CELLS  add_depth @ +  |TEMP-DOES ;

: TEMP-CREATE ( addr u -- )
 !TEMP-CREATE   DOES> @  2 +  CELLS  add_depth @ +   TEMP-DOES ;

: ->            ' 5 + @  2 +  CELLS  add_depth @ +  |TEMP-DOES!
; IMMEDIATE

: |DROP    R> RP@ + RP! ;

' |DROP VALUE '|DROP

: !!!!;  ( N N1 -- )
  DROP  TEMP-CNT @ CELLS LIT,    POSTPONE >R
  DROP            '|DROP LIT,    POSTPONE >R ;

: !!
  BEGIN  NextWord 2DUP S" !!" COMPARE 0<>
  WHILE          !TEMP-CREATE
  REPEAT  !!!!;  ; IMMEDIATE

: ||
  BEGIN  NextWord 2DUP S" ||" COMPARE 0<>
  WHILE  0 LIT,  !TEMP-CREATE
  REPEAT !!!!;   ; IMMEDIATE

: |
  BEGIN  NextWord 2DUP S" |"  COMPARE 0<>
  WHILE  0 LIT,   TEMP-CREATE
  REPEAT !!!!;   ; IMMEDIATE

: >|
  BEGIN  NextWord 2DUP S" |"  COMPARE 0<>
  WHILE           TEMP-CREATE
  REPEAT !!!!;   ; IMMEDIATE

: ((
  0
  BEGIN
    BL WORD DUP COUNT S" ))" COMPARE 0<>
  WHILE
    FIND IF >R 1+ ELSE 5012 THROW THEN
  REPEAT DROP
  BEGIN
    DUP 0<>
  WHILE
\    R> EXECUTE POSTPONE !     ( исправлено для поддержки || )
    R> 5 + @    2 + CELLS add_depth @ + 
    |TEMP-DOES!
    1-
  REPEAT DROP
; IMMEDIATE


\ ===
\ переопределение соответствующих слов для возможности использовать
\ временные переменные внутри  цикла DO LOOP  и независимо от изменения
\ содержимого стека возвратов  словами   >R   R>


: DO     POSTPONE DO     [  3 CELLS ] LITERAL  add_depth +!
; IMMEDIATE

: LOOP   POSTPONE LOOP   [ -3 CELLS ] LITERAL  add_depth +!
; IMMEDIATE

: +LOOP  POSTPONE +LOOP  [ -3 CELLS ] LITERAL  add_depth +!
; IMMEDIATE

: >R     POSTPONE >R     [  1 CELLS ] LITERAL  add_depth +!
; IMMEDIATE

: R>     POSTPONE R>     [ -1 CELLS ] LITERAL  add_depth +!
; IMMEDIATE

\ ===


: :: : ;

: : ( -- )
  : INIT-TEMP-NAMES
;
:: ; ( -- )
  DEL-TEMP-NAMES PREVIOUS
  POSTPONE ;
  add_depth 0!      \ на всякий случай ;)
; IMMEDIATE

