-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathmanual.mi
1518 lines (1378 loc) · 62.1 KB
/
manual.mi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
dnl $ Id: $
dnl Copyright{2000-2024}: Albert van der Horst, HCC FIG Holland by GNU Public License
@section Getting started
@subsection Hello world!
Type forthsamp({thisforth}) to get into your interactive Forth system.
You will see a signon message.
While sitting in your interactive Forth doing a ``hello world'' is easy:
forthexample({"Hello world!" TYPE
Hello world! OK })
Note that the computer ends its output with forthsamp({OK})
to indicate that it has completed the command.
forthbreak
Making it into an interactively usable program is also easy:
forthexample(
{: HELLO "Hello world!" TYPE CR ;
OK
HELLO
Hello world!
OK })
This means you type the command forthsamp({HELLO}) while you
are in thisforth.
As soon as you leave thisforth,
the new command is gone.
_HOSTED_({
forthbreak
If you want to use the program a second time,
you can put it in a file forthfile({hello.frt}).
It just contains the definition we typed earlier:
forthexample({ : HELLO "Hello world!" TYPE CR ;})
This file can be forthcode({INCLUDED}) in order to add the command
forthsamp({HELLO}) to your Forth environment, like so:
forthexample(
{"hello.frt" INCLUDED
OK
HELLO
Hello world!
OK })
During development you probably have started with
forthsamp({thisforth -e}), so you need just type
forthexample({INCLUDE hello.frt})
In order to make a stand alone program to say hello you can
use that same source file, again forthfile({hello.frt}).
Now build the program by
forthbreak
thisforth -c hello.frt
forthbreak
(That is forthkey({c}) for compile.)
The result is a file _HOSTED_LINUX_({forthfile({hello})}) _PC_({forthfile({HELLO.EXE})}).
This file can be run from your command interpreter, or shell.
It then will execute the last word defined in the source file in this case forthsamp({HELLO}) .
It is a single file that you can pass to some one else to run on their
computer, without the need for them to install Forth.
For the compiler to run you must have the library correctly
installed.
})
If that failed, or anything else fails, you will
get a message with at least forthsamp({ ciforth ERROR ###})
and hopefully some more or less helpful text as well.
The forthsamp({###}) is an error number. forthxref({Errors}) Section Explanations.
Note for the old hands. Indeed the quoted strings are not ISO.
They surely are a Forth-like extension. Read up on denotations,
and the definition of forthcode({"}) .
In thisforth you never have to worry about the life time of those
quoted strings, they are allocated in the dictionary and are permanent.
@subsection The library.
If you want to run a program written on some other Forth, it
may use facilities that are not available in thisforth's kernel,
but they may be available in the forthdefi({library}).
A library is a store with facilities, available on demand.
Forth as such doesn't have a library mechanism,
but thisforth does.
thisforth uses the forthdefi({blocks}) as a library
by addition of the word forthcode({WANTED}) and a convention.
Starting with forthsamp({thisforth -w}) or most any option you have this
facility available. If you are already in thisforth, you can
type forthsamp({1 LOAD}).
_VERBOSE_({ The extension of forthsamp({.lab}) in
forthfile({forth.lab}) means Library Addressable by Block.})
Now we will add forthcode({DO-DEBUG}) using this library mechanism.
It is used immediately.
It is handy during development, after every line it
shows you what numbers Forth remembers for you.
Also from now on the header of each
block that is forthcode({LOAD})-ed is shown. forthbreak
Type (forthsamp({1 LOAD}) may not be necessary):
forthexample({1 LOAD
"DO-DEBUG" WANTED
OK
DO-DEBUG
S[ ] OK 1 2
S[ 1 2 ] OK})
(You can turn forthcode({DO-DEBUG}) off with forthcode({NO-DEBUG}) .)
More convenient than forthcode({WANTED}) is forthcode({WANT}) that adds
all words that are on the remainder of the line, so without quotes.
If you try to forthcode({INCLUDE}) a program, you may
get errors like forthsamp({TUCK? ciforth ERROR # 12 : NOT RECOGNIZED}).
forthxref({Errors}) Section Explanations.
Apparently, thisforth doesn't know about a forth word named
forthcode({TUCK}), but after forthsamp({"TUCK" WANTED}) maybe
it does. You may try again.
The library file must be organized for forthcode({WANTED}) in a
particular way to find something. It is in fact familiar.
It is divided into blocks of 16 lines.
The convention about the way the library file must be
organized for forthcode({WANTED}) to find something is
simple. It is divided into blocks of 16 lines.
The first line is the header of the block, the so called forthdefi({indexline})
If the word we are looking for is mentioned in the header,
that block is compiled.
There may be several blocks that define a particular
word.
If the first block is terminated early,
the word is not yet defined and the next blocks is loaded.
E.g. a words like forthcode({?32}) mark 32-bits code and the
screen is terminated if the Forth is 64 bits.
This goes on until the word is defined, or the end of the
screens is reached.
The terminators that cut loading a screen short, are
defined by the the forthcode({CONFIG}) defining word.
The last screen is marked by an empty index line.
There may be names that represent a whole package.
Among those symbolic names are forthsamp({-fp- -fpwa- ASSEMBLERi86
ASSEMBLERi86-HIGH -traditional- }).
After forthcode({WANT}) symbolic names may not be in the dictionary,
but note that they are not intended to be executed anyway.
There is really nothing much to it.
The bottom line is that one library file serves a range
of operating systems and cell sizes.
The library file contains examples for you
to load using forthcode({WANT}) .
Try
forthexample(
{WANT SIEVE
LIM # 4 ISN'T UNIQUE
OK
10 SIEVE
KEY FOR NEXT SCREEN
ERATOSTHENES SIEVE -- PRIMES LESS THAN 10 000
0 002 003 ...
(lots of prime numbers.)})
@subsection Development.
If you want to try things out, or write a program -- as
opposed to just running a ready made program -- you best
_HOSTED_({start up thisforth by forthsamp({thisforth -e}).
That is forthkey({e}) for elective.
forthsamp({thisforth -e}) instructs thisforth to load screen 5
(forthkey({e}) is the 5-th letter.)
}) _BOOTED_({do forthsamp({5 LOAD}) immediately.})
You can configure this screen 5 to suit your particular needs,
by just using some programmers editor.
We will come back to that later.
forthbreak
You will have available:
forthenumerate
forthitem
forthcode({WANTED}) and forthcode({WANT}) .
forthsamp({WANT xxx yyy}) is equivalent to
forthsamp({"xxx" WANTED "yyy" WANTED}) , but it is more convenient.
forthitem
forthcode({DH.}) forthcode({H.}) forthcode({B.}) forthcode({DUMP}) forthcode({FARDUMP})
For showing numbers in hex and parts of memory.
_PC_({
forthitem
forthcode({EDIT})
The editor for editing blocks of the library file.
})_END_({_PC_})
forthitem
forthcode({SEE})
To analyse words, showing the source code of compiled words.
(Also known as forthcode({CRACK}).)
_SOURCEFIELD_({
forthitem
forthcode({LOCATE})
To show the part of the source file where the word is defined,
or, if loaded from the library file, the block where it is defined.
})_END_({_SOURCEFIELD_})
_HOSTED_({
forthitem
forthcode({OS-IMPORT})
_HOSTED_LINUX_({
To be able to type shell-commands from within Forth as if you
were in a terminal window.
})_END_({_HOSTED_LINUX_}).
_PC_({
To be able to type DOS-commands from within Forth as if you
were in a terminal window.
})_END_({_PC_}).
})_END_({_HOSTED_}).
forthendenumerate
_HOSTED_({
Because this ciforth is ``hosted'', meaning that it is started from
an operating system, you can develop in a convenient way.
Start thisforth in a window, and use a separate window to start your
editor. Try out things in thisforth. If they work, paste the code into
your editor. If a word works, but its source has scrolled off the screen,
you can recover the source using forthcode({SEE}) .
If you have constructed a part or all of your program,
you can save it from your editor to a file. Then by the command
forthsamp({INCLUDE <file-name> }) load the program in thisforth
and do some further testing.
You are not obliged to work with separate windows.
Suppose your favorite editor
is called _PC_({forthfile({edlin})})_HOSTED_LINUX_({forthfile({vi})}). After
_PC_({forthexample({ "EDLIN" OS-IMPORT EDLIN })})
_HOSTED_LINUX_({forthexample({ "vi" OS-IMPORT vi })})
you can start editing a file in the same way as from
_PC_({a DOS window or plain DOS}) _HOSTED_LINUX_({the shell}).
Of course you now have to switch between editing a file
and thisforth. But at least you need not set up your Forth again,
until your testing causes your Forth to crash.
})_END_({_HOSTED_})
@subsection Finding things out.
If you want to find things out
you must
start up thisforth again by forthsamp({thisforth -e}).
The sequence
forthexample(
{WANT TUCK
LOCATE TUCK})
shows you the source for TUCK if it is in the library somewhere.
forthexample(
{WANT TUCK
SEE TUCK})
show you the source for TUCK if it is in the library or in the kernel,
but without comment or usage information.
@section Concepts
A forth user is well aware of how the memory of his
computer is organised. He allocates it for certain purposes,
and frees it again at will.
The last-in first-out buffer that remembers data for us is called
the forthdefi({data stack}) or sometimes forthdefi({computation stack}).
There are other stacks around,
but if there is no confusion it is often called just the forthdefi({stack}).
Every stack is in fact a buffer and needs also a forthdefi({stack pointer})dnl
to keep track of how far it has been filled.
It is just the address where the last data item has been stored in the buffer.
The forthdefi({dictionary}) is the part of the memory where the forthdefin({word})'s are
(forthpxref({DICTIONARY})).
Each word owns a part of the dictionary, starting with its name and
ending where the name of the next word starts.
This structure is called a forthdefi({dictionary entry}).
Its address is called a forthdefi({dictionary entry address})dnl
or forthdefi({DEA}). In ciforth's this address is used for external
reference in a consistent way. For example it is used as the
forthdefi({execution token}) of a word in the ISO sense.
In building a word the boundary between the dictionary and the free
space shifts up.
This process is called forthdefi({allocating}), and the boundary is marked by
a forthdefi({dictionary pointer}) called forthcode({DP}) .
A word can be executed by typing its name.
Each word in the dictionary belongs to precisely one forthdefi({word list}),
or as we will say here namespace.
Apart from the name, a word contains data and executable code,
(interpreted or not) and linking information
(forthpxref({NAMESPACE})).
The order of words in a wordlist is important for looking them up.
The most recent words are found first.
The concept word list is part of the ISO standard, but we will
use forthdefi({namespace}). A namespace is much more
convenient, being a word list with a name, created by
forthcode({NAMESPACE}) . ISO merely knows
forthdefi({word list identifier}) 's, a kind of handle,
abbreviated as forthdefi({WID}).
A new word list is created by the use of forthcode({NAMESPACE}).
When looking up a word, only the wordslists that are in the current
forthdefi({search order}) are found.
By executing the namespace word the associated word list is pushed
to the front of the search order.
In fact in ciforth's every DEA can serve as a WID. It defines a
wordlist consisting of itself and all earlier words in the same
namespace.
You can derive the WID from the DEA of a namespace by forthcode({>WID}).
A word that is defined using forthcode({:}) is often called a
forthdefi({colon definition}). Its code is called
forthdefi({high level}) code.
A high level word, one defined by forthcode({:}) , is little more than a
sequence of addresses of other words. The forthdefi({inner interpreter})dnl
takes care to execute these words in order.
It acts by fetching the address pointed by forthvar({HIP}) , storing
this value in register forthvar({WOR}). It then jumps to the address
pointed to by the address pointed to by forthvar({WOR}). forthvar({WOR}) dnl
points to the code field of a definition which (at offset forthdef({>CFA}) )
contains the address of the code which executes for that definition.
For speed reasons this offset is choosen to be zero.
This usage of indirect threaded code is a major contributor to the power,
portability, and extensibility of Forth.
If the inner interpreter must execute another high level word,
while it is interpreting, it must remember the old value of
forthvar({HIP}), and this so called forthdefi({nesting}) can go several
levels deep.
Keeping this on the data stack would interfere with the data the
words are expecting, so they are kept on a separate stack, the
forthdefi({return stack}).
Apart from forthvar({HIP}) and forthvar({WOR}) the return and data stack
are kept in registers named forthvar({RPO}) and forthvar({SPO}).
If you're interested in the actual registers, you can inspect the
assembler source file that goes with this Forth.
The usage of two stacks is another hall mark of Forth.
A word that generates a new entry in the dictionary is called a
forthdefi({defining word}) (forthpxref({DEFINING})).
The new word is created in the forthcode({CURRENT}) word list .
Each processor has a natural size for the information. (This is
sometimes called a machine word). For a Pentium processor this is
32 or 64 bit, for the older Intel 8086 it is 16 bit.
The pendant in Forth is called a forthdefi({cell}) and its size
may deviate from the processor you are running on.
For this ciforth it is _BITS_,
It applies to the data remembered in the data stack, the
return addresses on the return stack,
memory accesses forthcode({@@}) and forthcode({!}) , the size of forthcode({VARIABLE})' s
and forthcode({CONSTANT})' s.
In Forth a cell has no hair. It is interpreted by you as a
signed integer, a bit-map, a memory address or an unsigned number.
The operator forthcode({+}) can be used to add numbers, to set a bit in
a bitmap or advance a pointer a couple of bytes.
In accordance with this there are no errors such as overflow given.
Sometimes we use data of two cells, a forthdefi({double}).
The high-order cell is most accessible on the stack and if stored in
memory, it is lowest.
The code for a high level word can be typed in from the
terminal, but it can also fed into Forth by redirection from a
file, forthcode({INCLUDED}) from a file or you can
forthdefi({load}) it from the file forthfile({forth.lab}),
because you can load a piece of this library at will once you
know the block number. This file is divided into
forthdefi({blocks}) of 1 Kbyte. They may contain any data, but
a most important application is containing source code. A block
contain source code is called a forthdefi({screen}). It
consists of 16 lines of 64 characters. In ciforth the 64-th
character is forthkey(^J) such that they may be edited in a
normal way with some editors. To forthdefi({load}) such a
screen has the same effect as typing its content from the
terminal.
The extension lab stands for forthdefi({Library Addressable by Block}),
Traditionally Forthers have things called
forthdefi({number})'s, words that are present in the source be
it interpreted or compiled, and are thought of not as being
executed but rather being a description of something to be put
on the stack directly. In early implementations the word forthsamp({NUMBER})
was a catch-all for anything not found in the dictionary, and
could be adapted to the application.
For such an extensible language as
Forth, and in particular where strings and floating point
numbers play an increasing role, numbers must be generalised to
the concept of forthdefi({denotation})'s.
The need for a way to
catch those is as present as it was in those early days.
Denotations put a
constant object on the stack without the need to define it
first. Naturally they look, and in fact are, the same in both
modes. Here we adopt a practice of selecting a type of the denotations
based on the first letters, using forthcode({PREFIX}).
This is quite practical and familiar.
Examples of this are (some from C, some from assemblers, some
from this Forth) :
forthexample({10
'a'
^A
0DEAD
$8000403A
0x8000403A
#3487
0177
S" Arpeggio"
"JAMES BROWN IS DEAD"
" JK "
'DROP
' DROP})
These examples demonstrate
that a denotation may contain spaces, and still are easy to scan.
And yes, I insist that forthsamp({' DROP}) is a denotation.
But forthsamp({'DROP}) is clearer,
because it can only be interpreted as such;
it is not a valid word.
Of course a sensible programmer will not define a word that looks like
a denotation :
forthexample({ : 7 CR "This must be my lucky day" TYPE ; ( DON'T DO THIS) })
@section Portability
If you build your words from the words defined in the ISO standard,
and are otherwise careful, your programs may run on other systems that
are ISO standard.
There are no gratuitous deviations from the standard,
but a few things are not quite conforming.
forthenumerate
forthitem
The error system uses forthcode({CATCH}) and forthcode({THROW}) in a conforming way.
However the codes are not assigned according to the table
in the standard. Instead positive numbers are ciforth errors
and documented in this manual.
ciforth's errors identify a problem more precisely than the
standard admits. An error condition that is not detected
has no number assigned to it.
Negative numbers are identical
to the numbers used by the host operating system.
No attempt is made to do better than reproduce the messages
belonging to the number _HOSTED_LINUX_({as given by strerror.}) _PC_({stated
in Ralph Browns list, which is slightly better than the MSDOS
programmers Manual.})
forthitem
As forthcode({ABORT"}) forthcode({ABORT}) forthcode({QUIT}) are not implemented
using forthcode({THROW}) it is not possible to catch those words.
forthitem
There is no forthcode({REFILL}) . This is a matter of
philosophy in the background. You may not notice it.
forthbreak
Consequences are that forthcode({BLK}) is not inspected for every
word interpreted, but that blocks in use are locked.
Files are not read line by line, but read in full and
evaluated.
_CIF_IN_({
forthitem
It uses forthcode({PP}) instead of the ISO forthcode({>IN}).
The forthcode({>IN}) that is available via the library is to be
loaded only via forthcode({WANT -traditional-}) and then work as
in expected.
In particular forthcode({INCLUDED}) compiles a file line by line.
forthcode({PP}) could be manipulated to have such effects manipulating
forthcode({>IN})
}) dnl
forthitem
Counting in do loops do not wrap through the boundary between
negative and positive numbers.
This is not useful on Forths of 32 bits and higher;
for compatibility among {ciforths} 16 bit {ciforths} don't wrap either.
forthitem
Namespaces are wordlists with a name. They push the wordlist
to the search order, instead of replacing the topmost one,
as is done by VOCABULARY (not an ISO-word) that is present in some other
Forth's.
In this sense forthcode({FORTH}) and forthcode({ASSEMBLER}) words are not
conforming.
forthitem
This is not strictly non-conforming, but worth mentioning here.
In fact thisforth contains only one state-smart word
besides forthcode({LITERAL}) (that word is forthcode({."}) ).
All denotations are state-smart only because they use forthcode({LITERAL})
and the result is correct ISO behaviour for numbers.
Knowledge of this is used freely in the libraries of ciforth;
it is the right of a system developer to do so.
The library is not a supposedly ISO-conforming program.
It tends to rely on
ciforth-specific and thisforth-specific -- but hopefully documented -- behaviour.
Understanding it requires some study of non-portable facilities.
forthitem
When a file is forthcode({INCLUDED}) it is read in as a whole,
so there is no need for forthcode({REFILL}) .
After forthcode({ WANT REFILL}) a forthcode({REFILL}) is loaded that
sets the parse pointer to the start of the next line.
Moreover forthcode({0>IN}) will set the parse pointer to the start of
the current line.
In many cases this will accomplish the effect described by the standard.
If this doesn't help, use forthcode({-traditional-}) .
forthxref({Manual}), subsection forthsamp({REFILL}) .
forthendenumerate
Here we will explain how you must read the glossary of thisforth,
in relation to terminology in the ISO standard.
Whenever the glossary specifies under which conditions a word may
forthdefi({crash}), then you will see the euphemism forthdefi({ambiguous condition}) in
the ISO standard.
For example:
forthbreak
Using forthcodeni({HOLD}) other than between
forthcodeni({<#}) and forthcodeni({#>}) leads to a crash.
Whenever we explicitly mention ciforth in a sentence that appears
in a glossary entry,
the behaviour may not apply to other ISO standard systems.
This is called forthdefi({ciforth specific behaviour}). dnl
If it mentions ``this ciforth'' or ``thisforth'', you cannot even trust that
behaviour to be the same on other ciforth systems.
Often this is called an ``implementation defined'' behaviour in the standard.
A typical example is the size of a cell.
Indeed we are obliged to specify this behaviour in our glossary,
or we don't comply to the standard.
The behaviour of the other system may very well be a crash.
In that case the standard probably declares this an ``ambiguous condition''.
For example:
forthbreak
On this ciforth forthcodeni({OUT}) is set to zero whenever forthcodeni({CR}) is executed.
The bottom line is that you never want to write code where
thisforth may crash.
And that if you want your code to run on some other system,
you do not want to rely on forthdefi({ciforth specific behaviour}).
If you couldn't get around that,
you must keep the specific code separate.
That part has to be checked carefully against the documentation
of any other system,
where you want your code to run on.
By using forthcode({CELL+}) it is easy to keep your code 16/32/64 bit clean.
This means that it runs on 16, 32 and 64 bits systems.
@subsection REFILL
Some programs rely on line by line loading by forthcode({REFILL}) .
This is substantially different from normal ciforth practice.
You want at least forthcode({REFILL}) forthcode({>IN}) ,
and you probably use forthcode({WORD}) and forthcode({FIND}) and
the (traditional, but non standard) word of forthcode({VOCABULARY}) that
is different from forthcode({NAMESPACE}) .
This is accomplished by the symbolic target of forthdefi({-traditional-}).
forthexample(
{WANT -traditional- })
All the words that are loaded by this command are in the library and
they are marked with forthsamp({-traditional-}) in the index line.
The word forthcode({-traditional-}) is not itself defined, expect to get
get a warning for that.
This is done in order to be able to reload (and forcibly redefine) all words
by forthcode({WANT -traditional-}) .
It is recommended that this is the first facility loaded,
that way there is the least chance with interference.
The following sequence generates a traditional Forth:
forthexample({
lina -a
WANT -traditional- SAVE-SYSTEM
....
"traditionalforth" SAVE-SYSTEM
BYE
})
It is of course possible to enhance this Forth with more words
at the place of the dots.
@subsection Compatibility with thisforth 4.0.x
Since version 5.x changes have been made to increase compatibility
with existing practice.
By invoking forthcode({WANT -legacy-}) you load a screen that
forces compatibility with 4.x.x versions.
You will notice that existing programs either invoke this, or have
been reworked to not need legacy items.
In either case, those programs have been tested with version 5.x
What the legacy items are can be seen from the screen that has
forthcode({-legacy-}) in its index line.
In particular forthcode({REQUIRE REQUIRED PRESENT? }) are
to be found in those screens.
Note that by using legacy items your code may be in conflict with
upcoming standards.
It is also likely that in those programs traditional words are used
that are no longer present in the kernel such as forthcode({WORD FIND }).
These can be loaded by regular forthcode({WANT}) .
The names forthcode({VOCABULARY}) and forthcode({REQUIRE}) are
being proposed for standardisation.
The ciforth definitions with these names were not compatible with
this proposal.
So the forthcode({REQUIRE}) of older versions is now called forthcode({WANT}).
Likewise forthcode({REQUIRED}) is renamed to forthcode({WANTED}).
forthcode({VOCABULARY}) is renamed to forthcode({NAMESPACE}),
with the difference that forthcode({NAMESPACE}) is not immediate.
This allows to include the new standardised definitions
in a loadable screen.
@section Configuring
For configuring your thisforth,
you may use forthcode({"newforth" SAVE-SYSTEM}) .
This will do most of the time,
but then you build in the forthcode({SAVE-SYSTEM}) command as well.
For configuring your thisforth, without enlarging the dictionary,
you may use the following sequence
forthexample({ S" myforth.lab" BLOCK-FILE $! \ Or any configuration command
1 LOAD
WANT SAVE-SYSTEM
: DOIT
'_pad 'FORTH FORGET-VOC
'_pad >NFA @@ DP !
"newforth" SAVE-SYSTEM BYE ;
DOIT })
Here forthvar({DOIT}) trims the dictionary just before
saving your system into a file.
forthcode({_pad}) is the first word of
the facilities in screen 1 that was loaded.
(This was different in previous version of ciforth.)
forthcode({FAR-DP}) allows to have a disposable part of the
dictionary.
If you decide to use this facility for your own purposes,
make sure to always forthcode({FORGET}) the disposed off words.
The forthsamp({-c}) option uses this to avoid having
source files as part of an executable image.
@section Saving a new system
We have said it before: ``Programming Forth is extending the Forth language.''.
A facility to save your system after it has been extended is essential.
It can be argued that if you don't have that, you ain't have no Forth.
It is used for two purposes, that are in fact the same.
Make a customised Forth, like forthemph({you}) want to have it.
Make a customised environment, like a customer wants to have it.
Such a ``customised environment'', for example a game, is often
called a forthdefi({turnkey system}) in Forth parlance.
It hides the normal working of the underlying Forth.
_HOSTED_({
In fact this is what in other languages would be called ``just compiling'',
but compiling in Forth means adding definitions to an interactive Forth.
In ciforth ``just compiling'' is as easy as in any language
(forthpxref({Manual}), Hello world!).})
Of course, whether you have a
hosted system _HOSTED_LINUX_(like this one) _HOSTED_MSDOS_(like this one) or
a booted system _BOOTED_(like this one), it is clear that some
system-dependant information goes into accomplishing this.
This has all been sorted out for you. Just use
forthcode({SAVE-SYSTEM}) .
This accepts a string, the name you want the
program-file to have.
Having a program to execute a certain word is even easier,just use the
forthsamp({-c}) option. forthxref(Manual) Section Libraries and options.
In the following it is explained.
We use the naming convention of ISO about cells.
A cell is the fundamental unit of storage for the Forth engine.
Here it is _BITS_ bits (_BITS16_(2)_BITS32_(4)_BITS64_(8) bytes).
The change of the boot-up parameters at
forthcode({+ORIGIN}), in combination with storing an image on disk
goes a long way to extending the system.
This proceeds as follows:
forthenumerate
forthitem
All user variables are saved by copying them from forthsamp({U0 @@})
to forthsamp({0 +ORIGIN}).
The user variable forthcode({U0}) dnl
points to the start of the user area. The length of the area is M4_US cells.
If in doubt check out the variable forthvar({US}) in the assembler code.
forthitem
If all user variables are to be initialised to what they are in this live system
skip the next step.
forthitem
Adjust any variables to what you want them to be in the
saved system in the forthcode({+ORIGIN}) area.
The initialisation for user variable forthvar({Q}) can be found at
forthsamp({' Q >DFA @@ +ORIGIN}).
forthitem
Adjust version information (if needed)
forthitem
Copy your thisforth to a new file using forthcode({PUT-FILE}) .
The difficult part is to add to the system specific header information
about the new size, which is now
from forthcode({BM}) to forthcode({HERE}).
The command forthsamp({WANT SAVE-SYSTEM}) loads
a version that does that correctly for your hosted system.
forthendenumerate
@section Memory organization
A running ciforth has 3 distinct memory areas.
They occur sequentially from low memory to high.
forthitemize
forthitem
The dictionary
forthitem
Free memory, available for dictionary, from below, and stacks, from above
forthitem
The work area for each task with a total size of forthcode({TASK-SIZE})
that must be a power of two.
This may be replicated for multi-tasking.
It is evenly divided into the data stack, the return stack and user variables,
the input buffer for the console, _HIGH_BUF_({and disk block buffers}).
The work area is initialised on startup.
_THREADS_({
These areas have an alignment of 1/4 of the forthcode({TASK-SIZE}) .
This way the return stack pointer can serve double duty as a user pointer;
this is one register less to save for a task switch.
})
forthenditemize
The lowest part of the free memory is used as a scratch area: forthcode({PAD}) .
_LOW_BUF_({The disk block buffers are allocated in the dictionary,
because otherwise they would not be accessible to the BIOS})
The dictionary area is the only part that is initialised,
the other parts are just allocated.
_HOSTED_({
The program as residing on disk must contain the first area.
In addition it contains a header, to tell
the _OS_ how to transfer the program to memory. })
Logically the Forth system consists of these 7 parts.
forthitemize
forthitem
Boot-up parameters
forthitem
Machine code definitions
forthitem
Installation dependant code
forthitem
High level standard definitions
forthitem
High level user definitions
forthitem
System tools (optional)
forthitem
RAM memory workspace
forthenditemize
@subsection Boot-up Parameters
The boot-up area contains initial
values for the registers needed for the Forth engine,
like stack pointers, the pointers to the special memory area's,
and the very important dictionary pointer forthcode({DP})dnl
that determines the boundary between the dictionary and free space.
They are copied to a separate area the forthdefi({user area}) ,
each time Forth is started.
The bootup area itself is not changed, but the variables in the user
area are.
By having several user area's, and switching between them,
ciforth supports multitasking.
When you have made extensions to your system, like for instance you
have loaded an editor, you can make these permanent by updating the
initial values in the boot-area and saving the result to disk as an
executable program.
The boot-up parameters
extend from forthsamp({0 +ORIGIN}) and supply an initial value for all
of the user area.
This is the image for the forthdefi({user area}).
_SUPPRESSED({
It also extends 6 cells downwards, containing machine code for two
jumps, to the warm and the cold start, and a version number.})
In ciforth the bootup parameters are more or less the data area
belonging to the forthcode({+ORIGIN}) word.
Executing forthsamp({0 +ORIGIN}) leaves a pointer in this area.
_SUPPRESSED({but after the jump vectors and the release numbers.})
@subsection Installation Dependent Code
forthcode({KEY}) forthcode({EMIT}) forthcode({KEY?}) forthcode({TYPE})
forthcode({CR}) forthcode({BLOCK-READ}) and forthcode({BLOCK-WRITE})
are indeed different for different I/O models.
This is of little concern to you as a user,
because these are perfectly normal dictionary entries and the different
implementations serves to make them behave similarly.
There will however be more differences between the different configurations for
ciforth for these words than habitually.
These definitions are often revectored especially those for output.
Output is revectored using forthcode({TYPE}) . In other Forth's this is mostly
done via forthcode({KEY}) and forthcode({CR}) separately.
_HOSTED_X_({ Input revectoring cannot be done via forthcode({KEY}) .
Redirection works and is easier most of the time.})
@subsection Machine Code Definitions
The machine executable code definitions
play an important role because they
convert your computer into a standard Forth stack computer.
It is clear that although you can define words by other words,
you will hit a lowest level.
The forthdefi({code word})'s as these lowest level programs are called,
execute machine code directly, if you invoke them from
the terminal or from some other definition.
The other definitions, called forthdefi({high level}) code,
ultimately execute a sequence of the machine executable code words.
The Forth forthdefi({inner interpreter}) takes care that
these code words are executed in turn.
In the assembler source (if you care to look at it)
you will see that they are interspersed with the
high level Forth definitions.
In fact it is quite common to decide to rewrite a code definition in high level
Forth, or the other way around.
The forthdefi({Library Addressable by Block}) contains an assembler,
to add code definitions that will blend in like they were written
in the kernel.
Such definitions are to be closely matched with your particular
ciforth,
and you must be aware which registers play which role in ciforth.
This is documented in the assembler source of this ciforth that
accompanies this distribution.
Of course it is also a rich source of examples how to
make assembler definitions.
It bears repeating: code words are perfectly normal dictionary entries.
Note: if you want to change this
ciforth's assembler source to fit your needs,
follow the instructions present in the source,
assembling as well as linking instructions.
@subsection High-level Standard Definitions
The high level standard definitions add all
the colon-definitions, user variables, constants, and variables that
must be available in a
"Forth stack computer" according to the ISO standard.
They comprise the bulk of
the system, enabling you to execute and compile from the terminal,
execute and
forthdefi({load}) code from disk to add definitions
etc.
Changes here may result in deviations from the standard,
so you probably want to leave this area alone.
_VERBOSE_({The technique described for the next section,
forget and recompile,
is not always possible here because of circular references.
That is in fact no problem with an assembler listing,
but it is if you load Forth code.})
Again standard definitions words are perfectly normal dictionary entries.
@subsection User definitions
The user definitions
contain primarily definitions involving user interaction:
compiling aids, finding, forgetting, listing, and number formatting.
Some of these are fixed by the ISO standard too.
In ciforth most of those facilitities are not available in the kernel,
but from the library.
This applies even to the ISO standard words from the
forthvar({TOOLS}) wordset like forthcode({DUMP}) (show a memory area as
numbers and text) and forthcode({.S}) (show the data stack).
You can forthcode({FORGET}) part of
the high-level and re-compile altered definitions from disc.
Mostly this is a mistake, and to make sure you mean it,
you must change forthcode({FENCE}) to defeat a protection mechanism.
_LOAD_({A number of entries that could easily be made loadable
are integrated in the assembler source of this ciforth version.})
Instead of forgetting them, you can load your own version
on top of the existing system and waste some space.
Again user definitions words are perfectly normal dictionary entries.
@subsection System Tools
The boundary between categories are vague. A system tools is
contrary to a user tool, a larger set of cooperating words.
A text editor and machine code assembler are the first tools
normally available. In ciforth those facilities are mostly not
available in the kernel, but from the library.
For example, an assembler is not part of he kernel as delivered,
but it is available after forthsamp({WANT ASSEMBLERi86}).
Beware! The assembler can only be loaded on top of a
forthcode({CASE-SENSITIVE}) system.
_BITS32_({ It automatically loads the proper _BITS_-bits version.})
_BITS16_({ It automatically loads the proper _BITS_-bits version.})
dnl 64 bits is to do FIXME.
You can load a more elaborate assembler. forthxref(Assembler) Section Overview.
They are among the first candidates to be integrated into
your system by forthcode({SAVE-SYSTEM}) .
_PC_({ We are including a sample editor, that is quite handy})
_HOSTED_LINUX_({An editor is not part of ciforth as delivered.
Development in Linux uses the there available editors.
Even without tools, code can be
tested by piping it into Forth, then commanding Forth to
look to the console, as follows :
forthbreak
forthsamp({ (echo 1 LOAD; cat pascal.frt - )| thisforth })
forthbreak
Primitive and preliminary as this may seem,
it has been used for quite substantial developments like the
80386 assembler.
forthbreak
More advanced is using Your Favorite Editor, followed by
including files:
forthbreak
forthsamp({ "vim mysrc.frt" SYSTEM })
forthbreak
forthsamp({ "mysrc.frt" INCLUDED })
forthbreak
})forthxref(Manual) Section Getting Started.
forthbreak
In an installed system you will put forthsamp({WANT OS-IMPORT INCLUDE})
in your electives screen (5), and just type
forthsamp({vim mysrc.frt}) to edit a file, without leaving thisforth and
load it with forthsamp({INCLUDE mysrc.frt})
A Pentium 32 and a 8086
Forth assembler are available in forthfile({forth.lab}).
They are loaded in accordance with the system that is run.
The registers used by thisforth are called HIP, SPO, RPO and WOR.
The mapping on actual processor registers is documented in the
source.
It is essential that you regard thisforth as just a way to get started
with Forth.
Forth is an extensible language, and you can set it to your hand.
But that also means that you must not hesitate to throw
away parts of the system you don't like, and rebuilt them
even in conflict with standards.
_VERBOSE_(
{Additions and changes must be planned and
tested at the usual Forth high level.
Some words criticial for speed you can later rewrite as code words.
Some words are easier to write in code right away.
})
Again words belonging to tools are perfectly normal dictionary entries.
@subsection RAM Workspace
The RAM workspace contains the compilation space for the dictionary,
_HIGH_BUF_({disc buffers,}) the computation and return stacks, the user area,
and the console input buffer,
_VERBOSE_({From the figforth user manual
forthquotation
For a single user system, at least 2k bytes must be available above the
compiled system (the dictionary). A 16k byte total system is most typical.
forthendquotation})
It is indeed possible to do useful work,
like factoring numbers of a few hundred digits, in a workspace of 2k bytes.
More typical a workspace is several megabytes to over hundred megabytes.
_BITS16_({There is no longer a reason to put up with a 16-bit system less than 64K.})
_LARGE_({32 and 64 bits system are set at 64Mbyte but this is arbitrary and could be set much
higher or lower without consequences for system load or whatever.
Before long we will put the dictionary space on 32-bits Linux to 4G minus
something and forget about this issue forever. })
The boundary between this area and the previous ones is pretty sharp,
it is where forthcode({DP}) points.
The other areas are more of a logical distinction.
But even this boundary constantly changes as you add and forget definitions.
Multi-tasking requires allocation of extra areas.
forthxref({Manual}) Section Details of memory layout.
@section Specific layouts
@subsection The layout of a dictionary entry
We will divide the dictionary in entries.
A forthdefi({dictionary entry}) is a part of the dictionary that
belongs to a specific word.
A forthdefi({dictionary entry address}), abbreviated
forthdefi({DEA}) is a pointer to the header of
a dictionary entry.
In
ciforth a header extends from the lowest address of the entry, where the code
field is, to the forthdefi({past header address}), just after the last field address.
A forthdefin({dictionary entry}) apart from the header owns a part of
the dictionary space that can extend before the header (mostly the
name of the entry) and after it (mostly data and code).
A dictionary entry has fields, and the addresses of fields directly
offset from the dictionary entry address, are called
forthdefi({field address}). This is a bit strange terminology, but
it makes a distinction between those addresses and other addresses.
For example, this allows to make the distinction between a
forthdefi({data field address}), that is always present, and a
forthdefi({data field}) in the ISO sense that has only a
(differing) meaning for
forthcode({CREATE}) forthcode({DOES> }) definitions.
Typically, a field address contains a pointer. A
forthdefi({data field address}) contains a pointer to
near the forthdefi({data field}), whenever the latter exists.
They go from lowest in memory to highest:
forthenumerate
forthitem
The code field. This is one cell.
A pointer to such a field is called a forthdefi({code field address}).
It contains the address of the code to be executed for this word.
forthitem
The data field, of the DEA, not in the ISO sense.
This is one cell.
A pointer to such a field is called a forthdefi({data field address}).
It contains a pointer to an area owned by this definition.
forthitem
The flag field. This is one cell.
A pointer to such a field is called a forthdefi({flag field address}).
For the meaning of the bits of the flag field sea below.
forthitem
The link field. This is one cell.
A pointer to such a field is called a forthdefi({link field address}).
It contains the
dictionary entry address of the last word that was
defined in the same forthdefi({word list}) before this one.
forthitem
The name field. This is one cell.
This contains a pointer to a string.
A pointer to such a field is called a forthdefi({name field address}).
The name itself is stored outside of the dictionary header
in a regular string, i.e. a one cell count followed by as many characters,