Jump to content

Photo

Forth: A Brief Primer (#2)

forth primer tutorial

39 replies to this topic

#1 Willsy OFFLINE  

Willsy

    River Patroller

  • 3,009 posts
  • Location:Uzbekistan (no, really!)

Posted Wed May 10, 2017 5:59 AM

Forth: A Brief Primer
 
A Forth primer for anyone that is interested in dipping their toes into the Forth language…
 
Words (Forth parlance for routines/commands/subroutines) take their arguments off the stack, do something with them, and if necessary, push results back to the stack. In this way, Forth words are ‘chained’ together, using the stack to communicate with each other. It really is as simple as that.
 
TOM DICK HARRY
 
The above looks strange if you are used to BASIC, but the above is a valid Forth program (assuming those words exist in the Forth system that you are using). When Forth code executes it starts executing at the left, and proceeds to the right, so TOM executes first, then DICK, then HARRY then the “program” ends. Now, it may be that TOM places a number on the stack when he executes. DICK may take that number and do something with it, leaving a result for HARRY.
 
Let’s try an example:
 
: TOM ( n – n*2 ) 2 * ;
: DICK ( n – n*4 ) 4 * ;
: HARRY ( n – ) 9 + . ;
 
This probably looks terrifying. Baffling. But please don’t be afraid. Often, ones objections to learning Forth is based on the assumption that is it difficult and/or complicated, but in actual fact, it is the complete opposite. It’s so simple, that when you eventually “get it” you might even feel somewhat stupid, a bit like when you learn how a certain magic trick works when you’re a kid, and when you realise it, you think “Is that IT? Is that ALL it is? Are you KIDDING me?!”
 
Let’s break that little “program” above down and see how it works.
 
First, we see a colon. This symbol is used to say to the Forth system “Hey, I’m going to define a new word, so listen up”. Following the colon, we have the name of the new word: TOM. Note, there must be a space between the colon and the name. Next, the open bracket. This is actually the start of a comment (REM in BASIC). Inside the comment, we are using a simple convention/notation to describe stack requirements of the word, usually called the “stack signature”. Note: THIS IS NOT CODE. It’s a comment, and as such it’s purely optional, but it helps readers to understand what the word does to the stack without having to dissect the code inside the word. See the article Forth: A Sojourn Into Stack Comments for more information.
 
Inside TOM we see the following code:
 
2 *
 
Looks a little strange, but, following this from left to right, it’s quite easy to break down what happens. REMEMBER, the stack comment tells us that a number should already be on the stack when this word is called. Let’s say 9 as an example.
 
The next thing that happens is that TOM itself pushes the number 2 onto the stack, so the stack looks like this:
 
9 2 <--top of stack
 
Then, the * word executes, which simply means multiply. Multiply takes two values from the stack, multiplies them, and pushes the result back to the stack. So, 9*2 is 18. So, if we passed 9 in on the stack, 18 would “come out” of TOM onto the stack.
 
The next thing we see is a semi-colon ; which says to the Forth system “Hey, I’ve done with my definition of the word TOM, thanks very much.”
 
At this point, the Forth systems “knows” a new word, TOM, and you can test it immediately:
 
44 TOM .
 
The system will display the value 88 (44*2).
 
What just happened? We asked the Forth system to put 44 on the stack, then asked it to execute TOM, which it did. TOM took the value on the stack, multiplied it by two, and put the result back on the stack. Then the word . (dot) took the value off the stack (in other words, it consumed it), and displayed it for us.
 
So, TOM is written and tested. That wasn’t so hard, was it?
 
Let’s have a look at DICK:
 
: DICK ( n – n*4 ) 4 * ;
 
We can see that this word takes a value from the stack, multiplies it by 4, and leaves the result on the stack.
 
And finally, HARRY:
 
: HARRY ( n – ) 9 + . ;
 
Note the stack comment. There is nothing on the output side. This word takes the top value on the stack, adds 9 to it, and uses . (dot ) to display the result, placing nothing on the stack.
 
Now, this is simply a collection of “words”. It’s not really a “program” as such. It’s more like three subroutines that exist independently of each other. That’s how Forth programs are developed: You split your program up until logical blocks of functionality, each having its own word (a block of functionality may have many words – it’s up to you how you “factor” your program”). These words can be written independently of each other, and tested by supplying data from the stack. When they are tested to satisfaction, you call it done, and you move on to the next logical part of the program.
 
We could do with some glue; another word, to bind TOM DICK and HARRRY together into a program:
 
: TDH ( n -- ) TOM DICK HARRY ;
 
So, here’s a word called TDH (Tom, Dick, Harry!) that calls TOM, then DICK, then HARRY, in that order. The stack comment tells us that we need to pass a number in on the stack before calling TDH. How do we do that?
 
Simple:
 
99 TDH
 
When we type the above and press enter, we get the result 801: ((99x2)x4)+9
 
Let’s look briefly at TI BASIC version of the above program for comparison purposes:
 
10 N=99
20 GOSUB 100
30 GOSUB 200
40 GOSUB 300
50 PRINT N
60 END
100 N=N*2
110 RETURN
200 N=N*4
210 RETURN
300 N=N+9
310 RETURN
 
  • Lines 10 to 50 are the equivalent to the word TDH
  • Lines 100 to 110 are TOM
  • Lines 200 to 210 are DICK
  • Lines 300 to 310 are HARRY

Now, let us look at the Forth version again:

 
: TOM ( n – n*2 ) 2 * ;
: DICK ( n – n*4 ) 4 * ;
: HARRY ( n – ) 9 + . ;
: TDH ( n -- ) TOM DICK HARRY ;
 
A lot shorter, and uses no variables – the data is carried in and out of the words using the stack. Each word can be tested independently of the other words, and bound together at the end into a program that does some work.
 
If you've read this far, then hopefully you are thinking “Well, it’s kinda weird, but I get it”. If that is the case, congratulations, you have just learned Forth. I’m not being flippant. Forth is all about words, and the stack. And when you’ve got that concept down, the rest is just a matter of experience.
 
Forth on the TI-99/4A
Hopefully you’ll try the above out on your favourite TI-99/4A Forth. There’s the excellent fbForth written by Lee Stewart, which is a much more advanced version of TI’s original TI FORTH, and has the advantage of running from a cartridge. There’s also my own Forth cartridge, TurboForth (and its companion website, http://.turboforth.net) and there is Brian Fox’s new Forth system, the name of which escapes me at the moment (chime in, Brian!).
 
Feel free to post comments/questions. It’s all about learning, sharing, and having fun.


#2 TheBF ONLINE  

TheBF

    Moonsweeper

  • 308 posts
  • Location:The Great White North

Posted Wed May 10, 2017 8:07 AM

My as yet work in progress Forth is called CAMEL99. Why?

It is derived from a simple ANS/ISO Forth system called CAMEL Forth

 

The author of CAMEL Forth, a fellow Canadian, Brad Rodriguez Phd.  created the system in response to the 1994 ANS Forth spec.

The specification was designed by a committee...

 

"A camel is a horse designed by a committee"

 

I gather he was less than enthusiastic about the new language spec. :-)



#3 Retrospect OFFLINE  

Retrospect

    Dragonstomper

  • 866 posts
  • Location:Wakefield, England

Posted Wed May 10, 2017 8:39 AM

Excellent Willsy.

 

How would one set up a variable based on a random number?  We could define the word "DICE" to display a random number between 1 and 6 .. but how would we store that random number in a variable?



#4 TheBF ONLINE  

TheBF

    Moonsweeper

  • 308 posts
  • Location:The Great White North

Posted Wed May 10, 2017 8:52 AM

Excellent Willsy.

 

How would one set up a variable based on a random number?  We could define the word "DICE" to display a random number between 1 and 6 .. but how would we store that random number in a variable?

 

I can take this one if you like.

 

This is where we have a fundamental difference in how you think when writing in Forth vs BASIC.

Each language gives us a "structure" to work in and these 2 languages are quite different

 

So we need to have the random number words defined in our system. I will assume we have them.

 

In BASIC you have RND.  So in Forth we would call our word RND as well.

 

In BASIC you might write

 

100 MYRAND=RND

 

In Forth you could do the very same like this:

VARIABLE MYRAND  \ variables must be created before use

RND MYRAND !     \ RND puts a number on the stack
                 \ MYRAND puts its own memory address on the stack
                 \ '!' (pronounced 'STORE') stores the number in the memory address
                 

So in Forth it's more like using POKE() to put a number in variable.

 

In other words Forth is lower level than BASIC, a little like Assembler with some lipstick.

 

 

To get the contents of a variable we use the 'fetch' operator which is just a '@' character.

MYRAND @  . \ fetch the contents of MYRAND to the stack and print it with '.'
 457 ok
_

Note: Typically RND takes an input from the stack to control how big the result number will be.

         I left it out to simplify the explanation.


Edited by TheBF, Wed May 10, 2017 8:58 AM.


#5 Sinphaltimus OFFLINE  

Sinphaltimus

    Stargunner

  • 1,933 posts
  • Distracted at the Keyboard
  • Location:Poconos, PA

Posted Wed May 10, 2017 8:54 AM

Great question Retrospect. If I understand correctly, you wouldn't. You'd store the number in the stack. If I'm correct, then I guess you'd need a way to efficiently retrieve that number from the stack. Which would be my next question, how? Perhaps assign that result to a word?

Edited by Sinphaltimus, Wed May 10, 2017 8:55 AM.


#6 TheBF ONLINE  

TheBF

    Moonsweeper

  • 308 posts
  • Location:The Great White North

Posted Wed May 10, 2017 9:05 AM

You are correct Sinphaltimus.  You might not want or need to keep a random number in a variable.

You normally just get it and use it.

 

Which is the same with BASIC's RND function.  It just returns a value. Do whatever you want with it.

 

So  Forth RND typically wants a number on the stack to set the range from 0 to n

So here is DICE defined:

: DICE     ( -- n )  6 RND ;

When you type DICE at the console your will see 'ok"  :)

 

What the heck?   Well DICE just plopped a random number onto the stack. That's ALL it can do.

 

If you want that number it's there to use.

 

To see it use the '.' word. (called dot) :)

 

