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 de5bbe3..44e837b 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).
-       $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
 */
-       .set JONES_VERSION,28
+       .set JONES_VERSION,29
 /*
        INTRODUCTION ----------------------------------------------------------------------
 
index b8c5a61..e3140c4 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).
-\      $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
 \
 : ')' [ 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.
 ;
 
 (
-       [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
-       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.
 
+       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
                        OVER !b         ( save next character )
                        1+              ( increment address )
                REPEAT
+               DROP            ( drop the final " character )
                HERE @ -        ( calculate the length )
                HERE @          ( push the start address )
        THEN
 
 (
        ." 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 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? )
-               ' 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
-                 to the ending double quote.  Much simpler than the above code! )
+                 to the ending double quote. )
                BEGIN
                        KEY
                        DUP '"' = IF
 ;
 
 (
-       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.
 
        Normally while a word is being compiled, it is marked HIDDEN so that references to the