version 1.17, 1995/12/23 16:21:58
|
version 1.28, 1996/09/30 13:16:10
|
Line 104 require float.fs
|
Line 104 require float.fs
|
( otherwise ) dup postpone f@local# , |
( otherwise ) dup postpone f@local# , |
endcase ; |
endcase ; |
|
|
|
\ locals stuff needed for control structures |
|
|
|
: compile-lp+! ( n -- ) \ gforth compile-l-p-plus-store |
|
dup negate locals-size +! |
|
0 over = if |
|
else -1 cells over = if postpone lp- |
|
else 1 floats over = if postpone lp+ |
|
else 2 floats over = if postpone lp+2 |
|
else postpone lp+!# dup , |
|
then then then then drop ; |
|
|
|
: adjust-locals-size ( n -- ) \ gforth |
|
\ sets locals-size to n and generates an appropriate lp+! |
|
locals-size @ swap - compile-lp+! ; |
|
|
\ the locals stack grows downwards (see primitives) |
\ the locals stack grows downwards (see primitives) |
\ of the local variables of a group (in braces) the leftmost is on top, |
\ of the local variables of a group (in braces) the leftmost is on top, |
\ i.e. by going onto the locals stack the order is reversed. |
\ i.e. by going onto the locals stack the order is reversed. |
Line 142 variable locals-dp \ so here's the speci
|
Line 157 variable locals-dp \ so here's the speci
|
swap ! |
swap ! |
postpone >l ; |
postpone >l ; |
|
|
|
\ locals list operations |
|
|
|
: common-list ( list1 list2 -- list3 ) \ gforth-internal |
|
\ list1 and list2 are lists, where the heads are at higher addresses than |
|
\ the tail. list3 is the largest sublist of both lists. |
|
begin |
|
2dup u<> |
|
while |
|
2dup u> |
|
if |
|
swap |
|
then |
|
@ |
|
repeat |
|
drop ; |
|
|
|
: sub-list? ( list1 list2 -- f ) \ gforth-internal |
|
\ true iff list1 is a sublist of list2 |
|
begin |
|
2dup u< |
|
while |
|
@ |
|
repeat |
|
= ; |
|
|
|
: list-size ( list -- u ) \ gforth-internal |
|
\ size of the locals frame represented by list |
|
0 ( list n ) |
|
begin |
|
over 0<> |
|
while |
|
over |
|
((name>)) >body @ max |
|
swap @ swap ( get next ) |
|
repeat |
|
faligned nip ; |
|
|
|
: set-locals-size-list ( list -- ) |
|
dup locals-list ! |
|
list-size locals-size ! ; |
|
|
|
: check-begin ( list -- ) |
|
\ warn if list is not a sublist of locals-list |
|
locals-list @ sub-list? 0= if |
|
\ !! print current position |
|
." compiler was overly optimistic about locals at a BEGIN" cr |
|
\ !! print assumption and reality |
|
then ; |
|
|
: compile-pushlocal-f ( a-addr -- ) ( run-time: f -- ) |
: compile-pushlocal-f ( a-addr -- ) ( run-time: f -- ) |
locals-size @ alignlp-f float+ dup locals-size ! |
locals-size @ alignlp-f float+ dup locals-size ! |
swap ! |
swap ! |
Line 254 previous
|
Line 318 previous
|
: new-locals-reveal ( -- ) |
: new-locals-reveal ( -- ) |
true abort" this should not happen: new-locals-reveal" ; |
true abort" this should not happen: new-locals-reveal" ; |
|
|
create new-locals-map ' new-locals-find A, ' new-locals-reveal A, |
create new-locals-map ( -- wordlist-map ) |
|
' new-locals-find A, ' new-locals-reveal A, |
|
|
|
slowvoc @ |
|
slowvoc on |
vocabulary new-locals |
vocabulary new-locals |
|
slowvoc ! |
new-locals-map ' new-locals >body cell+ A! \ !! use special access words |
new-locals-map ' new-locals >body cell+ A! \ !! use special access words |
|
|
variable old-dpp |
variable old-dpp |
Line 380 forth definitions
|
Line 448 forth definitions
|
|
|
\ If this assumption is too optimistic, the compiler will warn the user. |
\ If this assumption is too optimistic, the compiler will warn the user. |
|
|
\ Implementation: migrated to kernal.fs |
\ Implementation: |
|
|
\ THEN (another control flow from before joins the current one): |
|
\ The new locals-list is the intersection of the current locals-list and |
|
\ the orig-local-list. The new locals-size is the (alignment-adjusted) |
|
\ size of the new locals-list. The following code is generated: |
|
\ lp+!# (current-locals-size - orig-locals-size) |
|
\ <then>: |
|
\ lp+!# (orig-locals-size - new-locals-size) |
|
|
|
\ Of course "lp+!# 0" is not generated. Still this is admittedly a bit |
|
\ inefficient, e.g. if there is a locals declaration between IF and |
|
\ ELSE. However, if ELSE generates an appropriate "lp+!#" before the |
|
\ branch, there will be none after the target <then>. |
|
|
|
\ explicit scoping |
\ explicit scoping |
|
|
Line 427 forth definitions
|
Line 482 forth definitions
|
lastcfa ! last ! |
lastcfa ! last ! |
DEFERS ;-hook ; |
DEFERS ;-hook ; |
|
|
|
\ THEN (another control flow from before joins the current one): |
|
\ The new locals-list is the intersection of the current locals-list and |
|
\ the orig-local-list. The new locals-size is the (alignment-adjusted) |
|
\ size of the new locals-list. The following code is generated: |
|
\ lp+!# (current-locals-size - orig-locals-size) |
|
\ <then>: |
|
\ lp+!# (orig-locals-size - new-locals-size) |
|
|
|
\ Of course "lp+!# 0" is not generated. Still this is admittedly a bit |
|
\ inefficient, e.g. if there is a locals declaration between IF and |
|
\ ELSE. However, if ELSE generates an appropriate "lp+!#" before the |
|
\ branch, there will be none after the target <then>. |
|
|
|
: (then-like) ( orig -- addr ) |
|
swap -rot dead-orig = |
|
if |
|
drop |
|
else |
|
dead-code @ |
|
if |
|
set-locals-size-list dead-code off |
|
else \ both live |
|
dup list-size adjust-locals-size |
|
locals-list @ common-list dup list-size adjust-locals-size |
|
locals-list ! |
|
then |
|
then ; |
|
|
|
: (begin-like) ( -- ) |
|
dead-code @ if |
|
\ set up an assumption of the locals visible here. if the |
|
\ users want something to be visible, they have to declare |
|
\ that using ASSUME-LIVE |
|
backedge-locals @ set-locals-size-list |
|
then |
|
dead-code off ; |
|
|
|
\ AGAIN (the current control flow joins another, earlier one): |
|
\ If the dest-locals-list is not a subset of the current locals-list, |
|
\ issue a warning (see below). The following code is generated: |
|
\ lp+!# (current-local-size - dest-locals-size) |
|
\ branch <begin> |
|
|
|
: (again-like) ( dest -- addr ) |
|
over list-size adjust-locals-size |
|
swap check-begin POSTPONE unreachable ; |
|
|
|
\ UNTIL (the current control flow may join an earlier one or continue): |
|
\ Similar to AGAIN. The new locals-list and locals-size are the current |
|
\ ones. The following code is generated: |
|
\ ?branch-lp+!# <begin> (current-local-size - dest-locals-size) |
|
|
|
: (until-like) ( list addr xt1 xt2 -- ) |
|
\ list and addr are a fragment of a cs-item |
|
\ xt1 is the conditional branch without lp adjustment, xt2 is with |
|
>r >r |
|
locals-size @ 2 pick list-size - dup if ( list dest-addr adjustment ) |
|
r> drop r> compile, |
|
swap <resolve ( list adjustment ) , |
|
else ( list dest-addr adjustment ) |
|
drop |
|
r> compile, <resolve |
|
r> drop |
|
then ( list ) |
|
check-begin ; |
|
|
|
: (exit-like) ( -- ) |
|
0 adjust-locals-size ; |
|
|
' locals-:-hook IS :-hook |
' locals-:-hook IS :-hook |
' locals-;-hook IS ;-hook |
' locals-;-hook IS ;-hook |
|
|
|
' (then-like) IS then-like |
|
' (begin-like) IS begin-like |
|
' (again-like) IS again-like |
|
' (until-like) IS until-like |
|
' (exit-like) IS exit-like |
|
|
\ The words in the locals dictionary space are not deleted until the end |
\ The words in the locals dictionary space are not deleted until the end |
\ of the current word. This is a bit too conservative, but very simple. |
\ of the current word. This is a bit too conservative, but very simple. |
|
|
Line 440 forth definitions
|
Line 570 forth definitions
|
\ things above are not control flow joins. Everything should be taken |
\ things above are not control flow joins. Everything should be taken |
\ over from the live flow. No lp+!# is generated. |
\ over from the live flow. No lp+!# is generated. |
|
|
\ !! The lp gymnastics for UNTIL are also a real problem: locals cannot be |
|
\ used in signal handlers (or anything else that may be called while |
|
\ locals live beyond the lp) without changing the locals stack. |
|
|
|
\ About warning against uses of dead locals. There are several options: |
\ About warning against uses of dead locals. There are several options: |
|
|
\ 1) Do not complain (After all, this is Forth;-) |
\ 1) Do not complain (After all, this is Forth;-) |
Line 488 forth definitions
|
Line 614 forth definitions
|
\ this gives a unique identifier for the way the xt was defined |
\ this gives a unique identifier for the way the xt was defined |
\ words defined with different does>-codes have different definers |
\ words defined with different does>-codes have different definers |
\ the definer can be used for comparison and in definer! |
\ the definer can be used for comparison and in definer! |
dup >code-address [ ' bits >code-address ] Literal = |
dup >code-address [ ' spaces >code-address ] Literal = |
\ !! this definition will not work on some implementations for `bits' |
\ !! this definition will not work on some implementations for `bits' |
if \ if >code-address delivers the same value for all does>-def'd words |
if \ if >code-address delivers the same value for all does>-def'd words |
>does-code 1 or \ bit 0 marks special treatment for does codes |
>does-code 1 or \ bit 0 marks special treatment for does codes |
Line 504 forth definitions
|
Line 630 forth definitions
|
code-address! |
code-address! |
then ; |
then ; |
|
|
: TO ( c|w|d|r "name" -- ) \ core-ext,local |
:noname |
\ !! state smart |
' dup >definer [ ' locals-wordlist >definer ] literal = |
0 0 0. 0.0e0 { c: clocal w: wlocal d: dlocal f: flocal } |
if |
' dup >definer |
>body ! |
state @ |
else |
if |
-&32 throw |
case |
endif ; |
[ ' locals-wordlist >definer ] literal \ value |
:noname |
OF >body POSTPONE Aliteral POSTPONE ! ENDOF |
0 0 0. 0.0e0 { c: clocal w: wlocal d: dlocal f: flocal } |
[ ' clocal >definer ] literal |
comp' drop dup >definer |
OF POSTPONE laddr# >body @ lp-offset, POSTPONE c! ENDOF |
case |
[ ' wlocal >definer ] literal |
[ ' locals-wordlist >definer ] literal \ value |
OF POSTPONE laddr# >body @ lp-offset, POSTPONE ! ENDOF |
OF >body POSTPONE Aliteral POSTPONE ! ENDOF |
[ ' dlocal >definer ] literal |
[ comp' clocal drop >definer ] literal |
OF POSTPONE laddr# >body @ lp-offset, POSTPONE d! ENDOF |
OF POSTPONE laddr# >body @ lp-offset, POSTPONE c! ENDOF |
[ ' flocal >definer ] literal |
[ comp' wlocal drop >definer ] literal |
OF POSTPONE laddr# >body @ lp-offset, POSTPONE f! ENDOF |
OF POSTPONE laddr# >body @ lp-offset, POSTPONE ! ENDOF |
-&32 throw |
[ comp' dlocal drop >definer ] literal |
endcase |
OF POSTPONE laddr# >body @ lp-offset, POSTPONE 2! ENDOF |
else |
[ comp' flocal drop >definer ] literal |
[ ' locals-wordlist >definer ] literal = |
OF POSTPONE laddr# >body @ lp-offset, POSTPONE f! ENDOF |
if |
-&32 throw |
>body ! |
endcase ; |
else |
interpret/compile: TO ( c|w|d|r "name" -- ) \ core-ext,local |
-&32 throw |
|
endif |
|
endif ; immediate |
|
|
|
: locals| |
: locals| |
\ don't use 'locals|'! use '{'! A portable and free '{' |
\ don't use 'locals|'! use '{'! A portable and free '{' |
\ implementation is anslocals.fs |
\ implementation is compat/anslocals.fs |
BEGIN |
BEGIN |
name 2dup s" |" compare 0<> |
name 2dup s" |" compare 0<> |
WHILE |
WHILE |