Add 'make remote' rule for building on oirase.
[rrq/jonesforth.git] / jonesforth.f
index b8c5a61b20e8428d23cb508a39ca4abc729dbe41..7f2051770ba0a75388f0553eb0cacd2daac139b3 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.3 2007-09-25 09:50:54 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
 
        First ALLOT, where n ALLOT allocates n bytes of memory.  (Note when calling this that
        it's a very good idea to make sure that n is a multiple of 4, or at least that next time
 
        First ALLOT, where n ALLOT allocates n bytes of memory.  (Note when calling this that
        it's a very good idea to make sure that n is a multiple of 4, or at least that next time
-       a word is compiled that n has been left as a multiple of 4).
+       a word is compiled that HERE has been left as a multiple of 4).
 )
 : ALLOT                ( n -- addr )
 )
 : ALLOT                ( n -- addr )
-       HERE @ SWAP     ( here n -- )
+       HERE @ SWAP     ( here n )
        HERE +!         ( adds n to HERE, after this the old value of HERE is still on the stack )
 ;
 
        HERE +!         ( adds n to HERE, after this the old value of HERE is still on the stack )
 ;
 
        Notice that 'VAL' on its own doesn't return the address of the value, but the value itself,
        making values simpler and more obvious to use than variables (no indirection through '@').
        The price is a more complicated implementation, although despite the complexity there is no
        Notice that 'VAL' on its own doesn't return the address of the value, but the value itself,
        making values simpler and more obvious to use than variables (no indirection through '@').
        The price is a more complicated implementation, although despite the complexity there is no
-       particular performance penalty at runtime.
+       performance penalty at runtime.
 
        A naive implementation of 'TO' would be quite slow, involving a dictionary search each time.
        But because this is FORTH we have complete control of the compiler so we can compile TO more
 
        A naive implementation of 'TO' would be quite slow, involving a dictionary search each time.
        But because this is FORTH we have complete control of the compiler so we can compile TO more
        BEGIN
                DUP 0<>         ( while link pointer is not null )
        WHILE
        BEGIN
                DUP 0<>         ( while link pointer is not null )
        WHILE
-               DUP ?HIDDEN NOT IF
-                       DUP ID.         ( print the word )
+               DUP ?HIDDEN NOT IF      ( ignore hidden words )
+                       DUP ID.         ( but if not hidden, print the word )
                THEN
                SPACE
                @               ( dereference the link pointer - go to previous word )
                THEN
                SPACE
                @               ( dereference the link pointer - go to previous word )
        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.