To store it in a variable see my previous post.

 

Make sense?



#7 TheBF ONLINE  

TheBF

    Moonsweeper

  • 308 posts
  • Location:The Great White North

Posted Wed May 10, 2017 9:09 AM

Actually it's best to load a Forth onto your machine and play around with the stack.

You will crash the machine because it is your right to do so when you are brave enough to work directly with the hardware.

 

Get "Starting Forth" https://www.forth.co...starting-forth/

 

or read Willy's tutorial pages.



#8 TheBF ONLINE  

TheBF

    Moonsweeper

  • 308 posts
  • Location:The Great White North

Posted Wed May 10, 2017 10:00 AM

Here is some material from a manual I am writing for people who know TI-BASIC and want to play with Forth.

 

 

Look at the program listing below:

10 CALL CLEAR

20 PRINT “Hello world!”

30 GOTO 20

 

Now look at it in CAMEL99 Forth with some "helper" words loaded

: 10:  CLEAR ;

: 20:  C" HELLO WORLD" PRINT ;

: RUN  10:  BEGIN  20: AGAIN ;

 

 

To a TI-BASIC programmer it looks weird.  This program is to help you understand how BASIC is really working and what it takes for a compiled programming language to imitate BASIC.

We have loaded our TI-BASIC word set into CAMEL99 so we have some familiar word names, but they seem to be backwards. Why?  That has to do with how Forth uses something called the Stack which we will explain in the next lesson. Also notice we don’t have to CALL those sub-programs. That’s because all Forth words are sub-programs so they are all called by Forth by default.

 

