Commit 4205df49 authored by paysan's avatar paysan
Browse files

Doer/Make stuff

parent 488f5d2d
Loading
Loading
Loading
Loading
+69 −107
Original line number Diff line number Diff line
@@ -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.)
@@ -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.
@@ -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
@@ -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.\\
@@ -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.\\
@@ -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
@@ -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.
@@ -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
@@ -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).
@@ -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.

@@ -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
+95 −54
Original line number Diff line number Diff line
@@ -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
@@ -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.

@@ -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>}).
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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.)

@@ -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
@@ -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
+4 −4
Original line number Diff line number Diff line
@@ -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}}
@@ -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}}
@@ -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}}
@@ -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 . }).
+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
@@ -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
@@ -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
@@ -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
+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
@@ -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}}
@@ -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
@@ -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