Copyright Bill Muench All rights reserved.
Permission is granted for non-commercial use, provided this notice is included.
Contact Bill Muench concerning commercial use.

CR .( Meta Compiler with Late Binding )
CR .( Copyright Bill Muench All rights reserved. )
CR ( 8086 eForth ITC 16bit inline model for MS-DOS )

( Bill Muench \ OntoLogic )
(             \ Santa Cruz  CA  95065 )

(        tracks ============================================= )
( 971014 no host interpreter/compiler vectoring needed, almost ANS )
(        replace  SP@ with DEPTH  INCLUDE with INCLUDED )
(        use WORDLIST  INSIDE OUTSIDE )
( 971003 change to INSIDE :I ;I [I]  OUTSIDE :O ;O [O] )
(        change EVOKE EMPLOY  fix error handling, again )
( 950720 add ENDIAN _C" )
( 941006 add META[ ]META )
(        change _]-T SERR PROC  remove HEADS )
( 940817 ITC 1616 and ITC 3232 )
( 930804 POSTFIX ASSEMBLER  ?BREAK  C"| )
( 930329 HEADS ON/OFF )
( 930221 BTC only )
( 920126 COMPILE, RECURSE  fix error handling )
( 910722 update C" ,C" RECURSE )
( 901030 start small model )
(        coyote ============================================= )

DECIMAL

: ROOT ( -- ) FORTH-WORDLIST DUP 2 SET-ORDER  DEFINITIONS ;

ROOT

VARIABLE CSP-T
: !CSP-T ( -- ) DEPTH CSP-T !  0 BREAK? ! ;

!CSP-T ( start error check )

\ : PARSE-WORD ( -- a u ) BL WORD COUNT ;

: INCLUDE ( 'filespec' -- )
  PARSE-WORD ['] INCLUDED CATCH ?DUP IF ROOT THROW THEN ;

: SERR ( a u -- ) CR CR .S SPACE TYPE ROOT 1 THROW ;

: ?CSP-T ( -- )
  BREAK? @ IF 0 BREAK? ! S" ctrl-break" SERR THEN
  DEPTH CSP-T @ XOR IF S" csp-t" SERR THEN ;

: WID' ( wid 'name' -- xt )
  >R  GET-ORDER  R> 1 SET-ORDER  ['] ' CATCH
  IF S" undefined" SERR THEN >R  SET-ORDER  R> ;

( database management ======================================= )

VARIABLE ISEG ( image segment )
VARIABLE #IMAGE ( maximum image size )
: >IMAGE ( a -- d ) #IMAGE @ OVER U< IF S" image" SERR THEN ISEG @ ;

: ALLOC-T ( u -- )
  >R  0  R@
  IF R@ 0 16 UM/MOD NIP alloc IF S" seg alloc" SERR THEN
    DUP ISEG ! R> [CHAR] b ( a s u c ) LFILL EXIT
  THEN S" 0 alloc" SERR ;

: SAVE-T ( -- ) ( save code, external segments )
  ACTIVE @ ( save current file id )
  S" EFORTH.COM" 2DUP 0 ( normal ) CREATE-FILE ?DOS  hHCB
  H# 100 ( offset for .COM file )
  #IMAGE @ OVER -  ISEG @ LONG!  WRITE  CLOSE
  ACTIVE ! ( restore open file if any ) ;

VARIABLE 'ENDIAN
: ENDIAN ( n -- n ) 'ENDIAN @EXECUTE ;
: ?ENDIAN ( -- ) ( check host byte order )
  BASE C@
  IF ['] NOOP ( little endian )
  ELSE ['] FLIP ( big endian )
  THEN 'ENDIAN ! ;

( storage for new system words ============================== )

WORDLIST CONSTANT TARGET-WORDLIST
TARGET-WORDLIST >VOC TARGET

( define words used inside target definitions =============== )

WORDLIST CONSTANT INSIDE-WORDLIST
INSIDE-WORDLIST >VOC INSIDE

: :I ( 'name' -- ) INSIDE-WORDLIST SET-CURRENT  :  ;
: ;I ( -- ) [COMPILE] ; DEFINITIONS ; IMMEDIATE
: [I] ( 'name' -- ) INSIDE-WORDLIST WID' COMPILE, ; IMMEDIATE

( define words used outside target definitions ============== )

WORDLIST CONSTANT OUTSIDE-WORDLIST
OUTSIDE-WORDLIST >VOC OUTSIDE

: :O ( 'name' -- ) OUTSIDE-WORDLIST SET-CURRENT  :  ;
: ;O ( -- ) [COMPILE] ; DEFINITIONS ; IMMEDIATE
: [O] ( 'name' -- ) OUTSIDE-WORDLIST WID' COMPILE, ; IMMEDIATE

( late binding ============================================== )

: _BIND ( a u wid -- )
  GET-ORDER DUP BEGIN ?DUP WHILE 1- ROT >R REPEAT >R ( save order )
  1 SET-ORDER ['] EVALUATE CATCH IF S" bind" SERR THEN
  R> DUP BEGIN ?DUP WHILE 1- R> -ROT REPEAT SET-ORDER ( restore order ) ;

: BIND ( wid 'ccc' -- ) ( -- a u wid )
  BL PARSE  [COMPILE] SLITERAL  [COMPILE] LITERAL  ['] _BIND COMPILE, ;

( EVOKE - to call Forth, elicit )
: EVOKE ( 'ccc' -- ) OUTSIDE-WORDLIST BIND ; IMMEDIATE
: EMPLOY ( 'ccc' -- ) TARGET-WORDLIST BIND ; IMMEDIATE

( target CHAR and CELL size ================================= )

16 CONSTANT #BITS ( bits per cell ) :O #BITS #BITS ;O

:O CHARS ( n -- n ) ;O      :I CHARS ( n -- n ) ;I
:O CHAR+ ( n -- n ) 1+ ;O   :O CHAR- ( n -- n ) 1- ;O

:O CELLS ( n -- n ) [ #BITS 8 / ] LITERAL * ;O
:O CELL+ ( n -- n ) 1 [O] CELLS + ;O
:O CELL- ( n -- n ) 1 [O] CELLS - ;O

( target memory ============================================= )

VARIABLE DP-T ( target dictionary pointer )
:O ORG ( a -- ) DP-T ! ;O
:O HERE ( -- a ) DP-T @ ;O
:O ALLOT ( n -- ) DP-T +! ;O

:O C@ ( a -- c ) >IMAGE LC@ ;O
:O C! ( c a -- ) >IMAGE LC! ;O
:O C, ( c -- ) [O] HERE 1 [O] CHARS [O] ALLOT [O] C! ;O
:O COUNT ( a -- a u ) DUP [O] CHAR+ SWAP [O] C@ ;O

:O @ ( a -- n ) >IMAGE L@ ENDIAN ;O
:O ! ( n a -- ) SWAP ENDIAN SWAP >IMAGE L! ;O
:O , ( n -- ) [O] HERE 1 [O] CELLS [O] ALLOT [O] ! ;O

: MOVE-C ( a a n -- ) >R CS0 SWAP >IMAGE R> LCMOVE ;

VARIABLE WASTE ( alignment wasted bytes )
:O ALIGNED ( a -- a ) 1 [O] CELLS 1- + 1 [O] CELLS 1- INVERT AND ;O
:O ALIGN ( -- ) [O] HERE  DUP [O] ALIGNED  DUP [O] ORG  SWAP - WASTE +! ;O

:O COMPILE, ( xt -- ) [O] , ;O

( dictionary names ========================================== )

VARIABLE HEAD?
:O | ( -- ) 0 HEAD? ! ;O ( one headerless word )

VARIABLE LAST-T ( most recently defined name )
: HEAD,-T ( 'name' -- )
  HEAD? @ ( save name? )
  IF >IN @  PARSE-WORD ( a u )
    [O] ALIGN  LAST-T @ [O] ,
    [O] HERE  DUP LAST-T ! ( link )
    OVER 1+ [O] CHARS [O] ALLOT  2DUP [O] C! [O] CHAR+ ( save count )
    SWAP MOVE-C ( save name )
    0 [O] C, ( attribute byte )
    >IN !  EXIT
  THEN -1 HEAD? ! ;

VARIABLE HEAD>
: XHEAD,-T ( xt 'name' -- )
  TARGET-WORDLIST SET-CURRENT
  CREATE DEFINITIONS  HERE HEAD> !  ( lex ) 0 , ( xt ) ,
  DOES> 2@ IF S" immediate" SERR THEN [O] COMPILE, ;

: CODE-T ( 'name' -- )
  HEAD,-T [O] ALIGN [O] HERE  DUP XHEAD,-T  [O] CELL+ [O] , ; \ ITC

: LIST-T ( 'name' -- )
  HEAD,-T [O] ALIGN [O] HERE XHEAD,-T  EVOKE LIST1 [O] , ; \ ITC

: !LEX-T ( n -- )
  LAST-T @  [O] COUNT [O] CHARS +  DUP >R [O] C@ OR R> [O] C! ;
:O IMMEDIATE ( -- ) EVOKE =IMED HEAD? @ IF DUP !LEX-T THEN HEAD> @ ! ;O
:O COMPILE-ONLY ( -- ) HEAD? @ IF EVOKE =COMP !LEX-T THEN ;O

( compiler ================================================== )

:I RECURSE ( -- ) HEAD> @ CELL+ @ [O] COMPILE, ;I

:O ,C" ( 'ccc' -- )
  [CHAR] " PARSE  DUP [O] C, ( save count )
  [O] HERE  SWAP [O] CHARS  DUP [O] ALLOT  MOVE-C ( save string )
  [O] ALIGN ;O

:I ABORT" ( 'ccc' -- ) EMPLOY _ABORT" [O] ,C" ;I
:I ." ( 'ccc' -- ) EMPLOY _." [O] ,C" ;I
:I S" ( 'ccc' -- ) EMPLOY _S" [O] ,C" ;I

:I LITERAL ( n -- ) EMPLOY _LIT [O] , ;I
:I 2LITERAL ( d -- ) SWAP [I] LITERAL [I] LITERAL ;I

: X# ( radix 'ccc' -- n | d )
  BASE @ >R  BASE ! ( save and set radix )
  BL PARSE NUMBER? ( using new base )
  R> BASE ! ( restore radix before error check )
  IF EXIT THEN S" radix" SERR ;

: #O ( d -- n | d ) DPL @ 0< IF DROP THEN ;
: #I ( n | d ) DPL @ 0< IF DROP [I] LITERAL EXIT THEN [I] 2LITERAL ;

:O ' ( 'name' -- xt ) TARGET-WORDLIST WID' >BODY CELL+ @ ;O
:I ['] ( 'name' -- xt ) [O] ' [I] LITERAL ;I

:O ] ( -- ) TARGET-WORDLIST INSIDE-WORDLIST 2 SET-ORDER ;O
:O : ( 'name' -- ) LIST-T [O] ] ;O

:I [ ( -- ) OUTSIDE-WORDLIST 1 SET-ORDER  DEFINITIONS ;I
:I ; ( -- ) EMPLOY EXIT [I] [ ;I

( control flow ============================================== )

:I BEGIN ( -- a ) [O] HERE ;I
:I THEN ( a -- ) [I] BEGIN ( OVER - ) SWAP [O] ! ;I

: RESOLVE ( a -- ) ( [I] BEGIN - ) [O] , ;
: MARK ( -- a ) [O] HERE [I] BEGIN RESOLVE ;

:I IF ( -- a ) EMPLOY _IF MARK ;I
:I AHEAD ( -- a ) EMPLOY _ELSE MARK ;I
:I ELSE ( a -- a ) [I] AHEAD SWAP [I] THEN ;I
:I WHILE ( a -- a a ) [I] IF SWAP ;I

:I UNTIL ( a -- ) EMPLOY _IF RESOLVE ;I
:I AGAIN ( a -- ) EMPLOY _ELSE RESOLVE ;I
:I REPEAT ( a a -- ) [I] AGAIN [I] THEN ;I

( defining words ============================================ )

ALSO ASM86

: C@-T ( a -- n ) [O] C@ ;  : C!-T ( n a -- ) [O] C! ;
: C,-T ( n -- ) [O] C, ;    : HERE-T ( -- a ) [O] HERE ;

  ' C@-T 'C@ !  ' C!-T   'C!   ! ( vectored for assembler )
  ' C,-T 'C, !  ' HERE-T 'HERE !

: TASM ( -- ) ALSO ASM86  !ASM ;

DEFINITIONS

: next, ( -- ) EVOKE NEXT1 jmp ;
: END-CODE ( -- ) PREVIOUS ;

ROOT

:O EQU ( n 'name' -- ) CONSTANT ;O
:O LABEL ( 'name' -- ) [O] HERE [O] EQU ;O

:O CODE ( 'name' -- ) CODE-T TASM ;O
:O PROC ( 'name' -- ) [O] LABEL TASM ;O

: DUO ( 'name' -- ) >IN @ LIST-T >IN ! ;

:O CREATE ( 'name' -- ) DUO  EMPLOY _VAR  [O] LABEL ;O
:O VARIABLE ( 'name' -- ) [O] CREATE 0 [O] , ;O
:O USER ( n 'name' -- ) DUO  EMPLOY _USR  DUP [O] EQU [O] , ;O
:O CONSTANT ( n 'name' -- ) DUO  EMPLOY _CON  DUP [O] EQU [O] , ;O

( magic ===================================================== )

:O ( [COMPILE] ( ;O   :I ( [O] ( ;I
:O \ [COMPILE] \ ;I   :I \ [O] \ ;I
:O .( CR 2 SPACES [COMPILE] .( ?CSP-T ;O  :I .( [O] .( ;I

:O B#  2 X# #O ;O   :I B#  2 X# #I ;I ( binary )
:O D# 10 X# #O ;O   :I D# 10 X# #I ;I ( decimal )
:O H# 16 X# #O ;O   :I H# 16 X# #I ;I ( hex )

:O DUP DUP ;O   :O DROP DROP ;O :O SWAP SWAP ;O :O OVER OVER ;O
:O + + ;O       :O - - ;O       :O * * ;O       :O / / ;O
:O AND AND ;O   :O OR OR ;O     :O XOR XOR ;O   :O . . ;O
:O MIN MIN ;O   :O MAX MAX ;O
:O INVERT INVERT ;O             :O NEGATE NEGATE ;O
:O CHAR CHAR ;O :I [CHAR] [O] CHAR [I] LITERAL ;I
:O >ADR ( xt -- a ) ;O          :I >ADR [O] >ADR ;I
:O >BODY ( xt -- a ) [O] >ADR [O] CELL+ [O] CELL+ ;O
:O ROOT ROOT ;O   :O CR CR ;O   :O INCLUDE INCLUDE ;O

( initialize compiler ======================================= )

: META[ ( -- ) ( initialize )
  -1 HEAD? !  0 LAST-T !  0 WASTE !
  H# 0 [O] ORG
  DECIMAL  ?ENDIAN  !CSP-T  [I] [ ;

:O !IMAGE ( u -- ) DUP ALLOC-T  #IMAGE ! ;O

:O ]META ( -- ) ( initialize and save target )
  DECIMAL  ?CSP-T
  [O] HERE  EVOKE DP  [O] ! ( dictionary pointer )
  LAST-T @ EVOKE FORTH-WORDLIST [O] ! ( search order )
  EVOKE VCOLD  EVOKE RESET  1+ [O] ! ( patch reset vector )
  SAVE-T  ROOT
  CR ." Used=" [O] HERE 0 .R  2 SPACES ." Waste=" WASTE @ 0 .R
  CR ." Copyright Bill Muench All rights reserved." ;O

( =========================================================== )

?CSP-T