This gets S" and ." right.
authorrich <rich>
Mon, 24 Sep 2007 00:37:01 +0000 (00:37 +0000)
committerrich <rich>
Mon, 24 Sep 2007 00:37:01 +0000 (00:37 +0000)
jonesforth.S
jonesforth.f

index de5bbe3001f594391e570c2fbab5d4c7f7f5cb15..44e837be3e56c47d6e9010934f9ebe4cc50b100b 100644 (file)
@@ -1,11 +1,11 @@
 /*     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.28 2007-09-24 00:18:19 rich Exp $
+       $Id: jonesforth.S,v 1.29 2007-09-24 00:37:01 rich Exp $
 
        gcc -m32 -nostdlib -static -Wl,-Ttext,0 -o jonesforth jonesforth.S
 */
 
        gcc -m32 -nostdlib -static -Wl,-Ttext,0 -o jonesforth jonesforth.S
 */
-       .set JONES_VERSION,28
+       .set JONES_VERSION,29
 /*
        INTRODUCTION ----------------------------------------------------------------------
 
 /*
        INTRODUCTION ----------------------------------------------------------------------
 
index b8c5a61b20e8428d23cb508a39ca4abc729dbe41..e3140c4af1a348ad3a6d48a0a847d570308cf77b 100644 (file)
@@ -1,8 +1,8 @@
-\ -*- forth -*-
+\ -*- text -*-
 \      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.f,v 1.1 2007-09-24 00:18:19 rich Exp $
+\      $Id: jonesforth.f,v 1.2 2007-09-24 00:37:01 rich Exp $
 \
 \      The first part of this tutorial is in jonesforth.S.  Get if from http://annexia.org/forth
 \
 \
 \      The first part of this tutorial is in jonesforth.S.  Get if from http://annexia.org/forth
 \
 : ')' [ CHAR ) ] LITERAL ;
 : '"' [ CHAR " ] LITERAL ;
 
 : ')' [ CHAR ) ] LITERAL ;
 : '"' [ CHAR " ] LITERAL ;
 
+\ While compiling, '[COMPILE] word' compiles 'word' if it would otherwise be IMMEDIATE.
+: [COMPILE] IMMEDIATE
+       WORD            \ get the next word
+       FIND            \ find it in the dictionary
+       >CFA            \ get its codeword
+       ,               \ and compile that
+;
+
 \ So far we have defined only very simple definitions.  Before we can go further, we really need to
 \ make some control structures, like IF ... THEN and loops.  Luckily we can define arbitrary control
 \ structures directly in FORTH.
 \ So far we have defined only very simple definitions.  Before we can go further, we really need to
 \ make some control structures, like IF ... THEN and loops.  Luckily we can define arbitrary control
 \ structures directly in FORTH.
 ;
 
 (
 ;
 
 (
-       [NB. The following may be a bit confusing because of the need to use backslash before
-       each double quote character.  The backslashes are there to keep the assembler happy.
-       They are NOT part of the final output.  So here we are defining a function called
-       'S double-quote' (not 'S backslash double-quote').]
-
        S" string" is used in FORTH to define strings.  It leaves the address of the string and
        S" string" is used in FORTH to define strings.  It leaves the address of the string and
-       its length on the stac,k with the address at the top.  The space following S" is the normal
+       its length on the stack, with the address at the top.  The space following S" is the normal
        space between FORTH words and is not a part of the string.
 
        space between FORTH words and is not a part of the string.
 
+       This is tricky to define because it has to do different things depending on whether
+       we are compiling or in immediate mode.  (Thus the word is marked IMMEDIATE so it can
+       detect this and do different things).
+
        In compile mode we append
                LITSTRING <string length> <string rounded up 4 bytes>
        to the current word.  The primitive LITSTRING does the right thing when the current
        In compile mode we append
                LITSTRING <string length> <string rounded up 4 bytes>
        to the current word.  The primitive LITSTRING does the right thing when the current
                        OVER !b         ( save next character )
                        1+              ( increment address )
                REPEAT
                        OVER !b         ( save next character )
                        1+              ( increment address )
                REPEAT
+               DROP            ( drop the final " character )
                HERE @ -        ( calculate the length )
                HERE @          ( push the start address )
        THEN
                HERE @ -        ( calculate the length )
                HERE @          ( push the start address )
        THEN
 
 (
        ." is the print string operator in FORTH.  Example: ." Something to print"
 
 (
        ." is the print string operator in FORTH.  Example: ." Something to print"
-       The space after the operator is the ordinary space required between words.
-
-       This is tricky to define because it has to do different things depending on whether
-       we are compiling or in immediate mode.  (Thus the word is marked IMMEDIATE so it can
-       detect this and do different things).
+       The space after the operator is the ordinary space required between words and is not
+       a part of what is printed.
 
        In immediate mode we just keep reading characters and printing them until we get to
        the next double quote.
 
 
        In immediate mode we just keep reading characters and printing them until we get to
        the next double quote.
 
-       In compile mode we have the problem of where we're going to store the string (remember
-       that the input buffer where the string comes from may be overwritten by the time we
-       come round to running the function).  We store the string in the compiled function
-       like this:
-       ..., LITSTRING, string length, string rounded up to 4 bytes, EMITSTRING, ...
+       In compile mode we use S" to store the string, then add EMITSTRING afterwards:
+               LITSTRING <string length> <string rounded up to 4 bytes> EMITSTRING
+
+       It may be interesting to note the use of [COMPILE] to turn the call to the immediate
+       word S" into compilation of that word.  It compiles it into the definition of .",
+       not into the definition of the word being compiled when this is running (complicated
+       enough for you?)
 )
 : ." IMMEDIATE         ( -- )
        STATE @ IF      ( compiling? )
 )
 : ." IMMEDIATE         ( -- )
        STATE @ IF      ( compiling? )
-               ' LITSTRING ,   ( compile LITSTRING )
-               HERE @          ( save the address of the length word on the stack )
-               0 ,             ( dummy length - we don't know what it is yet )
-               BEGIN
-                       KEY             ( get next character of the string )
-                       DUP '"' <>
-               WHILE
-                       HERE @ !b       ( store the character in the compiled image )
-                       1 HERE +!       ( increment HERE pointer by 1 byte )
-               REPEAT
-               DROP            ( drop the double quote character at the end )
-               DUP             ( get the saved address of the length word )
-               HERE @ SWAP -   ( calculate the length )
-               4-              ( subtract 4 (because we measured from the start of the length word) )
-               SWAP !          ( and back-fill the length location )
-               HERE @          ( round up to next multiple of 4 bytes for the remaining code )
-               3 +
-               3 INVERT AND
-               HERE !
+               [COMPILE] S"    ( read the string, and compile LITSTRING, etc. )
                ' EMITSTRING ,  ( compile the final EMITSTRING )
        ELSE
                ( In immediate mode, just read characters and print them until we get
                ' EMITSTRING ,  ( compile the final EMITSTRING )
        ELSE
                ( In immediate mode, just read characters and print them until we get
-                 to the ending double quote.  Much simpler than the above code! )
+                 to the ending double quote. )
                BEGIN
                        KEY
                        DUP '"' = IF
                BEGIN
                        KEY
                        DUP '"' = IF
        HERE !          ( and store HERE with the dictionary address )
 ;
 
        HERE !          ( and store HERE with the dictionary address )
 ;
 
-(
-       While compiling, '[COMPILE] word' compiles 'word' if it would otherwise be IMMEDIATE.
-)
-: [COMPILE] IMMEDIATE
-       WORD            ( get the next word )
-       FIND            ( find it in the dictionary )
-       >CFA            ( get its codeword )
-       ,               ( and compile that )
-;
-
 (
        RECURSE makes a recursive call to the current word that is being compiled.
 
 (
        RECURSE makes a recursive call to the current word that is being compiled.