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

Doer/Make stuff

parent 488f5d2d
......@@ -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,30 +81,30 @@ definition \forthb{TEST}:
\bigskip{
\begin{tabular}{l@{\hspace{4ex}}>{\parindent-2ex}p{.5\textwidth}}
\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
\forthb{(MAKE)}, where the address of \forthb{JOE} is.\\
\verb%DUP 2+% & 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
pointing to \forth{JOE} (i.e., gets the address
of \forth{JOE}) and computes \forth{JOE}'s pfa, where
the vector address goes.\\
\verb%!% & Stores the address where the new code
begins (\forthb{CR}, etc.) into the vector
address of \forth{JOE}. \\
& 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
containing zero. Since the cell does
contain zero, the \forth{IF THEN} statement is
not performed.\\
\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 cell+% & Gets the address of the second cell after
\forthb{(MAKE)}, where the address of \forthb{JOE} is.\\
\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
pointing to \forth{JOE} (i.e., gets the address
of \forth{JOE}) and computes \forth{JOE}'s pfa, where
the vector address goes.\\
\verb%!% & Stores the address where the new code
begins (\forthb{CR}, etc.) into the vector
address of \forth{JOE}. \\
& 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
containing zero. Since the cell does
contain zero, the \forth{IF THEN} statement is
not performed.\\
\end{tabular}}
\bigskip
......@@ -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 ;
Variable marker
: (MAKE) r> dup 2+ dup 2+ 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 ;
\ 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 @ 2+ ( pfa) !
: (make) r> dup cell+ dup cell+ swap @ >body !
@ ?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
......@@ -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
......
......@@ -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 . }).
......
\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
......
\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
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment