projects
/
rrq
/
jonesforth.git
/ commitdiff
commit
grep
author
committer
pickaxe
?
search:
re
summary
|
shortlog
|
log
|
commit
| commitdiff |
tree
raw
|
patch
|
inline
| side by side (from parent 1:
0b5a6c8
)
Fixed a few typos.
author
rich
<rich>
Sat, 8 Sep 2007 17:02:11 +0000
(17:02 +0000)
committer
rich
<rich>
Sat, 8 Sep 2007 17:02:11 +0000
(17:02 +0000)
jonesforth.S
patch
|
blob
|
history
diff --git
a/jonesforth.S
b/jonesforth.S
index 6ad3e9221863d36d1bbf9c5d005e77dd860569ae..4fae872f2e5c3b68c7d2f8b332e093a57e8e9bfd 100644
(file)
--- a/
jonesforth.S
+++ b/
jonesforth.S
@@
-1,6
+1,7
@@
/* A sometimes minimal FORTH compiler and tutorial for Linux / i386 systems. -*- asm -*-
By Richard W.M. Jones <rich@annexia.org> http://annexia.org/forth
This is PUBLIC DOMAIN (see public domain release statement below).
/* A sometimes minimal FORTH compiler and tutorial for Linux / i386 systems. -*- asm -*-
By Richard W.M. Jones <rich@annexia.org> http://annexia.org/forth
This is PUBLIC DOMAIN (see public domain release statement below).
+ $Id: jonesforth.S,v 1.16 2007-09-08 17:02:11 rich Exp $
gcc -m32 -nostdlib -static -Wl,-Ttext,0 -o jonesforth jonesforth.S
gcc -m32 -nostdlib -static -Wl,-Ttext,0 -o jonesforth jonesforth.S
@@
-155,7
+156,7
@@
THE DICTIONARY ----------------------------------------------------------------------
THE DICTIONARY ----------------------------------------------------------------------
- In FORTH as you will know, functions are called "words", a
s
just as in other languages they
+ In FORTH as you will know, functions are called "words", a
nd
just as in other languages they
have a name and a definition. Here are two FORTH words:
: DOUBLE DUP + ; \ name is "DOUBLE", definition is "DUP +"
have a name and a definition. Here are two FORTH words:
: DOUBLE DUP + ; \ name is "DOUBLE", definition is "DUP +"
@@
-201,7
+202,7
@@
You shoud be able to see from this how you might implement functions to find a word in
the dictionary (just walk along the dictionary entries starting at LATEST and matching
You shoud be able to see from this how you might implement functions to find a word in
the dictionary (just walk along the dictionary entries starting at LATEST and matching
- the names until you either find a match or hit the NULL pointer at the end of the dictionary)
,
+ the names until you either find a match or hit the NULL pointer at the end of the dictionary)
;
and add a word to the dictionary (create a new definition, set its LINK to LATEST, and set
LATEST to point to the new word). We'll see precisely these functions implemented in
assembly code later on.
and add a word to the dictionary (create a new definition, set its LINK to LATEST, and set
LATEST to point to the new word). We'll see precisely these functions implemented in
assembly code later on.
@@
-235,7
+236,7
@@
and so on. How would a function, say 'f' above, be compiled by a standard C compiler?
Probably into assembly code like this. On the right hand side I've written the actual
and so on. How would a function, say 'f' above, be compiled by a standard C compiler?
Probably into assembly code like this. On the right hand side I've written the actual
-
16 bit
machine code.
+
i386
machine code.
f:
CALL a E8 08 00 00 00
f:
CALL a E8 08 00 00 00
@@
-269,7
+270,7
@@
%esi -> 1C 00 00 00
2C 00 00 00
%esi -> 1C 00 00 00
2C 00 00 00
- The all-important
x
86 instruction is called LODSL (or in Intel manuals, LODSW). It does
+ The all-important
i3
86 instruction is called LODSL (or in Intel manuals, LODSW). It does
two things. Firstly it reads the memory at %esi into the accumulator (%eax). Secondly it
increments %esi by 4 bytes. So after LODSL, the situation now looks like this:
two things. Firstly it reads the memory at %esi into the accumulator (%eax). Secondly it
increments %esi by 4 bytes. So after LODSL, the situation now looks like this:
@@
-503,11
+504,11
@@
DOCOL:
| addr of DOUBLE ---------------> +------------------+
+------------------+ %eax -> | addr of DOCOL |
%esi -> | addr of DOUBLE | +------------------+
| addr of DOUBLE ---------------> +------------------+
+------------------+ %eax -> | addr of DOCOL |
%esi -> | addr of DOUBLE | +------------------+
- +------------------+ | addr of DUP
-------------->
+ +------------------+ | addr of DUP
|
| addr of EXIT | +------------------+
+------------------+ | etc. |
| addr of EXIT | +------------------+
+------------------+ | etc. |
- First, the call to DOUBLE ca
use
s DOCOL (the codeword of DOUBLE). DOCOL does this: It
+ First, the call to DOUBLE ca
ll
s DOCOL (the codeword of DOUBLE). DOCOL does this: It
pushes the old %esi on the return stack. %eax points to the codeword of DOUBLE, so we
just add 4 on to it to get our new %esi:
pushes the old %esi on the return stack. %eax points to the codeword of DOUBLE, so we
just add 4 on to it to get our new %esi:
@@
-518,7
+519,7
@@
DOCOL:
| addr of DOUBLE ---------------> +------------------+
top of return +------------------+ %eax -> | addr of DOCOL |
stack points -> | addr of DOUBLE | + 4 = +------------------+
| addr of DOUBLE ---------------> +------------------+
top of return +------------------+ %eax -> | addr of DOCOL |
stack points -> | addr of DOUBLE | + 4 = +------------------+
- +------------------+ %esi -> | addr of DUP
-------------->
+ +------------------+ %esi -> | addr of DUP
|
| addr of EXIT | +------------------+
+------------------+ | etc. |
| addr of EXIT | +------------------+
+------------------+ | etc. |
@@
-661,7
+662,7
@@
name_\label :
+--|------+---+---+---+---+------------+
| LINK | 3 | D | U | P | code_DUP ---------------------> points to the assembly
+---------+---+---+---+---+------------+ code used to write DUP,
+--|------+---+---+---+---+------------+
| LINK | 3 | D | U | P | code_DUP ---------------------> points to the assembly
+---------+---+---+---+---+------------+ code used to write DUP,
- ^ len codeword which
is ended
with NEXT.
+ ^ len codeword which
ends
with NEXT.
|
LINK in next word
|
LINK in next word
@@
-742,11
+743,11
@@
code_\label : // assembler code follows
NEXT
defcode "4+",2,,INCR4
NEXT
defcode "4+",2,,INCR4
- addl $4,(%esp) //
increment
top of stack
+ addl $4,(%esp) //
add 4 to
top of stack
NEXT
defcode "4-",2,,DECR4
NEXT
defcode "4-",2,,DECR4
- subl $4,(%esp) //
decrement
top of stack
+ subl $4,(%esp) //
subtract 4 from
top of stack
NEXT
defcode "+",1,,ADD
NEXT
defcode "+",1,,ADD
@@
-756,7
+757,7
@@
code_\label : // assembler code follows
defcode "-",1,,SUB
pop %eax // get top of stack
defcode "-",1,,SUB
pop %eax // get top of stack
- subl %eax,(%esp) // and subtract i
f
from next word on stack
+ subl %eax,(%esp) // and subtract i
t
from next word on stack
NEXT
defcode "*",1,,MUL
NEXT
defcode "*",1,,MUL
@@
-1067,7
+1068,7
@@
var_\name :
and compiling code, we might be reading words to execute, we might be asking for the user
to type their name -- ultimately it all comes in through KEY.
and compiling code, we might be reading words to execute, we might be asking for the user
to type their name -- ultimately it all comes in through KEY.
- The implementation of KEY uses an input buffer
so
a certain size (defined at the end of the
+ The implementation of KEY uses an input buffer
of
a certain size (defined at the end of the
program). It calls the Linux read(2) system call to fill this buffer and tracks its position
in the buffer using a couple of variables, and if it runs out of input buffer then it refills
it automatically. The other thing that KEY does is if it detects that stdin has closed, it
program). It calls the Linux read(2) system call to fill this buffer and tracks its position
in the buffer using a couple of variables, and if it runs out of input buffer then it refills
it automatically. The other thing that KEY does is if it detects that stdin has closed, it