We have used the colon/semicolon structure  to create something that looks like line numbers.  PLEASE NOTE: They are NOT line numbers, they are now WORDs in Forth but they let you see how a line number in BASIC performs the same function as a WORD does in Forth. Line numbers are just an identifier, that the computer can use to find code when it needs to.

 

BASIC’s line numbers are labels to let the computer find pieces of code

 

Forth WORDs are labels to let the computer find pieces of code

 

Let’s review what our new Forth words (line numbers do)

 

10:   is obvious. It calls CLEAR, which fills the screen with spaces and puts the cursor on the bottom line.

 

20:   Uses C” to put a literal characters in the definition that end at the other quote. Literal means the characters are “compiled” into place in memory just as they appear. And PRINT can take a string like that and PRINT it to the screen.

 

30:   This is where things get different.  We defined a word called RUN. RUN is performing the function of the BASIC interpreter, which is to “RUN” the code in each line number in order one at a time.  

Forth does not have a RUN function so we did it manually. 

Structured Programming

Forth is known as a structured programming language so it does not have GOTO.  This may be a very weird thing for people who have only used BASIC.

Structured languages do not let you jump anywhere. They provide you with ways to jump but it is well… structured. To create an infinite loop (goes forever) we use the BEGIN/AGAIN structure.  AGAIN is a GOTO that can only jump backwards to BEGIN.  I hope it is clear in our RUN word that 20:  is going to go on forever because it is between BEGIN and AGAIN.

