-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSYNTAX.TXT
1680 lines (1233 loc) · 74.7 KB
/
SYNTAX.TXT
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
EDBE
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
--------------------------------------------------------------------------
Since THIRD follows no extant FORTH standards, you'll need to
spend some quality time with this glossary to make use of it.
--------------------------------------------------------------------------
! M: ( Value, Address -> ) core
R: ( -> )
! stores a cell from the math stack into memory at a specified address. It
pops the address and the value from the math stack then stores the value
in memory at the address.
--------------------------------------------------------------------------
M: ( -> )
$ R: ( -> ) compiling
INBUF is completely consumed, which implies that IN
is updated. DP is updated.
$ compiles a counted string into the dictionary. A new word is created to
contain the string; the name of this word is taken from the next token in
INBUF. The contents of the string are taken from the remainder of
INBUF.
$ uses CREATE to create the dictionary entry for the word. The code
field of the new word is pointed at ($).
Because GETLINE only stores printing characters and spaces in
INBUF, it is not possible to include control characters in a counted
string created by $.
--------------------------------------------------------------------------
M: ( Address, Count -> )
$, R: ( -> ) compiling
DP is updated.
$, appends a counted string to the dictionary. Each byte of the string is
appended to the dictionary using B,. After the string is copied, it is
padded with bytes of zero until the name ends on an even cell boundary. At
that even cell boundary, a cell containing the length of the string
(including the zeros appended to reach alignment) is appended to the
dictionary. The address and count of the string are popped from the math
stack.
$, is used to create the name portion of a dictionary entry. A dictionary
entry is referred to by its code field address, which comes after the
word's name in the dictionary. Placing the length of the string at the end
of the name allows the beginning of the name to be quickly and easily
found by looking backwards a fixed amount from the code field address.
Names in the dictionary are limited to being at most 63 characters long to
allow space for the IMMEDIATE flag as well as a bit to mark the first
word in the dictionary; it is the need for these two bits in addition to
the name length which constrains the byte size to be at least eight bits.
$, does not enforce this limitation; it assumes the caller has verified
the length of the string.
--------------------------------------------------------------------------
($) M: ( -> Address, Length ) core
R: ( -> )
($) knows how to execute definitions created by $. Such definitions
contain a counted string of bytes usually intended for display via
TYPE. ($) places the address of the first byte in the string and the
number of bytes contained in the string on the math stack.
--------------------------------------------------------------------------
M: ( Address 1, Count 1, Address 2, Count 2 -> 1 ) if the
$= strings are equal. core
M: ( Address 1, Count 1, Address 2, Count 2 -> 0 ) otherwise
R: ( -> )
$= compares two counted strings, pushing a flag which indicates whether
they are identical. The addresses and counts of the strings to be compared
are popped from the math stack.
To be considered identical, the counted strings must be the same length
and each byte in the counted string must have the same value.
--------------------------------------------------------------------------
M: ( Increment -> )
(+LOOP) R: ( Limit, Index -> ) if the loop exits core
R: ( Limit, Index -> Limit, Index + Increment ) otherwise
(+LOOP) knows how to execute the bottom of a do loop which increments
its index by the amount specified on the math stack. The amount by which
the index is to be incremented is popped from the math stack and added to
the index. If the updated index is less than the limit, the loop needs to
be repeated; (+LOOP) branches to the top of the loop. Otherwise, the loop
needs to be exited; (+LOOP) pops the limit and index from the return stack
and does not branch.
The reference to (+LOOP) is followed by a cell containing the offset to
the top of the loop. If the loop is repeated, (+LOOP) fetches this offset
and uses it to update the IP. If the loop is existed, (+LOOP) advances the
IP past the offset.
--------------------------------------------------------------------------
(:) M: ( -> ) core
R: ( -> IP )
(:) knows how to execute definitions which have been created by :.
Such definitions contain a list of offsets to other THIRD words.
(:) moves the IP to the return stack, loads the address of the current
word's definition into IP, and executes (NEXT).
--------------------------------------------------------------------------
(;) M: ( -> ) core
R: ( Return address -> )
(;) used by : to end a definition; it causes execution to return to
the THIRD word which called the word containing the reference to (;). It
pops the IP from the return stack and enters (NEXT).
--------------------------------------------------------------------------
(0BRANCH) M: ( Flag -> ) core
R: ( -> )
(0BRANCH) is used by compiling words such as IF and UNTIL to
create a conditional jump. It examines the cell on top of the math stack
to determine whether or not the branch should be taken. As with
(BRANCH), the reference to (0BRANCH) is followed by a cell containing
an offset to the address to which the system should branch. If the flag is
non-zero, this branch is taken by entering (BRANCH). If the flag is
zero, IP is advanced beyond the branch and (NEXT) is entered to
continue straight-line code. In both cases, the flag is dropped from the
math stack.
--------------------------------------------------------------------------
(BRANCH) M: ( -> ) core
R: ( -> )
(BRANCH) is used by compiling words such as IF to create a jump. The
reference to (BRANCH) is followed by a cell containing an offset to the
address to which the system should branch. (BRANCH) fetches this offset,
calculates the address to which the offset refers, stores the resulting
address in IP, then enters (NEXT) to begin execution at that address.
--------------------------------------------------------------------------
(COLD) M: Initialized core
R: Initialized
(COLD) performs intialization that should be done once at system startup.
It is assumed that the system-specific initialization code has intialized
the console and the various StupidCode registers needed by the system.
(COLD) initializes the math and return stacks, the dictionary pointer,
LAST, displays the sign-on banner, and then executes ABORT.
Because (COLD) initializes DP and LAST, executing (COLD) causes
the system to forget any user-created definitions which were stored in the
dictionary.
--------------------------------------------------------------------------
(CONSTANT) M: ( -> Value ) core
R: ( -> )
(CONSTANT) knows how to execute THIRD words created by CONSTANT. It
copies the first cell of the THIRD word's definition to the math stack.
--------------------------------------------------------------------------
(DO) M: ( Limit, Initial index -> ) core
R: ( -> Limit, Initial index )
(DO) does the work necessary to enter a do loop. It copies the limit
and initial value of the index to the return stack, where they can be
found by (LOOP) and/or (+LOOP) at the bottom of the loop.
--------------------------------------------------------------------------
(DP@) MP: ( -> InitialDP )
RP: ( -> )
(DP@) pushes a copy of the dictionary pointer's initial value onto the
math stack. This is the address of the first byte of system memory which
will be used to contain user-created definitions. (DP@) is used during
system initialization to initialize the dictionary pointer.
(DP@) gets the initial dictionary pointer from the StupidCode register
InitialDP (see InitialDP@). It is the responsibility of
system-specific code to initialize the InitialDP register before entering
THIRD.
1E0A
--------------------------------------------------------------------------
(LAST@) M: ( -> InitialLAST ) core
R: ( -> )
(LAST@) pushes a copy of the initial value for LAST onto the math
stack. This is the code field address of the last word which has been
pre-compiled into the THIRD dictionary. (LAST@) is used during system
initialization to initialize LAST.
(LAST@) gets the initial LAST pointer from the StupidCode register
InitialLAST (see InitialLAST@). It is the responsibility of
system-specific code to initialize the InitialLAST register before
entering THIRD.
--------------------------------------------------------------------------
(LIT) M: ( -> Literal ) core
R: ( -> )
(LIT) is used by : to create code which pushes a constant value onto
the math stack. The reference to (LIT) is followed by a cell containing
the constant to be pushed onto the math stack. (LIT) fetches the constant,
pushes it onto the math stack, and advances IP past the constant.
--------------------------------------------------------------------------
M: ( -> )
(LOOP) R: ( Limit, Index -> ) if the loop exits core
R: ( Limit, Index -> Limit, Index+1 ) otherwise
(LOOP) knows how to execute the bottom of a do loop which increments its
index by one. It increments the index for the loop and compares the index
to the limit. If the index is less than the limit, the loop needs to be
repeated; (LOOP) branches to the top of the loop. Otherwise, the loop
needs to be exited; (LOOP) pops the limit and index from the return stack
and does not branch.
The reference to (LOOP) is followed by a cell containing the offset to the
top of the loop. If the loop is repeated, (LOOP) fetches this offset and
uses it to update IP. If the loop is exited, (LOOP) advances IP past the
the offset.
--------------------------------------------------------------------------
(NEXT) M: ( -> ) core
R: ( -> )
(NEXT) is the inner interpreter for the system. It contains a chunk of
CODE which knows how to fetch and execute the next THIRD word. It is
called implicitly by CODE words and would not normally be referenced
directly by THIRD code (most FORTH systems implement the inner interpreter
in a headless word so it is imposible to refer to it). CODE words
usually execute (NEXT) via NEXT@ PC!, so even they do not refer
directly to (NEXT).
(NEXT) fetches the cell pointed at by IP and calculates the address of the
THIRD word to which the cell refers. It uses this to locate the CODE
word which knows how to execute the THIRD word, then enters that CODE
word; consequently, the THIRD word is executed.
Because THIRD is position-indepent, THIRD needs to do a bit more work than
a normal FORTH system does; the cell pointed to by IP contains an offset
to the THIRD word to be executed, rather than its address; the address of
the THIRD word to be executed must be calculated. Offsets are relative to
the location from which they are fetched, so the contents of IP must be
added to the offset to obtain the address of the next THIRD word to be
executed.
(NEXT) is the single most-frequently executed piece of code in the system.
The work that (NEXT) must do to calculate addresses from offsets is
therefore very expensive. Because of this, THIRD will never perform as
well as other FORTH systems which do not need to perform this relocation.
If you are that concerned about performance, you should investigate other
FORTH systems.
--------------------------------------------------------------------------
(OLIT) M: ( -> Address ) compiling
R: ( -> )
(OLIT) is used to create a relocatable reference to the address of another
word in the dictionary. The reference to (OLIT) is followed by a cell
containing the offset to the address involved. (OLIT) fetches this offset
and constructs the address to which it refers, pushing that address on the
stack.
(OLIT) is used in the definition of words such as IF, which must have
the address of another word handy (IF needs to be able to find
(0BRANCH); the executable code for IF contains the sequence (OLIT)
(0BRANCH) to construct the address of (0BRANCH)). (OLIT) allows
such words to be compiled with position-independent offsets rather than
absolute addresses.
--------------------------------------------------------------------------
(VAR) M: ( -> Address ) core
M: ( -> )
(VAR) knows how to execute THIRD words created by VARIABLE. It places
the address of the THIRD word's definition on the math stack.
--------------------------------------------------------------------------
+ M: ( a, b -> a+b ) core
R: ( -> )
+ adds the two cells on top of the math stack, pushing the sum onto the
math stack. The two cells used to create the sum are dropped from the math
stack.
--------------------------------------------------------------------------
++ M: ( Address -> ) core
R: ( -> )
++ increments a cell in memory. It pops the address from the math stack,
fetches a cell from memory at that address, adds one to the value read,
then writes the new value back into memory at the address.
--------------------------------------------------------------------------
M: ( Address of the top of the loop, 1 -> ) if used to
terminate a do loop.
+LOOP M: Initialized otherwise. compiling
R: ( -> ) if used to terminate a do loop. immediate
R: Initialized otherwise.
DP is updated.
+LOOP compiles the bottom of a do loop wherein the index is
incremented some variable amount. It appends a reference to (+LOOP)
followed by a reference to the top of the loop, the address of which is
obtained from the math stack.
+LOOP expects the cell on top of the math stack to contain a one as an
indication that the math stack describes a do loop; anything else is
considered an error and compilation is aborted (see :ABORT). Both the
one and the address of the top of the do loop are popped from the math
stack.
Because +LOOP is an IMMEDIATE word, it is executed by : instead of
compiled.
When +LOOP aborts compilation, it displays NEST?.
--------------------------------------------------------------------------
M: ( Value -> )
, R: ( -> ) compiling
DP is updated.
, appends a cell containing the value on top of the math stack to the
dictionary. The cell is written into memory at the address indicated by
DP, which is then incremented by the number of bytes in a cell to
account for the new cell. The value is popped from the math stack.
--------------------------------------------------------------------------
- M: ( a, b -> a-b ) core
R: ( -> )
- subtracts the cell on top of the math stack from the one second on the
math stack, pushing the result on the math stack. The two cells which were
used to create the result are popped from the math stack.
--------------------------------------------------------------------------
. M: ( Value -> ) core
R: ( -> )
. displays, in hex, the value contained in the cell on top of the math
stack. That value is dropped from the math stack.
--------------------------------------------------------------------------
.NYBBLE M: ( Value -> Value )
R: ( -> )
.NYBBLE displays, in hex, the most-significant four bits of the value in
the cell on top of the math stack. The cell is not discarded from the math
stack.
The reliance on .NYBBLE for displaying cells limits THIRD to machines for
which the cell size is a multiple of four bits.
--------------------------------------------------------------------------
.NYBBLES M: ( Value, Count -> ) core
R: ( -> )
.NYBBLES displays, in hex, the least significant Count nybbles of the
Value. Both the value displayed and the number of nybbles to be displayed
are dropped from the stack.
--------------------------------------------------------------------------
0 M: ( -> 0 ) core
R: ( -> )
0 pushes the constant value zero onto the math stack. It is used
frequently enough in the system code that having a word to hold the
constant requires less memory space than a (LIT) 0 sequence.
--------------------------------------------------------------------------
M: ( Value -> 1 ) if Value<0
0< M: ( Value -> 0 ) otherwise core
R: ( -> )
0< compares the value in the cell on top of the math stack against zero.
If the value is less than zero, it is replaced with one. Otherwise, the
value is replaced with zero.
--------------------------------------------------------------------------
M: ( Value -> 1 ) if Value=0
0= M: ( Value -> 0 ) otherwise core
R: ( -> )
This word compares the value in the cell on top of the math stack with
zero, replacing that value with the result. If the value in the cell on
top of the math stack is zero, it is replaced with one. Otherwise, it is
replaced with zero.
--------------------------------------------------------------------------
1 M: ( -> 1 ) core
R: ( -> )
1 pushes the constant value one onto the math stack. It is used frequently
enough in the system code that having a word to hold the constant requires
less memory space than a (LIT) 1 sequence.
--------------------------------------------------------------------------
M: ( -> ) if there are no compilation errors.
M: Initialized otherwise. R: ( -> ) if there are no
compilation errors.
: R: Initialized otherwise. LAST is updated. compiling
DP is updated.
Tokens are consumed from INBUF, which implies that
IN is updated.
:DP, :LAST, :MP, and :DONE are initialized.
: creates a new executable THIRD word. The definition of such a word
contains a list of references to other THIRD words; when the new word is
executed, those words are executed in sequence.
The name of the new word is taken from the next token available in
INBUF. : uses CREATE to create the header for the new word,
pointing it's code field at (:). Once the header is created, :
executes essentially as follows:
* Grab a token from INBUF, acquiring a new command line if
INBUF is empty. (see TOKEN and GETLINE)
* If that token is the name of a word in the dictionary, (see )
* If that word is an IMMEDIATE word, execute it.
* Otherwise, append a reference to that word to the dictionary.
(see O,)
10000
* If the word looks like a number, push a copy of the number onto the
math stack. (see ISNUMBER and >NYBBLES)
* Otherwise, display the bogus token followed by a question mark and
abort compilation. (see :ABORT)
* Repeat until compilation is done. (see :DONE and ;).
Upon exiting, : checks the math stack depth to ensure that all program
control structures have been completed. If there is stuff left on the math
stack from an incomplete program control structure, the error message in
NEST? is displayed and compilation is aborted.
When compilation is aborted, the changes to the dictionary made by : are
reversed; the dictionary is returned to the state it had before the
compilation was begun.
--------------------------------------------------------------------------
M: Initialized
:ABORT R: Initialized compiling
DP is restored from :DP.
LAST is restored from :LAST.
:ABORT is the escape hatch used by : when it detects a compilation
error. It restores the dictionary to it's state before the compilation was
begun and executes ABORT.
--------------------------------------------------------------------------
:DONE M: ( -> Address ) compiling
R: ( -> )
:DONE is a variable used by : to determine whether compilation is
complete. Because :DONE is a variable, executing it pushes the address of
its definition on the math stack.
: initializes :DONE to zero when it begins compiling a definition. An
IMMEDIATE word sets :DONE to a non-zero value to tell : to exit.
This is primarily done by ;.
--------------------------------------------------------------------------
:DP M: ( -> Address ) compiling
R: ( -> )
:DP is a variable used by : to hold a copy of the value in DP
before compilation started. This allows : to back out the changes
made to the dictionary if an error occurs during compilation. Because :DP
is a variable, executing it pushes the address of its definition on the
math stack.
--------------------------------------------------------------------------
:LAST M: ( -> Address ) compiling
R: ( -> )
:LAST is a variable used by : to hold a copy of the value in DP
before compilation started. This allows : to back out the changes
made to the dictionary if an error occurs during compilation. Because
:LAST is a variable, executing it pushes the address of its definition on
the math stack.
--------------------------------------------------------------------------
:MP M: ( -> Address ) compiling
R: ( -> )
:MP is a variable used by : to hold a copy of the value of the math
stack pointer before compilation started. This allows : to detect
that a control structure was not completed before the end of compilation
so it can report the error to the user. Because :MP is a variable,
executing it pushes the address of its definition on the math stack.
--------------------------------------------------------------------------
M: ( -> ) compiling
; R: ( -> ) immediate
:DONE is set to one.
; terminates a definition created by :. It appends a cell to the
dictionary which contains a reference to (;) then sets :DONE to
one; this causes : to perform its final error checking and exit.
Because ; is an IMMEDIATE word, : executes it instead of
compiling a reference to it.
--------------------------------------------------------------------------
M: ( a, b -> 1 ) if a<b
< M: ( a, b -> 0 ) otherwise core
R: ( -> )
< compares the values in the two cells on top of the math stack, pushing
the result onto the math stack. If the value in the cell on top of the
math stack is less than the value in the next cell, a one is pushed onto
the math stack. Otherwise, a zero is pushed. The cells used in the
comparison are dropped from the math stack.
--------------------------------------------------------------------------
<< M: ( Value, Count -> Value<<Count ) core
R: ( -> )
<< shifts the value in the second cell of the math stack to the left by
the number of bits specified in the cell on top of the math stack, pushing
the result onto the math stack. The two cells used to create the value are
dropped from the math stack.
Zeros are shifted into the rightmost bit positions.
--------------------------------------------------------------------------
<R M: ( -> Value ) core
R: ( Value -> )
<R moves a value from the return stack to the math stack. It pops a cell
from the return stack and pushes the value from that cell onto the math
stack.
--------------------------------------------------------------------------
M: ( a, b -> 1 ) if a=b
= M: ( a, b -> 0 ) otherwise core
R: ( -> )
= compares the values in the top two cells of the math stack, pushing the
result of the comparison onto the math stack. If the values are equal, a
one is pushed onto the math stack. Otherwise, a zero is pushed. The two
cells used in the comparison are dropped from the math stack.
--------------------------------------------------------------------------
M: ( a, b -> 1 ) if a>b
> M: ( a, b -> 0 ) otherwise core
R: ( -> )
> compares the values in the two cells on top of the math stack, pushing
the result onto the math stack. If the value in the cell on top of the
math stack is greater than the value in the next cell, a one is pushed
onto the math stack. Otherwise, a zero is pushed. The cells used in the
comparison are dropped from the math stack.
--------------------------------------------------------------------------
>> M: ( Value, Count -> Value>>Count ) core
R: ( -> )
>> shifts the value in the second cell of the math stack to the right by
the number of bits specified in cell on top of the math stack, pushing the
result onto the math stack. The two cells used to create the value are
dropped from the math stack.
The shift performed is a logical shift, not an arithmetic one; zeros are
shifted into the leftmost bit positions.
--------------------------------------------------------------------------
>NYBBLE M: ( Character -> Value ) core
R: ( -> )
>NYBBLE converts an character from an ASCII hexadecimal digit to its
corresponding binary value. It assumes the cell on top of the math stack
contains an ASCII hexadecimal digit. It replaces that digit with the
binary value corresponding to that digit.
--------------------------------------------------------------------------
>NYBBLES M: ( Address, Count -> Value ) core
R: ( -> )
>NYBBLES converts a counted string of ASCII hexadecimal digits into its
corresponding binary representation. The address and count of the string
are popped from the math stack and the corresponding binary representation
is pushed onto it.
>NYBBLES assumes each character in the counted string is either an ASCII
hexadecimal digit or the character '.'. The character '.' is ignored; the
ASCII hexadecimal digits are converted to binary. Ignoring '.' allows you
to use that character to separate long numbers into shorter, eaiser to
error-check numbers.
--------------------------------------------------------------------------
>R M: ( Value -> ) core
R: ( -> Value )
>R moves a value from the math stack to the return stack. It pops a cell
from the math stack and pushes the value from that cell onto the return
stack.
--------------------------------------------------------------------------
?ABORT M: ( -> ) if there is no byte available at the console. R: ( core
-> ) if there is no byte available at the console.
?ABORT calls ABORT if there is a character available at the console.
Because ABORT initializes the system, ?ABORT will only return if
there is no byte available at the console.
--------------------------------------------------------------------------
@ M: ( Address -> Value ) core
R: ( -> )
@ uses the cell on top of the math stack as a memory address. It pops the
address from the math stack, fetches a cell from memory at that address,
and pushes the value fetched onto the math stack.
--------------------------------------------------------------------------
ABORT M: Initialized core
R: Initialized
ABORT initializes the math and return stacks and enters INTERPRET. It
is used to put the system in a known state as part of error recovery.
Because ABORT does not initialize DP and LAST, ABORT does not
forget any user-created definitions stored in the dictionary.
--------------------------------------------------------------------------
M: ( Number of bytes -> )
ALLOT R: ( -> ) compiling
DP is updated.
ALLOT allocates a chunk of memory onto the end of the last word in the
dictionary. It does this by adding the specified number of bytes to
DP. The number of bytes is popped from the math stack.
The primary use of ALLOT is to create a variable containing space for an
array. However, care must be taken in this, because CREATE does not
fill in the code field address of a word it creates. The easiest way to
create a variable containing an array is through something like 0 VARIABLE
BOOGER size ALLOT. This creates a variable named BOOGER which contains the
value 0 and then appends size bytes to that definition. When BOOGER is
executed, the address of the cell containing zero is pushed on the math
stack. This wastes a cell of memory, but the alternatives are pretty messy
unless you are willing to create a word which creates the array (perhaps
something like : ARRAY CREATE (OLIT) (VAR) ,
ALLOT ; would work).
--------------------------------------------------------------------------
AND M: ( a, b -> a AND b ) core
R: ( -> )
AND forms the bitwise and of the two cells on top of the math stack,
pushing the result onto the math stack. The two cells used to create the
result are dropped from the math stack.
--------------------------------------------------------------------------
B! M: ( Value, Address -> ) core
R: ( -> )
B! stores a byte from the math stack into memory at a specified address.
It pops the address and the value from the math stack then stores the
least-significant byte of the value in memory at the address.
A byte is the smallest unit of memory which is addressable on the machine.
Although this is typically an 8-bit value, it is not necessarily so. A
cell contains at least one byte. A byte contains at least 8 bits.
--------------------------------------------------------------------------
M: ( Value -> )
B, R: ( -> ) compiling
DP is updated.
B, appends a byte containing the least-significant byte of the value on
top of the math stack to the dictionary. The byte is written into memory
at the address indicated by DP, which is then incremented to account
for the byte. The value is popped from the math stack.
A byte is the smallest unit of memory which is addressable on the machine.
Although this is typically an 8-bit value, it is not necessarily so. A
cell contains at least one byte. A byte contains at least eight bits.
--------------------------------------------------------------------------
B@ M: ( Address -&bt; Value ) core
R: ( -> )
B@ uses the cell on top of the math stack as a memory address. It pops the
address from the math stack, fetches a byte from memory at that address,
zero-extends the byte into a cell, and pushes the resulting value onto the
math stack.
A byte is the smallest unit of memory which is addressable on the machine.
Although this is typically an 8-bit value, it is not necessarily so. A
cell contains at least one byte. A byte contains at least 8 bits.
--------------------------------------------------------------------------
M: ( -> )
CODE R: ( -> ) compiling
A token is consumed from INBUF, which implies that
IN is updated. DP is updated.
CODE creates the header for a machine code word and points its code field
address at itself because a machine code word is a word which contains the
code which knows how to execute it.
CODE creates the header using CREATE. It then deposits the offset to
DP in the code field address (which will always be zero; i.e., the
offset to the code field address of the word containing the machine code
which knows how to execute this word is zero). When CODE is done, DP
points at the first byte of the word's definition.
THIRD does not provide an assembler to help you fill in the body of a CODE
word. You will have to do this by hand using , and related words. And
you'd dang well better know what you're doing!
--------------------------------------------------------------------------
M: ( Value -> )
CONSTANT R: ( -> ) compiling
A token is consumed from INBUF, which implies
that IN is updated. DP is updated.
CONSTANT creates a word in the dictionary which holds a constant value.
The name of the constant is taken from the next token in (a
href="#core_INBUF">INBUF, the input buffer. The value of the constant is
popped from the math stack and stored in the constant's definition. Upon
executing the new constant, the value stored in the first cell of its
definition is pushed onto the math stack.
CONSTANT using CREATE to create the header for the new constant. It
points the code field address of the constant at (CONSTANT), which
knows how to find the first cell in the definition of a word. It then
appends the value from the cell on top of the math stack to the word's
definition using ,.
--------------------------------------------------------------------------
COUNT M: ( Address -> Address+1, Count ) core
R: ( -> )
Given the address in memory of a counted string (see $), COUNT
extracts the length of the string and the address of the first byte of the
string.
--------------------------------------------------------------------------
CR M: ( -> ) core
R: ( -> )
CR displays a carriage return on the console. It is equivalent to 13
EMIT.
--------------------------------------------------------------------------
M: ( -> )
CREATE R: ( -> ) compiling
A token is consumed from INBUF, which implies that
IN is updated. DP is updated.
CREATE appends a new header to the dictionary. It creates the name, flag,
and link fields of the name and points LAST at the new header. A
dictionary entry consists of the following fields in this order:
* The name of the word. This is an ASCII string which is padded with
NULLs to an even cell boundary.
* The flag cell. This cell contains the length of the name, including
any NULLs which were added to the name to pad it to an even cell
boundaries. There are also two bits in this cell used as flags. Bit 7
is the IMMEDIATE flag. Bit 6 is set on (NEXT) to mark it as
the first one in the dictionary.
* The link field. This is a cell containing the offset from this word's
code field address to the code field address of the previous word.
* The code field. This is a cell containing the offset to the code field
of a word containing machine code which knows how to execute the word.
* The definition. Any memory allocated to the word after the code field
is part of its definition.
When CREATE is done, DP contains the code field address of the new
word. CREATE does not ensure the code field points to anything; whoever is
creating the word must deposit a code field using O, before the new
word is executed.
CREATE obtains the name of the new word from INBUF using TOKEN.
If there is no token available, CREATE displays NAME? and bebops on
over to ABORT.
CREATE may also fail if the token obtained from INBUF is longer than
63 characters. In this case, CREATE displays LEN? before it enters
ABORT.
--------------------------------------------------------------------------
CVTW@ M: ( Address -> Value ) core
R: ( -> )
CVTW@ uses the cell on top of the math stack as a memory address. It pops
the address from the math stack, fetches a word from memory at that
address, sign-extends that word to a cell, and pushes the resulting value
on the math stack.
A word in this case is an intermediate unit between a byte and a cell.
Although this is typically a 16-bit value, it is not necessarily so. A
cell contains at least one word.
This is similar to W@, except that W@ zero-extends the word to
convert it to a cell instead of sign-extending it.
--------------------------------------------------------------------------
DIGITMAP M: ( -> Address ) core
R: ( -> )
DIGITMAP is a variable which contains an array of bytes that are used to
determine whether an ASCII character is a hexadecimal digit. There is a
bit in the array for each possible ASCII character (0 through 7f hex)
which is set if the character is to be considered a hexadecimal digit.
Given a character code, the byte containing the bit for that character can
be found by shifting the character code right three bits and adding that
result to the address returned by executing digitmap; given a character
code on the math stack 3 << DIGITMAP + yields the address of the
byte in DIGITMAP corresponding to the character. The bit position within
that byte is given by three least significant bits of the character code;
the character code can be converted to a bit mask by 7 AND 1
SWAP >>.
To aid in the transcription of long numbers, '.' is accepted as being a
digit. Code which converts a string of ASCII characters to a binary number
should ignore '.'. This allows you to use '.' to break large numbers into
smaller, easier to error-check groups; you can use DEAD.BEEF as a synonym
for DEADBEEF.
--------------------------------------------------------------------------
M: ( -> Address of the top of the loop, 1 ) compiling
DO R: ( -> ) immediate
DP is updated.
DO compiles the top of a do loop. It appends a reference to (DO) to
the dictionary and pushes the address of the top of the loop onto the math
stack for later use by LOOP or +LOOP. It also pushes a one onto
the math stack to indicate that a do loop is being compiled.
Because DO is an IMMEDIATE word, it is executed by : instead of
compiled.
It is important to realize that there is a difference between the stack
effects of DO, which occur at compilation time, and those of (DO),
which occur at run time. DO compiles the top of a do loop while (DO)
actually enters the loop; the loop is not entered until execution reaches
the (DO) which has been appended to the dictionary by DO.
A do loop is a counted loop; it executes the loop some number of times,
maintaining a loop index which may be used to identify the iteration of
the loop. A do loop comes in two flavors: DO ... LOOP and DO ...
+LOOP. The first form always increments the loop index by one, while
the second increments the loop index by the value on top of the math stack
when the bottom of the loop is executed (not when it is compiled!). DO ...
LOOP is essentially equivalent to DO ... 1 +LOOP.
The do loop is executed when the index for the loop is no longer less than
the limit for the loop. Thus, 10 0 DO LOOP will execute its do loop
sixteen times with the index ranging from 0 through F. Similarly, 10 0 DO
2 +LOOP will execute its loop eight times with the index being first
0, then 2, then 4, etc. through E.
The loop index is stored on top of the return stack (see (DO),
(LOOP), and (+LOOP)), so it may be accessed inside the loop
using R.
--------------------------------------------------------------------------
DP M: ( -> Address ) compiling
R: ( -> )
DP is a variable containing the dictionary pointer. Executing DP pushes a
copy of the dictionary pointer onto the math stack.
The dictionary pointer is the memory address of the next byte which will
be allocated to a user-created definition.
--------------------------------------------------------------------------
DROP M: ( Value -> ) core
R: ( -> )
DROP discards the cell on top of the math stack.
--------------------------------------------------------------------------
DUP M: ( Value -> Value, Value ) core
R: ( -> )
DUP makes a copy of the cell on top of the math stack, pushing the copy
onto the math stack.
--------------------------------------------------------------------------
M: ( Address of the branch offset left behind by IF,
3 -> Address of a new branch offset, 3 ) if used to build
an if construct. compiling
ELSE M: Initialized otherwise. immediate
R: ( -> ) if used to build an if construct.
R: Initialized otherwise.
DP is updated.
ELSE is used to construct the false branch of an if construct. It
fills in the conditional branch left behind by IF, popping the
information describing that branch from the math stack, and creates an
unconditional branch to be filled in by ENDIF. The address of the
offset cell for the unconditional branch is pushed onto the math stack, as
well as a three to indicate that an if construct is being
constructed.
ELSE examines the cell on the top of the math stack to ensure it is being
used to build an if construct. If this is not the case, ELSE aborts
compilation (see :ABORT). When ELSE aborts compilation, it display
NEST? to indicate the reason for the abort.
Because ELSE is an IMMEDIATE word, it is executed by : rather
than compiled.
--------------------------------------------------------------------------
M: ( Address of branch offset, 3 -> ) if used to
complete an if construct. compiling
ENDIF M: Initialized otherwise. R: ( -> ) if used to complete immediate
an if construct.
R: Initialized otherwise.
ENDIF is used to complet the compilation of an if construct. It fills
in the cell reserved for a branch offset by either IF or ELSE,
obtaining the information about that cell from the math stack. The
information about the branch offset cell is dropped from the math stack.
ENDIF expects the cell on top of the math stack to contain a three as an
indication that an if construct is being compiled. If the cell on top
of the math stack contains any other value, compilation is aborted (see
:ABORT). When ENDIF aborts compilation, it displays NEST? to
indicate the reason for the abort.
Because ENDIF is an IMMEDIATE word, it is executed by : rather
than compiled.
--------------------------------------------------------------------------