2017年5月1日 星期一


Some Special Features in ABC forth

Ching-Tang Tseng
Hamilton, New Zealand
1 May 2017
ilikeforth@gmail.com
http://forthfortnight.blogspot.com

Some kinds of output format are hard to implement out by a traditional BASIC.
A few codes are hard to read out clearly in traditional FORTH coding style.
I improved.
A few such kinds of example are showing in this article.
ABC FORTH special features are emphasized here on purpose.

Example 1 : Output ability

First day I touched FORTH, I knew FORTH output ability is better than any other kinds of non-extensible language, especial compare to a traditional BASIC. No matter it is just to do a general printing output or is to do a complicated port output to a device, FORTH certainly is the best tool to do it.
Here is a simple question (courtesy of http://practicalcomputing.org/tips/rosetta) 
needs a program to print out a table, all elements inside are a regular order character attached by a regular order number as the following format.
Table.1
A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12
B1 B2 B3 B4 B5 B6 B7 B8 B9 B10 B11 B12
C1 C2 C3 C4 C5 C6 C7 C8 C9 C10 C11 C12
D1 D2 D3 D4 D5 D6 D7 D8 D9 D10 D11 D12
E1 E2 E3 E4 E5 E6 E7 E8 E9 E10 E11 E12
F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12
G1 G2 G3 G4 G5 G6 G7 G8 G9 G10 G11 G12
H1 H2 H3 H4 H5 H6 H7 H8 H9 H10 H11 H12
Traditional BASIC has a PRINT instruction for printing message out. Variable names, "....." , , , ; , or a mathematical expression are able to be used to follow a PRINT instruction. After PRINT, system must to do a line feed and carriage return once. Such a PRINT specification cannot help us to print out Table.1 except you use a artificial echo printing method.
In a general FOTH system, arrange an ASCII code EMIT and an index . (DOT) together such as 
"j emit i ." to be wrapped in double structure of DO ... LOOP as following, ForthTable and BasicTable are the answer codes.
: ForthTable ( -- )
  cr
  73 65
  do
     13 1
     do
          j emit i .
     loop
     cr
  loop ;
In ABC FORTH, use a powerful RUN instruction to do "j emit i .". Let you get the same effective output result. Traditional BASIC lack of such a feature.
2 integers i j
: BasicTable ( -- )
  basic
10 run cr
20 for j = 65 to 72
30 for i = 1 to 12
40 run j emit i .
50 next i
60 run cr
70 next j
80 end ;
Execution result:
ForthTable
A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12
B1 B2 B3 B4 B5 B6 B7 B8 B9 B10 B11 B12
C1 C2 C3 C4 C5 C6 C7 C8 C9 C10 C11 C12
D1 D2 D3 D4 D5 D6 D7 D8 D9 D10 D11 D12
E1 E2 E3 E4 E5 E6 E7 E8 E9 E10 E11 E12
F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12
G1 G2 G3 G4 G5 G6 G7 G8 G9 G10 G11 G12
H1 H2 H3 H4 H5 H6 H7 H8 H9 H10 H11 H12
 ok
BasicTable
A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12
B1 B2 B3 B4 B5 B6 B7 B8 B9 B10 B11 B12
C1 C2 C3 C4 C5 C6 C7 C8 C9 C10 C11 C12
D1 D2 D3 D4 D5 D6 D7 D8 D9 D10 D11 D12
E1 E2 E3 E4 E5 E6 E7 E8 E9 E10 E11 E12
F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12
G1 G2 G3 G4 G5 G6 G7 G8 G9 G10 G11 G12
H1 H2 H3 H4 H5 H6 H7 H8 H9 H10 H11 H12
 ok

Example 2. Chinese Remainder Theorem

One example of these questions is showing in the program. Please see line 20 logical branch condition.

\ simple version
integer i
: simple ( -- )
basic
10 for i = 1 to 100000000000
20 if     ( i mod 11 = 1 ) and ( i mod 13 = 2 )
      and ( i mod 15 = 3 ) and ( i mod 17 = 4 )
      and ( i mod 19 = 5 )
   then 60
30 next i
40 print " Question is inexact! "
50 goto 80
60 run 2drop
70 print " Answer = N * " ; i ; " , N = 1, 2, 3, ... "
80 end ;
\ turbo version: How does it speeded up? You ought to know.
: turbo ( -- )
basic
10 for i = 19 + 5 to 100000000000 step 19
20 if     ( i mod 11 = 1 ) and ( i mod 13 = 2 )
      and ( i mod 15 = 3 ) and ( i mod 17 = 4 )
      and ( i mod 19 = 5 )
   then 60
30 next i
40 print " Question is inexact! "
50 goto 80
60 run 2drop
70 print " Answer = N * " ; i ; " , N = 1, 2, 3, ... "
80 end ;
simple
turbo
Answer = N * 346413 , N = 1, 2, 3, ...
Answer = N * 346413 , N = 1, 2, 3, ...  OK

You are able to solve all kinds of Chinese Remainder Theorem problem with the same code listed above by just to replace the contents in line 20.
Upper limit index of FOR...NEXT to be set to such a big number is on purpose for testing in 64 bits system.
If ABC FORTH is not built in a general FORTH system, we are unable to deal with the code in line 60 RUN 2DROP. Is this ability to be called unstructured?
Example 3. 64 bits working range

ABC FORTH is very easy to follow up a new or a 64 bits FORTH system.
At the beginning of 64 bits era, a public domain 64 bits BASIC is not so easy coming out quickly.
For me, so long as there is a FORTH system existed already, I may have ABC FORTH added to it in less than 2 weeks. Even though a 64 bits new FORTH system is always lack of floating point functions, I am able to build my personal pure software floating point functions in it by ABC FORTH itself.
I don't like to work on any kinds of vendor's FORTH. I used to work on public domain FORTH only.
Apply a 64 bits ABC FORTH program to find prime numbers over a fixed 64 bits range can show you some special features.
These programs are simply based on the following three properties of Prime Numbers.
(1) The lowest even prime number is 2
(2) The lowest odd prime number is 3
(3) All prime numbers above 3 can be represented by the formula 6n + 1 and 6n - 1 for n>=1

This was the simplest version adopted by me at the beginning when I developed.  
5 integers I J L A B
: SimplePrange ( -- )
BASIC
10 print " Input start and stop numbers A and B, A < B, A must >= 10 " cr
20 inputi A , B
30 for J = A to B
40 if ( J mod 2 = 0 ) OR ( J mod 3 = 0 ) then 220
50 for I = 6 to sqrt ( J ) + 1 step 6
60 if ( J mod ( I - 1 ) = 0 ) OR ( J mod ( I + 1 ) = 0 ) then 210
70 next I
100 print J
110 goto 220
210 run 2drop
220 next J
300 end ;

The final consolidated TurboPrange code with proving output is as following.

You are able to get some detail features via to compare it to the SimplePrange code listed above.
5 integers I J A B C
: TurboPrange ( -- )
BASIC
10 print " Enter start and stop numbers A and B, A < B, A must >= 10 " cr
20 inputi A , B
30 LET C = 0
40 for J = A to B
50 if J mod 2 = 0 then 220
60 if J mod 3 = 0 then 220
70 for I = 6 to sqrt ( J ) + 1 step 6
80 if J mod ( I - 1 ) = 0 then 210
90 if J mod ( I + 1 ) = 0 then 210
100 next I
110 let C = C + 1
120 print J ; " = 6 x " ; J / 6 ; " + " ; J mod 6
130 goto 220
210 run 2drop
220 next J
310 PRINT " Total primes = " ; C
320 end ;

TurboPrange
Enter start and stop numbers A and B, A < B, A must >= 10 !
? 1000000000001000 1000000000002000

    1000000000001003 = 6 x 166666666666833 + 5
    1000000000001027 = 6 x 166666666666837 + 5
    1000000000001063 = 6 x 166666666666843 + 5
    1000000000001089 = 6 x 166666666666848 + 1
    1000000000001117 = 6 x 166666666666852 + 5
    1000000000001209 = 6 x 166666666666868 + 1
    1000000000001269 = 6 x 166666666666878 + 1
    1000000000001293 = 6 x 166666666666882 + 1
    1000000000001347 = 6 x 166666666666891 + 1
    1000000000001371 = 6 x 166666666666895 + 1
    1000000000001413 = 6 x 166666666666902 + 1
    1000000000001491 = 6 x 166666666666915 + 1
    1000000000001503 = 6 x 166666666666917 + 1
    1000000000001551 = 6 x 166666666666925 + 1
    1000000000001617 = 6 x 166666666666936 + 1
    1000000000001623 = 6 x 166666666666937 + 1
    1000000000001669 = 6 x 166666666666944 + 5
    1000000000001741 = 6 x 166666666666956 + 5
    1000000000001749 = 6 x 166666666666958 + 1
    1000000000001819 = 6 x 166666666666969 + 5
    1000000000001839 = 6 x 166666666666973 + 1
    1000000000001867 = 6 x 166666666666977 + 5
    1000000000001897 = 6 x 166666666666982 + 5

Total primes = 23  OK

Example 4: Self-built programming grammar

Courtesy of http://rosettacode.org/wiki/100_doors, I would like to cite contents in this website to test my ABC FORTH by means of some different codes.
For the purpose of convenience, 100 Doors question re-post here again:
Question:
There are 100 doors in a row that are all initially closed.
You make 100 passes by the doors.
The first time through, visit every door and   toggle   the door   (if the door is closed,   open it;   if it is open,   close it).
The second time, only visit every 2nd door   (door #2, #4, #6, ...),   and toggle it.
The third time, visit every 3rd door   (door #3, #6, #9, ...), etc,   until you only visit the 100th door.
Task:
Answer the question:   what state are the doors in after the last pass?   Which are open, which are closed?
The alternate solution over there has been ignored here, owing to have no interesting.  

Somebody did a FORTH version. Thanks to him. Instruction "toggle" is still useful for me. So quote it first.

: toggle ( c-addr -- )                  \ toggle the byte at c-addr
  dup c@ 1 xor swap c! ;

100  1+ ( 1-based indexing ) constant ndoors
create doors  ndoors allot

: finit ( -- )  doors ndoors erase ;     \ close all doors

: pass ( n -- )                         \ toggle every nth door
    ndoors over do
        doors i + toggle
    dup ( n ) +loop drop ;

: run ( -- )  ndoors 1 do  i pass  loop ;
: display ( -- )                        \ display open doors
    ndoors 1 do  doors i + c@ if  i .  then loop cr ;

: DoorsV1 CR finit run display ;

A few ABC FORTH versions can do the same thing out. All of them are using the same one array data structure DOOR(100). FORTH system used to do nothing about initialization for a data structure. Instruction "binit" is doing it.
DoorsV2 is a directive translated code from its original GW-BASIC demonstrated code.

100 (ARRAY) DOOR
2 integers HOP I

: binit ( -- )
basic
10 FOR I = 1 TO 100
20 LET DOOR ( I ) = 0
30 NEXT I
40 end ;

: DoorsV2 ( -- )
BASIC
10 run binit
40 FOR HOP = 1 TO 100
50 FOR I = 0 TO 100 STEP HOP
60 LET DOOR ( I ) = DOOR ( I ) + 1
70 NEXT I
80 NEXT HOP
90 FOR I = 1 TO 100
100 IF DOOR ( I ) MOD 2 = 1 THEN 120
110 GOTO 130
120 PRINT I
130 NEXT I
140 END ;

The following 3 codes use a common code named PrintResult.
: PrintResult
BASIC
10 FOR I = 1 TO 100
20 IF door ( I ) = 1 then 40
30 goto 50
40 PRINT " Door " ; I ; " is open "
50 NEXT I
60 END ;

DoorsV3 line 40 is showing one kind of self-built programming grammar. Phrase "address-of door ( I ) iarray" can give you the address of one array element Door(I). Original FORTH "toggle" word can help you to toggle its content.
: DoorsV3
basic
10 run binit
20 FOR hop = 1 TO 100
30 FOR I = hop TO 100 STEP hop
40 run address-of door ( I ) iarray toggle
50 NEXT I
60 NEXT hop
70 RUN PrintResult
80 end ;

DoorsV4 line 40 is showing another kind of self-built programming grammar. All contents of Door(I) toggled by means of mathematical calculation: original content plus 1 then MOD 2.
: DoorsV4
basic
10 run binit
20 FOR hop = 1 TO 100
30 FOR I = hop TO 100 STEP hop
40 LET DOOR ( I ) = ( DOOR ( I ) + 1 ) MOD 2
50 NEXT I
60 NEXT hop
70 RUN PrintResult
80 end ;
DoorsV5 line 40 is showing one more kind of self-built programming grammar. DoorsV5 adopt a functionalized method to solve this problem. Let ABC FORTH can do the same thing as what the other BASICs can do.
Beware! Here this BASIC function "NOT" is not the same as FORTH word "NOT". We must defined a FORTH "0/1" word first, then convert it to our new "NOT" function in BASIC environment.
: 0/1 ( n -- 1/0 )
  NOT ABS ;
' 0/1 IDEF NOT

: DoorsV5
basic
10 run binit
20 FOR hop = 1 TO 100
30 FOR I = hop TO 100 STEP hop
40 LET DOOR ( I ) = NOT ( DOOR ( I ) )
50 NEXT I
60 NEXT hop
70 RUN PrintResult
80 end ;

Execution results:

CR .( DoorsV1: )
DoorsV1
CR .( DoorsV2: )
DoorsV2
CR .( DoorsV3: )
DoorsV3
CR .( DoorsV4: )
DoorsV4
CR .( DoorsV5: )
DoorsV5

DoorsV1:
1 4 9 16 25 36 49 64 81 100

DoorsV2:
               1
               4
               9
              16
              25
              36
              49
              64
              81
             100

DoorsV3:
Door 1 is open
Door 4 is open
Door 9 is open
Door 16 is open
Door 25 is open
Door 36 is open
Door 49 is open
Door 64 is open
Door 81 is open
Door 100 is open

DoorsV4:
Door 1 is open
Door 4 is open
Door 9 is open
Door 16 is open
Door 25 is open
Door 36 is open
Door 49 is open
Door 64 is open
Door 81 is open
Door 100 is open

DoorsV5:
Door 1 is open
Door 4 is open
Door 9 is open
Door 16 is open
Door 25 is open
Door 36 is open
Door 49 is open
Door 64 is open
Door 81 is open
Door 100 is open  ok