Forth Version

Now please do not think I want you to write Forth code that looks like this BASIC with line numbers.

I simply wanted you to see something more familiar.  Now that you know what line numbers really do in BASIC look at how it could look in Forth if we used more descriptive names instead of line numbers:

 

: CLS  CLEAR ;

: HI!  C" HELLO WORLD" PRINT ;

: RUN  CLS  BEGIN  HI! AGAIN ;

 

In fact we really don’t need the first line because CLS is just calling the word CLEAR. So we can use CLEAR by itself and the program would become:

 

: HI!  C" HELLO WORLD" PRINT ;

: RUN  CLEAR  BEGIN  HI! AGAIN ;

 

 

And if we were really in a hurry we could remove the word HI! And put what it does right in our RUN word so it would look like this:

 

: RUN  CLEAR  BEGIN  C" HELLO WORLD" PRINT   AGAIN ;

 

Did that make your head spin a little.  It can when you are used to BASIC.  Compared to FORTH, BASIC is like a straight-jacket, forcing you do things in very specific ways with few exceptions. Forth gives you much more freedom, which means you have to think a little more about what you want but the program can do almost anything.

I will post a simple version of CAMEL99 with Graphics words and training wheels to assist in the transition shortly.



#9 Willsy OFFLINE  

Willsy

    River Patroller

  • Topic Starter
  • 3,009 posts
  • Location:Uzbekistan (no, really!)

Posted Wed May 10, 2017 11:21 AM

I can take this one if you like.


Perfect! That's exactly what I was hoping to see!



#10 Willsy OFFLINE  

Willsy

    River Patroller

  • Topic Starter
  • 3,009 posts
  • Location:Uzbekistan (no, really!)

Posted Wed May 10, 2017 11:38 AM

Great question Retrospect. If I understand correctly, you wouldn't. You'd store the number in the stack. If I'm correct, then I guess you'd need a way to efficiently retrieve that number from the stack. Which would be my next question, how? Perhaps assign that result to a word?

 

Yes. Generally, you'd try to avoid storing stuff in variables, but you can use them. Of course, we can't store all the variables of a program on the stack, your program would spend most of its time "juggling the stack" (stackrobatics) to get the value it needs to the top of the stack where it can work on it. Not good.

 

Variables in Forth are very easy to understand. Variables have a name, just like BASIC, but, as Brian mentioned, they are declared in advance using the VARIABLE keyword:

 

TurboForth:

VARIABLE X

fbForth

0 VARIABLE X

 

Note that fbForth requires an initial value for the variable, whereas TurboForth initialises new variables to 0. There are lots of subtle differences between the two systems as they built on different Forth language standards.

 

Now, as Brian said, variables push their address to the stack, not the value stored in the variable. Here's a demonstration (TurboForth)

 

VARIABLE X
X $.

 

TurboForth reponds with A2CE (on my system). A2CE is the address (in hex) of the variable x (the word $. prints whatever is on the stack as a hex value). You could also print it as an unsigned decimal number:

 

x u.
and see that it's at address 41678 decimal.

 

To write a value into a variable, you use the word ("store" or "poke", whichever you prefer). ! needs two values on the stack:

  • The value to store;
  • The address to store it in (as the top most stack item).

So, to store 100 in X we could simply write:

 

100 X !

 

