• Unable to write to file on GFORTH.

    From SpainHackForth@21:1/5 to fd-out on Sun Feb 12 18:36:34 2023
    Hi all,

    I have been trying to create a simple compiler for a VM I wrote. I'm writing the compiler on GForth.
    Here is the offending code.

    https://gist.github.com/jemo07/18a47eeb0bd99ffb350bd78002d8498e

    For what ever reason, I can't seem to figure out how to write data off the stack onto a file. Maybe that is my problem, that I need to extract the data first ? Just kind of thinking out loud as I'm off the bed.

    Here is how I was attempting to use the code:
    s" bytecode.out" open-output ok
    10 vm_c,lit ,, ok
    20 vm_c,lit ,, ok
    VM_UM_PLUS vm_c, , ok
    fd-out write-line throw
    :454: File I/O exception

    Then:

    s" bytecode.out" open-output ok
    10 vm_c,lit ,, ok
    20 vm_c,lit ,, ok
    VM_UM_PLUS vm_c, , ok
    fd-out write-line ok
    fd-out write-file
    :460: Invalid memory address
    fd-out >>>write-file<<<
    Backtrace:

    You can see here what looks like success but the file, although create, it's always empty.

    s" bytecode.out" open-output ok
    10 vm_c,lit ,, ok
    20 vm_c,lit ,, ok
    VM_UM_PLUS vm_c, , ok
    fd-out write-file ok
    fd-out close-file throw ok

    Please advice on what am I getting wrong.

    Thanks,

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Brian Fox@21:1/5 to SpainHackForth on Sun Feb 12 19:16:15 2023
    On Sunday, February 12, 2023 at 9:36:35 PM UTC-5, SpainHackForth wrote:
    Hi all,

    I have been trying to create a simple compiler for a VM I wrote. I'm writing the compiler on GForth.
    Here is the offending code.

    https://gist.github.com/jemo07/18a47eeb0bd99ffb350bd78002d8498e

    For what ever reason, I can't seem to figure out how to write data off the stack onto a file. Maybe that is my problem, that I need to extract the data first ? Just kind of thinking out loud as I'm off the bed.

    Here is how I was attempting to use the code:
    s" bytecode.out" open-output ok
    10 vm_c,lit ,, ok
    20 vm_c,lit ,, ok
    VM_UM_PLUS vm_c, , ok
    fd-out write-line throw
    :454: File I/O exception

    Then:

    s" bytecode.out" open-output ok
    10 vm_c,lit ,, ok
    20 vm_c,lit ,, ok
    VM_UM_PLUS vm_c, , ok
    fd-out write-line ok
    fd-out write-file
    :460: Invalid memory address
    fd-out >>>write-file<<<
    Backtrace:

    You can see here what looks like success but the file, although create, it's always empty.

    s" bytecode.out" open-output ok
    10 vm_c,lit ,, ok
    20 vm_c,lit ,, ok
    VM_UM_PLUS vm_c, , ok
    fd-out write-file ok
    fd-out close-file throw ok

    Please advice on what am I getting wrong.

    Thanks,

    write-line has this stack diagram:

    WRITE-LINE ( c-addr u fileid -- ior )
    So you don't write the data from the stack per se.
    The data needs to be in memory somewhere and you provide the address and the size.

    Same with write-file
    WRITE-FILE ( c-addr u fileid -- ior )

    So something like this might work assuming FD-OUT is the file handle.
    (don't use Gforth much)

    HERE 10 vm_c, lit , , ( -- caddr )
    HERE OVER - ( -- caddr u )
    FD-OUT WRITE-LINE ( -- ior)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From dxforth@21:1/5 to Brian Fox on Mon Feb 13 16:45:19 2023
    On 13/02/2023 2:16 pm, Brian Fox wrote:
    On Sunday, February 12, 2023 at 9:36:35 PM UTC-5, SpainHackForth wrote:
    Hi all,

    I have been trying to create a simple compiler for a VM I wrote. I'm writing the compiler on GForth.
    Here is the offending code.

    https://gist.github.com/jemo07/18a47eeb0bd99ffb350bd78002d8498e

    For what ever reason, I can't seem to figure out how to write data off the stack onto a file. Maybe that is my problem, that I need to extract the data first ? Just kind of thinking out loud as I'm off the bed.

    Here is how I was attempting to use the code:
    s" bytecode.out" open-output ok
    10 vm_c,lit ,, ok
    20 vm_c,lit ,, ok
    VM_UM_PLUS vm_c, , ok
    fd-out write-line throw
    :454: File I/O exception

    Then:

    s" bytecode.out" open-output ok
    10 vm_c,lit ,, ok
    20 vm_c,lit ,, ok
    VM_UM_PLUS vm_c, , ok
    fd-out write-line ok
    fd-out write-file
    :460: Invalid memory address
    fd-out >>>write-file<<<
    Backtrace:

    You can see here what looks like success but the file, although create, it's always empty.

    s" bytecode.out" open-output ok
    10 vm_c,lit ,, ok
    20 vm_c,lit ,, ok
    VM_UM_PLUS vm_c, , ok
    fd-out write-file ok
    fd-out close-file throw ok

    Please advice on what am I getting wrong.

    Thanks,

    write-line has this stack diagram:

    WRITE-LINE ( c-addr u fileid -- ior )
    So you don't write the data from the stack per se.
    The data needs to be in memory somewhere and you provide the address and the size.

    Same with write-file
    WRITE-FILE ( c-addr u fileid -- ior )

    So something like this might work assuming FD-OUT is the file handle.
    (don't use Gforth much)

    HERE 10 vm_c, lit , , ( -- caddr )
    HERE OVER - ( -- caddr u )
    FD-OUT WRITE-LINE ( -- ior)

    More forths should support READ-CHAR WRITE-CHAR. It's a logical extension when working at the byte/char level.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Anton Ertl@21:1/5 to SpainHackForth on Mon Feb 13 06:41:35 2023
    SpainHackForth <jemo07@gmail.com> writes:
    You can see here what looks like success but the file, although create, it's always empty.

    s" bytecode.out" open-output ok
    10 vm_c,lit ,, ok
    20 vm_c,lit ,, ok
    VM_UM_PLUS vm_c, , ok
    fd-out write-file ok
    fd-out close-file throw ok

    Please advice on what am I getting wrong.

    There are a number of words here that don't come from Gforth:
    OPEN-OUTPUT VM_C,LIT ,, VM_C, FD-OUT

    OPEN-OUTPUT and FD-OUT may have the same definitions as in <https://gforth.org/manual/Files-Tutorial.html#Create-file-for-output>.
    I can only guess what the others do. From the layout my guess would
    be that you don't pass the c-addr and u parameters to WRITE-FILE, but
    that will normally result in a stack underflow.

    Anyway, here's an example of writing some bytes:

    0 Value fd-out
    : open-output ( addr u -- ) w/o create-file throw to fd-out ;
    s" test.out" open-output
    create foo
    'a' c,
    'b' c,
    'c' c,
    foo here over - fd-out write-file throw
    fd-out close-file throw

    - anton
    --
    M. Anton Ertl http://www.complang.tuwien.ac.at/anton/home.html
    comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
    New standard: https://forth-standard.org/
    EuroForth 2022: https://euro.theforth.net

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From SpainHackForth@21:1/5 to All on Mon Feb 13 02:32:05 2023

    OPEN-OUTPUT and FD-OUT may have the same definitions as in <https://gforth.org/manual/Files-Tutorial.html#Create-file-for-output>.
    I can only guess what the others do. From the layout my guess would
    be that you don't pass the c-addr and u parameters to WRITE-FILE, but
    that will normally result in a stack underflow.

    Anyway, here's an example of writing some bytes:

    0 Value fd-out
    : open-output ( addr u -- ) w/o create-file throw to fd-out ;
    s" test.out" open-output
    create foo
    'a' c,
    'b' c,
    'c' c,
    foo here over - fd-out write-file throw
    fd-out close-file throw

    - anton

    Thank you for taking the time Anton et all!
    Here are the definitions for the words that I'm using.
    : open-output ( addr u -- ) w/o create-file throw to fd-out ;
    \ Compile a word into the bytecode
    : vm_c, ( n -- ) [char] , emit ;
    \ Compile a word and its argument into the bytecode
    : vm_c,lit ( n -- ) vm_c, vm_c, n ;

    Here is an interactive view of the outputs:

    Gforth 0.7.3, Copyright (C) 1995-2008 Free Software Foundation, Inc.
    Gforth comes with ABSOLUTELY NO WARRANTY; for details type `license'
    Type `bye' to exit
    ok
    ok
    s" bytecode.out" open-output ok
    .S <0> ok
    create foo ok
    .S <0> ok
    10 vm_c,lit ,, ok
    .S <2> 10 140542381430136 ok
    foo here over - fd-out write-file throw ok
    .S <2> 10 140542381430136 ok
    fd-out close-file throw ok
    .S <2> 10 140542381430136 ok

    As you can see, the stack does not get consumed. Note that the double-commas are not a word I'm typing, as in 10 vm_c,lit and after I hit enter the ' ,, ' appear.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Ron AARON@21:1/5 to dxforth on Mon Feb 13 15:33:39 2023
    On 13/02/2023 7:45, dxforth wrote:
    On 13/02/2023 2:16 pm, Brian Fox wrote:

    write-line  has this stack diagram:

    WRITE-LINE ( c-addr u fileid -- ior )
    So you don't write the data from the stack per se.
    The data needs to be in memory somewhere and you provide the address
    and the size.

    Same with write-file
    WRITE-FILE ( c-addr u fileid -- ior )

    So something like this might work assuming FD-OUT is the file handle.
    (don't use Gforth much)

    HERE 10 vm_c, lit ,  ,  ( -- caddr )
    HERE OVER -              ( -- caddr u )
    FD-OUT WRITE-LINE ( -- ior)

    More forths should support READ-CHAR WRITE-CHAR.  It's a logical
    extension when
    working at the byte/char level.

    8th has f:getc which returns one Unicode character from the file. No
    equivalnt f:putc exists.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From SpainHackForth@21:1/5 to SpainHackForth on Mon Feb 13 05:39:35 2023
    On Monday, February 13, 2023 at 11:32:07 AM UTC+1, SpainHackForth wrote:

    OPEN-OUTPUT and FD-OUT may have the same definitions as in <https://gforth.org/manual/Files-Tutorial.html#Create-file-for-output>.
    I can only guess what the others do. From the layout my guess would
    be that you don't pass the c-addr and u parameters to WRITE-FILE, but
    that will normally result in a stack underflow.


    Ok so I'm getting closer, had to redefine some of the words,

    vm_create ok
    10 vm_c,lit ,l ok
    .S <1> 10 ok
    20 vm_c,lit ,l ok
    .S <2> 10 20 ok
    VM_UM_PLUS vm_c, , ok
    .S <1> 30 ok
    vm_write
    :22: File I/O exception
    vm_write<<<
    Backtrace:
    $7FDC2D2A9E30 throw

    here are the offending words.

    \ Compile a word into the bytecode
    : vm_c, ( n -- ) [char] , emit ;

    \ Compile a word and its argument into the bytecode
    : vm_c,lit ( n -- ) [char] , emit [char] lit emit ;

    \ Output the generated bytecode to a file
    : vm_create ( -- ) s" bytecode.out" open-output ;
    : vm_write ( n -- )
    fd-out here over -
    fd-out write-file throw ;
    : vm_close ( -- ) close-file throw ;

    as you can see, somehow I'm not sending the data to the memory buffer, but rater executing the code on the machine.

    I tried this but still no go:

    create buffer redefined buffer ok
    : write-to-buffer ( n -- ) buffer c, ; ok
    : write-to-file ( -- ) buffer fd-out write-file throw ; ok
    : vm_c,lit ( n -- ) [char] lit emit write-to-buffer ; redefined vm_c,lit ok
    : vm_write ( -- ) write-to-file ; redefined vm_write ok

    vm_write
    :26: File I/O exception
    vm_write<<<
    Backtrace:
    $7F3CE486CEF0 throw
    $7F3CE486CF90 write-to-file

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From dxforth@21:1/5 to SpainHackForth on Tue Feb 14 03:03:20 2023
    On 14/02/2023 12:39 am, SpainHackForth wrote:

    I tried this but still no go:
    ...

    Here's a buffered output routine. PUTC writes a byte to file.
    Remember to CLOSE-OUTPUT when done to flush the buffer.

    -1 value FD-OUT

    64 constant #OBUF
    create OBUF #obuf allot
    variable OSIZ variable OPTR

    \ reset output buffer
    : /OBUF ( -- ) obuf optr ! 0 osiz ! ;

    : (flushwrite) ( -- ior )
    obuf osiz @ fd-out write-file /obuf ;

    : OPEN-OUTPUT ( adr len -- )
    r/w create-file throw to fd-out /obuf ;

    \ errors not reported
    : CLOSE-OUTPUT ( -- )
    fd-out dup 0> if (flushwrite) drop then
    close-file drop -1 to fd-out ;

    \ Write char to buffered output
    : PUTC ( char -- )
    osiz @ #obuf = if (flushwrite) throw then
    optr @ c! 1 optr +! 1 osiz +! ;

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From SpainHackForth@21:1/5 to dxforth on Mon Feb 13 09:22:32 2023
    On Monday, February 13, 2023 at 5:03:23 PM UTC+1, dxforth wrote:
    On 14/02/2023 12:39 am, SpainHackForth wrote:

    I tried this but still no go:
    ...

    Here's a buffered output routine. PUTC writes a byte to file.
    Remember to CLOSE-OUTPUT when done to flush the buffer.

    Fantastic FX,

    Here is my implementation based on your code:

    : VM_DROP DROP ;
    : VM_EXIT bye ;
    : VM_BRANCH branch ;
    : VM_DUP dup ;
    : VM_FETCH @ ;
    : VM_LIT lit ;
    : VM_R_FROM r> drop ;
    : VM_R_FETCH r@ ;
    : VM_TO_R >r ;
    : VM_STORE ! ;
    \ : VM_ENTER ['] ENTER ;
    : VM_OVER over ;
    : VM_AND and ;
    : VM_ZERO_LESS 0= ;
    : VM_SWAP swap ;
    : VM_COND_BRANCH ( flag dest -- ) dup 0= if swap branch then drop ;
    : VM_UM_PLUS + ;

    64 constant #OutBuff
    create OutBuff #OutBuff allot
    variable BUFSIZE
    variable BUFPOS
    variable n
    variable fd-out
    0 Value fd-in
    0 Value fd-out
    \ Reset the output buffer
    : /OutBuff ( -- ) OutBuff BUFPOS ! 0 BUFSIZE ! ;

    \ Flush the buffer to the output file
    : WFLUSH ( -- ior )
    OutBuff BUFSIZE @ fd-out write-file /OutBuff ;

    \ Open a file for writing
    : OPEN-OUTPUT ( adr u -- ) r/w create-file throw to fd-out /OutBuff ;

    \ Close the file, flushing the buffer if necessary
    : CLOSE-OUTPUT ( -- )
    fd-out dup 0> if WFLUSH drop then
    close-file drop ;

    \ Write a character to the buffer
    : WBUF ( char -- )
    BUFSIZE @ #OutBuff = if WFLUSH throw then
    BUFPOS @ c! 1 BUFPOS +! 1 BUFSIZE +! ;

    \ Compile a word into the bytecode
    : vm_c, ( n -- ) WBUF ;

    \ Compile a word and its argument into the bytecode
    : vm_c,lit ( n -- ) [char] lit emit WBUF ;

    \ Output the generated bytecode to a file
    : vm_create ( -- ) s" bytecode.out" open-output ;
    : vm_write ( n -- ) vm_c,lit n ;
    : vm_close ( -- ) close-output ;

    I can now see something is been written, but I now have to solve what that is, as the file is created and it grow, but a cat does not show the expected values. Cheers!

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From SpainHackForth@21:1/5 to All on Mon Feb 13 10:06:43 2023
    [ Aside : Calling a buffer a buffer is a bad idea because its
    also a word in the block wordset. ]


    Hello NN,

    I agree, I was trying something similar, but I could not get it to write to the file, but instead it wrote it to the stack.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From NN@21:1/5 to SpainHackForth on Mon Feb 13 09:37:41 2023
    On Monday, 13 February 2023 at 17:22:33 UTC, SpainHackForth wrote:
    On Monday, February 13, 2023 at 5:03:23 PM UTC+1, dxforth wrote:
    On 14/02/2023 12:39 am, SpainHackForth wrote:

    I tried this but still no go:
    ...

    Here's a buffered output routine. PUTC writes a byte to file.
    Remember to CLOSE-OUTPUT when done to flush the buffer.

    Fantastic FX,

    Here is my implementation based on your code:

    : VM_DROP DROP ;
    : VM_EXIT bye ;
    : VM_BRANCH branch ;
    : VM_DUP dup ;
    : VM_FETCH @ ;
    : VM_LIT lit ;
    : VM_R_FROM r> drop ;
    : VM_R_FETCH r@ ;
    : VM_TO_R >r ;
    : VM_STORE ! ;
    \ : VM_ENTER ['] ENTER ;
    : VM_OVER over ;
    : VM_AND and ;
    : VM_ZERO_LESS 0= ;
    : VM_SWAP swap ;
    : VM_COND_BRANCH ( flag dest -- ) dup 0= if swap branch then drop ;
    : VM_UM_PLUS + ;

    64 constant #OutBuff
    create OutBuff #OutBuff allot
    variable BUFSIZE
    variable BUFPOS
    variable n
    variable fd-out
    0 Value fd-in
    0 Value fd-out
    \ Reset the output buffer
    : /OutBuff ( -- ) OutBuff BUFPOS ! 0 BUFSIZE ! ;

    \ Flush the buffer to the output file
    : WFLUSH ( -- ior )
    OutBuff BUFSIZE @ fd-out write-file /OutBuff ;

    \ Open a file for writing
    : OPEN-OUTPUT ( adr u -- ) r/w create-file throw to fd-out /OutBuff ;

    \ Close the file, flushing the buffer if necessary
    : CLOSE-OUTPUT ( -- )
    fd-out dup 0> if WFLUSH drop then
    close-file drop ;

    \ Write a character to the buffer
    : WBUF ( char -- )
    BUFSIZE @ #OutBuff = if WFLUSH throw then
    BUFPOS @ c! 1 BUFPOS +! 1 BUFSIZE +! ;
    \ Compile a word into the bytecode
    : vm_c, ( n -- ) WBUF ;
    \ Compile a word and its argument into the bytecode
    : vm_c,lit ( n -- ) [char] lit emit WBUF ;
    \ Output the generated bytecode to a file
    : vm_create ( -- ) s" bytecode.out" open-output ;
    : vm_write ( n -- ) vm_c,lit n ;
    : vm_close ( -- ) close-output ;

    I can now see something is been written, but I now have to solve what that is, as the file is created and it grow, but a cat does not show the expected values. Cheers!


    0 [if] --------------------------------------------------------

    Here is a list of standard words used for manipulating files. https://forth-standard.org/standard/file


    [ Aside : Calling a buffer a buffer is a bad idea because its
    also a word in the block wordset. ]

    If you can write your byte-code into an area of memory , then you can write it out one one go.

    Here is an example code

    -------------------------------------------------------- [then]

    require random.fs

    ( create a buffer )
    create buf1 511 chars allot

    : fillbuf ( -- )
    511 0 do
    64 random 32 + buf1 i + c!
    loop

    ( insert cr to break up a long line)
    ( just for visual purposes and not needed )

    511 0 do
    10 buf1 i + c!
    128 random +loop
    ;

    : showdata ( -- )
    buf1 511 type ;

    fillbuf showdata

    0 [if] --------------------------------------------------------


    You will need :

    (1) Filename
    (2) File-id
    (3) Buffer addr and length

    Here is an example code

    -------------------------------------------------------- [then]

    0 value file-id

    variable file-name 50 chars allot
    s" testdata.txt" file-name place

    : (wo) ( -- )
    file-name count w/o create-file throw to file-id
    buf1 511 file-id write-file throw
    file-id close-file throw

    0 to file-id ;

    : wo ( -- )
    ['] (wo) catch if
    cr ." <ERR> While writing"
    else
    cr ." No errors"
    then ;

    wo

    cr cr cr

    bye

    0 [if] --------------------------------------------------------

    You should be able to check file "testdata.txt" using notepad.

    -------------------------------------------------------- [then]

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From dxforth@21:1/5 to SpainHackForth on Tue Feb 14 11:46:20 2023
    On 14/02/2023 4:22 am, SpainHackForth wrote:

    : vm_write ( n -- ) vm_c,lit n ;

    Action doesn't match stack comment. After taking value n from the
    stack and writing it to file, it then takes the address of variable
    n and places it on the stack. I doubt that's what you want.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From SpainHackForth@21:1/5 to dxforth on Tue Feb 14 14:00:37 2023
    On Tuesday, February 14, 2023 at 1:46:21 AM UTC+1, dxforth wrote:
    On 14/02/2023 4:22 am, SpainHackForth wrote:

    : vm_write ( n -- ) vm_c,lit n ;
    Action doesn't match stack comment. After taking value n from the
    stack and writing it to file, it then takes the address of variable
    n and places it on the stack. I doubt that's what you want.
    Hi DX,

    correct, I was expecting to take the value of n and writing that to the file. here was my original attempt to getting this done.

    \ Compile a word into the bytecode
    : vm_c, ( n -- ) [char] , emit ;

    \ Compile a word and its argument into the bytecode
    : vm_c,lit ( n -- ) [char] , emit [char] lit emit ;

    My original idea was that while in Forth, I could create a DSL to write just the byte code.

    I’m looking for a good tutorial on how to implement a cross compiler in gforth for my target system.

    Here is a link for the VM, https://github.com/jemo07/fastVM-16bit

    I’m in the middle of writing a minimal forth based on a 2009 discussion here on the minimal words needed to bootstrap a forth. Then add the rest of the words in forth. It will be slow, but I’m already working on another idea of a more robust VM. It
    will also have a circular stack, this way you can just take a value with a fetch 0/-x and access any value on the stack based on the TOS pointer.

    here is what I have so far in C https://godbolt.org/z/MbfvfsP1c

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Brian Fox@21:1/5 to SpainHackForth on Wed Feb 15 06:52:39 2023
    On Tuesday, February 14, 2023 at 5:00:39 PM UTC-5, SpainHackForth wrote:

    I’m looking for a good tutorial on how to implement a cross compiler in gforth for my target system.

    I wrote my own cross compiler some years back and I didn't find a paper that put it all together.
    I had to pick my way through other peoples code to get some concepts in my head.
    There are a lot of variations in how people do cross-compilers in Forth. No surprise there.

    IMHO a Forth cross compiler begins with versions of dictionary management words and
    a dictionary pointer variable that operate on a memory area separate from the main dictionary.

    From what have seen here, you are trying to compile your target code into the HOST Forth
    dictionary. That is probably a harder way to do it.

    Consider this code that creates a way to manage a Target dictionary memory area in the same
    way that Forth manages its dictionary. The names have a 'T' prefix as a reminder of their
    purpose. They could be made to look normal with DEFER words or a "TARGET" wordlist
    but that's not necessary if you don't mind this look.
    ---
    \ Target versions of HERE and ALLOT
    : THERE ( -- Taddr) TDP @ ; \ end of TARGET dictionary
    : TALLOT ( n -- ) TDP +! ; \ allot bytes in the target dictionary

    \ Target versions for storing
    : TC! ( n Taddr --) THERE + C! ;
    : T! ( n Taddr --) THERE + ! ;

    \ Target versions for fetching
    : TC@ ( n Taddr --) THERE + C@ ;
    : T@ ( n Taddr --) THERE + @ ;

    \ integer and byte "Target" compilers
    : T, ( n -- ) THERE ! 2 TALLOT ; \ compile a cell in target
    : TC, ( c -- ) THERE C! 1 TALLOT ; \ compile a byte in target

    CREATE TARGET-SEG HEX FFFF ALLOT \ 64K bytes for target image

    TARGET-SEG TDP ! \ dictionary now starts at TARGET-SEG memory
    ---

    Once you have these word, you build a Forth style Assembler that uses
    TARGET memory words. It's just bytes compiled into memory
    after all. :-) This becomes your cross-assembler.

    Once you have an Assembler, you can write your Forth compiler
    in the assembler that your just wrote.

    On
  • From Brian Fox@21:1/5 to Brian Fox on Wed Feb 15 08:08:06 2023
    On Wednesday, February 15, 2023 at 9:52:41 AM UTC-5, Brian Fox wrote:
    On Tuesday, February 14, 2023 at 5:00:39 PM UTC-5, SpainHackForth wrote:

    I’m looking for a good tutorial on how to implement a cross compiler in gforth for my target system.
    I wrote my own cross compiler some years back and I didn't find a paper that put it all together.
    I had to pick my way through other peoples code to get some concepts in my head.
    There are a lot of variations in how people do cross-compilers in Forth. No surprise there.

    IMHO a Forth cross compiler begins with versions of dictionary management words and
    a dictionary pointer variable that operate on a memory area separate from the main dictionary.

    From what have seen here, you are trying to compile your target code into the HOST Forth
    dictionary. That is probably a harder way to do it.

    Consider this code that creates a way to manage a Target dictionary memory area in the same
    way that Forth manages its dictionary. The names have a 'T' prefix as a reminder of their
    purpose. They could be made to look normal with DEFER words or a "TARGET" wordlist
    but that's not necessary if you don't mind this look.
    ---
    \ Target versions of HERE and ALLOT
    : THERE ( -- Taddr) TDP @ ; \ end of TARGET dictionary
    : TALLOT ( n -- ) TDP +! ; \ allot bytes in the target dictionary

    \ Target versions for storing
    : TC! ( n Taddr --) THERE + C! ;
    : T! ( n Taddr --) THERE + ! ;

    \ Target versions for fetching
    : TC@ ( n Taddr --) THERE + C@ ;
    : T@ ( n Taddr --) THERE + @ ;

    \ integer and byte "Target" compilers
    : T, ( n -- ) THERE ! 2 TALLOT ; \ compile a cell in target
    : TC, ( c -- ) THERE C! 1 TALLOT ; \ compile a byte in target

    CREATE TARGET-SEG HEX FFFF ALLOT \ 64K bytes for target image

    TARGET-SEG TDP ! \ dictionary now starts at TARGET-SEG memory
    ---
    Oops.
    Of course one needs to define the TDP variable first.

    VARIABLE TDP

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From SpainHackForth@21:1/5 to Brian Fox on Wed Feb 15 22:53:01 2023
    On Wednesday, February 15, 2023 at 5:08:08 PM UTC+1, Brian Fox wrote:
    On Wednesday, February 15, 2023 at 9:52:41 AM UTC-5, Brian Fox wrote:
    On Tuesday, February 14, 2023 at 5:00:39 PM UTC-5, SpainHackForth wrote:

    I’m looking for a good tutorial on how to implement a cross compiler in gforth for my target system.
    I wrote my own cross compiler some years back and I didn't find a paper that put it all together.
    I had to pick my way through other peoples code to get some concepts in my head.
    There are a lot of variations in how people do cross-compilers in Forth. No surprise there.

    IMHO a Forth cross compiler begins with versions of dictionary management words and
    a dictionary pointer variable that operate on a memory area separate from the main dictionary.

    From what have seen here, you are trying to compile your target code into the HOST Forth
    dictionary. That is probably a harder way to do it.

    Consider this code that creates a way to manage a Target dictionary memory area in the same
    way that Forth manages its dictionary. The names have a 'T' prefix as a reminder of their
    purpose. They could be made to look normal with DEFER words or a "TARGET" wordlist
    but that's not necessary if you don't mind this look.
    ---
    \ Target versions of HERE and ALLOT
    : THERE ( -- Taddr) TDP @ ; \ end of TARGET dictionary
    : TALLOT ( n -- ) TDP +! ; \ allot bytes in the target dictionary

    \ Target versions for storing
    : TC! ( n Taddr --) THERE + C! ;
    : T! ( n Taddr --) THERE + ! ;

    \ Target versions for fetching
    : TC@ ( n Taddr --) THERE + C@ ;
    : T@ ( n Taddr --) THERE + @ ;

    \ integer and byte "Target" compilers
    : T, ( n -- ) THERE ! 2 TALLOT ; \ compile a cell in target
    : TC, ( c -- ) THERE C! 1 TALLOT ; \ compile a byte in target

    CREATE TARGET-SEG HEX FFFF ALLOT \ 64K bytes for target image

    TARGET-SEG TDP ! \ dictionary now starts at TARGET-SEG memory
    ---
    Oops.
    Of course one needs to define the TDP variable first.

    VARIABLE TDP
    Thanks I will have a closer look.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From none) (albert@21:1/5 to brian.fox@brianfox.ca on Thu Feb 16 14:17:44 2023
    In article <723598ab-ab7c-4734-a431-bc49d6e501ebn@googlegroups.com>,
    Brian Fox <brian.fox@brianfox.ca> wrote:
    On Tuesday, February 14, 2023 at 5:00:39 PM UTC-5, SpainHackForth wrote:

    I’m looking for a good tutorial on how to implement a cross compiler in gforth for my target system.

    I wrote my own cross compiler some years back and I didn't find a paper that put it all together.
    I had to pick my way through other peoples code to get some concepts in my head.
    There are a lot of variations in how people do cross-compilers in Forth. No surprise there.

    IMHO a Forth cross compiler begins with versions of dictionary
    management words and a dictionary pointer variable that operate on a
    memory area separate from the main dictionary.

    I would think that you have to start with a decision whether to have an indirect threaded, direct threaded or subroutine threaded Forth (or whatever) The next decision is the layout of a dictionary entry. I'm an advocate
    for an uniform data structure (same for constant's, variable's, create/does words, defer words), but that can waste some memory (empty fields).
    If it is non uniform, you have to carefully design how definitions are
    chained and take care of any exceptions.
    Then there is the important decision, actually imposed, if the Forth runs
    stand alone or hosted on an operating system. In the latter case you can
    choose for a single executable, or a kind of loader, that supposedly
    yield some benefits for portability.
    Then you have to choose registers for the Forth program counter,
    data stack pointer, return stack pointer, and possibly more, e.g.
    floating point stack, locals stack.
    A decision that affects all code definitions is whether you hold
    the top of stack in memory in a register.

    Designing a Forth from scratch can be a waste of time.
    E.g. for ciforth I started from fig-Forth and there was minor
    mile stones, e.g. 32 bits, ANSI-compatible.
    The regression test was valid through a few thousands of iterations.

    <SNIP>
    Have fun!
    Agreed!
    Having you own Forth is fun, but never forget to do something useful
    with it. Otherwise you end up adding futile enhancements.

    Groetjes Albert
    --
    Don't praise the day before the evening. One swallow doesn't make spring.
    You must not say "hey" before you have crossed the bridge. Don't sell the
    hide of the bear until you shot it. Better one bird in the hand than ten in
    the air. First gain is a cat spinning. - the Wise from Antrim -

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Brian Fox@21:1/5 to none albert on Thu Feb 16 06:25:34 2023
    On Thursday, February 16, 2023 at 8:17:48 AM UTC-5, none albert wrote:
    IMHO a Forth cross compiler begins with versions of dictionary
    management words and a dictionary pointer variable that operate on a
    memory area separate from the main dictionary.
    I would think that you have to start with a decision whether to have an indirect threaded, direct threaded or subroutine threaded Forth (or whatever) The next decision is the layout of a dictionary entry. I'm an advocate
    for an uniform data structure (same for constant's, variable's, create/does words, defer words), but that can waste some memory (empty fields).
    If it is non uniform, you have to carefully design how definitions are chained and take care of any exceptions.
    Then there is the important decision, actually imposed, if the Forth runs stand alone or hosted on an operating system. In the latter case you can choose for a single executable, or a kind of loader, that supposedly
    yield some benefits for portability.
    Then you have to choose registers for the Forth program counter,
    data stack pointer, return stack pointer, and possibly more, e.g.
    floating point stack, locals stack.
    A decision that affects all code definitions is whether you hold
    the top of stack in memory in a register.

    Designing a Forth from scratch can be a waste of time.
    E.g. for ciforth I started from fig-Forth and there was minor
    mile stones, e.g. 32 bits, ANSI-compatible.
    The regression test was valid through a few thousands of iterations.

    <SNIP>
    Have fun!
    Agreed!
    Having you own Forth is fun, but never forget to do something useful
    with it. Otherwise you end up adding futile enhancements.

    Yes all those decisions are required as well.
    Unfortunately CiForth doesn't have a version for TMS9900. :-)))

    I actually did not do all the work. I stood on the work of Brad Rodriguez and used his Camel Forth as a stepping stone. Brad wrote the early versions in Assembler but all the comments for hi-level words are clear Forth definitions. I also used work from 1984 by engineers who wrote TI-Forth.

    So I did what I said _and_ what you recommended:
    - converted the TI-Forth Assembler to a cross-assembler for a PC Forth.
    - Made the internal decisions (ITC, TOS in register, memory location...)
    - wrote the primitives in the cross-assembler
    - Wrote the cross compiler
    - compiled Brad's comments as source code.
    Eventually it worked.

    My project was a "bucket list". I always wanted to build a compiler that built a compiler The lessons learned were invaluable for me but of no
    value to many others although I have found 9900 Forth allies in retro computing circles. (albeit it is a very short list) :-)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)