Loading chapter3.tex +5 −0 Original line number Diff line number Diff line Loading @@ -927,6 +927,11 @@ can look inside an object and its source code whenever you want. And table driven method dispatching can be quite efficient. \hfill\person{Bernd Paysan}}\fi \begin{tfnote}{Bernd Paysan} Object oriented programming within the \Forth{} context needs better coverage here. \end{tfnote} An object is a portion of code that can be invoked by a single name, but that can perform more than one function. To select a particular function you have to invoke the object and pass it a parameter or a Loading chapter7.tex +108 −103 Original line number Diff line number Diff line Loading @@ -2,7 +2,7 @@ %% Copyright (C) 2004 Leo Brodie %% Initial transcription by Nils M Holm %% Based on OCR scans by Steve Fisher %% %% -*-coding: iso-8859-1;-*- \chapter{Handling~Data: Stacks~and~States}\Chapmark{7} Loading Loading @@ -247,15 +247,11 @@ for drawing a box doesn't lend itself to the nature of the stack. If you're in a hurry, it would probably be best to take the easy way out: \begin{Code} Variable TOP ( y coordinates top of box) Variable LEFT ( x " left side) Variable BOTTOM ( y " bottom) Variable RIGHT ( x " right side) : [BOX] ( x1 y1 x2 y2) BOTTOM ! RIGHT ! TOP ! LEFT ! LEFT @ TOP @ RIGHT @ TOP @ LINE RIGHT @ TOP @ RIGHT @ BOTTOM @ LINE RIGHT @ BOTTOM @ LEFT @ BOTTOM @ LINE LEFT @ BOTTOM @ LEFT @ TOP @ LINE ; : [box] { x1 y1 x2 y2 -- } x1 y1 x2 y1 line x2 y1 x2 y2 line x2 y2 x1 y2 line x1 y2 x1 y1 line ; \end{Code} What we've done is create four named variables, one for each coordinate. The first thing \forth{[BOX]} does is fill these variables with the Loading Loading @@ -323,7 +319,7 @@ Or we might discover that this syntax feels more natural to the user: \begin{Code} 10 10 ORIGIN! 30 30 BOX 10 10 origin! 30 30 box \end{Code} where \forth{ORIGIN!} sets a two-element pointer to the ``origin,'' the place where the box will start (the upper left-hand corner). Then Loading Loading @@ -551,7 +547,7 @@ Once the loop has found the character sequence, we subtract its relative address from our current cursor position \begin{Code} its-position CURSOR @ swap - its-position cursor @ swap - \end{Code} to determine the distance between them. Loading Loading @@ -601,7 +597,7 @@ the next worst thing to the now ``forbidden'' GOTO. \wepsfigp{img7-211}{``Shot from a cannon on a fast-moving train, hurtling between the blades of a windmill, and expecting to grab a trapeze dangling from a hot-air balloon\dots{} I told you Ace, there were trapeze dangling from a hot-air balloon\dots{} I~told you Ace, there were too many variables!''} \noindent Earlier we suggested the use of local variables especially Loading Loading @@ -698,15 +694,15 @@ number radix for all numeric input and output. The following words are commonly found in \Forth{} systems: \begin{Code} : decimal 10 base ! ; : hex 16 base ! ; : decimal ( -- ) 10 base ! ; : hex ( -- ) 16 base ! ; \end{Code} Suppose we've written a word that displays a ``dump'' of memory. Ordinarily, we work in decimal mode, but we want the dump in hexadecimal. So we write: \begin{Code} : dump ( a # ) : dump ( a # -- ) hex ... ( code for the dump) ... decimal ; \end{Code} This works---most of the time. But there's a presumption that we want to Loading @@ -720,17 +716,17 @@ This means we have to tuck away the saved value temporarily, while we format the dump. The return stack is one place to do this: \begin{Code} : dump ( a # ) : dump ( a # -- ) base @ >r hex ( code for dump) r> base ! ; \end{Code} If things get too messy, we may have to define a temporary variable: \index{R!Return stack|)} \begin{Code} Variable OLD-BASE : dump ( a # ) base @ OLD-BASE ! hex ( code for dump ) OLD-BASE @ base ! ; Variable old-base : dump ( a # -- ) base @ old-base ! hex ( code for dump ) old-base @ base ! ; \end{Code} How quickly things get complicated.% \index{B!BASE|)} Loading @@ -740,20 +736,20 @@ belong only to your application (and not part of your system), and if this same situation comes up more than once, apply a technique of factoring: \begin{Code} : BURY ( a) dup 2+ 2 cmove ; : EXHUME ( a) dup 2+ swap 2 cmove ; : bury ( a -- ) dup 2+ 2 cmove ; : exhume ( a -- ) dup 2+ swap 2 cmove ; \end{Code} Then instead of defining two variables, such as \forth{CONDITION} and \forth{OLD-CONDITION}, define one double-length variable: \begin{Code} 2Variable CONDITION 2Variable condition \end{Code} Use \forth{BURY} and \forth{EXHUME} to save and restore the original value: \begin{Code} : DIDDLE CONDITION BURY 17 CONDITION ! ( diddle ) CONDITION EXHUME ; : diddle condition bury 17 condition ! ( diddle ) condition exhume ; \end{Code} \forth{BURY} saves the ``old'' version of condition at \forth{CONDITION 2+}. Loading Loading @@ -815,9 +811,9 @@ value, make sure it's not just a case of bad factoring. For example, suppose we have written: \begin{Code} : LONG 18 #HOLES ! ; : SHORT 9 #HOLES ! ; : GAME #HOLES @ 0 DO i HOLE PLAY LOOP ; : long ( -- ) 18 #holes ! ; : short ( -- ) 9 #holes ! ; : game ( -- ) #holes @ 0 DO i hole play LOOP ; \end{Code} The current \forth{GAME} is either \forth{LONG} or \forth{SHORT}. Loading @@ -826,7 +822,7 @@ we invoke \forth{GAME} making sure not to clobber the current value of \forth{\#HOLES}: \begin{Code} : HOLES ( n) #HOLES @ swap #HOLES ! GAME #HOLES ! ; : holes ( n -- ) #holes @ swap #holes ! game #holes ! ; \end{Code} Because we needed \forth{HOLES} after we'd defined \forth{GAME}, it seemed to be of greater complexity; we built \forth{HOLES} around Loading @@ -834,8 +830,8 @@ seemed to be of greater complexity; we built \forth{HOLES} around in order: \begin{Code} : HOLES ( n) 0 DO i HOLE PLAY LOOP ; : GAME #HOLES @ HOLES ; : holes ( n -- ) 0 DO i hole play LOOP ; : game ( -- ) #holes @ holes ; \end{Code} We can build \forth{GAME} around \forth{HOLES} and avoid all this saving/restoring nonsense.% Loading @@ -853,12 +849,16 @@ Here is the code for a user stack including very simple error checking (an error clears the stack): \begin{Code} Create STACK 12 allot \ { 2tos-pointer | 10stack [5 cells] } here Constant STACK> : INIT-STACK STACK STACK ! ; INIT-STACK : ?BAD ( ?) IF ." STACK ERROR " INIT-STACK abort THEN ; : PUSH ( n) 2 STACK +! STACK @ dup STACK> = ?BAD ! ; : POP ( -- n) STACK @ @ -2 STACK +! STACK @ STACK < ?BAD ; Create stack 6 cells allot \ { tos-pointer | stack [5 cells] } here Constant stack> : init-stack ( -- ) stack stack ! ; init-stack : ?bad ( ? -- ) IF ." stack error " init-stack abort THEN ; : push ( n -- ) cell stack +! stack @ dup stack> = ?bad ! ; : pop ( -- n ) stack @ @ cell negate stack +! stack @ stack < ?bad ; \end{Code} The word \forth{PUSH} takes a value from off of your data stack and ``pushes'' it onto this new stack. \forth{POP} is the opposite, Loading Loading @@ -943,12 +943,12 @@ how you want to decompose the problem. First, we could nest one condition within the other: \begin{Code} : [DISPLAY] ... : [display] ... ( the original definition, always does the output) ... ; Variable 'LOOKAHEAD? ( t=looking-ahead) : <DISPLAY> 'LOOKAHEAD? @ NOT IF [DISPLAY] THEN ; Variable 'TOC? ( t=setting-table-of-contents) : DISPLAY 'TOC? @ NOT IF <DISPLAY> THEN ; Variable 'lookahead? ( t=looking-ahead) : <display> ( -- ) 'lookahead? @ 0= IF [display] THEN ; Variable 'toc? ( t=setting-table-of-contents) : display ( -- ) 'toc? @ 0= IF <display> THEN ; \end{Code} {\sloppy \forth{DISPLAY} checks that we're not setting the table of contents Loading @@ -972,7 +972,8 @@ That's one approach to the use of two variables. Another is to include both tests within a single word: \begin{Code} : DISPLAY 'LOOKAHEAD? @ 'TOC @ or NOT IF [DISPLAY] THEN ; : display ( -- ) 'lookahead? @ 'toc @ or 0= IF [display] THEN ; \end{Code} But in this particular case, yet another approach can simplify the whole mess. We can use a single variable not as a flag, but as a counter. Loading @@ -980,10 +981,10 @@ mess. We can use a single variable not as a flag, but as a counter. We define: \begin{Code} Variable 'INVISIBLE? ( t=invisible) : DISPLAY 'INVISIBLE? @ 0= IF [DISPLAY] THEN ; : INVISIBLE 1 'INVISIBLE? +! ; : VISIBLE -1 'INVISIBLE? +! ; variable 'invisible? ( t=invisible) : display ( -- ) 'invisible? @ 0= IF [display] THEN ; : invisible 1 'invisible? +! ; : visible -1 'invisible? +! ; \end{Code} The lookahead code begins by invoking \forth{INVISIBLE} which bumps the counter up one. Non-zero is ``true,'' so \forth{DISPLAY} will not Loading @@ -999,16 +1000,16 @@ The subsequent invocation of \forth{INVISIBLE} decrements the counter to one, so we're still invisible, and will remain invisible until the table of contents has been run. (Note that we must substitute \forthb{0=} for \forthb{NOT}. The '83 Standard has changed \forthb{NOT} to mean one's complement, so that \forthb{1 NOT} yields true. By the way, I think this was a mistake.) %(Note that we must substitute \forthb{0=} for \forthb{NOT}. The '83 %Standard has changed \forthb{NOT} to mean one's complement, so that %\forthb{1 NOT} yields true. By the way, I think this was a mistake.) This use of a counter may be dangerous, however. It requires parity of command usage: two \forth{VISIBLE}s yields invisible. That is, unless \forth{VISIBLE} clips the counter: \begin{Code} : VISIBLE 'INVISIBLE? @ 1- 0 max 'INVISIBLE? ! ; : visible ( -- ) 'invisible? @ 1- 0 max 'invisible? ! ; \end{Code} \index{C!Components:!sharing|)}% \index{S!Sharing components|)} Loading Loading @@ -1038,12 +1039,12 @@ component, as shown in \Fig{fig7-2}. \labelfig{fig7-2} \begin{center} \begin{BVerbatim} VARIABLE TOP VARIABLE BOTTOM VARIABLE LEFT VARIABLE RIGHT VARIABLE INSIDE VARIABLE OUT Variable top Variable bottom Variable left Variable right Variable inside Variable out \end{BVerbatim} \end{center} \end{figure*} Loading @@ -1052,10 +1053,10 @@ VARIABLE OUT processing can take place, and later restore all of them. We could define: \begin{Code} : @STATE ( -- top bottom left right inside out) TOP @ BOTTOM @ LEFT @ RIGHT @ INSIDE @ OUT @ ; : !STATE ( top bottom left right inside out -- ) OUT ! INSIDE ! RIGHT ! LEFT ! BOTTOM ! TOP ! ; : @state ( -- top bottom left right inside out ) top @ bottom @ left @ right @ inside @ out @ ; : !state ( top bottom left right inside out -- ) out ! inside ! right ! left ! bottom ! top ! ; \end{Code} thereby saving all the values on the stack until it's time to restore them. Or, we might define alternate variables for each of the variables above, in Loading @@ -1078,22 +1079,22 @@ We've implemented this approach with the code in \Fig{fig7-4}. \labelfig{fig7-4} \begin{center} \begin{BVerbatim} 0 CONSTANT POINTERS \ address of state table PATCHED LATER : POSITION ( o -- o+2 ) CREATE DUP , 2+ DOES> ( -- a ) @ POINTERS + ; 0 Value pointers \ address of state table patched later : Position ( o -- o+2 ) Create dup , 2+ DOES> ( -- a ) @ pointers + ; 0 \ initial offset POSITION TOP POSITION BOTTOM POSITION LEFT POSITION RIGHT POSITION INSIDE POSITION OUT CONSTANT /POINTERS \ final computed offset HERE ' POINTERS >BODY ! /POINTERS ALLOT \ real table CREATE SAVED /POINTERS ALLOT \ saving place : SAVE POINTERS SAVED /POINTERS CMOVE ; : RESTORE SAVED POINTERS /POINTERS CMOVE ; Position top Position bottom Position left Position right Position inside Position out Constant /pointers \ final computed offset here to pointers /pointers allot \ real table Create saved /pointers allot \ saving place : save ( -- ) pointers saved /pointers cmove ; : restore ( -- ) saved pointers /pointers cmove ; \end{BVerbatim} \end{center} \end{figure*} Loading Loading @@ -1149,37 +1150,37 @@ appropriately. For instance: \labelfig{fig7-6} \begin{center} \begin{BVerbatim} VARIABLE 'POINTERS \ pointer to state table : POINTERS ( -- adr of current table) 'POINTERS @ ; : POSITION ( o -- o+2 ) CREATE DUP , 2+ DOES> ( -- a ) @ POINTERS + ; Variable 'pointers \ pointer to state table : pointers ( -- adr-of-current-table ) 'pointers @ ; : Position ( o -- o+2 ) Create dup , 2+ DOES> ( -- a ) @ pointers + ; 0 \ initial offset POSITION TOP POSITION BOTTOM POSITION LEFT POSITION RIGHT POSITION INSIDE POSITION OUT CONSTANT /POINTERS \ final computed offset CREATE REAL /POINTERS ALLOT \ real state table CREATE PSEUDO /POINTERS ALLOT \ temporary state table : WORKING REAL 'POINTERS ! ; WORKING : PRETENDING PSEUDO 'POINTERS ! ; Position top Position bottom Position left Position right Position inside Position out Constant /pointers \ final computed offset Create real /pointers allot \ real state table Create pseudo /pointers allot \ temporary state table : working real 'pointers ! ; working : pretending pseudo 'pointers ! ; \end{BVerbatim} \end{center} \end{figure*} \begin{Code}[commandchars=&\{\}] WORKING 10 TOP ! TOP &underline{? 10} PRETENDING 20 TOP ! TOP &underline{? 20} WORKING TOP &underline{? 10} PRETENDING TOP &underline{? 20} working 10 top ! top &underline{? 10} pretending 20 top ! top &underline{? 20} working top &underline{? 10} pretending top &underline{? 20} \end{Code} The major difference with this latter approach is that names go through an extra level of indirection (\forth{POINTERS} has been changed from a Loading @@ -1206,6 +1207,10 @@ described in \emph{Starting \Forth{}}, Chapter Nine. In this section we'll discuss a new syntax which I invented and which I think can be used in many circumstances more elegantly than the traditional methods. \begin{tfnote}{Bernd Paysan} \forth{DORE}/\forth{MAKE} need to be replaced with \forth{DEFER}/\forth{IS}. \end{tfnote} \index{D!DOER/MAKE|(}% The syntax is called \forth{DOER}/\forth{MAKE}. (If your system doesn't include these words, refer to \App{B} for code and implementation Loading tf.sty +1 −1 Original line number Diff line number Diff line Loading @@ -352,7 +352,7 @@ linecolor=midgreen,linewidth=0.3pt, shadowcolor=lightgrey,shadowsize=3pt,blur=true]{\unhbox\@tempboxa}% \ifodd\hypergetpageref{note-\thechapter.\arabic{notec}}% ~\vbox to \@tempdima{% vss}\hss% \vss}\hss% \else \hbox to 2.5em{\hss}% \fi Loading Loading
chapter3.tex +5 −0 Original line number Diff line number Diff line Loading @@ -927,6 +927,11 @@ can look inside an object and its source code whenever you want. And table driven method dispatching can be quite efficient. \hfill\person{Bernd Paysan}}\fi \begin{tfnote}{Bernd Paysan} Object oriented programming within the \Forth{} context needs better coverage here. \end{tfnote} An object is a portion of code that can be invoked by a single name, but that can perform more than one function. To select a particular function you have to invoke the object and pass it a parameter or a Loading
chapter7.tex +108 −103 Original line number Diff line number Diff line Loading @@ -2,7 +2,7 @@ %% Copyright (C) 2004 Leo Brodie %% Initial transcription by Nils M Holm %% Based on OCR scans by Steve Fisher %% %% -*-coding: iso-8859-1;-*- \chapter{Handling~Data: Stacks~and~States}\Chapmark{7} Loading Loading @@ -247,15 +247,11 @@ for drawing a box doesn't lend itself to the nature of the stack. If you're in a hurry, it would probably be best to take the easy way out: \begin{Code} Variable TOP ( y coordinates top of box) Variable LEFT ( x " left side) Variable BOTTOM ( y " bottom) Variable RIGHT ( x " right side) : [BOX] ( x1 y1 x2 y2) BOTTOM ! RIGHT ! TOP ! LEFT ! LEFT @ TOP @ RIGHT @ TOP @ LINE RIGHT @ TOP @ RIGHT @ BOTTOM @ LINE RIGHT @ BOTTOM @ LEFT @ BOTTOM @ LINE LEFT @ BOTTOM @ LEFT @ TOP @ LINE ; : [box] { x1 y1 x2 y2 -- } x1 y1 x2 y1 line x2 y1 x2 y2 line x2 y2 x1 y2 line x1 y2 x1 y1 line ; \end{Code} What we've done is create four named variables, one for each coordinate. The first thing \forth{[BOX]} does is fill these variables with the Loading Loading @@ -323,7 +319,7 @@ Or we might discover that this syntax feels more natural to the user: \begin{Code} 10 10 ORIGIN! 30 30 BOX 10 10 origin! 30 30 box \end{Code} where \forth{ORIGIN!} sets a two-element pointer to the ``origin,'' the place where the box will start (the upper left-hand corner). Then Loading Loading @@ -551,7 +547,7 @@ Once the loop has found the character sequence, we subtract its relative address from our current cursor position \begin{Code} its-position CURSOR @ swap - its-position cursor @ swap - \end{Code} to determine the distance between them. Loading Loading @@ -601,7 +597,7 @@ the next worst thing to the now ``forbidden'' GOTO. \wepsfigp{img7-211}{``Shot from a cannon on a fast-moving train, hurtling between the blades of a windmill, and expecting to grab a trapeze dangling from a hot-air balloon\dots{} I told you Ace, there were trapeze dangling from a hot-air balloon\dots{} I~told you Ace, there were too many variables!''} \noindent Earlier we suggested the use of local variables especially Loading Loading @@ -698,15 +694,15 @@ number radix for all numeric input and output. The following words are commonly found in \Forth{} systems: \begin{Code} : decimal 10 base ! ; : hex 16 base ! ; : decimal ( -- ) 10 base ! ; : hex ( -- ) 16 base ! ; \end{Code} Suppose we've written a word that displays a ``dump'' of memory. Ordinarily, we work in decimal mode, but we want the dump in hexadecimal. So we write: \begin{Code} : dump ( a # ) : dump ( a # -- ) hex ... ( code for the dump) ... decimal ; \end{Code} This works---most of the time. But there's a presumption that we want to Loading @@ -720,17 +716,17 @@ This means we have to tuck away the saved value temporarily, while we format the dump. The return stack is one place to do this: \begin{Code} : dump ( a # ) : dump ( a # -- ) base @ >r hex ( code for dump) r> base ! ; \end{Code} If things get too messy, we may have to define a temporary variable: \index{R!Return stack|)} \begin{Code} Variable OLD-BASE : dump ( a # ) base @ OLD-BASE ! hex ( code for dump ) OLD-BASE @ base ! ; Variable old-base : dump ( a # -- ) base @ old-base ! hex ( code for dump ) old-base @ base ! ; \end{Code} How quickly things get complicated.% \index{B!BASE|)} Loading @@ -740,20 +736,20 @@ belong only to your application (and not part of your system), and if this same situation comes up more than once, apply a technique of factoring: \begin{Code} : BURY ( a) dup 2+ 2 cmove ; : EXHUME ( a) dup 2+ swap 2 cmove ; : bury ( a -- ) dup 2+ 2 cmove ; : exhume ( a -- ) dup 2+ swap 2 cmove ; \end{Code} Then instead of defining two variables, such as \forth{CONDITION} and \forth{OLD-CONDITION}, define one double-length variable: \begin{Code} 2Variable CONDITION 2Variable condition \end{Code} Use \forth{BURY} and \forth{EXHUME} to save and restore the original value: \begin{Code} : DIDDLE CONDITION BURY 17 CONDITION ! ( diddle ) CONDITION EXHUME ; : diddle condition bury 17 condition ! ( diddle ) condition exhume ; \end{Code} \forth{BURY} saves the ``old'' version of condition at \forth{CONDITION 2+}. Loading Loading @@ -815,9 +811,9 @@ value, make sure it's not just a case of bad factoring. For example, suppose we have written: \begin{Code} : LONG 18 #HOLES ! ; : SHORT 9 #HOLES ! ; : GAME #HOLES @ 0 DO i HOLE PLAY LOOP ; : long ( -- ) 18 #holes ! ; : short ( -- ) 9 #holes ! ; : game ( -- ) #holes @ 0 DO i hole play LOOP ; \end{Code} The current \forth{GAME} is either \forth{LONG} or \forth{SHORT}. Loading @@ -826,7 +822,7 @@ we invoke \forth{GAME} making sure not to clobber the current value of \forth{\#HOLES}: \begin{Code} : HOLES ( n) #HOLES @ swap #HOLES ! GAME #HOLES ! ; : holes ( n -- ) #holes @ swap #holes ! game #holes ! ; \end{Code} Because we needed \forth{HOLES} after we'd defined \forth{GAME}, it seemed to be of greater complexity; we built \forth{HOLES} around Loading @@ -834,8 +830,8 @@ seemed to be of greater complexity; we built \forth{HOLES} around in order: \begin{Code} : HOLES ( n) 0 DO i HOLE PLAY LOOP ; : GAME #HOLES @ HOLES ; : holes ( n -- ) 0 DO i hole play LOOP ; : game ( -- ) #holes @ holes ; \end{Code} We can build \forth{GAME} around \forth{HOLES} and avoid all this saving/restoring nonsense.% Loading @@ -853,12 +849,16 @@ Here is the code for a user stack including very simple error checking (an error clears the stack): \begin{Code} Create STACK 12 allot \ { 2tos-pointer | 10stack [5 cells] } here Constant STACK> : INIT-STACK STACK STACK ! ; INIT-STACK : ?BAD ( ?) IF ." STACK ERROR " INIT-STACK abort THEN ; : PUSH ( n) 2 STACK +! STACK @ dup STACK> = ?BAD ! ; : POP ( -- n) STACK @ @ -2 STACK +! STACK @ STACK < ?BAD ; Create stack 6 cells allot \ { tos-pointer | stack [5 cells] } here Constant stack> : init-stack ( -- ) stack stack ! ; init-stack : ?bad ( ? -- ) IF ." stack error " init-stack abort THEN ; : push ( n -- ) cell stack +! stack @ dup stack> = ?bad ! ; : pop ( -- n ) stack @ @ cell negate stack +! stack @ stack < ?bad ; \end{Code} The word \forth{PUSH} takes a value from off of your data stack and ``pushes'' it onto this new stack. \forth{POP} is the opposite, Loading Loading @@ -943,12 +943,12 @@ how you want to decompose the problem. First, we could nest one condition within the other: \begin{Code} : [DISPLAY] ... : [display] ... ( the original definition, always does the output) ... ; Variable 'LOOKAHEAD? ( t=looking-ahead) : <DISPLAY> 'LOOKAHEAD? @ NOT IF [DISPLAY] THEN ; Variable 'TOC? ( t=setting-table-of-contents) : DISPLAY 'TOC? @ NOT IF <DISPLAY> THEN ; Variable 'lookahead? ( t=looking-ahead) : <display> ( -- ) 'lookahead? @ 0= IF [display] THEN ; Variable 'toc? ( t=setting-table-of-contents) : display ( -- ) 'toc? @ 0= IF <display> THEN ; \end{Code} {\sloppy \forth{DISPLAY} checks that we're not setting the table of contents Loading @@ -972,7 +972,8 @@ That's one approach to the use of two variables. Another is to include both tests within a single word: \begin{Code} : DISPLAY 'LOOKAHEAD? @ 'TOC @ or NOT IF [DISPLAY] THEN ; : display ( -- ) 'lookahead? @ 'toc @ or 0= IF [display] THEN ; \end{Code} But in this particular case, yet another approach can simplify the whole mess. We can use a single variable not as a flag, but as a counter. Loading @@ -980,10 +981,10 @@ mess. We can use a single variable not as a flag, but as a counter. We define: \begin{Code} Variable 'INVISIBLE? ( t=invisible) : DISPLAY 'INVISIBLE? @ 0= IF [DISPLAY] THEN ; : INVISIBLE 1 'INVISIBLE? +! ; : VISIBLE -1 'INVISIBLE? +! ; variable 'invisible? ( t=invisible) : display ( -- ) 'invisible? @ 0= IF [display] THEN ; : invisible 1 'invisible? +! ; : visible -1 'invisible? +! ; \end{Code} The lookahead code begins by invoking \forth{INVISIBLE} which bumps the counter up one. Non-zero is ``true,'' so \forth{DISPLAY} will not Loading @@ -999,16 +1000,16 @@ The subsequent invocation of \forth{INVISIBLE} decrements the counter to one, so we're still invisible, and will remain invisible until the table of contents has been run. (Note that we must substitute \forthb{0=} for \forthb{NOT}. The '83 Standard has changed \forthb{NOT} to mean one's complement, so that \forthb{1 NOT} yields true. By the way, I think this was a mistake.) %(Note that we must substitute \forthb{0=} for \forthb{NOT}. The '83 %Standard has changed \forthb{NOT} to mean one's complement, so that %\forthb{1 NOT} yields true. By the way, I think this was a mistake.) This use of a counter may be dangerous, however. It requires parity of command usage: two \forth{VISIBLE}s yields invisible. That is, unless \forth{VISIBLE} clips the counter: \begin{Code} : VISIBLE 'INVISIBLE? @ 1- 0 max 'INVISIBLE? ! ; : visible ( -- ) 'invisible? @ 1- 0 max 'invisible? ! ; \end{Code} \index{C!Components:!sharing|)}% \index{S!Sharing components|)} Loading Loading @@ -1038,12 +1039,12 @@ component, as shown in \Fig{fig7-2}. \labelfig{fig7-2} \begin{center} \begin{BVerbatim} VARIABLE TOP VARIABLE BOTTOM VARIABLE LEFT VARIABLE RIGHT VARIABLE INSIDE VARIABLE OUT Variable top Variable bottom Variable left Variable right Variable inside Variable out \end{BVerbatim} \end{center} \end{figure*} Loading @@ -1052,10 +1053,10 @@ VARIABLE OUT processing can take place, and later restore all of them. We could define: \begin{Code} : @STATE ( -- top bottom left right inside out) TOP @ BOTTOM @ LEFT @ RIGHT @ INSIDE @ OUT @ ; : !STATE ( top bottom left right inside out -- ) OUT ! INSIDE ! RIGHT ! LEFT ! BOTTOM ! TOP ! ; : @state ( -- top bottom left right inside out ) top @ bottom @ left @ right @ inside @ out @ ; : !state ( top bottom left right inside out -- ) out ! inside ! right ! left ! bottom ! top ! ; \end{Code} thereby saving all the values on the stack until it's time to restore them. Or, we might define alternate variables for each of the variables above, in Loading @@ -1078,22 +1079,22 @@ We've implemented this approach with the code in \Fig{fig7-4}. \labelfig{fig7-4} \begin{center} \begin{BVerbatim} 0 CONSTANT POINTERS \ address of state table PATCHED LATER : POSITION ( o -- o+2 ) CREATE DUP , 2+ DOES> ( -- a ) @ POINTERS + ; 0 Value pointers \ address of state table patched later : Position ( o -- o+2 ) Create dup , 2+ DOES> ( -- a ) @ pointers + ; 0 \ initial offset POSITION TOP POSITION BOTTOM POSITION LEFT POSITION RIGHT POSITION INSIDE POSITION OUT CONSTANT /POINTERS \ final computed offset HERE ' POINTERS >BODY ! /POINTERS ALLOT \ real table CREATE SAVED /POINTERS ALLOT \ saving place : SAVE POINTERS SAVED /POINTERS CMOVE ; : RESTORE SAVED POINTERS /POINTERS CMOVE ; Position top Position bottom Position left Position right Position inside Position out Constant /pointers \ final computed offset here to pointers /pointers allot \ real table Create saved /pointers allot \ saving place : save ( -- ) pointers saved /pointers cmove ; : restore ( -- ) saved pointers /pointers cmove ; \end{BVerbatim} \end{center} \end{figure*} Loading Loading @@ -1149,37 +1150,37 @@ appropriately. For instance: \labelfig{fig7-6} \begin{center} \begin{BVerbatim} VARIABLE 'POINTERS \ pointer to state table : POINTERS ( -- adr of current table) 'POINTERS @ ; : POSITION ( o -- o+2 ) CREATE DUP , 2+ DOES> ( -- a ) @ POINTERS + ; Variable 'pointers \ pointer to state table : pointers ( -- adr-of-current-table ) 'pointers @ ; : Position ( o -- o+2 ) Create dup , 2+ DOES> ( -- a ) @ pointers + ; 0 \ initial offset POSITION TOP POSITION BOTTOM POSITION LEFT POSITION RIGHT POSITION INSIDE POSITION OUT CONSTANT /POINTERS \ final computed offset CREATE REAL /POINTERS ALLOT \ real state table CREATE PSEUDO /POINTERS ALLOT \ temporary state table : WORKING REAL 'POINTERS ! ; WORKING : PRETENDING PSEUDO 'POINTERS ! ; Position top Position bottom Position left Position right Position inside Position out Constant /pointers \ final computed offset Create real /pointers allot \ real state table Create pseudo /pointers allot \ temporary state table : working real 'pointers ! ; working : pretending pseudo 'pointers ! ; \end{BVerbatim} \end{center} \end{figure*} \begin{Code}[commandchars=&\{\}] WORKING 10 TOP ! TOP &underline{? 10} PRETENDING 20 TOP ! TOP &underline{? 20} WORKING TOP &underline{? 10} PRETENDING TOP &underline{? 20} working 10 top ! top &underline{? 10} pretending 20 top ! top &underline{? 20} working top &underline{? 10} pretending top &underline{? 20} \end{Code} The major difference with this latter approach is that names go through an extra level of indirection (\forth{POINTERS} has been changed from a Loading @@ -1206,6 +1207,10 @@ described in \emph{Starting \Forth{}}, Chapter Nine. In this section we'll discuss a new syntax which I invented and which I think can be used in many circumstances more elegantly than the traditional methods. \begin{tfnote}{Bernd Paysan} \forth{DORE}/\forth{MAKE} need to be replaced with \forth{DEFER}/\forth{IS}. \end{tfnote} \index{D!DOER/MAKE|(}% The syntax is called \forth{DOER}/\forth{MAKE}. (If your system doesn't include these words, refer to \App{B} for code and implementation Loading
tf.sty +1 −1 Original line number Diff line number Diff line Loading @@ -352,7 +352,7 @@ linecolor=midgreen,linewidth=0.3pt, shadowcolor=lightgrey,shadowsize=3pt,blur=true]{\unhbox\@tempboxa}% \ifodd\hypergetpageref{note-\thechapter.\arabic{notec}}% ~\vbox to \@tempdima{% vss}\hss% \vss}\hss% \else \hbox to 2.5em{\hss}% \fi Loading