So, 100 goes on the stack, then X executes (it sounds weird to say that a variable "executes" but it really does - executing it makes it push it address to the stack), then the word ! (store) takes the address, and the value, and stores them for you.

 

We can prove that by reading it back with @ ("fetch", or "peek"):

 

x @ .

 

And you'll see 100 displayed.

 

Ta dah!

 

Not so hard, eh?

 

So, to store a dice roll in a variable, called ROLL, we could have something very simple like this:

 

VARIABLE ROLL
: ROLL-DICE ( -- ) 6 RND ROLL ! ;

 

And test it with the following:

 

ROLL-DICE ROLL @ .

 

Can you see what that is doing?

 

Note: RND, just like RND in BASIC always chooses a random number between 0 and the value you give it minus 1. So if you give 6 to RND you get a random number between 0 and 5 (which is of course 6 possible values). To make it between 1 and 6, simply add to the value that RND gives us and then store it:

 

: ROLL-DICE ( -- ) 6 RND  1 +  ROLL ! ;

 

So, here, we execute RND with 6 on the stack (so we get a number between 0 and 5 on the stack) and then we add 1 to it, then we store it in ROLL.



#11 Willsy OFFLINE  

Willsy

    River Patroller

  • Topic Starter
  • 3,009 posts
  • Location:Uzbekistan (no, really!)

Posted Wed May 10, 2017 11:46 AM

Attached File  ROLL-DICE.png   39.97KB   3 downloads



#12 TheBF ONLINE  

TheBF

    Moonsweeper

  • 308 posts
  • Location:The Great White North

Posted Wed May 10, 2017 2:06 PM

More on control structures.

 

Remember that little program we wrote in the CAMEL99 Trainer?

: RUN   CLEAR   BEGIN  C" HELLO WORLD" PRINT   AGAIN ;

Well it loops forever because of BEGIN  AGAIN. 

 

BASIC builds the BREAK control right into the running interpreter but Forth does not to keep loops fast.

 

So how do we stop it?

 

We want it to loop UNTIL something happens right?

 

Forth has the word UNTIL, that will loop like AGAIN until it sees a non-zero value on the stack.

 

In fact the definition for AGAIN  is equivalent to "0 UNTIL"  meaning that zero will make it loop forever.

 

Here is how we use UNTIL

: TEST  
       C" I am waiting here! ..." PRINT 
       BEGIN  KEY?  UNTIL ;

Paste this into the CAMEL99 Trainer and type TEST <enter>

You will see the string print and then nothing, until you press a key and then Forth will reply with ok.

 

What's happening? 

The word KEY?  calls the TI-99 KSCAN routine in the console ROMs.

If nothing is pressed it puts a zero on the stack.

If something is pressed it puts HEX FFFF on the stack (all 16 bits set is Forth's "true flag")

 

UNTIL keeps jumping back to BEGIN  until... it sees that true flag on the stack.

Then it exits the loop and returns to the Forth interpreter.

 

As you can see UNTIL does not care where that true flag came from.

It could be the result of a calculation, some logical operation or comparison.

Anything that gives us a non-zero result will cause the loop to stop.


Edited by TheBF, Wed May 10, 2017 2:08 PM.


#13 TheBF ONLINE  

TheBF

    Moonsweeper

  • 308 posts
  • Location:The Great White North

Posted Wed May 10, 2017 4:35 PM

For a full featured Forth system with all the bells and whistles you have to use Turbo Forth or FBForth.

 

But if you want to do a little exploring with something the feels kind of familiar (but a little bit reverse order)

download the CAMEL99 trainer here. https://github.com/bfox9900/CAMEL99

 

Just click on CAMEL99   and then click the download button.

 

It wakes up in 32 col graphics mode and you can try Forth with training wheels :)

 

You can't save your work, and it can't load a file (yet) so use notepad or your favourite editor and Classic99

and paste your code into it or type it at the keyboard.

 

