Merge pull request #75 from SeekingMeaning/0BSD
[pforth] / fth / ansilocs.fth
\ @(#) ansilocs.fth 98/01/26 1.3
\ local variable support words
\ These support the ANSI standard (LOCAL) and TO words.
\
\ They are built from the following low level primitives written in 'C':
\ (local@) ( i+1 -- n , fetch from ith local variable )
\ (local!) ( n i+1 -- , store to ith local variable )
\ (local.entry) ( num -- , allocate stack frame for num local variables )
\ (local.exit) ( -- , free local variable stack frame )
\ local-compiler ( -- addr , variable containing CFA of locals compiler )
\
\ Author: Phil Burk
\ Copyright 1994 3DO, Phil Burk, Larry Polansky, David Rosenboom
\
\ Permission to use, copy, modify, and/or distribute this
\ software for any purpose with or without fee is hereby granted.
\
\ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
\ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
\ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
\ THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
\ CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
\ FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
\ CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
\ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
\
\ 10/27/99 Fixed : foo { -- } 55 ; was entering local frame but not exiting.
anew task-ansilocs.fth
private{
decimal
16 constant LV_MAX_VARS \ maximum number of local variables
31 constant LV_MAX_CHARS \ maximum number of letters in name
lv_max_vars lv_max_chars $array LV-NAMES
variable LV-#NAMES \ number of names currently defined
\ Search name table for match
: LV.MATCH ( $string -- index true | $string false )
0 swap
lv-#names @ 0
?DO i lv-names
over $=
IF 2drop true i LEAVE
THEN
LOOP swap
;
: LV.COMPILE.FETCH ( index -- )
1+ \ adjust for optimised (local@), LocalsPtr points above vars
CASE
1 OF compile (1_local@) ENDOF
2 OF compile (2_local@) ENDOF
3 OF compile (3_local@) ENDOF
4 OF compile (4_local@) ENDOF
5 OF compile (5_local@) ENDOF
6 OF compile (6_local@) ENDOF
7 OF compile (7_local@) ENDOF
8 OF compile (8_local@) ENDOF
dup [compile] literal compile (local@)
ENDCASE
;
: LV.COMPILE.STORE ( index -- )
1+ \ adjust for optimised (local!), LocalsPtr points above vars
CASE
1 OF compile (1_local!) ENDOF
2 OF compile (2_local!) ENDOF
3 OF compile (3_local!) ENDOF
4 OF compile (4_local!) ENDOF
5 OF compile (5_local!) ENDOF
6 OF compile (6_local!) ENDOF
7 OF compile (7_local!) ENDOF
8 OF compile (8_local!) ENDOF
dup [compile] literal compile (local!)
ENDCASE
;
: LV.COMPILE.LOCAL ( $name -- handled? , check for matching locals name )
\ ." LV.COMPILER.LOCAL name = " dup count type cr
lv.match
IF ( index )
lv.compile.fetch
true
ELSE
drop false
THEN
;
: LV.CLEANUP ( -- , restore stack frame on exit from colon def )
lv-#names @
IF
compile (local.exit)
THEN
;
: LV.FINISH ( -- , restore stack frame on exit from colon def )
lv.cleanup
lv-#names off
local-compiler off
;
: LV.SETUP ( -- )
0 lv-#names !
;
: LV.TERM
." Locals turned off" cr
lv-#names off
local-compiler off
;
if.forgotten lv.term
}private
: (LOCAL) ( adr len -- , ANSI local primitive )
dup
IF
lv-#names @ lv_max_vars >= abort" Too many local variables!"
lv-#names @ lv-names place
\ Warn programmer if local variable matches an existing dictionary name.
lv-#names @ lv-names find nip
IF
." (LOCAL) - Note: "
lv-#names @ lv-names count type
." redefined as a local variable in "
latest id. cr
THEN
1 lv-#names +!
ELSE
\ Last local. Finish building local stack frame.
2drop
lv-#names @ dup 0= \ fixed 10/27/99, Thanks to John Providenza
IF
drop ." (LOCAL) - Warning: no locals defined!" cr
ELSE
[compile] literal compile (local.entry)
['] lv.compile.local local-compiler !
THEN
THEN
;
: VALUE
CREATE ( n <name> )
,
DOES>
@
;
: TO ( val <name> -- )
bl word
lv.match
IF ( -- index )
lv.compile.store
ELSE
find
0= abort" not found"
>body \ point to data
state @
IF \ compiling ( -- pfa )
[compile] aliteral
compile !
ELSE \ executing ( -- val pfa )
!
THEN
THEN
; immediate
: -> ( -- ) [compile] to ; immediate
: +-> ( val <name> -- )
bl word
lv.match
IF ( -- index )
1+ \ adjust for optimised (local!), LocalsPtr points above vars
[compile] literal compile (local+!)
ELSE
find
0= abort" not found"
>body \ point to data
state @
IF \ compiling ( -- pfa )
[compile] aliteral
compile +!
ELSE \ executing ( -- val pfa )
+!
THEN
THEN
; immediate
: : lv.setup : ;
: ; lv.finish [compile] ; ; immediate
: exit lv.cleanup compile exit ; immediate
: does> lv.finish [compile] does> ; immediate
privatize