Loading appendixb.tex +69 −107 Original line number Diff line number Diff line Loading @@ -27,7 +27,7 @@ place it on the return stack. That's all. \Forth{} execution then continues with this address on the return stack, which will cause the vectored function to be performed. It's like saying (in '83-Standard) \begin{Code} ' NOTHING >body >r <return> ' nothing >body >r <return> \end{Code} which executes \forth{NOTHING}. (This trick only works with colon definitions.) Loading @@ -48,7 +48,7 @@ DOER JOE & \\ \noindent Now suppose we define: \begin{Code} : TEST MAKE JOE cr ; : test make joe cr ; \end{Code} that is, we define a word that can vector \forth{JOE} to do a carriage return. Loading @@ -68,7 +68,7 @@ TEST & (MAKE) & 0 & JOE & CR & EXIT \\ \hline\noalign{\vspace{2pt}} \forthb{MAKE} inside a colon definition, \forthb{STATE} will be true, and we'll execute the phrase: \begin{Code} COMPILE (MAKE) here marker ! 0 , postpone (make) here marker ! 0 , \end{Code} We can see how \forthb{MAKE} has compiled the address of the run-time routine, \forthb{(MAKE)}, followed by a zero. (We'll explain what the Loading @@ -81,17 +81,17 @@ definition \forthb{TEST}: \bigskip{ \begin{tabular}{l@{\hspace{4ex}}>{\parindent-2ex}p{.5\textwidth}} \verb%R>% & Gets an address from the return stack. \verb%r>% & Gets an address from the return stack. This address points to the cell just past \forthb{(MAKE)}, where the zero is.\\ \verb%DUP 2+% & Gets the address of the second cell after \verb%dup cell+% & Gets the address of the second cell after \forthb{(MAKE)}, where the address of \forthb{JOE} is.\\ \verb%DUP 2+% & Gets the address of the third cell after \verb%dup cell+% & Gets the address of the third cell after \forthb{(MAKE)}, where the code we want to execute begins. The stack now has: \parindent2ex (~'marker,~'joe,~'code~--{}--~)\\ \verb%SWAP @ >BODY% & Fetches the contents of the address \verb%swap @ >body% & Fetches the contents of the address pointing to \forth{JOE} (i.e., gets the address of \forth{JOE}) and computes \forth{JOE}'s pfa, where the vector address goes.\\ Loading @@ -101,7 +101,7 @@ definition \forthb{TEST}: & Now \forth{JOE} points inside the definition of \forth{TEST}. When we type \forth{JOE}, we'll do a carriage return.\\ \verb%@ ?DUP IF >R THEN%& Fetches the contents of the cell \verb%@ ?dup IF >r THEN%& Fetches the contents of the cell containing zero. Since the cell does contain zero, the \forth{IF THEN} statement is not performed.\\ Loading @@ -112,7 +112,7 @@ That's the basic idea. But what about that cell containing zero? That's for the use of \forthb{;AND}. Suppose we changed \forth{TEST} to read: \begin{Code} : TEST MAKE JOE cr ;AND space ; : test make joe cr ;and space ; \end{Code} That is, when we invoke \forth{TEST} we'll vector \forth{JOE} to do a \forthb{CR}, and we'll do a \forthb{SPACE} right now. Here's what this Loading @@ -130,7 +130,7 @@ TEST & (MAKE) & adr & JOE & CR & EXIT & SPACE & EXIT \\ \hline\noalign{\vspace{2 \end{center} Here's the definition of \forthb{;AND}: \begin{Code} : ;AND COMPILE EXIT here marker @ ! ; immediate : ;and postpone EXIT here marker @ ! ; immediate \end{Code} We can see that \forthb{;AND} has compiled an \forthb{EXIT}\index{E!EXIT}, just as semicolon would. Loading @@ -156,15 +156,15 @@ One final note: on some systems you may encounter a problem. If you use you may not be able to find the most recently defined word. For instance, if you have: \begin{Code} : REFRAIN DO-DAH DO-DAH ; MAKE SONG CHORUS REFRAIN ; : refrain do-dah do-dah ; make song chorus refrain ; \end{Code} your system might think that refrain has not been defined. The problem is due to the placement of \forth{SMUDGE}. As a solution, try rearranging the order of definitions or, if necessary, put \forth{MAKE} code inside a definition which you then execute: \begin{Code} : SETUP MAKE SONG CHORUS REFRAIN ; SETUP : setup make song chorus refrain ; setup \end{Code} In Laboratory Microsystems PC/FORTH 2.0, the \forth{UNSMUDGE} on line 9 handles the problem. This problem does not arise with the Loading @@ -173,11 +173,11 @@ Laxen/Perry/Harris model. The final screen is an example of using \forthb{DOER/MAKE}. After loading the block, enter \begin{Code} RECITAL recital \end{Code} then enter \begin{Code} WHY? why? \end{Code} followed by return, as many times as you like (you'll get a different reason each time). Loading @@ -204,18 +204,18 @@ UNDO Usage: UNDO doer-name ; makes it safe to execute \end{Screen} \vfill \begin{Screen} \ DOER/MAKE FORTH-83 Laxen/Perry/Harris model LPB 12/05/83 : NOTHING ; : DOER Create ['] NOTHING >body , DOES> @ >r ; \ DOER/MAKE ANS Forth with real return-stack BP 22/04/06 : nothing ; : Doer Create ['] nothing >body , DOES> @ >r ; Variable marker : (MAKE) r> dup 2+ dup 2+ swap @ >body ! : (make) r> dup cell+ dup cell+ swap @ >body ! @ ?dup IF >r THEN ; : MAKE state @ IF ( compiling) COMPILE (MAKE) here marker ! 0 , ELSE here [compile] ' >body ! [compile] ] THEN ; immediate : ;AND COMPILE EXIT here marker @ ! ; immediate : UNDO ['] NOTHING >body [compile] ' >body ! ; : make state @ IF ( compiling) postpone (make) here marker ! 0 , ' , ELSE here ' >body ! ] THEN ; immediate : ;and postpone EXIT here marker @ ! ; immediate : undo ['] nothing >body ' >body ! ; \ The code in this screen is in the public domain. Loading @@ -223,79 +223,41 @@ Variable marker \end{Screen} \vfill \begin{Screen} ( DOER/MAKE FORTH-83 Lab. Micro PC/FORTH 2.0 LPB 12/05/83 ) : NOTHING ; : DOER Create ['] NOTHING >body , DOES> @ >r ; \ DOER/MAKE NC ANS Forth with real return-stack BP 22/04/06 : nothing ; : Doer Create ['] nothing , DOES> @ >r ; Variable marker : (MAKE) r> dup 2+ dup 2+ swap @ >body ! : (make) r> dup cell+ dup cell+ swap @ >body ! @ ?dup IF >r THEN ; : MAKE state @ IF ( compiling) COMPILE (MAKE) here marker ! 0 , ELSE here [compile] ' >body ! [compile] ] UNSMUDGE THEN ; immediate : ;AND COMPILE EXIT here marker @ ! ; immediate : UNDO ['] NOTHING >body [compile] ' >body ! ; ( The code in this screen is in the public domain.) \end{Screen} \vfill \begin{Screen} ( DOER/MAKE FIG model LPB 12/05/83 ) : NOTHING ; : DOES-PFA ( pfa -- pfa of child of <BUILD-DOES> ) 2+ ; : DOER <BUILDS ' NOTHING , DOES> @ >r ; 0 Variable marker : (MAKE) r> dup 2+ dup 2+ swap @ 2+ DOES-PFA ! @ -DUP IF >r THEN ; : MAKE state @ IF ( compiling) COMPILE (MAKE) here marker ! 0 , ELSE here [compile] ' DOES-PFA ! SMUDGE [compile] ] THEN ; immediate : ;AND COMPILE ;s here marker @ ! ; immediate : UNDO ' NOTHING [compile] ' DOES-PFA ! ; ;s The code in this screen is in the public domain. \end{Screen} \vfill \begin{Screen} ( DOER/MAKE 79-Standard MVP FORTH LPB 12/05/83 ) : NOTHING ; : DOER Create ' NOTHING , DOES> @ >r ; Variable marker : (MAKE) r> dup 2+ dup 2+ swap @ 2+ ( pfa) ! @ ?dup IF >r THEN ; : MAKE state @ IF ( compiling) COMPILE (MAKE) here marker ! 0 , ELSE here [compile] ' ! [compile] ] THEN ; immediate : ;AND COMPILE EXIT here marker @ ! ; immediate : UNDO ['] NOTHING [compile] ' ! ; : make state @ IF ( compiling) postpone (make) here marker ! 0 , ' , ELSE here ' >body ! ] THEN ; immediate : ;and postpone EXIT here marker @ ! ; immediate : undo ['] nothing ' >body ! ; \ The code in this screen is in the public domain. ( The code in this screen is in the public domain.) \end{Screen} \vfill \begin{Screen} ( TODDLER: Example of DOER/MAKE 12/01/83 ) DOER ANSWER : RECITAL \ toddler: Example of DOER/MAKE 12/01/83 ) Doer answer : recital cr ." Your daddy is standing on the table. Ask him 'WHY?' " MAKE ANSWER ." To change the light bulb." make answer ." To change the light bulb." BEGIN MAKE ANSWER ." Because it's burned out." MAKE ANSWER ." Because it was old." MAKE ANSWER ." Because we put it in there a long time ago." MAKE ANSWER ." Because it was dark!" MAKE ANSWER ." Because it was night time!!" MAKE ANSWER ." Stop saying WHY?" MAKE ANSWER ." Because it's driving me crazy." MAKE ANSWER ." Just let me change this light bulb!" false UNTIL ; : WHY? cr ANSWER quit ; make answer ." Because it's burned out." make answer ." Because it was old." make answer ." Because we put it in there a long time ago." make answer ." Because it was dark!" make answer ." Because it was night time!!" make answer ." Stop saying WHY?" make answer ." Because it's driving me crazy." make answer ." Just let me change this light bulb!" AGAIN ; : why? cr answer quit ; \end{Screen} \index{D!DOER/MAKE|)} \vfill chapter7.tex +95 −54 Original line number Diff line number Diff line Loading @@ -1242,10 +1242,6 @@ 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 @@ -1253,38 +1249,38 @@ details.) It works like this: You define the word whose behavior will be vectorable with the defining word \forthb{DOER}, as in \begin{Code} DOER PLATFORM Doer platform \end{Code} Initially, the new word \forth{PLATFORM} does nothing. Then you can write words that change what \forth{PLATFORM} does by using the word \forthb{MAKE}: \begin{Code} : LEFTWING MAKE PLATFORM ." proponent " ; : RIGHTWING MAKE PLATFORM ." opponent " ; : leftwing make platform ." proponent " ; : rightwing make platform ." opponent " ; \end{Code} When you invoke \forth{LEFTWING}, the phrase \forth{MAKE PLATFORM} changes what \forth{PLATFORM} will do. Now if you type \forth{PLATFORM}, you'll see: \begin{Code}[commandchars=\&\{\}] LEFTWING ok PLATFORM &underline{proponent ok} leftwing &underline{ ok} platform &underline{proponent ok} \end{Code} \forth{RIGHTWING} will make \forth{PLATFORM} display ``opponent.'' You can use \forth{PLATFORM} within another definition: \begin{Code} : SLOGAN ." Our candidate is a longstanding " PLATFORM : slogan ." Our candidate is a longstanding " platform ." of heavy taxation for business. " ; \end{Code} The statement \begin{Code} LEFTWING SLOGAN leftwing slogan \end{Code} will display one campaign statement, while \begin{Code} RIGHTWING SLOGAN rightwing slogan \end{Code} will display another. Loading Loading @@ -1361,12 +1357,14 @@ behavior is vectored by the code in \forth{DUMP} and \forth{CDUMP}. ``\forthb{LOOP}''.) \begin{Code}[commandchars=\&\{\}] DOER .UNIT ( a -- increment) \ display byte or cell : <DUMP> ( a # ) Doer .unit ( a -- increment) \ display byte or cell : <dump> ( a # -- ) 0 DO i 16 mod 0= IF cr dup i + 5 u.r 2 spaces THEN dup i + &poorbf{.UNIT} +LOOP drop ; : dump ( a #) MAKE .UNIT @ 6 u.r 2 ;AND <DUMP> ; : CDUMP ( a #) MAKE .UNIT c@ 4 u.r 1 ;AND <DUMP> ; dup i + &poorbf{.unit} +LOOP drop ; : dump ( a # -- ) make .unit @ 3 cells u.r 1 cells ;and <dump> ; : cdump ( a # -- ) make .unit c@ 4 u.r 1 chars ;and <dump> ; \end{Code} Notice how \forth{DUMP} and \forth{CDUMP} \emph{set-up} the vector, then go on to \emph{execute} the shell (the word \forth{<DUMP>}). Loading @@ -1375,18 +1373,18 @@ then go on to \emph{execute} the shell (the word \forth{<DUMP>}). command. For instance: \begin{Code} DOER TYPE' DOER EMIT' DOER SPACES' DOER CR' : VISIBLE MAKE TYPE' type ;AND MAKE EMIT' emit ;AND MAKE SPACES' spaces ;AND MAKE CR' cr ; : INVISIBLE MAKE TYPE' 2drop ;AND MAKE EMIT' drop ;AND MAKE SPACES' drop ;AND MAKE CR' ; Doer type' Doer emit' Doer spaces' Doer cr' : visible make type' type ;and make emit' emit ;and make spaces' spaces ;and make cr' cr ; : invisible make type' 2drop ;and make emit' drop ;and make spaces' drop ;and make cr' ; \end{Code} Here we've defined a vectorable set of output words, each name having a ``prime'' mark at the end. \forth{VISIBLE} sets them to their Loading @@ -1406,11 +1404,11 @@ shorter message. \goodbreak We write: \begin{Code} DOER ANNOUNCE : LONG MAKE ANNOUNCE Doer announce : long make announce cr ." You're in a large hall with a huge throne" cr ." covered with a red velvet canopy." MAKE ANNOUNCE make announce cr ." You're in the throne room." ; \end{Code} The word \forth{ANNOUNCE} will display either message. First we say Loading @@ -1427,19 +1425,19 @@ letting each one set the next. The following example (though not terribly practical) illustrates the point. \begin{Code} DOER WHERE Variable SHIRT Variable PANTS Variable DRESSER Variable CAR Doer where Variable shirt Variable pants Variable dresser Variable car : order \ specify search order MAKE WHERE SHIRT MAKE WHERE PANTS MAKE WHERE DRESSER MAKE WHERE CAR MAKE WHERE 0 ; make where shirt make where pants make where dresser make where car make where 0 ; : HUNT ( -- a|0 ) \ find location containing 17 order 5 0 DO WHERE dup 0= over @ 17 = or IF : hunt ( -- a|0 ) \ find location containing 17 order 5 0 DO where dup 0= over @ 17 = or IF LEAVE ELSE drop THEN LOOP ; \end{Code} In this code we've created a list of variables, then defined an Loading @@ -1456,11 +1454,11 @@ We can even define a \forthb{DOER} word that toggles its own behavior endlessly: \begin{Code} DOER SPEECH : ALTERNATE BEGIN MAKE SPEECH ." HELLO " MAKE SPEECH ." GOODBYE " 0 UNTIL ; Doer speech : alternate BEGIN make speech ." Hello " make speech ." Goodbye " AGAIN ; \end{Code} \item To implement a forward reference. A forward reference is usually needed as a ``hook,'' that is, a word invoked in a low-level definition Loading @@ -1470,12 +1468,12 @@ To implement a forward reference, build the header of the word with \forthb{DOER}, before invoking its name. \begin{Code} DOER STILL-UNDEFINED Doer still-undefined \end{Code} Later in the listing, use \forth{MAKE}; \begin{Code} MAKE STILL-UNDEFINED ALL THAT JAZZ ; Make still-undefined all that jazz ; \end{Code} (Remember, \forth{MAKE} can be used outside a colon definition.) Loading @@ -1491,21 +1489,21 @@ GCD of a, b = a IF b = 0 This translates nicely into: \begin{Code} DOER GCD ( a b -- gcd) MAKE GCD ?dup IF dup rot rot mod GCD THEN ; Doer gcd ( a b -- gcd) make gcd ?dup IF dup rot rot mod gcd THEN ; \end{Code} Indirect recursion occurs when one word invokes a second word, while the second word invokes the first. This can be done using the form: \begin{Code} DOER B Doer B : A ... B ... ; MAKE B ... A ... ; make B ... A ... ; \end{Code} \item Debugging. I often define: \begin{Code} DOER SNAP Doer snap \end{Code} (short for \forth{SNAPSHOT}), then edit \forth{SNAP} into my application at a point where I want to see what's going on. For Loading @@ -1522,6 +1520,49 @@ approach are those in which you need control over the address of the vector, such as when vectoring through an element in a decision table, or attempting to save/restore the contents of the vector. \section{DEFER/IS instead of DOER/MAKE} Despite \person{Leo Brodie} has proposed \forth{DOER/MAKE} 20 years ago, it didn't become widely used. Instead, a somewhat different vectored execution word pair, \forthb{DEFER/IS} are popular now. Why is this? First of all, \forth{DEFER/IS} are trivial to implement, even if you don't know much about the underlying Forth system. They don't rely on the return stack, but use execution tokens (what comes out of \forth{'}) instead. Look at the portable definition: \begin{Code} : Defer Create ['] noop , DOES> @ execute ; : IS ( xt "name" -- ) state @ IF ' >body postpone Literal postpone ! ELSE ' >body ! THEN ; immediate \end{Code} Being portable is only one reason --- if \forth{DOER/MAKE} were important enough to implement, each \Forth{} would have one. The second reason is named vectors. Let's take a look at the \forth{DUMP} example written with \forth{DEFER/IS} instead: \begin{Code}[commandchars=\&\{\}] Defer .unit ( a -- increment ) \ display byte or cell : <dump> ( a # -- ) 0 DO i 16 mod 0= IF cr dup i + 5 u.r 2 spaces THEN dup i + &poorbf{.unit} +LOOP drop ; : ?+ ( a -- inc ) @ 3 cells u.r 1 cells ; : c?+ ( a -- inc ) c@ 4 u.r 1 chars ; : dump ( a # -- ) ['] ?+ IS .unit <dump> ; : cdump ( a # -- ) ['] c?+ IS .unit <dump> ; \end{Code} This looks more complicated, with the explicit components --- but remember: You have to test your program as well. So here, you can use your simpe component (\forth{?+} or \forth{c?+}) in isolation, without the more complicated logic of the complete application. You can do that, because they have a name. And words that have a name can be used as factors for other words. \section{Summary} In this chapter we've examined the tradeoffs between using the stack and using variables and other data structures. Using the stack is preferable Loading fig7-7.tex +4 −4 Original line number Diff line number Diff line Loading @@ -2,7 +2,7 @@ \sf \setlength{\topsep}{0pt} \begin{framed} \textbf{DOER JOE}\underline{ ok} \textbf{Doer joe}\underline{ ok} \medskip {\begin{tabular}{|c|}\hline \boxto{MAKE}{JOE}\\ \hline\end{tabular}} Loading @@ -12,7 +12,7 @@ Creates a \textbf{DOER} word called JOE, that does nothing. \end{framed} \begin{framed} \textbf{: TEST~~MAKE JOE~~1 . ;}\underline{ ok} \textbf{: test~~make joe~~1 . ;}\underline{ ok} \medskip {\begin{tabular}{|c|}\hline \boxto{MAKE}{JOE}\\ \hline\end{tabular}} Loading @@ -27,7 +27,7 @@ Defines a new word called TEST \end{framed} \begin{framed} \textbf{TEST}\underline{ ok} \textbf{test}\underline{ ok} \medskip \relax\rnode{A}{\begin{tabular}{|c|}\hline \boxto{MAKE}{JOE}\\ \hline\end{tabular}} Loading @@ -45,7 +45,7 @@ Defines a new word called TEST \end{framed} \begin{framed} \textbf{JOE}\underline{ 1 ok} \textbf{joe}\underline{ 1 ok} \medskip Executes the code that JOE points to ( \textbf{1 . }). Loading fig7-8.tex +6 −6 Original line number Diff line number Diff line \begin{minipage}{\textwidth}\sf \setlength{\topsep}{0pt} \begin{framed} \textbf{DOER SAM}\underline{ ok} \textbf{Doer sam}\underline{ ok} \textbf{DOER BIFF}\underline{ ok} \textbf{Doer biff}\underline{ ok} \medskip \begin{tabular}{|c|}\hline SAM \\ \hline\end{tabular}\kern 4cm Loading @@ -14,7 +14,7 @@ Creates two \textbf{DOER} words that do nothing. \end{framed} \begin{framed} \textbf{: TESTB MAKE SAM 2 . ;AND MAKE BIFF 3 . ;}\underline{ ok} \textbf{: testb make sam 2 . ;and make biff 3 . ;}\underline{ ok} \medskip \begin{tabular}{|c|c|c|c|c|c|c|c|c|c|c|}\hline Loading @@ -26,7 +26,7 @@ Defines a new word called TESTB. \end{framed} \begin{framed} \textbf{TESTB}\underline{ ok} \textbf{testb}\underline{ ok} \medskip \rnode{A1}{\begin{tabular}{|c|}\hline SAM \\ \hline\end{tabular}}\kern 4cm Loading Loading @@ -62,9 +62,9 @@ redirects BIFF. \end{framed} \begin{framed} \textbf{SAM}\underline{ 2 ok} \textbf{sam}\underline{ 2 ok} \textbf{BIFF}\underline{ 3 ok} \textbf{biff}\underline{ 3 ok} \medskip Two \textbf{DOER} words have been redirected at the same time by the Loading fig7-9.tex +4 −4 Original line number Diff line number Diff line \begin{minipage}{\textwidth}\sf \setlength{\topsep}{0pt} \begin{framed} \textbf{: TESTC~~MAKE JOE 4 .~~MAKE JOE 5 . ;}\underline{ ok} \textbf{: testc~~make joe 4 .~~make joe 5 . ;}\underline{ ok} \medskip \begin{tabular}{|c|c|c|c|c|c|c|c|c|c|}\hline Loading @@ -13,7 +13,7 @@ Defines a new word called TESTC. \end{framed} \begin{framed} \textbf{TESTC}\underline{ ok} \textbf{testc}\underline{ ok} \medskip \rnode{A4}{\begin{tabular}{|c|}\hline JOE \\ \hline\end{tabular}} Loading @@ -30,7 +30,7 @@ TESTC & MAKE & JOE & \smash{\rnode{B4}{4\large\strut}} & . & MAKE & JOE & 5 & . \end{framed} \begin{framed} \textbf{JOE}\underline{ 4 ok} \textbf{joe}\underline{ 4 ok} \medskip \begin{tabular}{|c|c|c|c|c|c|c|c|c|c|}\hline Loading Loading @@ -58,7 +58,7 @@ point to the five. (There was no \textbf{;AND} to stop it.). \end{framed} \begin{framed} \textbf{JOE}\underline{ 5 ok} \textbf{joe}\underline{ 5 ok} \medskip \begin{tabular}{|c|c|c|c|c|c|c|c|c|c|}\hline Loading Loading
appendixb.tex +69 −107 Original line number Diff line number Diff line Loading @@ -27,7 +27,7 @@ place it on the return stack. That's all. \Forth{} execution then continues with this address on the return stack, which will cause the vectored function to be performed. It's like saying (in '83-Standard) \begin{Code} ' NOTHING >body >r <return> ' nothing >body >r <return> \end{Code} which executes \forth{NOTHING}. (This trick only works with colon definitions.) Loading @@ -48,7 +48,7 @@ DOER JOE & \\ \noindent Now suppose we define: \begin{Code} : TEST MAKE JOE cr ; : test make joe cr ; \end{Code} that is, we define a word that can vector \forth{JOE} to do a carriage return. Loading @@ -68,7 +68,7 @@ TEST & (MAKE) & 0 & JOE & CR & EXIT \\ \hline\noalign{\vspace{2pt}} \forthb{MAKE} inside a colon definition, \forthb{STATE} will be true, and we'll execute the phrase: \begin{Code} COMPILE (MAKE) here marker ! 0 , postpone (make) here marker ! 0 , \end{Code} We can see how \forthb{MAKE} has compiled the address of the run-time routine, \forthb{(MAKE)}, followed by a zero. (We'll explain what the Loading @@ -81,17 +81,17 @@ definition \forthb{TEST}: \bigskip{ \begin{tabular}{l@{\hspace{4ex}}>{\parindent-2ex}p{.5\textwidth}} \verb%R>% & Gets an address from the return stack. \verb%r>% & Gets an address from the return stack. This address points to the cell just past \forthb{(MAKE)}, where the zero is.\\ \verb%DUP 2+% & Gets the address of the second cell after \verb%dup cell+% & Gets the address of the second cell after \forthb{(MAKE)}, where the address of \forthb{JOE} is.\\ \verb%DUP 2+% & Gets the address of the third cell after \verb%dup cell+% & Gets the address of the third cell after \forthb{(MAKE)}, where the code we want to execute begins. The stack now has: \parindent2ex (~'marker,~'joe,~'code~--{}--~)\\ \verb%SWAP @ >BODY% & Fetches the contents of the address \verb%swap @ >body% & Fetches the contents of the address pointing to \forth{JOE} (i.e., gets the address of \forth{JOE}) and computes \forth{JOE}'s pfa, where the vector address goes.\\ Loading @@ -101,7 +101,7 @@ definition \forthb{TEST}: & Now \forth{JOE} points inside the definition of \forth{TEST}. When we type \forth{JOE}, we'll do a carriage return.\\ \verb%@ ?DUP IF >R THEN%& Fetches the contents of the cell \verb%@ ?dup IF >r THEN%& Fetches the contents of the cell containing zero. Since the cell does contain zero, the \forth{IF THEN} statement is not performed.\\ Loading @@ -112,7 +112,7 @@ That's the basic idea. But what about that cell containing zero? That's for the use of \forthb{;AND}. Suppose we changed \forth{TEST} to read: \begin{Code} : TEST MAKE JOE cr ;AND space ; : test make joe cr ;and space ; \end{Code} That is, when we invoke \forth{TEST} we'll vector \forth{JOE} to do a \forthb{CR}, and we'll do a \forthb{SPACE} right now. Here's what this Loading @@ -130,7 +130,7 @@ TEST & (MAKE) & adr & JOE & CR & EXIT & SPACE & EXIT \\ \hline\noalign{\vspace{2 \end{center} Here's the definition of \forthb{;AND}: \begin{Code} : ;AND COMPILE EXIT here marker @ ! ; immediate : ;and postpone EXIT here marker @ ! ; immediate \end{Code} We can see that \forthb{;AND} has compiled an \forthb{EXIT}\index{E!EXIT}, just as semicolon would. Loading @@ -156,15 +156,15 @@ One final note: on some systems you may encounter a problem. If you use you may not be able to find the most recently defined word. For instance, if you have: \begin{Code} : REFRAIN DO-DAH DO-DAH ; MAKE SONG CHORUS REFRAIN ; : refrain do-dah do-dah ; make song chorus refrain ; \end{Code} your system might think that refrain has not been defined. The problem is due to the placement of \forth{SMUDGE}. As a solution, try rearranging the order of definitions or, if necessary, put \forth{MAKE} code inside a definition which you then execute: \begin{Code} : SETUP MAKE SONG CHORUS REFRAIN ; SETUP : setup make song chorus refrain ; setup \end{Code} In Laboratory Microsystems PC/FORTH 2.0, the \forth{UNSMUDGE} on line 9 handles the problem. This problem does not arise with the Loading @@ -173,11 +173,11 @@ Laxen/Perry/Harris model. The final screen is an example of using \forthb{DOER/MAKE}. After loading the block, enter \begin{Code} RECITAL recital \end{Code} then enter \begin{Code} WHY? why? \end{Code} followed by return, as many times as you like (you'll get a different reason each time). Loading @@ -204,18 +204,18 @@ UNDO Usage: UNDO doer-name ; makes it safe to execute \end{Screen} \vfill \begin{Screen} \ DOER/MAKE FORTH-83 Laxen/Perry/Harris model LPB 12/05/83 : NOTHING ; : DOER Create ['] NOTHING >body , DOES> @ >r ; \ DOER/MAKE ANS Forth with real return-stack BP 22/04/06 : nothing ; : Doer Create ['] nothing >body , DOES> @ >r ; Variable marker : (MAKE) r> dup 2+ dup 2+ swap @ >body ! : (make) r> dup cell+ dup cell+ swap @ >body ! @ ?dup IF >r THEN ; : MAKE state @ IF ( compiling) COMPILE (MAKE) here marker ! 0 , ELSE here [compile] ' >body ! [compile] ] THEN ; immediate : ;AND COMPILE EXIT here marker @ ! ; immediate : UNDO ['] NOTHING >body [compile] ' >body ! ; : make state @ IF ( compiling) postpone (make) here marker ! 0 , ' , ELSE here ' >body ! ] THEN ; immediate : ;and postpone EXIT here marker @ ! ; immediate : undo ['] nothing >body ' >body ! ; \ The code in this screen is in the public domain. Loading @@ -223,79 +223,41 @@ Variable marker \end{Screen} \vfill \begin{Screen} ( DOER/MAKE FORTH-83 Lab. Micro PC/FORTH 2.0 LPB 12/05/83 ) : NOTHING ; : DOER Create ['] NOTHING >body , DOES> @ >r ; \ DOER/MAKE NC ANS Forth with real return-stack BP 22/04/06 : nothing ; : Doer Create ['] nothing , DOES> @ >r ; Variable marker : (MAKE) r> dup 2+ dup 2+ swap @ >body ! : (make) r> dup cell+ dup cell+ swap @ >body ! @ ?dup IF >r THEN ; : MAKE state @ IF ( compiling) COMPILE (MAKE) here marker ! 0 , ELSE here [compile] ' >body ! [compile] ] UNSMUDGE THEN ; immediate : ;AND COMPILE EXIT here marker @ ! ; immediate : UNDO ['] NOTHING >body [compile] ' >body ! ; ( The code in this screen is in the public domain.) \end{Screen} \vfill \begin{Screen} ( DOER/MAKE FIG model LPB 12/05/83 ) : NOTHING ; : DOES-PFA ( pfa -- pfa of child of <BUILD-DOES> ) 2+ ; : DOER <BUILDS ' NOTHING , DOES> @ >r ; 0 Variable marker : (MAKE) r> dup 2+ dup 2+ swap @ 2+ DOES-PFA ! @ -DUP IF >r THEN ; : MAKE state @ IF ( compiling) COMPILE (MAKE) here marker ! 0 , ELSE here [compile] ' DOES-PFA ! SMUDGE [compile] ] THEN ; immediate : ;AND COMPILE ;s here marker @ ! ; immediate : UNDO ' NOTHING [compile] ' DOES-PFA ! ; ;s The code in this screen is in the public domain. \end{Screen} \vfill \begin{Screen} ( DOER/MAKE 79-Standard MVP FORTH LPB 12/05/83 ) : NOTHING ; : DOER Create ' NOTHING , DOES> @ >r ; Variable marker : (MAKE) r> dup 2+ dup 2+ swap @ 2+ ( pfa) ! @ ?dup IF >r THEN ; : MAKE state @ IF ( compiling) COMPILE (MAKE) here marker ! 0 , ELSE here [compile] ' ! [compile] ] THEN ; immediate : ;AND COMPILE EXIT here marker @ ! ; immediate : UNDO ['] NOTHING [compile] ' ! ; : make state @ IF ( compiling) postpone (make) here marker ! 0 , ' , ELSE here ' >body ! ] THEN ; immediate : ;and postpone EXIT here marker @ ! ; immediate : undo ['] nothing ' >body ! ; \ The code in this screen is in the public domain. ( The code in this screen is in the public domain.) \end{Screen} \vfill \begin{Screen} ( TODDLER: Example of DOER/MAKE 12/01/83 ) DOER ANSWER : RECITAL \ toddler: Example of DOER/MAKE 12/01/83 ) Doer answer : recital cr ." Your daddy is standing on the table. Ask him 'WHY?' " MAKE ANSWER ." To change the light bulb." make answer ." To change the light bulb." BEGIN MAKE ANSWER ." Because it's burned out." MAKE ANSWER ." Because it was old." MAKE ANSWER ." Because we put it in there a long time ago." MAKE ANSWER ." Because it was dark!" MAKE ANSWER ." Because it was night time!!" MAKE ANSWER ." Stop saying WHY?" MAKE ANSWER ." Because it's driving me crazy." MAKE ANSWER ." Just let me change this light bulb!" false UNTIL ; : WHY? cr ANSWER quit ; make answer ." Because it's burned out." make answer ." Because it was old." make answer ." Because we put it in there a long time ago." make answer ." Because it was dark!" make answer ." Because it was night time!!" make answer ." Stop saying WHY?" make answer ." Because it's driving me crazy." make answer ." Just let me change this light bulb!" AGAIN ; : why? cr answer quit ; \end{Screen} \index{D!DOER/MAKE|)} \vfill
chapter7.tex +95 −54 Original line number Diff line number Diff line Loading @@ -1242,10 +1242,6 @@ 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 @@ -1253,38 +1249,38 @@ details.) It works like this: You define the word whose behavior will be vectorable with the defining word \forthb{DOER}, as in \begin{Code} DOER PLATFORM Doer platform \end{Code} Initially, the new word \forth{PLATFORM} does nothing. Then you can write words that change what \forth{PLATFORM} does by using the word \forthb{MAKE}: \begin{Code} : LEFTWING MAKE PLATFORM ." proponent " ; : RIGHTWING MAKE PLATFORM ." opponent " ; : leftwing make platform ." proponent " ; : rightwing make platform ." opponent " ; \end{Code} When you invoke \forth{LEFTWING}, the phrase \forth{MAKE PLATFORM} changes what \forth{PLATFORM} will do. Now if you type \forth{PLATFORM}, you'll see: \begin{Code}[commandchars=\&\{\}] LEFTWING ok PLATFORM &underline{proponent ok} leftwing &underline{ ok} platform &underline{proponent ok} \end{Code} \forth{RIGHTWING} will make \forth{PLATFORM} display ``opponent.'' You can use \forth{PLATFORM} within another definition: \begin{Code} : SLOGAN ." Our candidate is a longstanding " PLATFORM : slogan ." Our candidate is a longstanding " platform ." of heavy taxation for business. " ; \end{Code} The statement \begin{Code} LEFTWING SLOGAN leftwing slogan \end{Code} will display one campaign statement, while \begin{Code} RIGHTWING SLOGAN rightwing slogan \end{Code} will display another. Loading Loading @@ -1361,12 +1357,14 @@ behavior is vectored by the code in \forth{DUMP} and \forth{CDUMP}. ``\forthb{LOOP}''.) \begin{Code}[commandchars=\&\{\}] DOER .UNIT ( a -- increment) \ display byte or cell : <DUMP> ( a # ) Doer .unit ( a -- increment) \ display byte or cell : <dump> ( a # -- ) 0 DO i 16 mod 0= IF cr dup i + 5 u.r 2 spaces THEN dup i + &poorbf{.UNIT} +LOOP drop ; : dump ( a #) MAKE .UNIT @ 6 u.r 2 ;AND <DUMP> ; : CDUMP ( a #) MAKE .UNIT c@ 4 u.r 1 ;AND <DUMP> ; dup i + &poorbf{.unit} +LOOP drop ; : dump ( a # -- ) make .unit @ 3 cells u.r 1 cells ;and <dump> ; : cdump ( a # -- ) make .unit c@ 4 u.r 1 chars ;and <dump> ; \end{Code} Notice how \forth{DUMP} and \forth{CDUMP} \emph{set-up} the vector, then go on to \emph{execute} the shell (the word \forth{<DUMP>}). Loading @@ -1375,18 +1373,18 @@ then go on to \emph{execute} the shell (the word \forth{<DUMP>}). command. For instance: \begin{Code} DOER TYPE' DOER EMIT' DOER SPACES' DOER CR' : VISIBLE MAKE TYPE' type ;AND MAKE EMIT' emit ;AND MAKE SPACES' spaces ;AND MAKE CR' cr ; : INVISIBLE MAKE TYPE' 2drop ;AND MAKE EMIT' drop ;AND MAKE SPACES' drop ;AND MAKE CR' ; Doer type' Doer emit' Doer spaces' Doer cr' : visible make type' type ;and make emit' emit ;and make spaces' spaces ;and make cr' cr ; : invisible make type' 2drop ;and make emit' drop ;and make spaces' drop ;and make cr' ; \end{Code} Here we've defined a vectorable set of output words, each name having a ``prime'' mark at the end. \forth{VISIBLE} sets them to their Loading @@ -1406,11 +1404,11 @@ shorter message. \goodbreak We write: \begin{Code} DOER ANNOUNCE : LONG MAKE ANNOUNCE Doer announce : long make announce cr ." You're in a large hall with a huge throne" cr ." covered with a red velvet canopy." MAKE ANNOUNCE make announce cr ." You're in the throne room." ; \end{Code} The word \forth{ANNOUNCE} will display either message. First we say Loading @@ -1427,19 +1425,19 @@ letting each one set the next. The following example (though not terribly practical) illustrates the point. \begin{Code} DOER WHERE Variable SHIRT Variable PANTS Variable DRESSER Variable CAR Doer where Variable shirt Variable pants Variable dresser Variable car : order \ specify search order MAKE WHERE SHIRT MAKE WHERE PANTS MAKE WHERE DRESSER MAKE WHERE CAR MAKE WHERE 0 ; make where shirt make where pants make where dresser make where car make where 0 ; : HUNT ( -- a|0 ) \ find location containing 17 order 5 0 DO WHERE dup 0= over @ 17 = or IF : hunt ( -- a|0 ) \ find location containing 17 order 5 0 DO where dup 0= over @ 17 = or IF LEAVE ELSE drop THEN LOOP ; \end{Code} In this code we've created a list of variables, then defined an Loading @@ -1456,11 +1454,11 @@ We can even define a \forthb{DOER} word that toggles its own behavior endlessly: \begin{Code} DOER SPEECH : ALTERNATE BEGIN MAKE SPEECH ." HELLO " MAKE SPEECH ." GOODBYE " 0 UNTIL ; Doer speech : alternate BEGIN make speech ." Hello " make speech ." Goodbye " AGAIN ; \end{Code} \item To implement a forward reference. A forward reference is usually needed as a ``hook,'' that is, a word invoked in a low-level definition Loading @@ -1470,12 +1468,12 @@ To implement a forward reference, build the header of the word with \forthb{DOER}, before invoking its name. \begin{Code} DOER STILL-UNDEFINED Doer still-undefined \end{Code} Later in the listing, use \forth{MAKE}; \begin{Code} MAKE STILL-UNDEFINED ALL THAT JAZZ ; Make still-undefined all that jazz ; \end{Code} (Remember, \forth{MAKE} can be used outside a colon definition.) Loading @@ -1491,21 +1489,21 @@ GCD of a, b = a IF b = 0 This translates nicely into: \begin{Code} DOER GCD ( a b -- gcd) MAKE GCD ?dup IF dup rot rot mod GCD THEN ; Doer gcd ( a b -- gcd) make gcd ?dup IF dup rot rot mod gcd THEN ; \end{Code} Indirect recursion occurs when one word invokes a second word, while the second word invokes the first. This can be done using the form: \begin{Code} DOER B Doer B : A ... B ... ; MAKE B ... A ... ; make B ... A ... ; \end{Code} \item Debugging. I often define: \begin{Code} DOER SNAP Doer snap \end{Code} (short for \forth{SNAPSHOT}), then edit \forth{SNAP} into my application at a point where I want to see what's going on. For Loading @@ -1522,6 +1520,49 @@ approach are those in which you need control over the address of the vector, such as when vectoring through an element in a decision table, or attempting to save/restore the contents of the vector. \section{DEFER/IS instead of DOER/MAKE} Despite \person{Leo Brodie} has proposed \forth{DOER/MAKE} 20 years ago, it didn't become widely used. Instead, a somewhat different vectored execution word pair, \forthb{DEFER/IS} are popular now. Why is this? First of all, \forth{DEFER/IS} are trivial to implement, even if you don't know much about the underlying Forth system. They don't rely on the return stack, but use execution tokens (what comes out of \forth{'}) instead. Look at the portable definition: \begin{Code} : Defer Create ['] noop , DOES> @ execute ; : IS ( xt "name" -- ) state @ IF ' >body postpone Literal postpone ! ELSE ' >body ! THEN ; immediate \end{Code} Being portable is only one reason --- if \forth{DOER/MAKE} were important enough to implement, each \Forth{} would have one. The second reason is named vectors. Let's take a look at the \forth{DUMP} example written with \forth{DEFER/IS} instead: \begin{Code}[commandchars=\&\{\}] Defer .unit ( a -- increment ) \ display byte or cell : <dump> ( a # -- ) 0 DO i 16 mod 0= IF cr dup i + 5 u.r 2 spaces THEN dup i + &poorbf{.unit} +LOOP drop ; : ?+ ( a -- inc ) @ 3 cells u.r 1 cells ; : c?+ ( a -- inc ) c@ 4 u.r 1 chars ; : dump ( a # -- ) ['] ?+ IS .unit <dump> ; : cdump ( a # -- ) ['] c?+ IS .unit <dump> ; \end{Code} This looks more complicated, with the explicit components --- but remember: You have to test your program as well. So here, you can use your simpe component (\forth{?+} or \forth{c?+}) in isolation, without the more complicated logic of the complete application. You can do that, because they have a name. And words that have a name can be used as factors for other words. \section{Summary} In this chapter we've examined the tradeoffs between using the stack and using variables and other data structures. Using the stack is preferable Loading
fig7-7.tex +4 −4 Original line number Diff line number Diff line Loading @@ -2,7 +2,7 @@ \sf \setlength{\topsep}{0pt} \begin{framed} \textbf{DOER JOE}\underline{ ok} \textbf{Doer joe}\underline{ ok} \medskip {\begin{tabular}{|c|}\hline \boxto{MAKE}{JOE}\\ \hline\end{tabular}} Loading @@ -12,7 +12,7 @@ Creates a \textbf{DOER} word called JOE, that does nothing. \end{framed} \begin{framed} \textbf{: TEST~~MAKE JOE~~1 . ;}\underline{ ok} \textbf{: test~~make joe~~1 . ;}\underline{ ok} \medskip {\begin{tabular}{|c|}\hline \boxto{MAKE}{JOE}\\ \hline\end{tabular}} Loading @@ -27,7 +27,7 @@ Defines a new word called TEST \end{framed} \begin{framed} \textbf{TEST}\underline{ ok} \textbf{test}\underline{ ok} \medskip \relax\rnode{A}{\begin{tabular}{|c|}\hline \boxto{MAKE}{JOE}\\ \hline\end{tabular}} Loading @@ -45,7 +45,7 @@ Defines a new word called TEST \end{framed} \begin{framed} \textbf{JOE}\underline{ 1 ok} \textbf{joe}\underline{ 1 ok} \medskip Executes the code that JOE points to ( \textbf{1 . }). Loading
fig7-8.tex +6 −6 Original line number Diff line number Diff line \begin{minipage}{\textwidth}\sf \setlength{\topsep}{0pt} \begin{framed} \textbf{DOER SAM}\underline{ ok} \textbf{Doer sam}\underline{ ok} \textbf{DOER BIFF}\underline{ ok} \textbf{Doer biff}\underline{ ok} \medskip \begin{tabular}{|c|}\hline SAM \\ \hline\end{tabular}\kern 4cm Loading @@ -14,7 +14,7 @@ Creates two \textbf{DOER} words that do nothing. \end{framed} \begin{framed} \textbf{: TESTB MAKE SAM 2 . ;AND MAKE BIFF 3 . ;}\underline{ ok} \textbf{: testb make sam 2 . ;and make biff 3 . ;}\underline{ ok} \medskip \begin{tabular}{|c|c|c|c|c|c|c|c|c|c|c|}\hline Loading @@ -26,7 +26,7 @@ Defines a new word called TESTB. \end{framed} \begin{framed} \textbf{TESTB}\underline{ ok} \textbf{testb}\underline{ ok} \medskip \rnode{A1}{\begin{tabular}{|c|}\hline SAM \\ \hline\end{tabular}}\kern 4cm Loading Loading @@ -62,9 +62,9 @@ redirects BIFF. \end{framed} \begin{framed} \textbf{SAM}\underline{ 2 ok} \textbf{sam}\underline{ 2 ok} \textbf{BIFF}\underline{ 3 ok} \textbf{biff}\underline{ 3 ok} \medskip Two \textbf{DOER} words have been redirected at the same time by the Loading
fig7-9.tex +4 −4 Original line number Diff line number Diff line \begin{minipage}{\textwidth}\sf \setlength{\topsep}{0pt} \begin{framed} \textbf{: TESTC~~MAKE JOE 4 .~~MAKE JOE 5 . ;}\underline{ ok} \textbf{: testc~~make joe 4 .~~make joe 5 . ;}\underline{ ok} \medskip \begin{tabular}{|c|c|c|c|c|c|c|c|c|c|}\hline Loading @@ -13,7 +13,7 @@ Defines a new word called TESTC. \end{framed} \begin{framed} \textbf{TESTC}\underline{ ok} \textbf{testc}\underline{ ok} \medskip \rnode{A4}{\begin{tabular}{|c|}\hline JOE \\ \hline\end{tabular}} Loading @@ -30,7 +30,7 @@ TESTC & MAKE & JOE & \smash{\rnode{B4}{4\large\strut}} & . & MAKE & JOE & 5 & . \end{framed} \begin{framed} \textbf{JOE}\underline{ 4 ok} \textbf{joe}\underline{ 4 ok} \medskip \begin{tabular}{|c|c|c|c|c|c|c|c|c|c|}\hline Loading Loading @@ -58,7 +58,7 @@ point to the five. (There was no \textbf{;AND} to stop it.). \end{framed} \begin{framed} \textbf{JOE}\underline{ 5 ok} \textbf{joe}\underline{ 5 ok} \medskip \begin{tabular}{|c|c|c|c|c|c|c|c|c|c|}\hline Loading