Here are some of the training wheels that have been put it to make playing with Forth a little easier for the
TI-Basic programmer.
NEW      starts a new session. All code added to the system is removed.
CLEAR    clears the screen and puts the cursor on the bottom line where it belongs!
         (no need to CALL it. It's smart enough to call itself)
 
STRING:  lets you make string variables and use them similar to BASIC
          50 STRING: A$ makes a string that can hold 50 bytes.
PRINT    well it only works for strings, but it just feels correct so go ahead.
 
Try this:              
50 STRING: A$ 
A$ =" Hello world!"
A$ PRINT
Hello world! ok
 
(mind the space after ="   It is a Forth word )
 
And you have these string functions, which like BASIC can be used together.
Example: A$ 0 5 SEG$ CHAR
: LEN        ( $ -- n )
: CPOS      ( $ char -- position) 
: LEFT$     ( $ # -- top$)
: RIGHT$    ( $ #  -- top$) 
: SEG$      ( $ start# char# -- top$)
: STR$       ( n -- top$)
: VAL$       ( adr$ - # )
: CHR$      ( ascii# -- top$ )
Concatenate 2 strings USAGE: A$ B$ &   PRINT
:  &       ( $1 $2 -- top$)  ( changed from ADD$. it's RPN. be careful)
: COMPARE$   ( $1 $2 -- flag) 
: =$         ( $1 $1 -- flag) 
: >$         ( $1 $2 -- flag) 
: <$         ( $1 $2 -- flag) 
And something that BASIC does not have
: SKIP$    ( $ char -- $ )  ( removes leading chars)
----------------------------
GRAPHICS stuff like TI-BASIC.
Screen coordinates are base 0.  0..23 Rows,  0..32 columns
*NEW*
Give it an ascii value and it returns the character set no.
no need to remember the color set# Yay!
SET#  ( ascii -- set#)    ( usage:  CHAR A SET# 2 8 COLOR)
*NEW*
Change contiguous character sets at once
COLOR ( character-set fg-color bg-color -- )  Uses same color numbers as Basic.
COLORS  ( set1 set2 fg bg  -- )
SCREEN ( color -- )  
GRAPHICS  ( -- )    Changes to familiar CYAN screen

\ CHAR sub-program is renamed to CHARDEF
\ USAGE: HEX" 7C7C 7C7C 7C7C 7C00" 30 CHARDEF
: CHARDEF  ( FFFF FFFF FFFF FFFF char# --)
*NEW*
CHARDEF@ ( char# -- FFFF FFFF FFFF FFFF) fetches a pattern from VDP RAM and puts the numbers on the stack
GCHAR ( row col -- char)
( NOTE: for HCHAR & VCHAR you must give the cnt. Forth requires 4 parameters always)
: HCHAR  ( col row char cnt -- )
: VCHAR  ( x y char cnt -- )

Edited by TheBF, Thu May 11, 2017 7:35 PM.


#14 Retrospect OFFLINE  

Retrospect

    Dragonstomper

  • 866 posts
  • Location:Wakefield, England

Posted Thu May 11, 2017 2:38 AM

Right.  So, for example, would a "Dopewars" game be possible with Forth?  

 

My way of doing mine was roughly this in Basic

 

! D$ is Items on the market / inventory

! P$ is the places (streets of new york for example)

! MP is the market price 

! MA is the market amounts (quantities of each item)

! IP is the inventory prices paid

! IA is the inventory amounts carried

! HI represents a high price for items on the market

! LO represents the lower prices of items on the market

 

1 ! DOPEWARS TI

2 RANDOMIZE

10 DIM D$(6),P$(6),MP(6),MA(6),IP(6),IA(6),LO(6),HI(6)

20 FOR LOOP=1 TO 6 :: READ X$ :: READ Y$ :: READ X :: READ Y 

30 D$(LOOP)=X$ :: P$(LOOP)=Y$ :: HI(LOOP)=X :: LO(LOOP)=Y :: NEXT LOOP

40 DATA COCAINE,BRONX,10000,19000

50 DATA HEROIN,GHETTO,50000,9000

60 DATA SHROOMS,"CENTRAL PARK",10000,4000

70 DATA HASHISH,MANHATTEN,5000,2250

80 DATA ACID,BROOKLYN,1500,500

90 DATA LUDES,"NEW JERSEY",100,10

 

100 CASH=2500 :: DEBT=5000 :: DAY=0 :: FOR LOOP=1 TO 6 :: IA(LOOP)=0 :: IP(LOOP)=0 :: NEXT LOOP

 

110 ! NEW DAY

120 DAY=DAY+1 

130 DI=INT(DEBT/16) :: DEBT=DEBT+DI 

 

140 ! GET MARKET AMOUNTS & PRICES FOR NEW DAY

150 FOR LOOP=1 TO 6

160 MA(LOOP)=INT(100*RND)+1 :: MP(LOOP)=INT(HI(LOOP)*RND)+LO(LOOP)

170 XX=INT(6*RND)+1 :: IF XX=LOOP THEN 171 ELSE 180

171 MA(LOOP)=0 :: MP(LOOP)=0 ! THIS IS SIMULATING THERE BEING NONE OF THAT PARTICULAR ITEM THAT DAY

180 NEXT LOOP

 

200 ! SHOW THE MAIN SCREEN

210 CALL CLEAR

220 PRINT "ITEM";TAB(12);"QTY";TAB(18);"COST";TAB(26);"NUM" :: PRINT

230 FOR LOOP=1 TO 6

240 PRINT D$(LOOP);TAB(11);MA(LOOP);TAB(17);MP(LOOP);TAB(26);LOOP

250 NEXT LOOP

 

......and so on, and so forth ..... :)


Edited by Retrospect, Thu May 11, 2017 2:39 AM.


#15 TheBF ONLINE  

TheBF

    Moonsweeper

  • 308 posts
  • Location:The Great White North

Posted Thu May 11, 2017 10:19 AM

I gotta run, but will try to give you a Forth version, with BASIC code as the comments.

The technical answer is that Forth is a Turing complete language so it can in theory code anything.

The real answer is Forth is close to Assembler so you end up building up from low level pieces,
some of the stuff you take for granted in BASIC.

But... that can be fun and once you do it, you have it forever if you need it again.

So those string arrays will need to be created, but I think we can do something simple.

And I should add some of the things that seem natural to do in BASIC, you just don't do that way in Forth.


B

#16 TheBF ONLINE  

TheBF

    Moonsweeper

  • 308 posts
  • Location:The Great White North

Posted Thu May 11, 2017 7:29 PM

So I have become slightly crazy since I started comparing BASIC to FORTH.

 

I posted a literal translation of deNile  here: http://atariage.com/...n-denile/page-2

 

Now for anyone who is interested I took the same Forth code, which is very bad Forth style and re-organized in the way the Forth programs are written.

You can see this "factoring" of the program into small parts in  Lee's code.

The stack stuff might make your head spin, so this shows Forth style but still using some Variables and strings like the original did.

All we did was re-organize how to think about it. That's important for programming in any language if you move from BASIC.

 

I think the thing to know is Chuck Moore believes every Forth WORD (sub-routine) should be so simple that there was no question what it does.

And the name should clearly let you know what it's going to do.

 

So with those to things in mind here is deNile using more "WORDS" which is how Forth programs are made.

 

*Look at how many lines were removed by creating a WORD to clip values and then using that clipping word to make automatic functions to control the water characters.

And hopefully we get more clarity when we are done because we have created a little language to solve the problem.

 

( Let me know if this is helpful or not

  I can shut-up anytime, but with a venue to teach about Forth I can be chatterbox)

 

Spoiler

 


Edited by TheBF, Thu May 11, 2017 7:41 PM.


#17 TheBF ONLINE  

TheBF

    Moonsweeper

  • 308 posts
  • Location:The Great White North

Posted Thu May 11, 2017 10:09 PM

OK I promise this is the last one for Primer #2.

 

Now we have removed all the BASIC comments to make space on the page.

With that space we have shown you some alternative ways to format Forth code

to make it read nicely.  Forth source code is free form so you can express

yourself in whatever way works for you.

 

We also introduce:  

 

COLORS ( set# set# FG,BG -- )

SET# ( char -- set$) 

VREAD  ( vdp-addr cpu-addr cnt -- )  (also known as VMBR)

VWRITE ( cpu-addr vdp-addr cnt -- ) ( a.k.a VMBW )

 

With those words we create a way to save the all the patterns and restore them when the program ends.

And we include a little TI BASIC  "HONK" so it's official.

 

Spoiler


#18 Lee Stewart ONLINE  

Lee Stewart

    River Patroller

  • 3,326 posts
  • Location:Silver Run, Maryland

Posted Fri May 12, 2017 5:30 PM

These Forth tutorials are great, Willsy!  Just when you decided to start #2, I was in surgery for a complete right knee replacement.  Today is the first time I have felt up to doing anything much online.  I am sorry I was not here to participate from the start.  I still may be a little slow to get back in the saddle.  Again, wonderful effort.  :thumbsup:  :thumbsup:  :thumbsup:

 

...lee



#19 TheBF ONLINE  

TheBF

    Moonsweeper

  • 308 posts
  • Location:The Great White North

Posted Fri May 12, 2017 10:05 PM

These Forth tutorials are great, Willsy!  Just when you decided to start #2, I was in surgery for a complete right knee replacement.  Today is the first time I have felt up to doing anything much online.  I am sorry I was not here to participate from the start.  I still may be a little slow to get back in the saddle.  Again, wonderful effort.  :thumbsup:  :thumbsup:  :thumbsup:

 

...lee

 

I wondered why you were not here to correct all my mistakes. :-)

 

So happy that you are back.

 

Get back to 110% soon Lee.

 

You are in my thoughts.

 

B



#20 Willsy OFFLINE  

Willsy

    River Patroller

  • Topic Starter
  • 3,009 posts
  • Location:Uzbekistan (no, really!)

Posted Sat May 13, 2017 2:31 AM

Ah! Great to "see" you back here, Lee. I had wondered why you hadn't chimed in. Hope you're back up to full-speed soon!

 

#3 coming soon (I might write it up tonight). If you or Bruce want to add an article just go right ahead. Use "Forth: some title (#number)" as the format for the title, that way we can easily search for them later.



#21 Lee Stewart ONLINE  

Lee Stewart

    River Patroller

  • 3,326 posts
  • Location:Silver Run, Maryland

Posted Sat May 13, 2017 4:54 AM

Thanks, Guys!  It will not be long.  I will have to think about starting one of these tutorials---I don't know.  You fellows' teaching style is so much better than mine!  I cannot seem to avoid too much detail, for one thing.  Maybe I will limit my participation for a while to augmentation(!?). :grin:

 

...lee



#22 Sinphaltimus OFFLINE  

Sinphaltimus

    Stargunner

  • 1,933 posts
  • Distracted at the Keyboard
  • Location:Poconos, PA

Posted Sun May 14, 2017 4:33 AM

Attempting this - 
: TOM ( n n*2 ) 2 * ;
: DICK ( n n*4 ) 4 * ;
: HARRY ( n ) 9 + . ;

44 TOM.

 

and I get this:
 

 

Attached File  Untitled.png   28.78KB   3 downloads



#23 Sinphaltimus OFFLINE  

Sinphaltimus

    Stargunner

  • 1,933 posts
  • Distracted at the Keyboard
  • Location:Poconos, PA

Posted Sun May 14, 2017 4:48 AM

 

I got this one working - I missed the "test with" line at first. What am i doing wrong in the first post I put above?

 


Edited by Sinphaltimus, Sun May 14, 2017 4:52 AM.


#24 Lee Stewart ONLINE  

Lee Stewart

    River Patroller

  • 3,326 posts
  • Location:Silver Run, Maryland

Posted Sun May 14, 2017 5:56 AM

You typed a word that does not exist in the dictionary: TOM.

 

What you intended was:  TOM .

 

...lee



#25 TheBF ONLINE  

TheBF

    Moonsweeper

  • 308 posts
  • Location:The Great White North

Posted Sun May 14, 2017 6:08 AM

Attempting this - 
: TOM ( n n*2 ) 2 * ;
: DICK ( n n*4 ) 4 * ;
: HARRY ( n ) 9 + . ;

44 TOM.

 

and I get this:
 

 

attachicon.gifUntitled.png

 

Master Yoda says:

 

Beware of the Forth must you be.

For soon backing talkwards will you be!







Also tagged with one or more of these keywords: forth primer tutorial

0 user(s) are browsing this forum

0 members, 0 guests, 0 anonymous users