[net.sources] UNIX FORTH for the VAX

lwt1@aplvax.UUCP (06/22/84)

Here is part 1 of 8 of the source for FORTH for the VAX.
Delete everything thru the "-- cut here --" line, and extract with 'sh':

	sh part1 part2 ... part7

where 'part?' are whatever you've named the files.  Note the copyright
notice at the end of README.  Please let us know how things go.  While
we can't support this software, we'll be posting bug fixes/upgrades to
net.sources as time permits.

Have fun!



						-John Hayes
						 Johns Hopkins University
						 Applied Physics Laboratory
						 ... seismo!umcp-cs!aplvax!lwt1

---------------------------------- cut here ----------------------------------
echo x - META1
cat >META1 <<'!E!O!F'
( METACOMPILER, PART 1 -- ALLOWS METACOMPILATION OF PRIMITIVES )   HEX
 
: METACOMPILER  ;               ( MARK BEGINNING OF METACOMPILER FOR 'FORGET')

( METACOMPILER DATABASE )

VARIABLE OBJLINK                ( OBJECT SYSTEM VOCABULARY POINTER           )
2VARIABLE WDS                   ( OBJECT SYSTEM HEADER LENGTH IN BYTES       )
VARIABLE W0                     ( BASE OF OBJECT DICTIONARY SPACE            )
VARIABLE 'H                     ( OBJECT SYSTEM DICTIONARY POINTER           )
VARIABLE 'R                     ( OBJECT SYSTEM RAM POINTER                  )
VARIABLE RAMOBJECT              ( TRUE=RAM OBJECT, FALSE=PROM OBJECT         )
VARIABLE METASTATE              ( TRUE=METACOMPILE, FALSE=EXECUTE            )
 0 METASTATE !

VARIABLE METAMP                 ( METACOMPILER MAPPING ENABLE/DISABLE        )
: METAMAP  TRUE METAMP ! ;
: NOMETAMAP  FALSE METAMP ! ;
 
VARIABLE WRNMETA                ( METACOMPILER WARNING ENABLE/DISABLE        )
: METAWARN  TRUE WRNMETA ! ;
: NOMETAWARN  FALSE WRNMETA ! ;

VOCABULARY META IMMEDIATE
VOCABULARY HOST IMMEDIATE     HOST DEFINITIONS
 
: VOCSSAVE              ( --- V1 V2 ) ( SAVE VOCABS ON STACK                 )
	 CONTXT @ CURRENT @ ;
 
: VOCSRESTORE           ( V1 V2 --- ) ( UNDO 'VOCSSAVE'                      )
	 CURRENT ! CONTXT ! ;

: PREVIOUS	( --- N )   ( PRODUCES THE CONTENTS OF THE FIRST WORD OF     )
		( THE PARAMETER FIELD OF THE MOST RECENT DEFINTION IN 	     )
		( VOCABULARY META. IF THIS WAS AN 'EMPLACE' DEFINTION, THE   )
		( VALUE RETURNED WILL BE THE TARGET SYSTEM OPCODE OF THE     )
		( EMPLACE WORD. THIS IS USEFUL FOR IMMEDIATING.              )
	VOCSSAVE
	[COMPILE] META DEFINITIONS
	LATEST CFIELD 4 + @ -ROT
	VOCSRESTORE ;

: FIND          ( ADDR[NAME] --- ADDR2 N ) ( DICTIONARY SEARCH               )
		( RESTRICTED TO VOCABULARY 'META'                            )
	 VOCSSAVE >R >R                 ( SAVE CONTEXT, CURRENT ON RET STACK )
	 [COMPILE] META DEFINITIONS     ( SELECT META VOCABULARY             )
	 FIND                           ( SEARCH DICTIONARY                  )
	 R> R> VOCSRESTORE ;            ( RESTORE CURRENT AND CONTEXT        )
 
: HOST-->META   ( --- ) ( UNLINK LATEST ENTRY IN VOCABULARY 'HOST' AND       )
		( RELINK IT INTO VOCABULARY 'META'.                          )
	 VOCSSAVE                       ( SAVE CONTEXT AND CURRENT ON STACK  )
	 [COMPILE] HOST DEFINITIONS     ( SET CONTEXT AND CURRENT TO 'HOST'  )
	 LATEST DUP 6 + @ CURRENT @ !   ( MOVE BACK 'HOST' VOCAB POINTER     )
	 [COMPILE] META DEFINITIONS     ( SET CONTEXT AND CURRENT TO 'META'  )
	 LATEST @ 4D84 =                ( SET LINK OF FIRST ENTRY IN 'META'  )
	 IF 0 ELSE LATEST               ( [I.E., THE ONE AFTER 'META' ITSELF])
	 THEN OVER 6 + !                ( TO 0, ELSE LINK NORMALLY           )
	 CURRENT @ !                    ( MOVE UP 'META' VOCAB POINTER       )
	 VOCSRESTORE ;                  ( RESTORE OLD CURRENT AND CONTEXT    )
 
: METASMUDGE    ( --- ) ( SMUDGE THE MOST RECENT META DEFINITION             )
	 VOCSSAVE
	 [COMPILE] META DEFINITIONS SMUDGE
	 VOCSRESTORE ;
 
: HERE 'H @ ;   ( --- N ) ( RETURN VALUE OF OBJECT DICTIONARY POINTER        )

: RAMHERE       ( --- N ) ( RETURN VALUE OF OBJECT RAM POINTER               )
         RAMOBJECT @ IF HERE ELSE 'R @ THEN ;

: ALLOT         ( N --- ) ( ALLOT 'N' WORDS OF OBJECT DICTIONARY SPACE       )
	 'H +! ;

: RAMALLOT      ( N --- ) ( ALLOT 'N' WORDS OF OBJECT RAM SPACE              )
	 RAMOBJECT @
	 IF ALLOT
	 ELSE 'R +!
	 THEN ;

: RAM           ( N --- ) ( SET RAMOBJECT FLAG TRUE [RAM], INITIALIZE        )
		( 'H, W0 AND 'R TO N, AND ZERO ENTIRE OBJECT DICTIONARY.     )
		( 'H, W0 AND 'R TO N, OBJLINK TO 0, AND ZERO ENTIRE          )
		( OBJECT DICTIONARY.                                         )
         TRUE RAMOBJECT !
         DUP 'H !  DUP W0 !  'R !  0 OBJLINK ! ;
 
: PROM          ( N --- ) ( SET RAMOBJECT FLAG FALSE [PROM], INITIALIZE      )
		( 'H AND W0 TO N, OBJLINK TO 0, OBJECT DICTIONARY TO 0'S.    )
         FALSE RAMOBJECT !
         DUP 'H !  W0 !  0 OBJLINK ! ;
 
: NOHEAD  0 WDS ! ;     ( --- ) ( MAKE NEXT OBJECT DEFINITION HEADLESS       )
: HEADS  8 8 WDS 2! ;   ( --- ) ( FOLLOWING OBJECT DEFINITIONS HAVE HEADS    )
: NOHEADS  0 0 WDS 2! ; ( --- ) ( FOLLOWING OBJECT DEFINITIONS HEADLESS      )
 
( CODE FOR HANDLING META-COMPILATION RANDOM ACCESS FILES ) DECIMAL

VARIABLE BUFFER 1022 FORTH ALLOT HOST
	BUFFER 1024 -1 FILL

VARIABLE DIRTY                          ( TRUE IF BUFFER IS INCONSISTENT     )
 FALSE DIRTY !				( WITH DISK FILE.                    )
 
VARIABLE IMAGE	       			( HOLDS TARGET ADDRESS THAT COR-     )
 -1 IMAGE !				( RESPONDS TO BUFFER.                )

VARIABLE FILED                          ( FILE DESCRIPTOR OF META OBJECT FILE)

: ?FLUSH				( --- )   ( FLUSH BUFFER IF DIRTY    )
					( FLAG SET.                          )
 DIRTY @ IF
    FILED @ IMAGE @ 0 SEEK              ( SEEK POSITION IN FILE FOR BUFFER   )
    BUFFER 1024 FILED @ WRITE DROP 	( WRITE BACK TO DISK )
    FALSE DIRTY !			( BUFFER IS CONSISTENT WITH DISK )
 THEN ;

: GET					( ADDR --- )   ( TRIES TO READ 512 )
					( BYTES FROM DISK AT ADDR AND PUTS )
					( INTO BUFFER.  	           )
 BUFFER 1024 0 FILL			( ZERO BUFFER )
 DUP IMAGE ! 				( RECORD ADDRESS )
 FILED @ SWAP 0 SEEK			( POSITION FILE READ POINTER )
 FILED @ BUFFER 1024 READ DROP ; 	( TRY TO READ 512 BYTES )

HEX
 
: T->R					( ADDR --- ADDR' )   ( TRANSLATES )
					( TARGET ADDRESS IN ADDRESS IN    )
					( BUFFER. DOES BUFFER FLUSHING    )
					( AND READING IF NECESSARY.       )
 20 +					( SKIP A.OUT HEADER )
 DUP 3FF AND SWAP FC00 AND 		( OFFSET 512*BLOCK# )
 DUP IMAGE @ = IF			( IF ALREADY IN RAM )
    DROP				( DO NOTHING )
 ELSE
    ?FLUSH GET				( ELSE GET NEEDED BLOCK )
 THEN BUFFER + ;

: C@					( ADDR --- BYTE )
 T->R C@ ;

: C!					( BYTE ADDR --- )
 T->R C! TRUE DIRTY ! ;

: @					( ADDR --- WORD )
 DUP 1+ C@ 8 ROTATE			( FETCH HIGH BYTE FIRST )
 SWAP C@ OR ;				( THEN FETCH LOW BYTE )

: !					( WORD ADDR --- )
 >R DUP FF AND R@ C!			( STORE LOW BYTE )
 FF00 AND 8 ROTATE R> 1+ C! ;		( STORE HIGH BYTE )

: ,					( WORD --- )
 HERE ! 2 ALLOT ;

: C,					( BYTE --- )
 HERE C! 1 ALLOT ;

: EMPLACE       ( --- ) ( LOGS AND CREATES A WORD WHOSE PARAMETER FIELD      )
		( CONTAINS THE TARGET ADDRESS OF THE NEXT CODE FIELD IN THE  )
		( TARGET SPACE. WHEN THE WORD IS EXECUTED, THIS VALUE        )
		( [PRESUMABLY THE OPCODE OF THE 'EMPLACED' WORD] IS          )
		( COMPILED INTO THE OBJECT DICTIONARY.                       )
	 HERE FORTH WDS @ +			( HEADER?		     )
	 FORTH METAMP @
	 IF
	    DUP . HERE COUNT TYPE CR		( PRINT CFA[OCTAL] AND NAME  )
	 THEN
	 CREATE , DOES> @ HOST , ;
 
: HEADER        ( --- ) ( CREATES AN OBJECT DICTIONARY ENTRY AND A           )
		( CORRESPONDING 'EMPLACE' ENTRY IN THE HOST VOCABULARY.      )
	 WRNMETA FORTH @ HOST                   ( CHECK METAWARNING FLAG     )
	 IF >IN FORTH @                         ( SAVE INPUT POINTER         )
	 HERE 6 20 FILL 20 WORD HOST FIND       ( SEARCH META FOR NEW WORD   )
	   IF FORTH HERE COUNT TYPE             ( PRINT WARNING IF WORD FOUND)
	     SPACE ." isn't unique [Meta]" CR
	   THEN DROP
	   >IN ! HOST                           ( RESTORE INPUT POINTER      )
	 THEN
	 EMPLACE 			        ( CREATE 'EMPLACE' ENTRY     )
	 WDS FORTH @ HOST                       ( TEST FOR OBJ HDR CREATION  )
	 IF HERE FORTH LATEST @ HOST ,          ( OBJECT HEADER, 1ST WORD    )
	   FORTH LATEST 2+ @ HOST ,             ( OBJECT HEADER, 2ND WORD    )
	   FORTH LATEST 4 + @ HOST ,		( OBJECT HEADER, 3RD WORD    )
	   OBJLINK FORTH @ HOST ,               ( OBJECT LINK FIELD          )
	   OBJLINK FORTH ! HOST                 ( UPDATE PTR TO OBJECT VOCAB )
	 THEN WDS 2+ FORTH @ WDS ! HOST ;       ( RESET TEMP HEADER LENGTH   )
 
: LABEL
  HERE METAMP FORTH @ IF
    DUP .					( PRINT ADDRESS OF LABEL )
    >IN @ 					( PEEK AHEAD INTO INPUT STREAM )
    20 WORD COUNT TYPE ."  Label" CR
    >IN !
  THEN 
  CONSTANT HOST ;

: '		( --- CFA <OR> 0 )   ( RETURNS CFA OF TARGET WORD THAT FOLLOWS)
 FORTH HERE 6 20 FILL
 HOST 20 WORD FIND
 IF 4 + FORTH @ HOST
 ELSE DROP 0
 THEN ;
 
: DUMPOBJ       ( ADDR N --- ) ( DUMPS N WORDS OF OBJECT SPACE FROM ADDR     )
         CR OVER + SWAP
	 DO
 	    I 4 U.LZ ." :" SPACE
	    I 8 + I DO
	       I C@ 2 U.LZ SPACE
	    LOOP
	    I 8 + I DO
	       I C@ DUP 20 < OVER 7F = OR
	       IF DROP 2E THEN
	       EMIT
            LOOP
	    CR
	 8 +LOOP ;

( CODE FOR CLEANING UP AFTER A METACOMPILATION )

VARIABLE A.OUT				( A.OUT HEADER )
 FORTH 107 A.OUT ! 0 , 0 , 0 , 0 , 0 , 0 , 0 , 
               0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , HOST

: CLEANUP				( FREE_DICT_SIZE --- )   ( CLEANS UP )
					( AFTER A METACOMPILATION. MAKES     )
					( DISK IMAGE FILE GROW UNTIL IT HAS  )
					( AT LEAST THE FREE_DICT_SIZE ASKED  )
					( FOR. WRITES THE A.OUT HEADER OUT.  )
 HERE + 20 + 400 + FC00 AND		( COMPUTE UPPER LIMIT DISK ADDRESS )
 HERE 20 +				( COMPUTE LOWER LIMIT DISK ADDRESS )
    DO 0 , LOOP				( GROW DICTIONARY )
 ?FLUSH
 HERE A.OUT 4 + FORTH !			( SIZE OBJECT SIZE IN A.OUT )
 FILED @ 0 0 SEEK			( REWIND FILE )
 A.OUT 20 FILED @ WRITE DROP		( WRITE A.OUT HEADER TO DISK )
 FILED @ CLOSE HOST ;

!E!O!F
echo x - META2
cat >META2 <<'!E!O!F'
( METACOMPILER, PART 2 -- ALLOWS METACOMPILATION OF : DEFINITIONS, )   HEX
(                         VARIABLES AND CONSTANTS IN A SINGLE VOCABULARY     )
 
: ]             ( --- ) ( MAIN METACOMPILER INTERPRETATION LOOP              )
         TRUE METASTATE FORTH !
	 BEGIN
	    FORTH >IN @ 20 WORD SWAP >IN !
	    C@ METASTATE @ AND WHILE
	    HERE 6 20 FILL 20 WORD HOST FIND IF 
	       EXECUTE
	    ELSE
	       NUMBER IF
	          META (LITERAL) HOST ,
	       ELSE
	          FORTH HERE COUNT TYPE ."  ? [Meta]" CR ENDINTERP
               THEN
	    THEN
	    ?STACK IF ."  Stack empty [Meta]" CR ENDINTERP THEN
	 REPEAT ; HOST
 
: FLOAD         ( --- ) ( METACOMPILER LOADER; CONTINUES META : DEFINITIONS  )
	 0 OPEN
	 DUP 0< IF
	    DROP ."  can't open" CR
	 ELSE
	    >R BEGIN
	       R@ FQUERY WHILE
	       METASTATE FORTH @ HOST IF
	          ]
	       THEN INTERPRET
	    REPEAT R> CLOSE CHUCKBUF
	 THEN ;
 
( METACOMPILER DIRECTIVES )
 
: (  29 WORD DROP ;   HOST-->META       ( START OF COMMENT                   )
: [                                     ( --- ) ( EXIT METACOMPILER LOOP ']' )
         FORTH FALSE METASTATE ! HOST ;   HOST-->META
: IF  META ?BRANCH  HOST HERE 0 , ;   HOST-->META
: WHILE  META IF HOST ;   HOST-->META
: ELSE  META BRANCH  HOST HERE 0 ,  HERE ROT ! ;   HOST-->META
: THEN  HERE SWAP ! ;   HOST-->META
: DO  META (DO)  FORTH CLUE @ 0 CLUE !  HOST HERE ;   HOST-->META
: LOOP  META (LOOP)  HOST , 
 FORTH CLUE @ ?DUP IF HOST HERE SWAP ! THEN
 FORTH CLUE ! HOST ;   HOST-->META
: +LOOP  META (+LOOP)  HOST ,
 FORTH CLUE @ ?DUP IF HOST HERE SWAP ! THEN
 FORTH CLUE ! HOST ;   HOST-->META
: LEAVE META (LEAVE)  HOST HERE FORTH CLUE ! HOST 0 , ;   HOST-->META
: BEGIN  HERE ;   HOST-->META
: UNTIL  META ?BRANCH  HOST , ;   HOST-->META
: AGAIN  META BRANCH  HOST , ;   HOST-->META
: REPEAT  META BRANCH  HOST SWAP ,  HERE SWAP ! ;   HOST-->META

: ;  META (;)  HOST HOST-->META 
	 FORTH FALSE METASTATE ! HOST ;   HOST-->META
 
( METACOMPILER IMMEDIATOR )
 
: IMMEDIATE       ( --- ) ( TOGGLES IMMEDIATE BIT IN LATEST TARGET HEAD)
	 PREVIOUS NFIELD DUP C@ 80 OR
	 SWAP C! ; 

( DEFINING WORDS )

: \CONSTANT     ( N --- ) ( DEFINES THE NEXT INPUT WORD AS A CONSTANT        )
		( 'N' IN THE RESIDENT SYSTEM'S CURRENT VOCABULARY            )
		( WITHOUT MOVING THE INPUT POINTER '>IN'.                    )
         >IN FORTH @  SWAP CONSTANT  >IN ! ;   HOST
 
: CONSTANT
	 DUP \CONSTANT
	 HEADER META (CONSTANT) HOST  ,  HOST-->META ;
 
: :
	 HEADER META (:) HOST ] ;
 
FORTH : VARIABLE        ( --- ) ( CREATES OBJECT VARIABLE INIT'ED TO 0       )
	 RAMOBJECT FORTH @ HOST
 	 IF HERE CFIELD 2+ \CONSTANT 		        ( RAM VERSION )
	    HEADER META (VARIABLE) HOST 0 , HOST-->META
	 ELSE RAMHERE CONSTANT 2 RAMALLOT	( PROM VERSION )
 	 THEN ;
 
FORTH : 2VARIABLE       ( --- ) ( CREATES OBJECT 2VARIABLE INIT'ED TO 0      )
         VARIABLE
         RAMOBJECT FORTH @ HOST
	 IF 0 ,                                 ( RAM VERSION                )
	 ELSE 2 RAMALLOT                        ( PROM VERSION               )
         THEN ;
!E!O!F

lwt1@aplvax.UUCP (06/22/84)

Here is part 2 of 8 of the source for FORTH for the VAX.
Delete everything thru the "-- cut here --" line, and extract with 'sh':

	sh part1 part2 ... part7

where 'part?' are whatever you've named the files.  Note the copyright
notice at the end of README.  Please let us know how things go.  While
we can't support this software, we'll be posting bug fixes/upgrades to
net.sources as time permits.

Have fun!



						-John Hayes
						 Johns Hopkins University
						 Applied Physics Laboratory
						 ... seismo!umcp-cs!aplvax!lwt1

---------------------------------- cut here ----------------------------------
echo x - METAASM
cat >METAASM <<'!E!O!F'
( FORTH VAX-11 ASSEMBLER ) HEX

: CODE     HEADER HERE 2+ , HOST-->META ;

: PRIM     HEADER HOST-->META ;

: MNEMONIC			( OPCODE --- )   ( DEFINING WORD: AT COMPILE  )
				( TIME, SAVES AN OPCODE; AT RUN-TIME, COMPILES)
				( OPCODE INTO DICTIONARY.		      )
 CREATE FORTH , DOES> @ HOST C, ;

: MODE				( MODE# --- )   ( DEFINING WORD: AT COMPILE  )
				( TIME, SAVES MODE; AT RUN-TIME CATENATE THE )
				( MODE AND REG# AND COMPILES INTO DICTIONARY.)
 CREATE 4 ROTATE FORTH , DOES> @ + HOST C, ;

F CONSTANT PC			( PC REGISTER )

( ADDRESSING MODES )

4 MODE []	5 MODE REG	6 MODE )
7 MODE -(	8 MODE )+	9 MODE *)+
C MODE W(	D MODE *W(

: OFFSET			( OFFSET REG# MODE --- )   ( ASSEMBLES A )
				( DISPLACEMENT OR DISPLACEMENT DEFERRED  )
				( ADDRESSING MODE ACCORDING 'MODE'. IF   )
				( OFFSET WILL FIT IN A BYTE, BYTE OFFSET )
				( IS USED. OTHERWISE WORD OFFSET IS USED.)
 4 ROTATE +
 OVER DUP 80 U< SWAP FF7F U> OR ( WILL OFFSET FIT IN A BYTE? )
 IF C, C, ELSE 20 + C, , THEN ;

: X(				( OFFSET REG# --- )   ( TRIES TO ASSEMBLE A )
				( BYTE OFFSET. OTHERWISE WORD OFFSET IS USED)
 A OFFSET ;

: *X(				( OFFSET REG# --- )   ( TRIES TO ASSEMBLE A )
				( BYTE OFFSET. OTHERWISE WORD OFFSET IS USED)
 B OFFSET ;

: B$				( BYTE --- )   ( ASSEMBLE AN IMMEDIATE BYTE. )
				( IF POSSIBLE, A SHORT LITERAL IS USED.      )
 DUP 40 U< IF C, ELSE 8F C, C, THEN ;

: W$				( WORD --- )   ( ASSEMBLE AN IMMEDIATE WORD. )
				( IF POSSIBLE, A SHORT LITERAL IS USED.      )
 DUP 40 U< IF C, ELSE 8F C, , THEN ;

: L$				( WORD --- )   ( ASSEMBLE AN IMMEDIATE LONG. )
				( IF POSSIBLE, A SHORT LITERAL IS USED.      )
 DUP 40 U< IF C, ELSE 8F C, S->D SWAP , , THEN ;

: *$				( ADDR --- )   ( AN ABSOLUTE ADDRESS IS AS- )
				( SEMBLED AS A LONG WORD.		    )
 9F C, , 0 , ;

: REL				( ADDR --- )   ( PC WORD RELATIVE ADDRESS IS )
				( ASSEMBLED. NO ATTEMPT IS MADE TO COMPACT   )
				( TO BYTE RELATIVE MODE.		     )
 PC W( HERE 2+ - , ;

: *REL				( ADDR --- )   ( PC WORD RELATIVE ADDRESS IS )
				( ASSEMBLED. NO ATTEMPT IS MAKE TO COMPACT   )
				( TO BYTE RELATIVE MODE.		     )
 PC *W( HERE 2+ - , ;

( LOCAL LABELS:  EIGHT LOCAL LABELS ARE ALLOWED NUMBERED FROM 0 TO 7 )
( ONLY ONE FORWARD BRANCH PER LABEL IS ALLOWED.  ANY NUMBER OF BACK- )
( WARD BRANCHES IS ALLOWED.					     )

VARIABLE LTABLE  FORTH 0 , 8 1- 4 * ALLOT HOST
 LTABLE 8 4 * 0 FILL		( LABEL TABLE )

: FWD				( LABEL# --- )   ( LEAVE ONE BYTE OF SPACE )
				( FOR OFFSET AND LEAVE ADDRESS IN TABLE.   )
 1 ALLOT HERE SWAP 2* 2* LTABLE + 2+ FORTH ! HOST ;

: BACK				( LABEL# --- )   ( ASSEMBLE BYTE OFFSET FROM )
				( ADDRESS IN TABLE AND CURRENT ADDRESS.      )
 2* 2* LTABLE + FORTH @ HOST HERE 1+ - C, ;

: L:				( LABEL# --- )   ( RESOLVE FORWARD BRANCHES, )
				( PURGE TABLE, AND ADD CURRENT ADDRESS.      )
 2* 2* LTABLE + DUP 2+ FORTH @ ?DUP IF	( IF LABEL NEEDS RESOLUTION )
 HOST HERE OVER - SWAP 1- C! THEN
 0 OVER 2+ FORTH !		( OLD LABEL ADDRESS IS DEFUNCT )
 HOST HERE SWAP FORTH ! HOST ;	( CURRENT ADDRESS )

( MNEMONICS )

90 MNEMONIC MOVB	B0 MNEMONIC MOVW	D0 MNEMONIC MOVL
DD MNEMONIC PUSHL	94 MNEMONIC CLRB	B4 MNEMONIC CLRW
D4 MNEMONIC CLRL	8E MNEMONIC MNEGB	AE MNEMONIC MNEGW
CE MNEMONIC MNEGL	92 MNEMONIC MCOMB	B2 MNEMONIC MCOMW
D2 MNEMONIC MCOML	32 MNEMONIC CVTWL    	9B MNEMONIC MOVBWZ
9A MNEMONIC MOVZBL	3C MNEMONIC MOVZWL	91 MNEMONIC CMPB
B1 MNEMONIC CMPW	D1 MNEMONIC CMPL	96 MNEMONIC INCB
B6 MNEMONIC INCW	D6 MNEMONIC INCL	95 MNEMONIC TSTB
B5 MNEMONIC TSTW	D5 MNEMONIC TSTL	A0 MNEMONIC ADDW2
A1 MNEMONIC ADDW3	C0 MNEMONIC ADDL2	A2 MNEMONIC SUBW2
A3 MNEMONIC SUBW3	C2 MNEMONIC SUBL2	97 MNEMONIC DECB
B7 MNEMONIC DECW	D7 MNEMONIC DECL	C4 MNEMONIC MULL2
C5 MNEMONIC MULL3	CD MNEMONIC XORL3
7B MNEMONIC EDIV	A8 MNEMONIC BISW2	A9 MNEMONIC BISW3
C8 MNEMONIC BISL2	C9 MNEMONIC BISL3	AA MNEMONIC BICW2
AB MNEMONIC BICW3	CA MNEMONIC BICL2	CB MNEMONIC BICL3
AC MNEMONIC XORW2	78 MNEMONIC ASHL	9C MNEMONIC ROTL
12 MNEMONIC BNEQ	13 MNEMONIC BEQL	14 MNEMONIC BGTR
15 MNEMONIC BLEQ	18 MNEMONIC BGEQ	19 MNEMONIC BLSS
1E MNEMONIC BGTRU	1B MNEMONIC BLEQU	1C MNEMONIC BVC
1D MNEMONIC BVS		1E MNEMONIC BGEQU	1F MNEMONIC BLSSU
1E MNEMONIC BCC		1F MNEMONIC BCS
E8 MNEMONIC BLBS	E9 MNEMONIC BLBC
11 MNEMONIC BRB		F5 MNEMONIC SOBGTR	16 MNEMONIC JSB
05 MNEMONIC RSB		FB MNEMONIC CALLS	17 MNEMONIC JMP
BC MNEMONIC CHMK	3B MNEMONIC SKPC	00 MNEMONIC HALT
04 MNEMONIC RET		DF MNEMONIC PUSHAL	DE MNEMONIC MOVAL
28 MNEMONIC MOVC3

( MACROS )
 
8 CONSTANT PSP		9 CONSTANT IAR			E CONSTANT SP
C CONSTANT AP
 
: EVEN				( --- )   ( FORCE WORD ALIGNMENT )
 HERE 1 AND ALLOT ;

!E!O!F
echo x - README
cat >README <<'!E!O!F'
.TL
Unix-FORTH for the VAX
.AU 
John R. Hayes
.AI
Applied Physics Lab
Johns Hopkins University
.ND
.PP
.bp
.PP
.UL Introduction.
FORTH running under unix is now available.  Typing 'forth'
from the terminal will invoke a FORTH process for you.  This memo describes
the unix specific features of this version of FORTH and how to boot the system.
The last section of 
this document deals entirely with unix-FORTH I/O programming.
.PP
Unix-FORTH is a subset of FORTH-83.  The only place that unix-FORTH
and FORTH-83 diverge is in the implementation of I/O.  It seems natural 
that a unix FORTH should take advantage of unix's elegant I/O structure
even at the cost of standardization.  Therefore, unix-FORTH is a process
that reads commands from its standard input and sends results to its standard
output.  If the standard input is the user's terminal, an interactive FORTH
session results.  Or a file of batch commands can be attached to the 
standard input and executed non-interactively.
.PP
A programmer used to typical FORTH systems will immediately note the
absence of FORTH screens.  FORTH screens are inadequate for managing
anything but the smallest programs and arbitrarily constrain software
modules to be sixteen lines long.  Unix-FORTH uses the unix file system and 
programs are created with any text editor.  Therefore, the entire unix 
toolbox is available for operation on FORTH source files.  Unix-FORTH
provides a set of I/O words that are very similar to their unix system-call
counterparts.  The user can have up to fifteen (system dependent) files
open simultaneously.
This, along with unix-FORTH's I/O implementation, allow the use of nested
loads.
.PP
A number of other enhancements are available to the user of unix-FORTH.
Any program resident in the unix file system can be executed from within
FORTH.  For example, to list the files in your current directory on the line
printer, you would type:
.DS L
     " ls | lpr" SYSTEM
.DE
A new subshell can be spawned
without disturbing your current FORTH environment by typing SHELL.  Typing
a ^C will cause FORTH to execute its warm start code.  This allows you
to terminate a program run amok without killing FORTH.  ^D (eof) will 
terminate the FORTH process.
.PP
.UL Bootstrapping.
Booting FORTH consists of two steps.  First, assemble the bootstrap system
with the command:
.DS L
 as -o bootforth  prim.as os.as
.DE
This will generate a FORTH subset system adequate for metacompiling the actual
system.  Bootforth is an executable
object file of a small FORTH system.  You might want to test it before going
on.
.PP
The second step consists of using  bootforth to metacompile the actual system.
Type:
.DS L
 bootforth <auto | tee map
.DE
auto is a file containing forth commands to control the metacompilation.
map will contain a memory map of the system useful for debugging.  The new
system will be called newforth.  A good test of the new system is to see if 
it can metacompile itself.
.PP
Two possible portability problems exist.  The first is in the a.out format
used.  Our version of unix (4.2BSD) uses:
.DS L
/*
 * Header prepended to each a.out file.
 */
struct exec {
	long	a_magic;	/* magic number */
unsigned long	a_text;		/* size of text segment */
unsigned long	a_data;		/* size of initialized data */
unsigned long	a_bss;		/* size of uninitialized data */
unsigned long	a_syms;		/* size of symbol table */
unsigned long	a_entry;	/* entry point */
unsigned long	a_trsize;	/* size of text relocation */
unsigned long	a_drsize;	/* size of data relocation */
};

#define	OMAGIC	0407		/* old impure format */
#define	NMAGIC	0410		/* read-only text */
#define	ZMAGIC	0413		/* demand load format */

.DE
This information is embedded in META1.  The second problem is in the number
of open files per process allowed by the operating system.  The FILEPOS table
is SYS:ASM must have as many entries as open files allowed by your version
of unix.  There are currently fifteen entries in this table.
.PP
.UL I/O.
The following paragraphs review low-level unix I/O programming.  Some 
previous knowledge is assumed, so you may want to read the low-level I/O
section in "Unix Programming".  Refer to the glossary for an exact description
of how any word behaves.
.PP
Most I/O words use a file descriptor as a parameter instead of the name of 
the file.  A file descriptor is a small non-negative integer that indexs a
unix internal file table.  File descriptors are not the same as the file
pointers used in the C standard I/O library.  The FORTH word READ is typical
in its use of a file descriptor.  The input parameters to READ are the file
descriptor of the file to be read, the address of a receiving buffer, and
the number of bytes to read. READ returns the actual number of bytes read. 
If this is less than the requested number, EOF was encountered or an error
occurred.  The action of WRITE is similar.  All files are accessed sequentially
unless an explicit SEEK command is issued.  The parameters to SEEK are a file
descriptor and a double word file position.
.PP
The OPEN word is used to associate a file name with a file descriptor.  The
parameters to OPEN are the address of a file name text string and a file 
mode.  The string must be null terminated instead of a standard FORTH
counted string.  Unix-FORTH provides some useful words for handling null
terminated strings.  These are described below.  The file mode can be 
0=read-only, 1=write-only, and 2=read-write.  OPEN either returns a file 
descriptor that will be used for accessing the file or returns a -1 indicating
an error of some sort.  Since there are a finite number of file descriptors
per process, the programmer should CLOSE unneeded files to free
file descriptors.  The parameter to CLOSE is a file descriptor.
.PP
To create a new file, the CREAT word is available.  The parameters are the
address of a file name text string and a protection mode bit mask.  The file
is created and opened for writing.  If the file already exists, its length is
truncated to zero.  CREAT returns either a file descriptor or a -1 indicating
an error.
.PP
When the FORTH process is started, three files with file descriptors 0, 1,
and 2 have already been opened.  These correspond to the standard input, 
standard output, and standard error.  FORTH expects commands from the standard
input and types results to the standard output.  The standard error file is
not used by FORTH.  Two CONSTANTS, STDIN and STDOUT with values 0 and 1
respectively are pre-defined in unix-FORTH.
.PP
Unix-FORTH has two words, FEXPECT and FQUERY for line oriented input.
FEXPECT's parameters are a file descriptor, the address of a receive buffer,
and the number of characters to read. FEXPECT reads the requested number of
characters unless a newline or an EOF is encountered and returns the number 
of characters actually read. FEXPECT also converts tabs to blanks.
FQUERY is like FEXPECT expect that FQUERY reads up to 120 characters into 
TIB, the FORTH text input buffer. 
.PP
All FORTH system output goes through the FORTH-83 standard word TYPE.  To
allow FORTH to control redirection of its output, TYPE sends its output
to each file in a table of four file descriptors.  Two words, OUTPUT and
SILENT, are used to edit the table.  Both words use a single file descriptor
as a parameter.  OUTPUT will add the file descriptor to the table if the
table is not already full.  SILENT will remove all instances of its file
descriptor from the table.  As an experiment, try typing:
.DS L
     STDOUT OUTPUT
.DE
.PP
The word FLOAD is used to load FORTH source code.  It's single parameter
is the address of a null terminated string describing the path name of
the desired FORTH file.  There are two words in unix-FORTH for converting
strings in the input stream into null terminated strings. The word " reads
the input stream until a second " is found, moves the string to PAD placing
a null at the end, and returns the address of PAD.  The word "" is a 
compiling version of " to be used inside colon definitions.  The address
of the null terminated string isn't put on the stack until run-time.
Both " and "" are defined in terms of the word STRING.  STRING converts
a counted string to a null terminated string without modifying the counted
string.
.PP
Unix-FORTH maintains a 512 byte block of memory used for buffering the most
recently used read file.  Writing to a file is unbuffered by unix-FORTH.
Due to the read buffering the unix-FORTH file position and the unix maintained
file position can become inconsistent.  This is never a problem with read-only
or write-only files.  However, this can cause loss of data in read-write 
files unless the following simple rule is followed with read-write files.
Always use a SEEK call when switching from reading to writing or from writing
to reading.
.DS L
Copyright 1984 by The Johns Hopkins University/Applied Physics Lab.
Free non-commercial distribution is *encouraged*, provided that:

	1.  This copyright notice is included in any distribution, and
	2.  You let us know that you're using it.

Please notify:

	John Hayes
	JHU/Applied Physics Lab
	Johns Hopkins Road
	Laurel, MD 20707
	(301) 953-5000 x8086

	Usenet:  ... seismo!umcp-cs!aplvax!lwt1


Unix-FORTH was developed under NASA contract NAS5-27000 for the
Hopkins Ultraviolet Telescope, a March 1986 Space Shuttle mission.  (we
hope to take a peek at Halley's comet!)

Written entirely by Wizard-In-Residence John R. Hayes.

* Unix is a trademark of Bell Labs.
.DE

!E!O!F

lwt1@aplvax.UUCP (06/22/84)

Here is part 3 of 8 of the source for FORTH for the VAX.
Delete everything thru the "-- cut here --" line, and extract with 'sh':

	sh part1 part2 ... part7

where 'part?' are whatever you've named the files.  Note the copyright
notice at the end of README.  Please let us know how things go.  While
we can't support this software, we'll be posting bug fixes/upgrades to
net.sources as time permits.

Have fun!



						-John Hayes
						 Johns Hopkins University
						 Applied Physics Laboratory
						 ... seismo!umcp-cs!aplvax!lwt1

---------------------------------- cut here ----------------------------------
echo x - SYS:ASM
cat >SYS:ASM <<'!E!O!F'

( Copyright 1984 by the Johns Hopkins University/Applied Physics Lab	)
( Free non-commercial distribution is *encouraged*, provided that: 	)
(  									)
( 	1.  This copyright notice is included in any distribution, and 	)
( 	2.  You let us know that you're using it. 			)
(  									)
( Please notify: 							)
(  									)
( 	John Hayes 							)
( 	JHU/Applied Physics Lab 					)
( 	Johns Hopkins Road 						)
( 	Laurel, MD 20707 						)
( 	[301] 953-5000 x8086 						)
(  									)
( 	Usenet:  ... seismo!umcp-cs!aplvax!lwt1 			)
(  									)
(  									)
( Unix-FORTH was developed under NASA contract NAS5-27000 for the 	)
( Hopkins Ultraviolet Telescope, a March 1986 Space Shuttle mission.  	)
( We hope to take a peek at Halley's comet!				)
(  									)
( Written entirely by Wizard-In-Residence John R. Hayes. 		)
(  									)
( * Unix is a trademark of Bell Labs. 					)
(  									)

( VAX FORTH ASSEMBLY LANGUAGE NUCLEUS ) HEX
	0 ,			( ENTRY MASK )
JMP -1 *$			( JUMP TO STARTUP CODE: WILL BE BACKPATCHED )

LABEL	rsp0 0 , 0 ,		( INITIAL VALUE OF RETURN STACK POINTER )
LABEL 	in 0 ,			( >IN: INPUT PARSER )
LABEL	initvocab 0 ,		( INITIAL FORTH VOCABULARY )
LABEL 	dp 0 ,			( END OF DICTIONARY POINTER )

	400 RAMALLOT		( 256 BYTE PARAMETER STACK )
LABEL inbuf
	78 RAMALLOT		( 120 BYTE INPUT BUFFER )

( INDIRECT THREADED CODE INNER INTERPRETER )

PRIM (:)			( CALL: SHOULD NOT BE USED IN A COLON DEF. )
 MOVW IAR REG   SP -(
 MOVW 0 REG   IAR REG

LABEL NEXT			( NEXT )
 MOVZWL IAR )+   0 REG
 MOVZWL 0 )+   1 REG
 JMP 1 )

CODE (;)			( RETURN )
 MOVZWL SP )+   IAR REG
 MOVZWL IAR )+    0 REG		( NEXT CODE REPEATED FOR SPEED )
 MOVZWL 0 )+   1 REG
 JMP 1 )

( [VARIABLE], [CONSTANT], AND [DOES>] ARE RUN TIME WORDS AND SHOULD NOT BE )
( USED IN COLON DEFINITIONS.  POINTERS TO THEIR PFA'S SHOULD BE COMPILED   )
( BY A DEFINING WORD.  THIS IS AN ALTERNATIVE TO ;CODE USED IN SOME FORTH  )
( SYSTEMS.								   )

PRIM (VARIABLE)
 MOVW 0 REG   PSP -(
 JMP NEXT REL

PRIM (CONSTANT)
 MOVW 0 )   PSP -(
 JMP NEXT REL

PRIM (DOES>)
 MOVW IAR REG   SP -(
 MOVZWL 0 )+   IAR REG
 MOVW 0 REG   PSP -(
 JMP NEXT REL

( CONTROL FLOW PRIMITIVES )

CODE (LITERAL)
 MOVW IAR )+   PSP -(
 JMP NEXT REL

CODE BRANCH
 1 L: MOVZWL IAR )   IAR REG
 JMP NEXT REL

CODE ?BRANCH
 TSTW PSP )+
 BEQL 1 BACK
 ADDW2 2 W$   IAR REG
 JMP NEXT REL

CODE EXECUTE
 MOVZWL PSP )+   0 REG
 MOVZWL 0 )+   1 REG
 JMP 1 )

CODE (DO)
 ADDW3 2 PSP X(   8000 W$   0 REG
 MOVW 0 REG   SP -(
 SUBW3 0 REG   PSP )+   SP -(
 ADDW2 2 W$   PSP REG
 JMP NEXT REL

CODE (LOOP)
 INCW SP )
 BVC 1 BACK
 ADDL2 4 L$   SP REG
 ADDW2 2 W$   IAR REG
 JMP NEXT REL

CODE (+LOOP)
 ADDW2 PSP )+   SP )
 BVC 1 BACK
 ADDL2 4 L$   SP REG
 ADDW2 2 W$   IAR REG
 JMP NEXT REL

CODE I
 ADDW3 SP )   2 SP X(   PSP -(
 JMP NEXT REL

CODE J
 ADDW3 4 SP X(   6 SP X(   PSP -(
 JMP NEXT REL

CODE (LEAVE)
 ADDL2 4 L$   SP REG
 MOVZWL IAR )   IAR REG
 JMP NEXT REL

( BASIC UNIX SYSTEM INTERFACE )

( LOW LEVEL SYSTEM CALLS )

LABEL _READ	0 ,		( ENTRY MASK )
 CHMK 3 W$
 BCC 1 FWD
 CLRL 0 REG
1 L: RET

LABEL _WRITE	0 ,		( ENTRY MASK )
 CHMK 4 W$
 BCC 1 FWD
 MNEGL 1 L$  0 REG
1 L: RET

LABEL _LSEEK	0 ,		( ENTRY MASK )
 CHMK 13 W$
 BCC 1 FWD
 CLRL 0 REG
1 L: RET

LABEL _CREAT	0 ,		( ENTRY MASK )
 CHMK 8 W$
 BCC 1 FWD
 MNEGL 1 L$   0 REG		( RETURN A -1 IF ERROR )
1 L: RET

LABEL _OPEN	0 ,		( ENTRY MASK )
 CHMK 5 W$
 BCC 1 FWD
 MNEGL 1 L$   0 REG		( RETURN -1 IF ERROR )
1 L: RET

LABEL _CLOSE	0 ,		( ENTRY MASK )
 CHMK 6 W$
 RET

LABEL _EXIT	0 , 		( ENTRY MASK )
 CHMK 1 W$			( SHOULD NEVER RETURN )
 HALT

LABEL _FORK	0 , 		( ENTRY MASK )
 CHMK 2 W$
 BGEQU 1 FWD
 MNEGL 1 L$   0 REG		( ERROR )
 RET
1 L: BLBC 1 REG   2 FWD
 CLRL 0 REG			( RETURN ZERO IF CHILD )
2 L: RET

LABEL _SIGNAL	0 ,		( ENTRY MASK )
 CHMK 30 W$
 BGEQU 1 FWD
 MNEGL 1 L$  0 REG		( ERROR )
1 L: RET

LABEL _WAIT	0 ,		( ENTRY MASK )
 CHMK 7 W$
 BGEQU 1 FWD
 MNEGL 1 L$   0 REG		( ERROR )
 RET
1 L: TSTL 4 AP X(
 BEQL 2 FWD
 MOVL 1 REG   4 AP *X(
2 L: RET

LABEL _EXECVE	0 ,		( ENTRY MASK )
 CHMK 3B W$
 HALT				( SHOULD NEVER BE EXECUTED )

EVEN				( INTERRUPT ROUTINES MUST START AT WORD ADDR )
LABEL vector 0 ,		( SIGINT INTERRUPT SERVICE ROUTINE )
 MOVZWL -1 W$   IAR REG		( MOVE ABORT TO IAR; WILL BE BACKPATCHED )
 PUSHAL vector *$		( PUSH ADDRESS OF INTERRUPT ROUTINE )
 PUSHL 2 L$			( SIGINT )
 CALLS 2 L$   _SIGNAL *$	( IGNORE INTERRUPTS )
 JMP NEXT REL 

( DATA AND CODE FOR SPAWNING OFF SUB-PROCESSES )
 LABEL STATUS 0 , 0 ,		( LONG WORD FOR RECEIVING STATUS FROM WAIT )
 LABEL NAME	622F , 6E69 , 632F , 6873 , 0 ,	( "/bin/csh" )
 LABEL 0ARG	7363 , 68 ,			( "csh" )
 LABEL 1ARG	632D , 0 ,			( "-c" )
 LABEL ARGV	0ARG , 0 , 1ARG , 0 , 0 , 0 ,	( ARGUMENT LIST )
		0 , 0 ,				( LIST TERMINATOR )

CODE SHELL			( --- )   ( SPAWN OFF INTERACTIVE SUB-SHELL )
 CLRL ARGV 4 + *$		( sh WITH NO ARGUMENTS )
0 L:				( SPAWN SUB-PROCESS; SYSTEM SHARES THIS CODE )
 CALLS 0 L$   _FORK *$		( FORK )
 TSTL 0 REG
 BNEQ 1 FWD			( BRANCH IF NOT THE CHILD PROCES )
 PUSHL rsp0 *$			( ENVIRONMENT POINTER )
 PUSHAL ARGV *$			( ADDRESS OF ARGUMENT ARRAY )
 PUSHAL NAME *$			( ADDRESS OF COMMAND NAME )
 CALLS 3 L$   _EXECVE *$	( EXEC CALL; SHOULD NOT RETURN )

1 L:
 PUSHL 1 L$			( SIG_IGN )
 PUSHL 2 L$			( SIGIGT )
 CALLS 2 L$   _SIGNAL *$	( DISABLE INTERRUPTS )
 MOVL 0 REG   2 REG		( SAVE OLD INTERRUPT ADDRESS )
 PUSHAL STATUS *$		( ADDRESS OF STATUS WORD )
 CALLS 1 L$   _WAIT *$		( WAIT )
 PUSHL 2 REG			( OLD INTERRUPT ADDRESS )
 PUSHL 2 L$			( SIGINT )
 CALLS 2 L$   _SIGNAL *$	( RESTORE OLD INTERRUPT STATE )
 JMP NEXT REL 

CODE SYSTEM			( ADDR[STRING] --- )   ( PASS NULL-TERMINATED )
				( STRING TO SHELL FOR EXECUTION.	      )
 MOVZWL 1ARG W$   ARGV 4 + *$	( MOVE POINTER TO "-c" TO ARGUMENT LIST )
 MOVZWL PSP )+   ARGV 8 + *$	( MOVE POINTER TO COMMAND STRING TO LIST )
 BRB 0 BACK			( BRANCH TO CODE TO SPAWN SUB-SHELL )

( 	I/O BUFFER AND CONTROL VARIABLES )

LABEL BLOCK	400 RAMALLOT	( 1024 BYTE INPUT BUFFER )
LABEL SIZE	0 ,		( SIZE OF BUFFER IN BYTES )
LABEL INDEX	0 ,		( CURRENT OFFSET INTO BLOCK )
LABEL FD	0 ,		( FILE DESCRIPTOR OF ASSOCIATED FILE )

( FILE POSITION TABLE : EACH SLOT HAS A 32 BIT FILE OFFSET.  FILE DES- )
( CRIPTOR IS OFFSET INTO TABLE.  THERE ARE 15 SLOTS.		       )

LABEL FILEPOS	0 , 0 ,
		0 , 0 ,
		0 , 0 ,
		0 , 0 ,
		0 , 0 ,
		0 , 0 ,
		0 , 0 ,
		0 , 0 ,
		0 , 0 ,
		0 , 0 ,
		0 , 0 ,
		0 , 0 ,
		0 , 0 ,
		0 , 0 ,
		0 , 0 ,

( SUBROUTINE GETC:  HANDLES ALL INPUT AND DOES BUFFERING  )
(	INPUT: FILE DESCRIPTOR IN R2			  )
(	OUTPUT: CHARACTER OR EOF IN R0			  )
( 	SIDE EFFECTS: R3 IS MODIFIED			  )

LABEL GETC
 CMPW 2 REG   FD REL
 BEQL 1 FWD			( SEEK IF NEW FD IS NOT SAME AS OLD FD )
 MOVW 2 REG   FD REL
 MOVW SIZE REL   INDEX REL	( INDICATE THAT BUFFER IS EMPTY )
 CLRL SP -(			( WHENCE IS START OF FILE )
 PUSHL 2 []   FILEPOS REL	( PUSH FILE POSITION )
 PUSHL 2 REG			( PUSH FILE DESCRITPTOR )
 CALLS 3 L$   _LSEEK REL	( SEEK )
1 L: MOVZWL INDEX REL   3 REG	( R3 HAS INDEX )
 CMPW 3 REG   SIZE REL
 BLSS 2 FWD			( READ FILE IF BUFFER IS EMPTY )
 PUSHL 400 L$			( PUSH BLOCK SIZE )
 PUSHL BLOCK L$			( PUSH ADDRESS OF BLOCK )
 PUSHL 2 REG			( PUSH FILE DESCRIPTOR )
 CALLS 3 L$   _READ REL		( READ )
 MOVW 0 REG   SIZE REL		( SAVE SIZE )
 CLRL 3 REG			( RESET INDEX )
2 L: CMPW 3 REG   SIZE REL
 BEQL 3 FWD			( BRANCH IF END OF FILE )
 INCL 2 []   FILEPOS REL	( UPDATE FILE POSITION )
 MOVZBL BLOCK 3 X(   0 REG	( RETURN CHARACTER )
 INCW 3 REG			( UPDATE INDEX )
 BRB 4 FWD
3 L: MNEGL 1 L$ 0 REG		( RETURN EOF: -1 )
4 L: MOVW 3 REG   INDEX REL	( SAVE INDEX )
 RSB

CODE FEXPECT			( FD ADDR COUNT --- ACTCOUNT )
 MOVZWL 2 PSP X(   4 REG	( BUFFER ADDRESS )
 MOVZWL PSP )+   5 REG		( COUNT )
 BEQL 3 FWD
1 L: MOVZWL 2 PSP X(   2 REG	( FILE DESCRIPTOR )
 JSB GETC REL			( GET NEXT CHARACTER )
 CMPW 0 REG   -1 W$
 BEQL 4 FWD			( LEAVE LOOP ON EOF )
 CMPB 0 REG    09 B$
 BNEQ 2 FWD
 MOVB 20 B$   0 REG		( CHANGE TABS TO BLANKS )
2 L: MOVB 0 REG   4 )+		( SAVE CHARACTER )
 CMPB 0 REG   0A B$
 BEQL 5 FWD			( LEAVE LOOP ON NEW LINE )
 SOBGTR 5 REG   1 BACK		( DECREMENT COUNT AND CONTINUE IF NON-ZERO )
3 L:  4 L:  5 L:
 SUBW2 PSP )+   4 REG		( COMPUTE ACTUAL NUMBER OF CHARACTERS READ )
 MOVW 4 REG   PSP )		( RETURN ACTUAL NUMBER )
 JMP NEXT REL

CODE READ			( FD ADDR COUNT --- ACTCOUNT )
 MOVZWL 2 PSP X(    4 REG	( BUFFER ADDRESS )
 MOVZWL PSP )+   5 REG		( COUNT )
 BEQL 3 FWD
1 L: MOVZWL 2 PSP X(   2 REG	( FILE DESCRIPTOR )
 JSB GETC REL			( GET NEXT CHARACTER )
 CMPW 0 REG   -1 W$
 BEQL 4 FWD			( LEAVE LOOP ON END OF FILE )
 MOVB 0 REG   4 )+		( SAVE CHARACTER )
 SOBGTR 5 REG    1 BACK 	( DECREMENT COUNT AND CONTINUE IF NON-ZERO )
3 L:  4 L:
 SUBW2 PSP )+   4 REG		( COMPUTE ACTUAL NUMBER OF CHARACTERS READ )
 MOVW 4 REG   PSP )		( RETURN ACTUAL COUNT )
 JMP NEXT REL

CODE WRITE			( ADDR COUNT FD --- ACTCOUNT )
 MOVZWL PSP )+   0 REG		( FILE DESCRIPTOR )
 MOVZWL PSP )+   SP -( 		( STACK COUNT )
 MOVZWL PSP )   SP -( 		( STACK ADDRESS )
 PUSHL 0 REG			( STACK FILE DESCRIPTOR )
 CALLS 3 L$   _WRITE REL	( WRITE )
 MOVW 0 REG PSP )		( RETURN ACTUAL COUNT )
 JMP NEXT REL

CODE SEEK			( FD OFFSETL OFFSETH --- )
 MOVW 2 PSP X(   PSP -(
 MOVL PSP )+   0 REG		( OFFSET )
 ADDW2 2 W$   PSP REG
 MOVZWL PSP )+   1 REG		( FILE DESCRIPTOR )
 CMPW 1 REG   FD REL
 BNEQ 1 FWD
 MOVW SIZE REL   INDEX REL	( IF SEEKING BUFFERED FILE, RESET BUFFER )
1 L: MOVL 0 REG   1 []  FILEPOS REL
				( SAVE NEW POSITION IN POSITION TABLE )
 CLRL SP -(			( WHENCE IS START OF FILE )
 PUSHL 0 REG			( OFFSET )
 PUSHL 1 REG			( FD )
 CALLS 3 W$   _LSEEK REL	( SEEK )
 JMP NEXT REL

CODE CREAT			( ADDR[STRING] PMODE --- FD )
 MOVZWL PSP )+   SP -(		( STACK PROTECTION MODE )
 MOVZWL PSP )   SP -(		( STACK ADDRESS OF FILE NAME STRING )
 CALLS 2 W$   _CREAT REL	( CREAT SYSTEM CALL )
 MOVW 0 REG   PSP )		( RETURN FILE DESCRIPTOR )
 BLSS 1 FWD			( SKIP IF CREATION FAILED )
 CLRL 0 [] FILEPOS REL		( SET FILE POSITION TO ZERO )
1 L: JMP NEXT REL

CODE OPEN			( ADDR[STRING] MODE --- FD )
 MOVZWL PSP )+   SP -(		( STACK MODE )
 MOVZWL PSP )   SP -(		( STACK ADDRESS OF FILE NAME )
 CALLS 2 W$   _OPEN REL		( OPEN )
 MOVW 0 REG   PSP )		( RETURN FILE DESCRIPTOR )
 BLSS 1 FWD			( SKIP IF OPEN FAILED )
 CLRL 0 []   FILEPOS REL	( RESET FILE POSITION )
1 L: JMP NEXT REL

CODE CLOSE			( FD --- )
 MOVZWL PSP )+   SP -(		( STACK FILE DESCRIPTOR )
 CALLS 1 W$   _CLOSE REL	( CLOSE )
 JMP NEXT REL

CODE TERMINATE			( --- )
 CLRL SP -(			( RETURN GOOD STATUS )
 CALLS 1 W$   _EXIT REL		( EXIT )
 JMP NEXT REL				( SHOULD NEVER BE EXECUTED )

( HIGH LEVEL UTILITIES WRITTEN IN ASSEMBLY LANGUAGE FOR SPEED )

CODE (FIND)			( ADDR[WORD] ADDR[VOCAB] --- 0 <OR> NFA )
 MOVZWL PSP )+   0 REG
 BEQL 3 FWD
 MOVZWL PSP )   1 REG
 MOVL 1 )   2 REG
1 L: BICL3 80 L$   0 )   3 REG
 CMPL 2 REG   3 REG
 BNEQ 2 FWD
 CMPW 4 1 X(   4 0 X(
 BEQL 4 FWD
2 L: MOVZWL 6 0 X(   0 REG
 BNEQ 1 BACK
3 L:
4 L: MOVW 0 REG  PSP )
 JMP NEXT REL

CODE WORD			( DEL --- ADDR )
 CLRL 1 REG
 ADDW3 inbuf W$   in REL   1 REG
 SKPC PSP )   100 W$   1 )
 MOVZWL PSP )   0 REG
 MOVZWL dp REL   2 REG
 MOVW 2 REG   PSP )
 MOVL 1 REG   3 REG
1 L: CMPB 0 REG   3 )
 BEQL 2 FWD
 CMPB 0A B$   3 )
 BEQL 3 FWD
 INCW 3 REG
 BRB 1 BACK
2 L:
3 L: SUBW2 1 REG   3 REG
 MOVB 3 REG   2 )+
 BEQL 5 FWD
4 L: MOVB 1 )+   2 )+
 SOBGTR 3 REG   4 BACK
5 L: CMPB 0A B$   1 )
 BEQL 6 FWD
 INCW 1 REG
6 L: SUBW3   inbuf W$   1 REG   in REL
 MOVB 20 B$   2 )
 JMP NEXT REL

( STACK PRIMITIVES )

CODE !
 MOVZWL PSP )+   0 REG
 MOVW PSP )+   0 )
 JMP NEXT REL

CODE !SP
 MOVZWL PSP )   PSP REG
 JMP NEXT REL

CODE +
 ADDW2 PSP )+   PSP )
 JMP NEXT REL

CODE +!
 MOVZWL PSP )+   0 REG
 ADDW2 PSP )+   0 )
 JMP NEXT REL

CODE -
 SUBW2 PSP )+   PSP )
 JMP NEXT REL

CODE -1
 MNEGW 1 W$   PSP -(
 JMP NEXT REL

CODE 0
 CLRW PSP -(
 JMP NEXT REL

CODE 0<
 CLRW 0 REG
 TSTW PSP )
 BGEQ 1 FWD
 MNEGW 1 W$   0 REG
1 L: MOVW 0 REG   PSP )
 JMP NEXT REL

CODE 0=
 CLRW 0 REG
 TSTW PSP )
 BNEQ 1 FWD
 MNEGW 1 W$   0 REG
1 L: MOVW 0 REG   PSP )
 JMP NEXT REL

CODE 1
 MOVW 1 W$   PSP -(
 JMP NEXT REL

CODE 1+
 INCW PSP )
 JMP NEXT REL

CODE 1-
 DECW PSP )
 JMP NEXT REL

CODE 2
 MOVW 2 W$   PSP -(
 JMP NEXT REL

CODE 2+
 ADDW2 2 W$   PSP )
 JMP NEXT REL

CODE 2-
 SUBW2 2 W$   PSP )
 JMP NEXT REL

CODE 2*
 MOVW PSP )   0 REG
 ASHL 1 B$   0 REG   0 REG
 MOVW 0 REG   PSP )
 JMP NEXT REL

CODE 2/
 CVTWL PSP )   0 REG
 ASHL -1 B$   0 REG   0 REG
 MOVW 0 REG   PSP )
 JMP NEXT REL

CODE <
 CLRW 0 REG
 CMPW PSP )+   PSP )
 BLEQ 1 FWD
 MNEGW 1 W$   0 REG
1 L: MOVW 0 REG    PSP )
 JMP NEXT REL

CODE =
 CLRW 0 REG
 CMPW PSP )+   PSP )
 BNEQ 1 FWD
 MNEGW 1 W$   0 REG
1 L: MOVW 0 REG   PSP )
 JMP NEXT REL

CODE >
 CLRW 0 REG
 CMPW PSP )+   PSP )
 BGEQ 1 FWD
 MNEGW 1 W$   0 REG
1 L: MOVW 0 REG   PSP )
 JMP NEXT REL

CODE >R
 MOVW PSP )+   SP -(
 JMP NEXT REL

CODE @
 MOVZWL PSP )   0 REG
 MOVW 0 )   PSP )
 JMP NEXT REL

CODE @SP
 MOVW PSP REG   0 REG
 MOVW 0 REG   PSP -(
 JMP NEXT REL

CODE AND
 MCOMW PSP )+   0 REG
 BICW2 0 REG   PSP )
 JMP NEXT REL

CODE C!
 MOVZWL PSP )+   0 REG
 MOVB PSP )+   0 )
 INCW PSP REG
 JMP NEXT REL

CODE C@
 MOVZWL PSP )   0 REG
 MOVBWZ  0 )   PSP )
 JMP NEXT REL

CODE CMOVE
 MOVZWL PSP )+  2 REG
 BEQL 2 FWD
 MOVZWL PSP )   0 REG
 MOVZWL 2 PSP X(   1 REG
1 L: MOVB 1 )+   0 )+
 SOBGTR 2 REG   1 BACK
2 L: ADDW2 4 W$   PSP REG
JMP NEXT REL

CODE D+
 MOVW 2 PSP X(   PSP -(
 MOVW 8 PSP X(   4 PSP X(
 ADDL2 PSP )+   PSP )
 MOVW PSP )+   2 PSP X(
 JMP NEXT REL

CODE DNEGATE
 MOVW 2 PSP X(   PSP -(
 MNEGL PSP )  PSP )
 MOVW PSP )+   2 PSP X(
 JMP NEXT REL

CODE D<
 MOVW 2 PSP X(   PSP -(
 MOVW 8 PSP X(   4 PSP X(
 CLRW 0 REG
 CMPL PSP )+   PSP )+
 BLEQ 1 FWD
 MNEGW 1 W$   0 REG
1 L: MOVW 0 REG   PSP )
 JMP NEXT REL

CODE DROP
 ADDW2 2 W$   PSP REG
 JMP NEXT REL

CODE DUP
 MOVW PSP )   PSP -(
 JMP NEXT REL

CODE M*				( S1 S3 --- [S1*S2]L [S1*S2]H )
 CVTWL PSP )+   0 REG
 CVTWL PSP )   1 REG
 MULL3 0 REG   1 REG   PSP -(
 MOVW PSP )+   2 PSP X(
 JMP NEXT REL

CODE M/				( SDL SDH DIV --- REM QUOT )
 CVTWL PSP )   0 REG		( DIVISOR IS IN R0 )
 MOVW 4 PSP X(   PSP )
 CLRL 2 REG
 MOVL PSP )+   1 REG
 BGEQ 1 FWD
 DECL 2 REG			( SIGNED QUADWORD DIVIDEND IS IN R1,R2 )
1 L: XORL3 2 REG   0 REG   3 REG	( SIGN IS IN R3 )
 EDIV 0 REG   1 REG   4 REG   5 REG
 TSTL 3 REG
 BGEQ 2 FWD			( BRANCH IF SIGN IS NOT NEGATIVE )
 TSTL 5 REG
 BEQL 3 FWD			( BRANCH IF REMAINDER IS ZERO )
 DECL 4 REG			( SUBTRACT ONE FROM QUOTIENT )
 ADDL2 0 REG   5 REG		( ADD DIVISOR TO REMAINDER )
2 L:  3 L:
 MOVW 5 REG   PSP )		( REMAINDER )
 MOVW 4 REG   PSP -(		( QUOTIENT )
 JMP NEXT REL

CODE NEGATE
 MNEGW PSP )   PSP )
 JMP NEXT REL

CODE NOT
 MCOMW PSP )   PSP )
 JMP NEXT REL

CODE OR
 BISW2 PSP )+   PSP )
 JMP NEXT REL

CODE OVER
 MOVW 2 PSP X(   PSP -(
 JMP NEXT REL

CODE R>
 MOVW SP )+   PSP -(
 JMP NEXT REL

CODE R@
 MOVW SP )   PSP -(
 JMP NEXT REL

CODE RESET
 MOVL rsp0 REL   SP REG
 JMP NEXT REL

CODE ROT
 MOVW 4 PSP X(   0 REG
 MOVW 2 PSP X(   4 PSP X(
 MOVW PSP )   2 PSP X(
 MOVW 0 REG   PSP )
 JMP NEXT REL

CODE ROTATE
 BICW3 FFF0 W$   PSP )   0 REG
 MOVW 2 PSP X(   PSP )
 MOVL PSP )   1 REG
 ADDW2 2 W$   PSP REG
 ROTL 0 REG   1 REG   1 REG
 MOVW 1 REG   PSP )
 JMP NEXT REL

CODE SWAP
 MOVW 2 PSP X(   0 REG
 MOVW PSP )   2 PSP X(
 MOVW 0 REG   PSP )
 JMP NEXT REL

CODE U<
 CLRW 0 REG
 CMPW PSP )+   PSP )
 BLEQU 1 FWD
 MNEGW 1 W$   0 REG
1 L: MOVW 0 REG   PSP )
 JMP NEXT REL

CODE U>
 CLRW 0 REG
 CMPW PSP )+   PSP )
 BGEQU 1 FWD
 MNEGW 1 W$   0 REG
 1 L: MOVW 0 REG   PSP )
 JMP NEXT REL

CODE UM*
 MOVZWL PSP )+   0 REG
 MOVZWL PSP )   1 REG
 MULL2 1 REG   0 REG
 MOVL 0 REG   PSP -(
 MOVW PSP )+   2 PSP X(
 JMP NEXT REL

CODE UM/
 MOVZWL PSP )   2 REG
 MOVW 4 PSP X(   PSP )
 MOVL PSP )+   3 REG
 CLRL 4 REG
 EDIV 2 REG   3 REG   0 REG   1 REG
 MOVW 1 REG   PSP )
 MOVW 0 REG   PSP -(
 JMP NEXT REL

CODE XOR
 XORW2 PSP )+   PSP )
 JMP NEXT REL

!E!O!F

lwt1@aplvax.UUCP (06/22/84)

Here is part 4 of 8 of the source for FORTH for the VAX.
Delete everything thru the "-- cut here --" line, and extract with 'sh':

	sh part1 part2 ... part7

where 'part?' are whatever you've named the files.  Note the copyright
notice at the end of README.  Please let us know how things go.  While
we can't support this software, we'll be posting bug fixes/upgrades to
net.sources as time permits.

Have fun!



						-John Hayes
						 Johns Hopkins University
						 Applied Physics Laboratory
						 ... seismo!umcp-cs!aplvax!lwt1

---------------------------------- cut here ----------------------------------
echo x - SYS:SRC
cat >SYS:SRC <<'!E!O!F'
( HIGH LEVEL FORTH DEFINITIONS ) HEX

( SYSTEM CONSTANTS AND VARIABLES )

inbuf     CONSTANT TIB 			( START OF TEXT INPUT BUFFER )
inbuf     CONSTANT SP0			( TOP OF PARAMETER STACK AREA )
dp        CONSTANT DP			( CURRENT DICTIONARY POINTER )
in        CONSTANT >IN			( TEXT SCANNER )
initvocab CONSTANT INITVOCAB		( INITIAL FORTH VOCABULARY )
	  VARIABLE WRN			( ENABLE 'NOT UNIQUE' WARNINGS )
          VARIABLE STATE		( INTERPRETATION STATE )
	  VARIABLE BASE			( BASE HEX )
	  VARIABLE CURRENT		( CURRENT VOCABULARY )
	  VARIABLE CONTXT		( CONTEXT VOCABULARY )
          VARIABLE CLUE			( USED FOR COMPILING LEAVE )

0         CONSTANT STDIN		( STANDARD INPUT FILE DESCRIPTOR )
1 	  CONSTANT STDOUT		( STANDARD OUTPUT FILE DESCRIPTOR )
0A	  CONSTANT EOL			( END OF LINE )
-1 	  CONSTANT TRUE			( TRUE )
0	  CONSTANT FALSE		( FALSE )

( CODE EXTENSIONS: THESE ARE LOW LEVEL WORDS THAT MAY BE CANDIDATES )
( FOR REWRITING AS CODE DEFINTIONS.                                 )

: ?DUP   DUP IF DUP THEN ;		( N --- N N <OR> 0 )

: -ROT   ROT ROT ;			( N1 N2 N3 --- N3 N1 N2 )

: *   UM* DROP ;			( N1 N2 --- N1*N2 ) ( SIGNED MULTIPLY )
  
: 2DUP   OVER OVER ;			( N1 N2 --- N1 N2 N1 N2 )

: S->D   DUP 0< ;			( N1 --- DL DH )   ( SIGN EXTEND )

: +-   0< IF NEGATE THEN ;		( N1 N2 --- SIGN[N2]*N1 )

: D+-   0< IF DNEGATE THEN ;		( D1L D1H N1 --- D2L D2H )

: ABS   DUP +- ;			( N --- |N| )

: DABS   DUP D+- ;			( D --- |D| )

: 2DROP   DROP DROP ;			( N1 N2 --- )

: 0>    0 > ;				( N --- T/F )
 
: MAX   2DUP < IF SWAP THEN DROP ;	( N1 N2 --- MAX[N1,N2] )

: MIN   2DUP > IF SWAP THEN DROP ;	( N1 N2 --- MIN[N1,N2] )

: <>   = NOT ;				( N1 N2 --- T/F )

( UNSIGNED MULTIPLCATION AND DIVISITON OPERATORS )

: UM*M					( UL UH MUL --- UL' UH' )
 SWAP OVER UM* DROP >R UM* 0 R> D+ ;

: M/MMOD				( DL DH DIV --- REM QUOTL QUOTH )
 >R 0 R@ UM/ R> SWAP >R UM/ R> ;

: UM/MOD				( DL DH DIV --- REM QUOT )
 M/MMOD DROP ;

( SIGNED MULTIPLICATION AND DIVISION OPERATORS )
 
: /MOD					( N1 DIV --- REM QUOT )
 >R S->D R> M/ ;

: /					( N DIV --- DIVIDEND )
 /MOD SWAP DROP ;

: MOD					( N DIV --- MOD )
 /MOD DROP ;

: */MOD					( N MUL DIV --- REM QUOT )
 >R M* R> M/ ;

: */					( N MUL DIV --- QUOT )
 */MOD SWAP DROP ;

: DEPTH                                 ( --- N )   ( RETURN DEPTH OF STACK )
					( IN WORDS NOT COUNTING N.          )
 @SP SP0 SWAP - 2/ ;

: PICK					( N1 --- N2 )   ( N2 IS A COPY OF THE )
					( N1TH STACK ITEM NOT COUNTING N1.    )
					( 0 PICK IS EQUIVALENT TO DUP.	      )
 2* @SP + 2+ @ ;

: FILL					( ADDR N BYTE --- )
 SWAP ?DUP IF
    >R OVER C!
    DUP 1+ R> 1- CMOVE
 ELSE 2DROP
 THEN ;

: CMOVE>				( ADDR1 ADDR2 U --- )   ( MOVE U BYTES )
					( FROM ADDR1 TO ADDR2. STARTS MOVING   )
					( HIGH ADDRESSED CHARACTERS FIRST.     )
 ?DUP IF
    DUP >R + 1- SWAP DUP R> + 1-
    DO I C@ OVER C! 1- -1 +LOOP
 ELSE DROP
 THEN DROP ;

: ROLL					( <'N' VALUES> N --- <'N' VALUES> )
					( THE NTH STACK ITEM NOT COUNTING )
					( N ITSELF IS TRANSFERRED TO THE  )
					( TOP OF THE STACK, MOVING THE RE-)
					( MAINING VALUES INTO THE VACATED )
					( POSITION. 0 ROLL IS A NOP.      )
 DUP >R PICK
 @SP DUP 2+ R> 1+ 2* CMOVE> DROP ;

: TOGGLE				( ADDR BITS --- )    ( TOGGLE THE IN- )
					( DICATED BITS AT ADDR.               )
 OVER @ XOR SWAP ! ;

: 2!					( DL DH ADDR --- )   ( M[ADDR]<--DH, )
					( M[ADDR+2]<--DL.                    )
 SWAP OVER ! 2+ ! ;

: 2@					( ADDR --- DL DH )   ( DH<--M[ADDR], )
					( DL<--M[ADDR+2].		     )
 DUP 2+ @ SWAP @ ;

: HEX   10 BASE ! ;			( SET BASE TO HEX )
: DECIMAL   A BASE ! ;			( SET BASE TO DECIMAL )
: OCTAL   8 BASE ! ;			( SET BASE TO OCTAL )

( COMPILING WORDS )

: HERE   DP @ ;				( --- ADDR )

: PAD   HERE 50 + ;			( --- ADDR )

: LATEST   CURRENT @ @ ;		( --- ADDR )   ( RETURNS ADDR OF MOST )
					( RECENTLY COMPILED NAME FIELD.       )

: ALLOT   DP +! ;			( BYTECOUNT --- )   ( ALLOT DICTIONARY )

: ,   HERE ! 2 ALLOT ;			( WORD --- )   ( ADD TO DICTIONARY )

: IMMEDIATE   LATEST 80 TOGGLE ;	( --- )   ( MAKE MOST RECENTLY COM- )
					( PILED WORD IMMEDIATE.             )

: SMUDGE   LATEST 40 TOGGLE ;		( --- )   ( SMUDGE MOST  RECENTLY )
					( COMPILED WORD.                  )

: COMPILE
 R> DUP @ , 2 + >R ;

: <MARK					( --- ADDR )   ( USED AS DESTINATION )
					( OF BACKWARD BRANCH.                )
 HERE ;

: <RESOLVE				( ADDR --- )   ( RESOLVE BACKWARD )
					( BRANCH.		          )
 , ;

: >MARK					( --- ADDR )   ( SOURCE OF FORWARD )
					( BRANCH.			   )
 HERE 2 ALLOT ;

: >RESOLVE				( ADDR --- )   ( RESOLVE FORWARD )
					( BRANCH.			 )
 HERE SWAP ! ;

: >>RESOLVE				( OLDLINK --- )   ( RESOLVE A CHAIN )
					( OF FORWARD BRANCHES.		    )
 BEGIN
    DUP WHILE
    DUP @ HERE ROT !
 REPEAT DROP ;

: IF					( --- ADDR )
 COMPILE ?BRANCH >MARK ; IMMEDIATE METASMUDGE

: THEN					( ADDR --- )
 >RESOLVE ; IMMEDIATE METASMUDGE

: ELSE					( ADDR --- ADDR' )
 COMPILE BRANCH >MARK
 SWAP >RESOLVE ; IMMEDIATE METASMUDGE

: BEGIN					( --- ADDR )
 <MARK ; IMMEDIATE METASMUDGE

: UNTIL					( ADDR --- )
 COMPILE ?BRANCH <RESOLVE ; IMMEDIATE METASMUDGE

: AGAIN					( ADDR --- )
 COMPILE BRANCH <RESOLVE ; IMMEDIATE METASMUDGE

: WHILE					( --- ADDR )
 COMPILE ?BRANCH >MARK ; IMMEDIATE METASMUDGE

: REPEAT				( ADDR1 ADDR2 --- )
 COMPILE BRANCH SWAP <RESOLVE >RESOLVE ; IMMEDIATE METASMUDGE

: SEL
 0 ; IMMEDIATE METASMUDGE

: << 					( OLDLINK --- OLDLINK )
 COMPILE DUP ; IMMEDIATE METASMUDGE

: =>					( --- IFADDR )
 COMPILE ?BRANCH >MARK 
 COMPILE DROP ; IMMEDIATE METASMUDGE

: ==>					( --- IFADDR )
 COMPILE =
 COMPILE ?BRANCH >MARK
 COMPILE DROP ; IMMEDIATE METASMUDGE

: >>					( OLDLINK IFADDR --- NEWLINK )
 COMPILE BRANCH SWAP ,
 >RESOLVE 
 HERE 2- ; IMMEDIATE METASMUDGE 

: OTHERWISE				( --- )    ( [OPTIONALLY] COMPILE )
					( AN OTHERWISE CASE.		  )
 COMPILE DUP ; IMMEDIATE METASMUDGE

: ENDSEL				( OLDLINK --- )
 COMPILE DROP >>RESOLVE ; IMMEDIATE METASMUDGE

( THE CODE WORDS [DO], [LOOP], AND [+LOOP] IMPLEMENT FORTH-83 DO..LOOPS. )
( [LEAVE] IS A FORTH-83 LEAVE. CLUE IS USED TO IMPLEMENT LEAVE. IN THIS  )
( VERSION, ONLY ONE LEAVE IS ALLOWED PER LOOP LEVEL.			 )

: DO					( --- CLUE HERE )
 COMPILE (DO) CLUE @ 0 CLUE ! <MARK ; IMMEDIATE METASMUDGE

: LOOP					( CLUE HERE --- )
 COMPILE (LOOP) <RESOLVE
 CLUE @ >>RESOLVE
 CLUE ! ; IMMEDIATE METASMUDGE

: +LOOP					( CLUE HERE --- )
 COMPILE (+LOOP) <RESOLVE
 CLUE @ >>RESOLVE
 CLUE ! ; IMMEDIATE METASMUDGE

: LEAVE					( --- )
 COMPILE (LEAVE) HERE CLUE @ , CLUE ! ; IMMEDIATE METASMUDGE

: EXIT					( --- )   ( EXIT THE CURRENT )
					( COLON DEFINTION. CAN'T BE  )
					( USED INSIDE A LOOP.        )
 R> DROP ;

: [   0 STATE ! ; IMMEDIATE METASMUDGE
: ]   1 STATE ! ;

: (   29 WORD DROP ; IMMEDIATE METASMUDGE

( I/O WORDS: MOST OF THE I/O IS WRITTEN IN ASSEMBLY LANGUAGE )

VARIABLE OUTTABLE			( TABLE OF FILE DESCRIPTORS USED )
					( BY TYPE.			 )
 STDOUT OUTTABLE ! 0 , 0 , 0 ,		( ZERO INDICATES NO FILE )

: FOREACHOUTPUT				( --- ADDR2 ADDR1 )   ( RETURNS UPPER)
					( AND LOWER ADDRESSES OF OUTPUT TABLE)
					( IN FORMAT SUITABLE FOR DO.	     )
 OUTTABLE 8 + OUTTABLE ;

: OUTPUT				( FD --- )   ( ADD THE FILE DESCRIP-  )
					( TOR TO THE OUTPUT TABLE IF THERE IS )
					( ROOM.				      )
 FOREACHOUTPUT DO
    I @ 0= IF DUP I ! LEAVE THEN
 2 +LOOP DROP ;

: SILENT				( FD --- )   ( DELETE THE FILE DES- )
					( CRIPTOR FROM THE OUTPUT TABLE.    )
 FOREACHOUTPUT DO
    DUP I @ = IF 0 I ! THEN
 2 +LOOP DROP ;

: TYPE					( ADDR COUNT --- )   ( SEND COUNT )
					( BYTES TO EACH FILE IN THE OUTPUT)
					( TABLE.			  )

FOREACHOUTPUT DO
    I @ ?DUP IF >R 2DUP R> WRITE DROP THEN
 2 +LOOP 2DROP ;

: EMIT					( CHAR --- )   ( SEND CHARACTER TO )
					( STDOUT.			   )
 @SP 1 TYPE DROP ;

: CR					( --- )   ( SEND NEWLINE CHARACTER )
 EOL EMIT ;

: FQUERY				( FD --- ACTCOUNT )   ( READ ONE   )
					( LINE, UP TO 120 CHARACTERS, FROM )
					( INDICATED FILE. ACTCOUNT IS      )
					( ACTUAL NUMBER OF CHARACTERS READ.)
					( WILL BE ZERO ON END OF FILE.     )
0 >IN ! TIB 78 FEXPECT ;

: COUNT					( ADDR --- ADDR+1 LEN )
 DUP 1+ SWAP C@ ;

: ,WORD					( DEL --- )   ( ADD TEXT DELIMITED BY )
					( DEL INTO DICTIONARY. 		      )
 WORD C@ 1+ ALLOT ;

: (.")					( --- )
 R> COUNT 2DUP TYPE + >R ;

: ."
 COMPILE (.") 22 ,WORD ; IMMEDIATE METASMUDGE

FORTH : ."
	 META (.") FORTH
	 22 WORD COUNT DUP HOST C,
	 OVER + SWAP DO
	    I FORTH C@ HOST C, 
	 LOOP ; HOST-->META

: SPACE					( --- )   ( EMIT SPACE )
 20 EMIT ;

: SPACES 				( COUNT --- )
 0 MAX ?DUP IF 0 DO SPACE LOOP THEN ;

: -TRAILING				( ADDR N1 --- ADDR N2 )   ( THE CHAR- )
					( ACTER COUNT OF A STRING BEGINNING   )
					( AT ADDR IS ADJUSTED TO REMOVE TRAIL-)
					( ING BLANKS. IF N1 IS ZERO, THEN N2  )
					( IS ZERO. IF THE ENTIRE STRING CON-  )
					( SISTS OF SPACES, THEN N2 IS ZERO.   )
 DUP IF
    DUP 0 DO
       2DUP + 1- C@ 20 - IF LEAVE ELSE 1- THEN
    LOOP
 THEN ;

: STRING				( ADDR[COUNTED_STRING] ---           )
					(		    ADDR[UNIX_STRING )
 COUNT DUP >R PAD SWAP CMOVE 0 PAD R> + C! PAD ; 

: "					( --- ADDR[STRING] )
 22 WORD STRING ;

: ("")					( --- ADDR[STRING] )
 R> DUP COUNT + >R STRING ;

: ""
 COMPILE ("") 22 ,WORD ; IMMEDIATE METASMUDGE

( DEFINING WORDS )

: CFIELD				( NFA --- CFA )
 8 + ;

: NFIELD				( CFA --- NFA )
 8 - ;

: -IMM					( NFA --- CFA N )   ( GIVEN A NAME )
					( FIELD ADDRESS, CONVERTS TO CODE  )
					( FIELD ADDRESS AND RETURNS A FLAG )
					( N WHICH IS -1 IF THE WORD IS NON-)
					( IMMEDIATE AND 1 IF THE WORD IS   )
					( IMMEDIATE.			   )
 DUP CFIELD -1 ROT C@ 80 AND IF NEGATE THEN ;

: FIND					( ADDR[NAME] --- ADDR2 N )   ( TRIES )
					( TO FIND NAME IN THE DICTIONARY.    )
					( ADDR2 IS ADDR[NAME] AND N IS 0 IF  )
					( NOT FOUND. IF THE NAME IS FOUND,   )
					( ADDR2 IS THE CFA. N IS -1 IF THE   )
					( WORD IS NON-IMMEDIATE AND 1 IF IT  )
					( IS IMMEDIATE.			     )
 DUP CONTXT @ @ (FIND)			( LOOKUP IN CONTEXT VOCABULARY )
 ?DUP IF 				( ADDR[NAME] NFA )
    SWAP DROP -IMM
 ELSE
    DUP LATEST (FIND)			( LOOKUP IN CURRENT VOCABULARY )
    ?DUP IF
       SWAP DROP -IMM
    ELSE
       0				( NOT FOUND )
    THEN
 THEN ;

: '					( --- 0 <> CFA )   ( MOVES NEXT )
					( WORD IN INPUT STREAM TO HERE  )
					( AND LOOKS UP IN CONTEXT AND   )
					( CURRENT VOCABULARIES. RETURNS )
					( CFA IF FOUND, ZERO OTHERWISE. )
 HERE 6 20 FILL				( BLANK HERE AREA )
 20 WORD FIND 0= IF DROP 0 THEN ;

: HEADER				( --- )   ( CREATE DICTIONARY )
					( HEADER FOR NEXT WORD IN     )
					( INPUT STREAM.    	      )
 ' IF
    WRN @ IF
       HERE COUNT TYPE ."  isn't unique" CR
    THEN
 THEN
 HERE 6 ALLOT LATEST , CURRENT @ ! ;

: :
 CURRENT @ CONTXT !			( SET CONTEXT TO CURRENT )
 HEADER COMPILE (:) ] SMUDGE ;

: ;
 COMPILE (;) SMUDGE 0 STATE ! ; IMMEDIATE METASMUDGE

: VARIABLE
 HEADER COMPILE (VARIABLE) 0 , ;

: CONSTANT
 HEADER COMPILE (CONSTANT) , ;

: 2VARIABLE
 VARIABLE 0 , ;

: DOES>
 R> LATEST CFIELD 2+ ! ;

: CREATE
 HEADER COMPILE (DOES>) 0 , DOES> ;

: VOCABULARY
 CREATE HERE 2+ , LATEST ,
 DOES> @ CONTXT ! ;

: DEFINITIONS
 CONTXT @ CURRENT ! ;

: FORTH
 INITVOCAB CONTXT ! ; IMMEDIATE

( FORMATTED OUTPUT ) 

VARIABLE HLD

: HOLD					( CHAR --- )  ( ADD CHARACTER TO )
					( FRONT OF STRING POINTED TO BY  )
					( HLD. 			         )
 -1 HLD +! HLD @ C! ;

: <#					( --- )
 PAD HLD ! ;

: #>					( DL DH --- ADDR COUNT )
 2DROP HLD @ PAD OVER - ;

: SIGN					( SIGN --- )
 0< IF 2D HOLD THEN ;

: # 					( DL DH --- DL' DH' )
 BASE @ M/MMOD ROT 9 OVER < IF 7 + THEN
 30 + HOLD ;

: #S					( DL DH --- 0 0 )
 BEGIN # 2DUP OR 0= UNTIL ;

: D.R					( DL DH FILEDSIZE --- )
 >R SWAP OVER DABS <# #S ROT SIGN #>
 R> OVER - SPACES TYPE ;

: ZEROES				( N --- )   ( EMIT N ZEROES )
 0 MAX ?DUP IF 0 DO 30 EMIT LOOP THEN ;

: D.LZ					( DL DH FIELDSIZE --- )
 >R SWAP OVER DABS <# #S ROT SIGN #>
 R> OVER - ZEROES TYPE ;

: D.					( DL DH --- )
 0 D.R SPACE ;

: .R   >R S->D R> D.R ;			( N FIELDSIZE --- )

: .					( N --- )
 S->D D. ;

: U.R   0 SWAP D.R ;			( N FIELDSIZE --- )

: U.LZ   0 SWAP D.LZ ;			( N FIELDSIZE --- )

: U.   0 D. ;				( N --- )

: ?   @ . ;				( ADDR --- )

: U?   @ U. ;				( ADDR --- )

( UTILITIES )

: [COMPILE]
 ' , ; IMMEDIATE METASMUDGE

: [']
 ' COMPILE (LITERAL) , ; IMMEDIATE METASMUDGE

: LITERAL
 COMPILE (LITERAL) , ; IMMEDIATE METASMUDGE

: .(
 29 WORD COUNT TYPE CR ; IMMEDIATE METASMUDGE

: DUMP
 CR 
 FFFF 0 <# #S #> SWAP DROP -ROT
 FF   0 <# #S #> SWAP DROP -ROT
 OVER + SWAP DO
    I 2 PICK U.LZ ." :" SPACE
    I 8 + I DO
       I C@ OVER U.LZ SPACE
    LOOP 4 SPACES
    I 8 + I DO
       I C@ DUP 20 < OVER 7E > OR
       IF DROP 2E THEN
       EMIT
    LOOP
 CR 8 +LOOP 2DROP ;

: FORGET				( --- )   ( DELETE THE NEXT WORD    )
					( IN THE INPUT STREAM FROM THE COM- )
					( PILATION VOCABULARY.		    )
 HERE 6 20 FILL
 20 WORD LATEST (FIND) ?DUP
 IF DUP DP ! 6 + @ CURRENT @ !
 ELSE HERE COUNT TYPE ."  ?" CR
 THEN ;

( OPERATING SYSTEM SUPPORT WORDS )

: DIGIT					( CHR --- N TRUE <OR> FALSE )
 30 -
 DUP 9 > OVER 11 < AND IF
    DROP FALSE
 ELSE
    DUP 9 U> IF 7 - THEN
    DUP BASE @ 1- U> IF 
       DROP FALSE
    ELSE
       TRUE
    THEN
 THEN ;

: CONVERT				( DL DH ADDR1 --- DL' DH' ADDR2 )
 					( CONVERT CHARACTERS TO NUMBERS )
					( STARTING AT ADDR1 ACCUMULATING)
					( IN D. ADDR2 IS THE ADDRESS OF )
					( THE FIRST UNCONVERTIBLE CHAR. )
 >R BEGIN
    R> 1+ DUP >R C@ DIGIT		( TRY TO CONVERT NEXT DIGIT )
    WHILE >R BASE @ UM*M R> 0 D+
 REPEAT R> ;

: NUMBER				( ADDR --- N TRUE <OR> FALSE )
 DUP 1+ C@ 2D = DUP >R -		( SAVE SIGN ON RETURN STACK )
 0 0 ROT CONVERT
 C@ 20 = IF 				( IF SUCCESSFUL )
    DROP R> +- TRUE			( TRUNCATE, APPLY SIGN, RETURN TRUE )
 ELSE
    2DROP R> DROP FALSE			( ELSE RETURN FALSE )
 THEN ;

: ?STACK				( --- T/F )   ( RETURNS TRUE )
					( ON STACK UNDERFLOW.        )
 @SP SP0 > ;

: CHUCKBUF				( --- )   ( FLUSH REST OF INPUT LINE )
 TIB >IN @ + BEGIN
    DUP C@ EOL <>
    WHILE 1+
 REPEAT TIB - >IN ! ;

: ENDINTERP				( --- )   ( RESET STACK POINTER AND )
					( FLUSH REST OF INPUT LINE.         )
 SP0 !SP CHUCKBUF ;

: INTERPRET				( --- )
 BEGIN
    HERE 6 20 FILL
    20 WORD C@ WHILE			( WHILE NOT AT END OF LINE )
    HERE FIND ?DUP IF
       STATE @ + IF EXECUTE ELSE , THEN
    ELSE
       NUMBER IF
          STATE @ IF
             COMPILE (LITERAL) ,
          THEN
       ELSE
          HERE COUNT TYPE ."  ?" CR ENDINTERP
       THEN
    THEN
    ?STACK IF
       ."  Stack empty" CR ENDINTERP
    THEN
 REPEAT ;

: FLOAD					( ADDR[UNIX_STRING] --- )
 0 OPEN
 DUP 0< IF
    DROP ." can't open" CR
 ELSE
    >R BEGIN R@ FQUERY WHILE INTERPRET REPEAT
    R> CLOSE CHUCKBUF
 THEN ;

: QUIT					( --- )
 RESET 0 STATE !			( RESET RETURN STACK; INTERPRET STATE )
 BEGIN
    CR STDIN FQUERY WHILE
    INTERPRET STATE @ 0= IF ."  OK" THEN
 REPEAT CR TERMINATE ;

: ABORT					( --- )
 SP0 !SP QUIT ;

: ABORT"				( T/F --- )  ( PRINTS MESSAGE AND )
					( ABORTS IF FLAG IS TRUE.         )
 COMPILE ?BRANCH >MARK
 COMPILE (.") 22 ,WORD COMPILE ABORT
 >RESOLVE ; IMMEDIATE METASMUDGE

( BACKPATCH )

' ABORT 2+ vector 4 + !			( PATCH INTERRUPT ROUTINE )
HERE 4 !				( PATCH JUMP TO STARTUP CODE )

( STARTUP CODE )

 MOVZWL inbuf W$   PSP REG		( INITIAL PSP )
 PUSHL 1 L$				( SIG_IGN )
 PUSHL 2 L$				( SIGINT )
 CALLS 2 L$   _SIGNAL *$		( DISABLE INTERRUPTS )
 BLBS 0 REG   1 FWD			( BRANCH IF INTERRUPS ALREADY IGNORED )
 PUSHAL vector *$			( PUSH ADDRESS OF INTERRUPT ROUTINE )
 PUSHL 2 L$				( SIGINT )
 CALLS 2 L$   _SIGNAL *$		( CATCH SIGNALS )
1 L: MOVL SP )   0 REG
 INCL 0 REG   INCL 0 REG
 MOVAL 0 [] SP )   rsp0 *$		( SAVE ENVIRONMENT POINTER )
 MOVZWL HERE 8 + W$  IAR REG		( TRICKY; INITIALIZE IAR )
 JMP NEXT REL

( HIGH LEVEL STARTUP CODE )

] HEX   TRUE WRN !   0 CLUE !
 FORTH DEFINITIONS
 CR ." VAX FORTH, version 2.0"
 CR ." (c) 1984 JHU/Applied Physics Lab"
 ABORT
[

( INITILIZE VARIABLES AT COMPILE TIME )

HERE DP !				( INITIAL DP )
OBJLINK FORTH @ HOST initvocab !	( INITIAL VOCABULARY )
!E!O!F

lwt1@aplvax.UUCP (06/22/84)

Here is part 5 of 8 of the source for FORTH for the VAX.
Delete everything thru the "-- cut here --" line, and extract with 'sh':

	sh part1 part2 ... part7

where 'part?' are whatever you've named the files.  Note the copyright
notice at the end of README.  Please let us know how things go.  While
we can't support this software, we'll be posting bug fixes/upgrades to
net.sources as time permits.

Have fun!



						-John Hayes
						 Johns Hopkins University
						 Applied Physics Laboratory
						 ... seismo!umcp-cs!aplvax!lwt1

---------------------------------- cut here ----------------------------------
echo x - auto
cat >auto <<'!E!O!F'
" META1" FLOAD
" METAASM" FLOAD
" newforth"  -1 CREAT CLOSE
" newforth" 2 OPEN DUP . FORTH FILED !
0 WRN ! HOST
0 RAM   HEADS    METAMAP    METAWARN
" SYS:ASM" FLOAD
" META2" FLOAD
" SYS:SRC" FLOAD
DECIMAL 10000 CLEANUP
!E!O!F
echo x - format.c
cat >format.c <<'!E!O!F'
/*	
 *	Use:
 *		format [-l num] [-t file] [file file ... ]
 *
 *	This program formats records of arbitrary size and pretty-prints
 *	them.  Records are delimited by '\'.  A title is printed on each
 *	page and the records are separated by a line of dashes.  Records
 *	are prevented from spanning page boundaries.  The -l flag is used
 *	to specify the number of lines per page of your output device.
 *	The default is 63.  The -t flag is used to specify a file that
 *	contains a title that is to be printed on the top of each page.
 */

#include <stdio.h>

#define MAXLINES 15
#define LINELENGTH 120

	char title[10*LINELENGTH]="";	/* default: no title */
	int titlelen=0;

	int linesppage=63;		/* default: 63 lines per page */

main(argc,argv)
int argc;
char *argv[];
{
	char *s;
	FILE *fp;

	while (--argc>0 && **++argv=='-')
		switch (*(*argv+1)){
			case 't':
				argc--; argv++;
				if ((fp=fopen(*argv,"r"))!=NULL){
					s=title;
					while (fgets(s,LINELENGTH,fp)!=NULL){
						s+=strlen(s);
						titlelen++;
					}
					fclose(fp);
				}
				else fprintf(stderr,
                                        "format: can't open %s\n",*argv);
				break;
			case 'l':
				argc--; argv++;
				if (sscanf(*argv,"%d",&linesppage)==0)
					fprintf(stderr,
                                           "format: %s isn't a number\n",*argv);
				break;
			default:
				fprintf(stderr,
				   "format: bad flag %c\n",*(*argv+1));
				break;
		}
		if (argc>0)
			while (argc-- > 0){
				if ((fp=fopen(*argv,"r"))!=NULL){
					format(fp);
					fclose(fp);
				}
				else
					fprintf(stderr,
                                           "format: can't open %s\n",*argv);
				argv++;
			}
		else
			format(stdin);
}

format(input)
FILE *input;
{
	char buf[MAXLINES*LINELENGTH];
	char *bufp=buf;

	int nextline=0;

	while(fgets(bufp,LINELENGTH,input)!=NULL){
		if(*bufp!='\\'){
			nextline++;
			bufp+=strlen(bufp);
		}
		else {
			*bufp='\0';
			printrec(buf,nextline);
			bufp=buf;
			nextline=0;
		}
	}
}

printrec(lines,nlines)
char *lines;
int nlines;
{
	static int linect=1000;			/* absurd number forces
						   title on first page */

	int i;

	if (nlines+1 > linesppage-linect){
		printf("\f%s",title);
		linect=titlelen;
	}
	for (i=1; i<80; i++) putchar('-');
	printf("\n%s",lines);
	linect+=nlines+1;
}
!E!O!F
echo x - forth.1h
cat >forth.1h <<'!E!O!F'
.TH FORTH 1H
.SH NAME
forth
\- invoke a forth process.
.SH SYNOPSIS
forth
.SH DESCRIPTION
Forth invokes a FORTH-language process.  The process reads commands from the
standard input and sends results to the standard output.  If the standard 
input is a terminal, an interactive forth session results.  This is a subset
of FORTH-83 diverging only in the I/O.
.SH AUTHORS
J. Hayes
!E!O!F

lwt1@aplvax.UUCP (06/22/84)

Here is part 6 of 8 of the source for FORTH for the VAX.
Delete everything thru the "-- cut here --" line, and extract with 'sh':

	sh part1 part2 ... part7

where 'part?' are whatever you've named the files.  Note the copyright
notice at the end of README.  Please let us know how things go.  While
we can't support this software, we'll be posting bug fixes/upgrades to
net.sources as time permits.

Have fun!



						-John Hayes
						 Johns Hopkins University
						 Applied Physics Laboratory
						 ... seismo!umcp-cs!aplvax!lwt1

---------------------------------- cut here ----------------------------------
echo x - glossary
cat >glossary <<'!E!O!F'
!			n addr			-

n is stored at addr.
\
!SP			n			-

Parameter stack pointer is set to n.
\
"			-			addr[string]

Generates a null-terminated string.  Used in the form:
	" string"
Copies the input stream to PAD until a second " is found, places a null at
the end of the string, and returns the address of the string.
\
""			-			addr[string]

Compiling word. Generates a null-terminated string at run time. Used as:
	"" string"
Adds a counted string copied from the input stream to the dictionary. At
run-time, converts the string to a null-terminated string and returns address
of string.
\
#			d1l d1h			d2l d2h

The remainder of d1 divided by the value of BASE is converted to an
ASCII character and appended to the pictured output string growing toward
lower memory addresses.  d2 is the quotient and is maintained for further
processing.  Typically used between <# and #>.
\
#>			dl dh			addr +n

Pictured numeric output conversion is ended dropping d.  addr is the
address of the resulting output string and +n is the length of the string.
\
#S			dl dh			0 0

d is converted appending each resultant character onto the pictured
numeric output string until the quotient is zero.  A single zero is added
to the output string if d is zero.  Typically used between <# and #>.
\
'			-			cfa

Used in the form:
	' <name>
cfa is the compilation address of <name>.  A zero is returned if <name> 
could not be found in the dictionary.
\
(FIND)			addr[name] addr[dict]	0 <or> nfa

Searches the vocabulary whose latest dictionary entry nfa is pointed to
by addr[dict] for the counted string pointed to by addr[name].  Returns
the nfa of the word if found, otherwise a zero is returned.  If addr[dict]
is zero, indicating an empty vocabulary, a zero is returned.
\
(LITERAL)		-			word

Pushes the word pointed to by the IAR onto the parameter stack and adds two
to the IAR.
\
*			w1 w2			w3

w3 is the least-significant 16 bits of the arithmetic product of w1 times
w2.
\
*/			n1 n2 n3		quot

n1 is first multiplied by n2 producing an intermediate 32-bit result. quot
is the floor of the quotient of the intermediate 32-bit result divided by
the divisor n3.  The product of n1 times n2 is maintained as an intermediate 
32-bit result for greater precision than the otherwise equivalent sequence:
n1 n2 * n3 / .  An error condition results if the divisor is zero or if the
quotient falls outside the range {-32768..32767}.
\
*/MOD			n2 n3 n3		rem quot

n1 is first multiplied by n2 producing an intermediate 32-bit result.  quot
is the floor of the quotient of the intermediate 32-bit result divided by the
divisor n3.  A 32-bit intermediate product is used as for */ .  rem has the 
same sign as n3 or is zero.  An error condition results if the divisor is 
zero or if the quotient falls outside of the range {-32768..32767}.
\
+			w1 w2			w3

w3 is the arithmetic sum of w1 and w2.
\
+!			w1 addr			-

w1 is added to the contents of addr.
\
+-			n1 n2			n3

Apply the sign of n2 to n1 to obtain n3.  n3 := sign(n2) * n1.
\
+LOOP			n			-

n is added to the loop index.  If the new index was incremented across
the boundary between limit-1 and limit then the loop is terminated and
loop control parameters are discarded.  When the loop is not terminated,
execution continues just after the corresponding DO.
\
,			n			-

ALLOT one word of space at the end of the dictionary and store n in this
space.
\
,WORD			char			-

Compile text from the input stream delimited by char into the dictionary as
a counted string.  The minimum even number of bytes that will hold the text
is ALLOTted.
\
-			w1 w2			w3

w3 is the result of subrtracting w2 from w1.
\
-1			-			-1

CONSTANT that returns -1.
\
-IMM			nfa			cfa n 

Given a name field address, returns the corresponding code field address
and a flag n which is -1 if the word is non-immediate and 1 if the word
is immediate.
\
-ROT			w1 w2 w3		w3 w1 w2

The top three stack entries are rotated, moving the top entry to the
bottom.  -ROT is the converse of ROT.
\
-TRAILING		addr +n1		addr +n2

The character count +n1 of a text string beginning at addr is adjusted to
exclude trailing spaces.  If +n1 is zero, then +n2 is zero.  If the entire
string consists of spaces, then +n2 is zero.
\
.			n			-

The absolute value of n is displayed in a free field format with leading 
minus sign if n is negative.
\
."			-			-

Compiling word used in the form:
	." cccc"
Later execution will display the character cccc up to but not including the
delimiting " (close-quote).  The blank following ." is not part of cccc.
\
.(			-			-

Immediate word used in the form:
	.( cccc)
The characters cccc up to but not including the delimiting ) (closing paren-
thesis) are displayed.  The blank following .( is not part of cccc.
\
.R			n size			-

Attempts to display n right-justified in a field of size characters.
\
/			n1 n2 			n3

n3 is the floor of the quotient of n1 divided by the divisor n2.  An
error condition results if the divisor is zero or if the quotient falls out-
side of the range {-32768..32767}.
\
/MOD			n1 n2			rem quot

rem is the remainder and quot the floor of the quotient of n1 divided by
the divisor n2.  rem has the same sign as n2 or is zero.  An error condition
results if the divisor is zero or if the quotient falls outside of the range
{-32768..32767}.
\
0			-			0

CONSTANT returns zero.
\
0<			n			flag

flag is true if n is less than zero (negative).
\
0=			n			flag

flag is true if n is zero.
\
0>			n			flag

flag is true if n is greater than zero.
\
1			-			1

CONSTANT returns 1.
\
1+			w1			w2

w2 is w1 + 1 (modulo 65536).
\
1-			w1			w2

w2 is w1 - 1 (modulo 65536).
\
2			-			2

CONSTANT returns 2.
\
2!			dl dh addr		-

Store high word dh at addr and store low word dl at addr+2.
\
2*			w1			w2

w2 is the result of shifting w1 left one bit.  A zero is shifted into the
vacated bit position.
\
2+			w1			w2

w2 is w1 + 2 (modulo 65536).
\
2-			w1			w2

w2 is w1 - 2 (modulo 65536).
\
2/			n1			n2

n2 is the result of arithmetically shifting n1 right one bit.  The sign is
included in the shift and remains unchanged.
\
2@			addr			dl dh

dh is contents of addr, dl is contents of addr+2.
\
2DROP			w1 w2			-

w1 and w2 are dropped from the stack.
\
2DUP			w1 w2			w1 w2 w1 w2

w1 and w2 are duplicated on the stack.
\
2VARIABLE		-			-

A defining word used in the form:
	2VARIABLE <name>
A dictionary entry for <name> is created and four bytes are ALLOTted in its
parameter field.  When <name> is later executed, the address of its parameter
field is placed on the stack.
\
:			-			-

A defining word used in the form:
	: <name>  ... ;
Create a definition for <name> in the compilation vocabulary and sets compil-
ation state.  The search order is changed so that the first vocabulary in the
search order is replaced by the compilation vocabulary.  The compilation
vocabulary is unchanged.  The text from the input stream is subsequently
compiled.  The newly created definition for <name> cannot be found in the
dictionary until the corresponding ; or equivalent operation is performed.
\
;			-			-

Compiling word stops compilation of a colon definition, allow the <name> to
be found in the dictionary; sets interpret state; and compiles (;), a word
functionally equivalent to EXIT.
\
<			n1 n2			flag

flag is true if n1 is less than n2.
\
<#			-			-

Initialize pictured numeric output conversion.   The words:
	# #> #S <# HOLD SIGN
can be used to specify the conversion of a double number into an ASCII text
string stored in right-to-left order.
\
<<			-			-

Immediate word to signal the beginning of a case inside the SELlect case
control structure.  See SEL for an example of how to use the case words.
\
<>			n1 n2			flag

flag is true if n1 is not equal to n2.
\
<MARK			-			addr

Used at the destination of a backward branch.  addr is typically only used
by <RESOLVE to compile a branch address.
\
<RESOLVE		addr			-

Used at the source of a backward branch after either BRANCH or ?BRANCH.
Compiles a branch address using addr as the destination address.
\
=			n1 n2			flag

flag is true if n1 equals n2.
\
==>			-			-

Immediate word separates a case structure equality test from the corresponding
case action.  See SEL for an example of how to use the case words.
\
=>			-			-

Immediate word separates a case structure test from the corresponding case
action.  See SEL for an example of how to use the case words.
\
>			n1 n2			flag

flag is true if n1 is greater than n2.
\
>>			-			-

Immediate word ends a case inside a case SEL control structure.  See SEL for
an example of how to use the case words.
\
>>RESOLVE		addr			-

Resolves a list of multiple forward references.  addr points to the first
element of a linked list.  Each link is stored in the address field of an
unresolved BRANCH or ?BRANCH instruction.  >>RESOLVE threads down the 
list pointing the BRANCHes to HERE.  A null list is indicated by addr equal
to zero.
\
>IN			-			addr

VARIABLE that conatains the present character offset within the input stream.
\
>MARK			-			addr

Used at the source of a forward branch.  Typically used after either BRANCH
or ?BRANCH.  Compiles space in ther dictionary for a branch address which will
later by resolved by >RESOLVE.
\
>R			n			-

Transfers n to the return stack.
\
>RESOLVE		addr			-

Used at the destination of a forward branch.  Places a branch address to HERE
in the space left by >MARK.
\
?			addr			-

The contents of addr are displayed in free field format with a leading minus
sign if negative.
\
?BRANCH			flag			-

When used in the form:  COMPILE ?BRANCH  a conditional branch operation is
compiled.  See BRANCH for further details.  When executed, if flag is false
the branch is performed as with BRANCH.  When flag is true execution continues
at the compilation address immediately following the branch address.
\
?DUP			n			n n <or> 0

n is duplicated if it is non-zero.
\
?STACK			-			flag

flag is true if stack has underflowed.
\
@			addr			n

n is the value at addr.
\
@SP			-			addr

addr is the address of the top stack item before @SP was executed.
\
ABORT			-			-

Clears the data stack and performs the function of QUIT.
\
ABORT"			flag 			-

Immediate word used in the form:
	flag ABORT" cccc"
When later executed, if flag is true, the characters cccc, delimited by "
(close-quote), are displayed and ABORT is executed.  If flag is false, the
flag is dropped and execution continues.  The blank following ABORT" is 
not part of cccc.  This word violates the principles of structured program-
ming and its use should be avoided.
\
ABS			n			u

u is the absolute value of n.  If n is -32768 then u is the same value.
\
AGAIN			-			-

Compiling word used in the form:
	BEGIN ... AGAIN
compiles an infinite loop.
\
ALLOT			w			-

Allocates w bytes in the dictionary.  WARNING: never ALLOT an odd number of 
bytes.
\
AND			n1 n2			n3

n3 is the bit-by-bit logical 'and' of n1 and n2.
\
BASE			-			addr

VARIABLE containing the current numeric conversion radix.
\
BEGIN			-			-

Immediate word marks the start of a word sequence for repetitive execution.
\
BRANCH			-			-

When used in the form:  COMPILE BRANCH  a conditional branch operation is
compiled.  A branch address must be compiled immediately following this
compilation address.  The branch address is typically generated by follow-
ing BRANCH with <RESOLVE, >MARK, or >>RESOLVE.
\
C!			n addr			-

The least significant 8 bits of n are stored into the byte at addr.
\
C@			addr			byte

The byte stored at addr is fetched.
\
CFIELD			nfa			cfa

Converts a name field address to the corresponding code field address.
\
CHUCKBUF		-			-

Flush rest of input buffer by moving >IN to the EOL mark.
\
CLOSE			fd			-

Close the Unix file with given file descriptor.
\
CMOVE			addr1 addr2 u		-

Move u bytes beginning at address addr1 to addr2.  The byte at addr1 is moved
first, proceeding toward high memory.  If u is zero, nothing is moved.
\
CMOVE>			addr1 addr2 u		-

Move the u bytes at address addr1 to addr2.  The move begins by moving the
byte at (addr1 + u - 1) to (addr2 + u - 1) and proceeds to successively 
lower addresses.  If u is zero nothing is moved.
\
COMPILE			-			-

Typically used in the form:
	: <name> ... COMPILE <namex> ... ;
When name is executed, COMPILE compiles the execution address of <namex> into
the dictionary.  Execution continues after <namex>.
\
CONSTANT		n			-

A defining word used in the form:
	n CONSTANT <name>
Creates a dictionary entry for <name> so that when <name> is later executed,
n will be left on the stack.
\
CONTXT			-			addr

addr is the address of a variable that points to the dictionary search
vocabulary.  This word is called CONTEXT in FORTH-83.
\
CONVERT			dl1 dh1 addr1		dl2 dh2 addr2

d2 is the result of converting the characters within the text beginning at 
addr1 + 1 into digits, using the value of BASE, and accumulating each into
d1 after multiplying d1 by the value of BASE.  Conversion continues until
an unconvertible character is encountered.  addr2 is the address of the first
unconvertivle character.
\
COUNT			addr			addr+1 n

Assumes a counted string is stored at addr.  Returns n, the byte stored
at addr, and increments addr.
\
CR			-			-

EMITs a linefeed character.
\
CREAT			addr[string] pmode	fd <or> -1

Try to create a file whose name is pointed to be addr with protection bits
pmode.  The file is opened for writing and the file descriptor is returned.
If the file already exists, its length is truncated to zero.  A -1 is returned
in the event of an error.
\
CREATE			-			-

A defining word used in the form:
	CREATE <name>
Creates a dictionary entry for <name>.  After <name> is created, the next
available dictionary location is the first byte of <name>'s parameter field.
When <name> is subsequently executed, the address of <name>'s parameter field
is left on the stack.  CREATE does not allocate space is <name>'s parameter
field.
\
CURRENT			-			addr

addr is the address of a variable pointing to the vocabulary in which new 
word definitions are appended.
\
D+			d1l d1h d2l d2h		dl3 dh3

d3 is is the arithmetic sum of d1 and d2.
\
D+-			d1l d1h n		d2l d2h

d2 is obtained by applying the sign of n to d1.  d2 := sign(n) * d1.
\
D.			dl dh			-

Print the double precision number d in free field format with a leading
minus sign if necessary.
\
D.LZ			dl dh size		-

Print the double precision number d right-justified in a field of size 
characters with leading zeros appended.
\
D.R			dl dh size		-

Print the double precision number d right-justified in a field of size
characters.
\
D<			d1l d1h d2l d2h		flag

flag is true if d1 is less than d2.
\
DABS			d1l d1h			d2l d2h

d2 is the absolute value of the double precision number d1. If d1 is equal
to -2,147,483,647 then d2 has the same value.
\
DECIMAL			-			-

Set the input-output conversion base to ten.
\
DEFINITIONS		-			-

The compilation vocabulary is changed to be the same as the search vocabulary.
\
DEPTH			-			n

N is the number of 16-bit values contained on the parameter stack before
DEPTH was executed.
\
DIGIT			char			n true <or> false

If char represents a valid digit in the current BASE, it is converted to 
the value n and true is returned.  Otherwise false is returned.
\
DNEGATE			d1l d1h			d2l d2h

d2 is the two's complement of of d1.
\
DO			n1 n2			-

Compiling word used in the form:
	DO ... LOOP  or  DO ... +LOOP
Begins a loop which terminates based on control parameters.  The loop index
begins at n2 and terminates based on the limit n1.  See LOOP and +LOOP
for details on how the loop is terminated.  The loop is always executed at
least once.
\
DOES>			-			addr

Defines the run-time action of a word created by the high-level defining
word CREATE.  Used in the form:
	: <namex> ... <create> ... DOES> ... ;
and then
	<namex> <name>
where <create> is CREATE or any user defined word which executes CREATE.
Marks the termination of the defining part of the defining word <namex>
and then begins the definition of the run-time action for words that will
later be defined by <namex>.  When <name> is later executed, the address
of <name>'s parameter field is placed on the stack and then the sequence
of words between DOES> and ; are executed.
\
DP			-			addr

VARIABLE that has the address of the first free byte at the end of the
dictionary.
\
DROP			n			-

n is DROPped from the stack.
\
DUMP			addr n			-

DUMPs n bytes of memory in pretty format starting at addr.
\
DUP			n			n n

n is DUPlicated on the stack.
\
ELSE			-			-

Immediate word used in the form:
	flag IF ... ELSE ... THEN
At run-time ELSE branches to just after the THEN.
\
EMIT			n			-

The least significant 8 bits of n are sent to the standard output.
\
ENDINTERP		-			-

Reset parameter stack pointer and throw away rest of input line.
\
ENDSEL			-			-

Immediate word ends a case control structure.  See SEL for an example
of how to use the case words.
\
EOL			-			char

CONSTANT defined as newline character (linefeed).
\
EXECUTE			cfa			-

The word definition indicated by cfa is executed.
\
EXIT			-			-

When executed inside a colon defintion, returns control to the definition
that passed control to it.  Cannot be used inside a DO ... LOOP.
\
FALSE			-			false

Places false flag (0) on the stack.
\
FEXPECT			fd addr count		actcount

Reads up to count bytes from the file denoted by file descriptor fd into
the buffer at addr.  Tabs are converted to blanks and encountering a line-
feed or and EOF will terminate the read.  The actual number of bytes read
actcount is returned.
\
FLOAD			addr[string]		-

Attempts to open the file indicated by the null-terminated string 'string'
for reading.  If successful, the text in the file is interpreted until an
EOF is encountered.  If the file can't be opened, a message is printed.
\
FQUERY			fd			actcount

FEXPECTs 120 characters from the file denoted by the file descriptor fd.
The text is placed in TIB, the text input buffer.  The actual number of bytes
read is returned.
\
FILL			addr u byte		-

u bytes of memory beginning at addr are set to byte.  No action is taken if
u is zero.
\
FIND			addr1 			addr2 n

addr1 is the address of a counted name string.  Tries to find the name in the
search vocabulary or in the compilation vocabulary.  If the word is not found, 
addr2 is the string address addr1, and n is zero.  If the word is found, addr2
is the compilation address and n is set to one of two non-zero values.  If
the word found has the immediate attribute, n is set to one.  If the word is
non-immediate, n is set to minus one.
\
FORGET			-			-

Used in the form:
	FORGET <name>
If <name> is found is the compilation vocabulary, delete <name> from the dic-
tionary and all words added to the dictionary after <name> regardless of their
vocabulary.  An error message is printed if <name> is not found.
\
FORTH			-			-

The name of the primary vocabulary.  Execution sets the search vocabulary to
FORTH.
\
HEADER			-			-

Create dictionary header in compilation vocabulary for next word in input
stream.  The header contains only the name field and link field.
\
HERE			-			addr

The address of the next available dictionary location.
\
HEX			-			-

Set the input-output conversion base to hex.
\
HLD			-			addr

VARIABLE holds the address of the last character added to the current
pictured numeric output conversion.
\
HOLD			char			-

char is inserted into a pictured numeric output string.  Typically used
between <# and #>.
\
I			-			n

n is a copy of the loop index.  May only be used in the form:
	DO ... I ... LOOP  or  DO ... I ... +LOOP
\
IF			-			-

Immediate word used in the form:
	flag IF ... ELSE ... THEN  or  flag IF ... THEN
If flag is true, the words following IF are executed and the words following
ELSE until just after THEN are skipped.  The ELSE part is optional.  If flag
is false, words from IF through ELSE, or from IF through THEN (when no ELSE
is used), are skipped.
\
INTERPRET		-			-

Interpret the text in the input buffer until an EOL is encountered.
\
J			-			n

n is a copy of the index of the next outer loop.  May only be used within
a nested DO-LOOP.
\
LATEST			-			nfa

Returns name field address of word most recently added to the compilation
vocabulary.
\
LEAVE			-			-

Transfers execution to just beyond the next LOOP or +LOOP.  The loop is
terminated and loop control parameters are discarded.  May only be used in
the form:
	DO ... LEAVE ... LOOP  or  DO ... LEAVE ... +LOOP
Leave may appear within other control structures which are nested within 
the DO-LOOP structure.  More than one LEAVE may appear within a DO-LOOP.
\
LITERAL			n			-

Immediate word typically used in the form:
	[ n ] LITERAL
compiles n as a literal.  At run-time, n will be put on the stack.
\
LOOP			-			-

Increments the DO-LOOP index by one.  If the new index was incremented 
across the boundary between limit-1 and limit, the loop is terminated and
loop control parameters are discarded.  When the loop is not terminated,
execution continues to just after the corresponding DO.
\
M*			n1 n2			dl dh

The signed numbers n1 and n2 and are multiplied to obtain the signed double
precision number d.
\
M/			dl dh divisor		rem quot

Signed mixed mode floored division. d is 32 bits.
\
M/MMOD			dl dh divisor		rem quotl quoth

unsigned mixed mode division.  Dividend and quotient are 32 bits.
\
MAX			n1 n2			n3

n3 is the greater of n1 and n2 according to the operation of >.
\
MIN			n1 n2			n3

n3 is the lesser of n1 and n2 according to the operation of <.
\
MOD			n1 n2			n3

n3 is the remainder after dividing n1 by the divisor n2.  n3 has the same
sign as n2 or is zero.  An error condition results if the divisor is zero
or if the quotient falls outside of the range {-32768..32767}.
\
NEGATE			n1			n2

n2 is the two's complement of n1.
\
NFIELD			cfa			nfa

Convert a code field address to its corresponding name field address.
\
NOT			n1			n2

n2 is the one's complement of n1.
\
NUMBER			addr			n true <or> false

addr points to a counted string.  NUMBER attempts to convert this string
to a number using the current BASE.  The converted number n and a true flag
are returned if successful.  Otherwise a false is returned.  For the con-
version to be successful, there must be a blank at the end of the string.
This is taken care of by WORD.
\
OCTAL			-			-

Set the input-output conversion base to octal.
\
OPEN			addr[string] mode	fd <or> -1

Try to open a file whose name is pointed to by addr with mode attributes.
Returns a file descriptor fd if successful, a -1 otherwise.  string is
a null terminated text string.  File modes are 0=read-only, 1=write-only,
and 2=read-write.
\
OR			n1 n2			n3

n3 is the bit-by-bit inclusive-or of n1 and n2.
\
OTHERWISE		-			-

Optionally compile an OTHERWISE case into a case control structure.  See
SEL for description of its use.
\
OUTPUT			fd			-

Add file descriptor to output table used by TYPE if there is room in the table.
If there is no room, the command is ignored.
\
OVER			n1 n2			n1 n2 n1

Duplicates n1 on stack.
\
PAD			-			addr

The lower address of a scratch area used to hold data for intermediate pro-
cessing.  The address or contents of PAD may change and the data lost if the 
address of the next available dictionary location is changed.
\
PICK			n1			n2

n2 is a copy of the n1'th stack item not counting n1 itself.  0 PICK is 
equivalent to DUP, 1 PICK is equivalent to OVER, etc.
\
QUIT			-			-

Sets interpret state, accepts new input from the current input device, and
begins text interpretation.  This word diverges from the FORTH-83 word QUIT
in that it does not reset the return stack.  This may be changed in the 
future.
\
R>			-			n

n is removed from the return stack and transferred to the parameter stack.
\
R@			-			n

n is a copy of the top of the return stack.
\
READ			fd addr count		actcount

READs up to count bytes from the file denoted by file descriptor fd to
the buffer at addr.   actcount is the number of bytes actually read.
If this is not equal to count, the end of file was encountered or an error
occurred.
\
REPEAT			-			-

Immediate word used in the form:
	BEGIN ... flag WHILE ... REPEAT
At run-time, REPEAT continues execution just after the corresponding
BEGIN.
\
ROLL			n			-

The n'th stack value, not counting n itself is first removed and then trans-
ferred to the top of the stack, moving the remaining values into the vacated
position.  2 ROLL is equivalent to ROT.  0 ROLL is a null operation.
\
ROT			n1 n2 n3		n2 n3 n1

The top three stack entries are rotated, bringing the deepest to the top.
\
ROTATE			n1 nbits		n2

ROTATE n1 nbits.  If nbits is greater than zero, n1 is ROTATEd left.  If
nbits is less than zero, n1 is ROTATEd right.  If nbits is zero, nothing
happens.
\
S->D			n			dl dh

Sign extend n into a double precision number.
\
SEEK			fd offsetl offseth	-

Perform random-access seek on file denoted by file descriptor fd. offset
is a double precision number specifying a new file position offset from the
start of the file.
\
SEL			-			-

Immediate case structure word used in the form:
<selector> SEL
	      <<    1      ==> ... >>
	      <<    2      ==> ... >>
	      <<    5      ==> ... >>
	      << OTHERWISE ==> ... >>
           ENDSEL
The constants 1, 2, and 5 are just shown as an example.  Any word that leaves
one item on the stack can be used in the select field.  The action code 
symbolized by ..., can be any thing including another case structure.  The
<selector> is no longer on the stack when the action code begins execution.
The OTHERWISE clause is optional.  If none of the words in the select fields
match the <selector>, the <selector> is dropped by ENDSEL.
\
SHELL			-			-

Spawn a new sub-shell under the forth process.  Typing a ^D will cause control
to return to forth.
\
SIGN			n			-

If n is negative, an ASCII "-" is appended to the pictured numeric output
string.  Typically used between <# and #>.
\
SILENT			fd			-

Remove all instances of fd from the table used by TYPE.
\
SMUDGE			-			-

Toggle smudge bit in name field of word most recently added to the compilation
vocabulary.
\
SP0			-			addr

addr is address of 'top of stack' for an empty stack.  Used for resetting
stack pointer.
\
SPACE			-			-

EMIT an ASCII space.
\
SPACES			n			-

EMIT n ASCII spaces.  Nothing is EMITted if n is negative or zero.
\
STATE			-			addr

VARIABLE has current interpret-compile state.  0=interpret, 1=compile.
\
STDIN			-			0

CONSTANT returns file descriptor of standard input.
\
STDOUT			-			1

CONSTANT returns file descriptor of standard output.
\
STRING			addr[counted string]	addr[unix string]

Converts a counted string to a unix-style null-terminated string.  A copy of
the counted string is moved to PAD so that the conversion does not alter
the original string.
\
SWAP			n1 n2			n2 n1

The top two stack entries are exchanged.
\
SYSTEM			addr[string]		-

Spawns a sub-shell to execute the unix command string pointed to by addr.
The string must be null-terminated.  Typically used in the form:
	" cccc" SYSTEM  or inside a colon definition as:
	"" cccc" SYSTEM
\
TERMINATE		-			-

Terminate the forth process.  Returns 'good' status value.
\
THEN			-			-

Immediate word used in the form:
	flag IF ... ELSE ... THEN  or  flag IF ... THEN
THEN is the point where execution continues after ELSE, or IF when no ELSE
is present.
\
TIB			-			addr

addr is the address of the text input buffer.
\
TOGGLE			addr bits		-

The contents of addr are exclusive-or'ed with bits and the results stored
at addr.
\
TRUE			-			true

Places a true flag (-1) on the stack.
\
TYPE			addr count		-

count bytes of memory beginning at addr are sent to the standard output.
\
U.			u			-

u is displayed as an unsigned number in a free-field format.
\
U.LZ			u size			-

u is displayed as an unsigned number right-justified in a field of size 
characters with leading zeros.
\
U.R			u size			-

u is displayed as an unsigned number right-justified in a field of size
characters.
\
U<			u1 u2			flag

flag is true if the unsigned number u1 is less than the unsigned number u2.
\
U>			u1 u2			flag

flag is true if the unsigned number u1 is greater than the unsigned number n2.
\
U?			addr			-

Display the contents of addr as an unsigned number in free-field format.
\
UM*			n1 n2			ul uh

u is the 32-bit product of the unsigned multiplication of n1 and n2.
\
UM*M			u1l u1h mul		u2l u2h

u2 is the 32-bit product of the unsigned multiplication of u1 and mul.
\
UM/			ul uh div		rem quot

rem and quot are remainder and quotient of unsigned division of 31-bit u
by the unsigned divisor 'div'.
\
UM/MOD			ul uh div		rem quot

'rem' and 'quot' are remainder and quotient of unsigned division of 32-bit 'u'
by the unsigned divisor 'div'.
\
UNTIL			-			-

Immediate word used in the form:
	BEGIN ... flag UNTIL
Marks the end of a BEGIN-UNTIL loop which will terminate based on flag.  If
flag is true, the loop is terminated.  If flag is false, execution continues
just after the corresponding BEGIN.
\
VARIABLE		-			-

A defining word used in the form:
	VARIABLE <name>
A dictionary entry for <name> is created and two bytes are ALLOTted in its
parameter field.  This parameter field is to be used for the contents of the
VARIABLE.   The application is responsible for initializing the contents of 
the VARIABLE.  When <name> is later executed, the address of  its parameter
field is placed on the stack.
\
VOCABULARY		-			-

A defining word used in the form:
	VOCABULARY <name>
A dictionary entry for <name> is created.  Subsequent execution of <name> 
sets the search vocabulary to <name>.  When <name> becomes the compilation
vocabulary, new definitions will be appended to <name>'s list.
\
WHILE			-			-

Immediate word used in the form:
	BEGIN ... flag WHILE ... REPEAT
Selects conditional execution based on flag.  When flag is true, execution
continues just after the WHILE.  When flag is false, execution continues
just after the REPEAT, exiting the control structure.
\
WORD			char			addr

Generates a counted string by non-destructively accepting characters from
the input stream until the delimiting character char is found or the 
input stream is exhausted.  Leading delimiters are ignored.  The entire
character string is stored in memory beginning at addr as a sequence of
bytes.  The string is followed by a blank which is not included in the count.
The first byte of the string is the number of characters {0..255}.  If the
string is longer than 255 characters, the count is unspecified.  If the input
stream is already exhausted as WORD is called, then a zero length character
string will result.
\
WRITE			addr count fd		actcount

count bytes of memory starting at addr are sent to the file denoted by
file descritor fd.  The actual number of bytes written actcount is re-
turned.  If this number does not equal count, an error of some sort has
occurred.
\
WRN			-			addr

VARIABLE that holds the state the warning message enable/disable.  If WRN
is true, the user will be notified if he tries to add a word to the 
dictionary whose name conflicts with a word already in the dictionary.
\
XOR			n1 n2			n3

n3 is the bit-by-bit exclusive-or of n1 and n2.
\
ZEROES			n			-

EMIT n ASCII zeroes.  Nothing is EMITted if n is zero or negative.
\
[			-			-

Immediate word that sets the interpretation state to interpret.
\
[']			-			addr

Immediate word used in the form:
	['] <name>
Compiles the compilation address of <name> as a literal.  At run-time
the cfa of <name> is put on the stack.  If <name> is not found in the
dictionary, a literal zero is compiled.
\
[COMPILE]		-		-

Immediate word used in the form:
	[COMPILE] <name>
Forces compilation of the following word <name>.  This allow compilation of
an immediate word when it would otherwise have been executed.
\
]			-		-

Sets interpretation state to compile.  The text from the input stream is
subsequently compiled.
\
!E!O!F

lwt1@aplvax.UUCP (06/22/84)

Here is part 7 of 8 of the source for FORTH for the VAX.
Delete everything thru the "-- cut here --" line, and extract with 'sh':

	sh part1 part2 ... part7

where 'part?' are whatever you've named the files.  Note the copyright
notice at the end of README.  Please let us know how things go.  While
we can't support this software, we'll be posting bug fixes/upgrades to
net.sources as time permits.

Have fun!



						-John Hayes
						 Johns Hopkins University
						 Applied Physics Laboratory
						 ... seismo!umcp-cs!aplvax!lwt1

---------------------------------- cut here ----------------------------------
echo x - os.as
cat >os.as <<'!E!O!F'
/*
        FORTH operating system in assembler format


        System variables and constants

        The upper case labels are so that assembly language routines can refer
        to the values of these variables
*/

/* TIB                                  */
	.byte 3; .ascii "TIB  "
	.word exor-8
tib:	.word con+2

	.word inbuf

/* SP0                                  */
	.byte 3; .ascii "SP0  "
	.word tib-8
sp0:	.word con+2

	.word pstack

/* DP0                                  */
	.byte 3; .ascii "DP0  "
	.word sp0-8
dp0:	.word con+2

	.word dict

/* WRN                                  */
	.byte 3; .ascii "WRN  "
	.word dp0-8
wrn:	.word var+2

	.word -1

/* DP                                   */
	.byte 2; .ascii "DP   "
	.word wrn-8
dp:	.word var+2

DP:     .word 0

/* >IN                                  */
	.byte 3; .ascii ">IN  "
	.word dp-8
in:	.word var+2

IN:     .word 0

/* STATE                                */
	.byte 5; .ascii "STATE"
	.word in-8
state:	.word var+2

	.word 0

/* BASE                                 */
	.byte 4; .ascii "BASE "
	.word state-8
base:	.word var+2

BASE:   .word 0

/* INITVOCAB                          ( intial vocabulary - will be FORTH ) */
	.byte 11; .ascii "INITV"
	.word base-8
initvocab:	.word var+2

INITVOCAB: .word 0

/* CONTXT                                ( context vocabulary )        */
	.byte 6; .ascii "CONTX"
	.word initvocab-8
context:	.word var+2

	.word INITVOCAB

/* CURRENT                               ( current vocabulary )         */
	.byte 7; .ascii "CURRE"
	.word context-8
current:	.word var+2

	.word INITVOCAB

/* CLUE                                 */
	.byte 4; .ascii "CLUE "
	.word current-8
clue:	.word var+2

	.word 0

/* STDIN                                */
	.byte 5; .ascii "STDIN"
	.word clue-8
stdin:	.word con+2

	.word 0

/* STDOUT                               */
	.byte 6; .ascii "STDOU"
	.word stdin-8
stdout:	.word con+2

	.word 1

/* EOL                                  */
	.byte 3; .ascii "EOL  "
	.word stdout-8
eol:	.word con+2

	.word 012

/* TRUE                                 */
	.byte 4; .ascii "TRUE "
	.word eol-8
true:	.word con+2

	.word -1

/* FALSE                                */
	.byte 5; .ascii "FALSE"
	.word true-8
false:	.word con+2

	.word 0

/*    Code extensions                   */

/* ?DUP                                 */
	.byte 4; .ascii "?DUP "
	.word false-8
qdup:	.word call

	.word dup, zbranch, 1f, dup; 1: .word return

/* -ROT                                 */
	.byte 4; .ascii "-ROT "
	.word qdup-8
mrot:	.word call

	.word rot, rot, return

/* *                                    */
	.byte 1; .ascii "*    "
	.word mrot-8
star:	.word call

	.word umstar, drop, return

/* 2DUP                                 */
	.byte 4; .ascii "2DUP "
	.word star-8
twodup:	.word call

	.word over, over, return

/* S->D                                 */
	.byte 4; .ascii "S->D "
	.word twodup-8
stod:	.word call

	.word dup, zeroless, return

/* +-                                   */
	.byte 2; .ascii "+-   "
	.word stod-8
plusminus:	.word call

	.word zeroless, zbranch, 1f, negate; 1: .word return

/* D+-                                  */
	.byte 3; .ascii "D+-  "
	.word plusminus-8
dplusminus:	.word call

	.word zeroless, zbranch, 1f, dnegate; 1: .word return

/* ABS                                  */
	.byte 3; .ascii "ABS  "
	.word dplusminus-8
abs:	.word call

	.word dup, plusminus, return

/* DABS                                         */
	.byte 4; .ascii "DABS "
	.word abs-8
dabs:	.word call

	.word dup, dplusminus, return

/* 2DROP                                        */
	.byte 5; .ascii "2DROP"
	.word dabs-8
twodrop:	.word call

	.word drop, drop, return

/* UM*M                          ( ul uh mul --- ul' uh' )      */
	.byte 4; .ascii "UM*M "
	.word twodrop-8
umstarm:	.word call

	.word swap, over, umstar, drop, tor, umstar, zero, fromr, dplus
	.word return

/* M/MMOD                                       */
	.byte 6; .ascii "M/MMO"
	.word umstarm-8
mslashmmod:	.word call

	.word tor, zero, rat, umslash, fromr, swap, tor, umslash, fromr
	.word return

/* FILL                                         */
	.byte 4; .ascii "FILL "
	.word mslashmmod-8
fill:	.word call

	.word mrot, qdup, zbranch, 2f
	.word         over, plus, swap, pdo; 1:
	.word                 dup, i, cstore, ploop, 1b, branch, 3f
		2: .word drop
	3: .word drop, return

/* TOGGLE                                       */
	.byte 6; .ascii "TOGGL"
	.word fill-8
toggle:	.word call

	.word over, at, exor, swap, store, return

/* <>                                           */
	.byte 2; .ascii "<>   "
	.word toggle-8
nequal:	.word call

	.word equal, not, return

/* MAX                                          */
	.byte 3; .ascii "MAX  "
	.word nequal-8
max:	.word call

	.word twodup, less, zbranch, 1f, swap; 1: .word drop, return

/* HEX                                          */
	.byte 3; .ascii "HEX  "
	.word max-8
hex:	.word call

	.word lit, 16, base, store, return

/* DECIMAL                                      */
	.byte 7; .ascii "DECIM"
	.word hex-8
decimal:	.word call

	.word lit, 10, base, store, return

/* OCTAL                                        */
	.byte 5; .ascii "OCTAL"
	.word decimal-8
octal:	.word call

	.word lit, 8, base, store, return

/* 2!                                    ( n1 n2 addr --- )     */
	.byte 2; .ascii "2!   "
	.word octal-8
twostore:	.word call

	.word swap, over, store, twoplus, store, return

/*    Compiling words                           */

/* HERE                                         */
	.byte 4; .ascii "HERE "
	.word twostore-8
here:	.word call

	.word dp, at, return

/* PAD                                          */
	.byte 3; .ascii "PAD  "
	.word here-8
pad:	.word call

	.word here, lit, 80, plus, return

/* LATEST                                       */
	.byte 6; .ascii "LATES"
	.word pad-8
latest:	.word call

	.word current, at, at, return

/* ALLOT                                        */
	.byte 5; .ascii "ALLOT"
	.word latest-8
allot:	.word call

	.word dp, plusstore, return

/* ,                                            */
	.byte 1; .ascii ",    "
	.word allot-8
comma:	.word call

	.word here, store, two, allot, return

/* IMMEDIATE                                    */
	.byte 9; .ascii "IMMED"
	.word comma-8
immediate:	.word call

	.word latest, lit, 0200, toggle, return

/* SMUDGE                                       */
	.byte 6; .ascii "SMUDG"
	.word immediate-8
smudge:	.word call

	.word latest, lit, 0100, toggle, return

/* COMPILE                                      */
        .byte 7; .ascii "COMPI"
	.word smudge-8
compile:	.word call

	.word fromr, dup, at, comma, two, plus, tor, return

/* IF                                           */
	.byte 2+128; .ascii "IF   "
	.word compile-8
if:	.word call

	.word compile, zbranch, here, two, allot, return

/* THEN                                         */
	.byte 4+128; .ascii "THEN "
	.word if-8
then:	.word call

	.word here, swap, store, return

/* ELSE                                         */
	.byte 4+128; .ascii "ELSE "
	.word then-8
else:	.word call

	.word compile, branch, here, two, allot, here, rot, store, return

/* BEGIN                                        */
	.byte 5+128; .ascii "BEGIN"
	.word else-8
begin:	.word call

	.word here, return

/* UNTIL                                        */
	.byte 5+128; .ascii "UNTIL"
	.word begin-8
until:	.word call

	.word compile, zbranch, comma, return

/* AGAIN                                        */
	.byte 5+128; .ascii "AGAIN"
	.word until-8
again:	.word call

	.word compile, branch, comma, return

/* WHILE                                        */
	.byte 5+128; .ascii "WHILE"
	.word again-8
while:	.word call

	.word compile, zbranch, here, two, allot, return

/* REPEAT                                       */
	.byte 6+128; .ascii "REPEA"
	.word while-8
repeat:	.word call

	.word compile, branch, swap, comma, here, swap, store, return

/* DO                                           */
	.byte 2+128; .ascii "DO   "
	.word repeat-8
do:	.word call

	.word compile, pdo, clue, at, zero, clue, store, here, return

/* LOOP                                         */
	.byte 4+128; .ascii "LOOP "
	.word do-8
loop:	.word call

	.word compile, ploop, comma, clue, at, qdup, zbranch, 1f
	.word         here, swap, store
	1: .word clue, store, return

/* +LOOP                                        */
	.byte 5+128; .ascii "+LOOP"
	.word loop-8
plusloop:	.word call

	.word compile, pploop, comma, clue, at, qdup, zbranch, 1f
	.word        here, swap, store
	1: .word clue, store, return

/* LEAVE                                        */
	.byte 5+128; .ascii "LEAVE"
	.word plusloop-8
leave:	.word call

	.word compile, pleave, here, clue, store, two, allot, return

/* [                                            */
	.byte 1+128; .ascii "[    "
	.word leave-8
lbracket:	.word call

	.word zero, state, store, return

/* ]                                            */
	.byte 1; .ascii "]    "
	.word lbracket-8
rbracket:	.word call

	.word one, state, store, return

/* (                                            */
	.byte 1+128; .ascii "(    "
	.word rbracket-8
paren:	.word call

	.word lit, 051, word, drop, return

/*     I/O words                                */

/* TYPE                          ( addr count --- )     */
	.byte 4; .ascii "TYPE "
	.word paren-8
type:	.word call

	.word stdout, write, drop, return

/* EMIT                          ( chr --- )    */
	.byte 4; .ascii "EMIT "
	.word type-8
emit:	.word call

	.word atsp, one, type, drop, return

/* CR                                           */
	.byte 2; .ascii "CR   "
	.word emit-8
cr:	.word call

	.word eol, emit, return

/* FQUERY                        ( fd --- actcount )    */
	.byte 6; .ascii "FQUER"
	.word cr-8
fquery:	.word call

	.word zero, in, store
	.word tib, lit, 120, fexpect, return

/* COUNT                                        */
	.byte 5; .ascii "COUNT"
	.word fquery-8
count:	.word call

	.word dup, oneplus, swap, cat, return

/* (.")                                         */
	.byte 4; .ascii "(.\") "
	.word count-8
pdotquote:	.word call

	.word fromr, count, twodup, type, plus, tor, return

/* ,WORD                                        */
	.byte 5; .ascii "WORD"
	.word pdotquote-8
commaword:	.word call

	.word word, cat, oneplus, allot, return

/* ."                                          */
	.byte 2+128; .ascii ".\"   "
	.word commaword-8
dotquote:	.word call

	.word compile, pdotquote, lit, 042, commaword, return

/* SPACE                                        */
	.byte 5; .ascii "SPACE"
	.word dotquote-8
space:	.word call

	.word lit, 040, emit, return

/* SPACES                                       */
	.byte 6; .ascii "SPACE"
	.word space-8
spaces:	.word call

	.word zero, max, qdup, zbranch, 2f
	.word        zero, pdo; 1: .word space, ploop, 1b
	2: .word return

/* STRING                        ( adr[counted_string] --- adr[string] ) */
	.byte 6; .ascii "STRIN"
	.word spaces-8
string:	.word call

	.word count, dup, tor, pad, swap, cmove, zero, pad, fromr, plus
	.word cstore, pad, return

/* "                             ( --- adr[string] )           */
	.byte 1; .ascii "\"    "
	.word string-8
quote:	.word call

	.word lit, 042, word, string, return

/* ("")                          ( --- adr[string] )            */
	.byte 4; .ascii "(\"\") "
	.word quote-8
pdquote:	.word call

	.word fromr, dup, count, plus, tor, string, return

/* ""                                           */
	.byte 2; .ascii "\"\"   "
	.word pdquote-8
dquote:	.word call

	.word compile, pdquote, lit, 042, commaword, return

/*       Defining words                         */

/* CFIELD                                       */
	.byte 6; .ascii "CFIEL"
	.word dquote-8
cfield:	.word call

	.word lit, 8, plus, return

/* NFIELD                                       */
	.byte 6; .ascii "NFIEL"
	.word cfield-8
nfield:	.word call

	.word lit, 8, minus, return

/* -IMM                          ( nfa --- cfa n )      */
	.byte 4; .ascii "-IMM "
	.word nfield-8
notimm:	.word call

	.word dup, cfield, minusone, rot, cat, lit, 0200, and
	.word zbranch, 1f, negate; 1: .word return

/* FIND                          ( addr[name] --- addr2 n )     */
	.byte 4; .ascii "FIND "
	.word notimm-8
find:	.word call

	.word dup, context, at, at, pfind
	.word qdup, zbranch, 1f, swap, drop, notimm, branch, 3f
	1: .word dup, latest, pfind
	   .word qdup, zbranch, 2f, swap, drop, notimm, branch, 3f
	   2: .word zero
	3: .word return

/* '                                            */
	.byte 1; .ascii "'    "
	.word find-8
tic:	.word call

	.word here, lit, 6, lit, 040, fill
	.word lit, 040, word
	.word find, zeroeq, zbranch, 1f, drop, zero; 1: .word return

/* HEADER                                       */
	.byte 6; .ascii "HEADE"
	.word tic-8
cheader:	.word call

	.word tic, zbranch, 1f
	.word        wrn, at, zbranch, 1f
	.word                here, count, type
	.word                pdotquote; .byte 13; .ascii " isn't unique"
	.word			cr
	1: .word here, lit, 6, allot, latest, comma, current, at, store
	.word return

/* :                                            */
	.byte 1; .ascii ":    "
	.word cheader-8
colon:	.word call

	.word current, at, context, store
	.word cheader, compile, call, rbracket, smudge, return

/* ;                                            */
	.byte 1+128; .ascii ";    "
	.word colon-8
semicolon:	.word call

	.word compile, return, smudge, zero, state, store, return

/* VARIABLE                                     */
	.byte 8; .ascii "VARIA"
	.word semicolon-8
variable:	.word call

	.word cheader, compile, var+2, zero, comma, return

/* CONSTANT                                     */
	.byte 8; .ascii "CONST"
	.word variable-8
constant:	.word call

	.word cheader, compile, con+2, comma, return

/* 2VARIABLE                                    */
	.byte 9; .ascii "2VARI"
	.word constant-8
twovar:	.word call

	.word variable, zero, comma, return

/* DOES>                                        */
	.byte 5; .ascii "DOES>"
	.word twovar-8
does:	.word call

	.word fromr, latest, cfield, twoplus, store, return

/* CREATE                                       */
	.byte 6; .ascii "CREAT"
	.word does-8
create:	.word call

	.word cheader, compile, pdoes+2, zero, comma, does, return

/* VOCABULARY                                   */
	.byte 10; .ascii "VOCAB"
	.word create-8
vocabulary:	.word call

	.word create, here, twoplus, comma, latest, comma
	.word does, at, context, store, return

/* DEFINITIONS                                  */
	.byte 11; .ascii "DEFIN"
	.word vocabulary-8
definitions:	.word call

	.word context, at, current, store, return

/* FORTH                                 FORTH vocabulary       */
	.byte 5+128; .ascii "FORTH"
	.word definitions-8
forth:	.word call

	.word initvocab, context, store, return

/*       numeric output words                   */

/* HLD                                          */
	.byte 3; .ascii "HLD  "
	.word forth-8
hld:	.word var+2

	.word 0

/* HOLD                                         */
	.byte 4; .ascii "HOLD "
	.word hld-8
hold:	.word call

	.word minusone, hld, plusstore, hld, at, cstore, return

/* <#                                           */
	.byte 2; .ascii "<#   "
	.word hold-8
lnum:	.word call

	.word pad, hld, store, return

/* #>                                           */
	.byte 2; .ascii "#>   "
	.word lnum-8
gnum:	.word call

	.word twodrop, hld, at, pad, over, minus, return

/* SIGN                                         */
	.byte 4; .ascii "SIGN "
	.word gnum-8
sign:	.word call

	.word zeroless, zbranch, 1f, lit, 055, hold; 1: .word return

/* #                                            */
	.byte 1; .ascii "#    "
	.word sign-8
num:	.word call

	.word base, at, mslashmmod, rot, lit, 011, over, less
	.word zbranch, 1f, lit, 7, plus; 1:
	.word lit, 060, plus, hold, return

/* #S                                           */
	.byte 2; .ascii "#S   "
	.word num-8
nums:	.word call

	1: .word num, twodup, or, zeroeq, zbranch, 1b, return

/* D.R                                          */
	.byte 3; .ascii "D.R  "
	.word nums-8
ddotr:	.word call

	.word tor, swap, over, dabs, lnum, nums, rot, sign, gnum
	.word fromr, over, minus, spaces, type, return

/* ZEROES                                       */
	.byte 6; .ascii "ZEROE"
	.word ddotr-8
zeroes:	.word call

	.word zero, max, qdup, zbranch, 2f, zero, pdo; 1:
	.word        lit, 060, emit, ploop, 1b
	2: .word return

/* D.LZ                                         */
	.byte 4; .ascii "D.LZ "
	.word zeroes-8
ddotlz:	.word call

	.word tor, swap, over, dabs, lnum, nums, rot, sign, gnum
	.word fromr, over, minus, zeroes, type, return

/* D.                                           */
	.byte 2; .ascii "D.   "
	.word ddotlz-8
ddot:	.word call

	.word zero, ddotr, space, return

/* .R                                           */
	.byte 2; .ascii ".R   "
	.word ddot-8
dotr:	.word call

	.word tor, stod, fromr, ddotr, return

/* .                                            */
	.byte 1; .ascii ".    "
	.word dotr-8
dot:	.word call

	.word stod, ddot, return

/* U.R                                          */
	.byte 3; .ascii "U.R  "
	.word dot-8
udotr:	.word call

	.word zero, swap, ddotr, return

/* U.LZ                                        */
	.byte 4; .ascii "U.LZ "
	.word udotr-8
udotlz:	.word call

	.word zero, swap, ddotlz, return

/*       utilities                              */

/* [COMPILE]                                    */
	.byte 9+128; .ascii "[COMP"
	.word udotlz-8
bcompile:	.word call

	.word tic, comma, return

/* DUMP                          ( addr bytes --- )     */
	.byte 4; .ascii "DUMP "
	.word bcompile-8
dump:	.word call

	.word cr, over, plus, swap, pdo; 1:
	.word        i, lit, 4, udotlz, pdotquote; .byte 1; .ascii ":"
	.word        space
	.word        i, lit, 8, plus, i, pdo; 2:
	.word                i, cat, two, udotlz, space, ploop, 2b
	.word        i, lit, 8, plus, i, pdo; 3:
	.word                i, cat, dup, lit, 040, less
	.word                over, lit, 0177, equal, or
	.word                zbranch, 4f, drop, lit, 056; 4:
	.word                emit, ploop, 3b
	.word        cr, lit, 8, pploop, 1b
	.word return

/*       operating system support words         */

/* DIGIT                         ( char --- n true <or> false ) */
	.byte 5; .ascii "DIGIT"
	.word dump-8
digit:	.word call

	.word lit, 060, minus
	.word dup, lit, 9, greater, over, lit,  17, less, and
	.word zbranch, 1f
	.word         drop, false, branch, 4f
	1: .word      dup, lit, 9, ugreater, zbranch, 2f
	.word                lit, 7, minus
		2: .word dup, base, at, oneminus, ugreater, zbranch, 3f
	.word                drop, false, branch, 4f
		3: .word     true
	4: .word return

/* CONVERT                       ( dl dh addr1 --- dl' dh' addr2 )      */
	.byte 7; .ascii "CONVE"
	.word digit-8
convert:	.word call

	.word tor; 1:
	.word   fromr, oneplus, dup, tor, cat, digit
	.word   zbranch, 2f, tor, base, at, umstarm, fromr, zero, dplus
	.word branch, 1b
	2: .word fromr, return

/* NUMBER                        ( ADDR --- N TRUE <OR> FALSE ) */
	.byte 6; .ascii "NUMBE"
	.word convert-8
number:	.word call

	.word dup, oneplus, cat, lit, 055, equal, dup, tor, minus
	.word zero, zero, rot, convert
	.word cat, lit, 040, equal, zbranch, 1f
	.word    drop, fromr, plusminus, true, branch, 2f
	   1: .word twodrop, fromr, drop, false
	2: .word return

/* ?STACK              ( --- T/F )  ( returns true if stack underflow ) */
	.byte 6; .ascii "?STAC"
	.word number-8
qstack:	.word call

	.word atsp, sp0, greater, return

/* CHUCKBUF                      ( chuck rest of input buffer ) */
	.byte 8; .ascii "CHUCK"
	.word qstack-8
chuckbuf:	.word call

	.word tib, in, at, plus
		1: .word dup, cat, eol, nequal, zbranch, 2f, oneplus
	.word        branch, 1b
	2: .word tib, minus, in, store, return

/* ENDINTERP                     ( --- )   ( flush reset of input buffer ) */
	.byte 9; .ascii "ENDIN"
	.word chuckbuf-8
endinterp:	.word call

	.word  sp0, storesp           /* reset stack pointer */
	.word chuckbuf, return

/* INTERPRET                                    */
	.byte 9; .ascii "INTER"
	.word endinterp-8
interpret:	.word call

	1: .word here, lit, 6, lit, 040, fill
	.word lit, 040, word, cat, zbranch, 9f
	.word here, find, qdup, zbranch, 4f
	.word        state, at, plus
	.word        zbranch, 2f, execute, branch, 3f; 2: .word comma; 3:
	.word        branch, 7f
	4: .word number, zbranch, 6f
	.word         state, at, zbranch, 5f, compile, lit, comma; 5:
	.word        branch, 7f
		6: .word here, count, type, pdotquote; .byte 2; .ascii " ?"
	.word                cr,endinterp
	7: .word qstack, zbranch, 8f, pdotquote
		.byte 12; .ascii " Stack empty"; .word cr, endinterp; 8:
	.word branch, 1b
	9: .word return

/* FLOAD                         ( adr[string] --- )    */
	.byte 5; .ascii "FLOAD"
	.word interpret-8
fload:	.word call

	.word zero, open, dup, zeroless, zbranch, 0f
	.word         drop, pdotquote; .byte 11; .ascii " can't open"
	.word           cr, branch, 3f
	0: .word tor
	1: .word rat, fquery, zbranch, 2f, interpret, branch, 1b
	2: .word fromr, close, chuckbuf
	3: .word return

/* QUIT                                         */
	.byte 4; .ascii "QUIT "
	.word fload-8
quit:	.word call

	.word zero, state, store, sp0, storesp
	.word cr, pdotquote; .byte 21; .ascii "VAX FORTH version 1.0"
	1: .word cr, stdin, fquery, zbranch, 3f
	.word        interpret
	.word        state, at, zeroeq, zbranch, 2f, pdotquote
			.byte 3; .ascii " OK"
	2: .word branch, 1b
	3: .word cr, terminate, return

/*       the rest of the dictionary            */
dict:   .space 20000
!E!O!F

lwt1@aplvax.UUCP (06/22/84)

Here is part 8 of 8 of the source for FORTH for the VAX.
Delete everything thru the "-- cut here --" line, and extract with 'sh':

	sh part1 part2 ... part7

where 'part?' are whatever you've named the files.  Note the copyright
notice at the end of README.  Please let us know how things go.  While
we can't support this software, we'll be posting bug fixes/upgrades to
net.sources as time permits.

Have fun!



						-John Hayes
						 Johns Hopkins University
						 Applied Physics Laboratory
						 ... seismo!umcp-cs!aplvax!lwt1

---------------------------------- cut here ----------------------------------
echo x - prim.as
cat >prim.as <<'!E!O!F'
/* Copyright 1984 by The Johns Hopkins University/Applied Physics Lab.
 * Free non-commercial distribution is *encouraged*, provided that:
 * 
 * 	1.  This copyright notice is included in any distribution, and
 * 	2.  You let us know that you're using it.
 * 
 * Please notify:
 * 
 * 	John Hayes
 * 	JHU/Applied Physics Lab
 * 	Johns Hopkins Road
 * 	Laurel, MD 20707
 * 	(301) 953-5000 x8086
 * 
 * 	Usenet:  ... seismo!umcp-cs!aplvax!lwt1
 * 
 * 
 * Unix-FORTH was developed under NASA contract NAS5-27000 for the
 * Hopkins Ultraviolet Telescope, a March 1986 Space Shuttle mission.  (we
 * hope to take a peek at Halley's comet!)
 * 
 * Written entirely by Wizard-In-Residence John R. Hayes.
 * 
 * * Unix is a trademark of Bell Labs.
 */

/*
 *	VAX-FORTH indirect threaded code inner interpreter
 */

	.text
	.word 0x0 			/* entry mask */


/*	start-up code */
	movzwl $pstack,r8		/* initialize r8 */
	movw $dict,DP			/* initialize dictionary pointer */
	movw $16,BASE			/* base is hex */
	movw $quit-8,INITVOCAB
	movzwl $quit+2,r9		/* initialize r9 */
	brw next

/*	parameter stack			*/
	.space 256
pstack:

/*	text input buffer		*/
inbuf:	.space 120

/* (:)					*/
	.byte 3; .ascii "(:)  "
	.word 0				/* end of dictionary */
pcolon:	.word call

call:	movw r9,-(sp)
	movw r0,r9

next:	movzwl (r9)+,r0
	movzwl (r0)+,r1
	jmp (r1)

/* (;)					*/
	.byte 3; .ascii "(;)  "
	.word pcolon-8
return:	.word return+2

	movzwl (sp)+,r9
	movzwl (r9)+,r0		/* repetion of next code for speed */
	movzwl (r0)+,r1
	jmp (r1)

/* (VARIABLE)					*/
	.byte 10; .ascii "(VARI"
	.word return-8
var:	.word var+2

	movw r0,-(r8)
	brw next

/* (CONSTANT)				*/
	.byte 10; .ascii "(CONS"
	.word var-8
con:	.word con+2

	movw (r0),-(r8)
	brw next

/* (DOES>)				*/
	.byte 7; .ascii "(DOES"
	.word con-8
pdoes:	.word pdoes+2

	movw r9,-(sp)
	movzwl (r0)+,r9
	movw r0,-(r8)
	brw next

/* (LITERAL)				*/
	.byte 9; .ascii "(LITE"
	.word pdoes-8
lit:	.word lit+2

	movw (r9)+,-(r8)
	brw next

/* BRANCH				*/
	.byte 6; .ascii "BRANC"
	.word lit-8
branch:	.word branch+2

1:	movzwl (r9),r9
	brw next

/* ?BRANCH				*/
	.byte 7; .ascii "?BRAN"
	.word branch-8
zbranch:	.word zbranch+2

	tstw (r8)+
	beql 1b
	addw2 $2,r9
	brw next

/* EXECUTE				*/
	.byte 7; .ascii "EXECU"
	.word zbranch-8
execute:	.word execute+2

	movzwl (r8)+,r0
	movzwl (r0)+,r1
	jmp (r1)

/* (DO)					*/
	.byte 4; .ascii "(DO) "
	.word execute-8
pdo:	.word pdo+2

	addw3 2(r8),$0100000,r0
	movw r0,-(sp)
	subw3 r0,(r8)+,-(sp)
	addw2 $2,r8
	brw next

/* (LOOP)				*/
	.byte 6; .ascii "(LOOP"
	.word pdo-8
ploop:	.word ploop+2

	incw (sp)
	bvc 1b
	addl2 $4,sp
	addw2 $2,r9
	brw next

/* (+LOOP)				*/
	.byte 7; .ascii "(+LOO"
	.word ploop-8
pploop:	.word pploop+2

	addw2 (r8)+,(sp)
	bvc 1b
	addl2 $4,sp
	addw2 $2,r9
	brw next

/* I					*/
	.byte 1; .ascii "I    "
	.word pploop-8
i:	.word i+2

	addw3 (sp),2(sp),-(r8)
	brw next

/* J					*/
	.byte 1; .ascii "J    "
	.word i-8
j:	.word j+2

	addw3 4(sp),6(sp),-(r8)
	brw next

/* (LEAVE)				*/
	.byte 7; .ascii "(LEAV"
	.word j-8
pleave:	.word pleave+2

	addl2 $4,sp
	movzwl (r9),r9
	brw next

/*	basic  system interface	*/

/*	I/O buffer and control variables	*/
block:	.space 1024
size:	.word 0				/* size in bytes		     */
indx:	.word 0				/* current offset into block	     */
fd:	.word 0				/* file descriptor of associated file*/

/*	file position table: each slot has a 32 bit file ofsett.  file des-
	criptor is offset into table.  There are 15 slots	              */

filepos:
	.long 0
	.long 0
	.long 0
	.long 0
	.long 0
	.long 0
	.long 0
	.long 0
	.long 0
	.long 0
	.long 0
	.long 0
	.long 0
	.long 0
	.long 0

/*	low level system calls */

_read:	.word 0			/* entry mask */
	chmk $3
	bcc 1f
	clrl r0			/* if error, length is zero */
1:	ret

_write:	.word 0			/* entry mask */
	chmk $4
	bcc 1f
	mnegl $1,r0		/* return -1 on error */
1:	ret

_lseek:	.word 0			/* entry mask */
	chmk $19
	bcc 1f
	clrl r0			/* return zero if error */
1:	ret

_creat:	.word 0			/* entry mask */
	chmk $8
	bcc 1f
	mnegl $1,r0
1:	ret

_open:	.word 0			/* entry mask */
	chmk $5
	bcc 1f
	mnegl $1,r0		/* return negative file descriptor on error */
1:	ret

_close:	.word 0			/* entry mask */
	chmk $6
	ret			/* ignore errors */

_exit:	.word 0			/* entry mask */
	chmk $1			/* should never return */
	halt

/*	subroutine getc: handles all input and does buffering
		input: file descriptor in r2
		output: character of -1 in r0
		side effects: r2, r3
 */

getc:	cmpw r2,*$fd
	beql 1f			/* do seek if new fd is not same as old fd */
 	movw r2,*$fd
	movw *$size,*$indx	/* indicate that buffer is empty */
	clrl -(sp)		/* whence is start of file */
	pushl *$filepos[r2]	/* push file position */
	pushl r2		/* push file descriptor */
	calls $3,_lseek		/* seek */
1:	movzwl *$indx,r3	/* r3 has index */
	cmpw r3,*$size
	blss 2f			/* read file if buffer is empty */
	pushl $1024		/* push block size */
	pushl $block		/* push address of buffer */
	pushl r2		/* push file descriptor */
	calls $3,_read		/* read */
	movw r0,*$size		/* save size */
	clrl r3			/* reset index */
2:	cmpw r3,*$size
	beql 3f			/* branch if end of file */
	incl *$filepos[r2]	/* update file position */
	movzbl block(r3),r0	/* return character */
	incw r3			/* update index */
	brb 4f
3:	movl $-1,r0		/* return -1 */
4:	movw r3,*$indx		/* save index */
	rsb

/* FEXPECT		( fd addr count --- actcount )  */
	.byte 7; .ascii "FEXPE"
	.word pleave-8
fexpect:	.word fexpect+2

	movzwl 2(r8),r6	/* buffer address */
	movzwl (r8)+,r7	/* count */
	beql 3f			/* do nothing if count is zero */
1:	movzwl 2(r8),r2	/* file descriptor */
	jsb *$getc		/* get next character */
	cmpb r0,$-1
	beql 3f			/* leave loop on -1 */
	cmpb r0,$011
	bneq 2f
	movw $040,r0		/* change tabs to blanks */
2:	movb r0,(r6)+		/* save character */
	cmpb r0,$012
	beql 3f			/* leave loop on newline */
	sobgtr r7,1b		/* decrement counter and continue if non-zero */
3:	subw2 (r8)+,r6		/* compute actual number of characters read */
	movw r6,(r8)		/* return actual number */
	brw next

/* READ				( fd addr count --- actcount )  */
	.byte 4; .ascii "READ "
	.word fexpect-8
read:	.word read+2

	movzwl 2(r8),r4	/* buffer address */
	movzwl (r8)+,r5	/* count */
	beql 3f
1:	movzwl 2(r8),r2	/* file descriptor */
	jsb *$getc		/* get next character */
	cmpw r0,$-1
	beql 3f			/* leave loop on -1 */
	movb r0,(r4)+		/* save character */
	sobgtr r5,1b		/* decrement count and continue if non-zero */
3:	subw2 (r8)+,r4		/* compute actual number of characters read */
	movw r4,(r8)		/* return actual count */
	brw next

/* WRITE		( addr count fd --- actcount )  */
	.byte 5; .ascii "WRITE"
	.word read-8
write:	.word write+2

	movzwl (r8)+,r0	/* file descriptor */
	movzwl (r8)+,-(sp)	/* stack count */
	movzwl (r8),-(sp)	/* stack address */
	pushl r0		/* stack file descriptor */
	calls $3,_write		/* write */
	movw r0,(r8)		/* return actual count */
	brw next

/* SEEK				( fd offsetl offseth --- )   */
	.byte 4; .ascii "SEEK "
	.word write-8
seek:	.word seek+2

	movw 2(r8),-(r8)
	movl (r8)+,r0		/* offset */
	addw2 $2,r8
	movzwl (r8)+,r1	/* file descriptor */
	cmpw r1,*$fd
	bneq 1f
	movw *$size,*$index	/* if seeking buffered file, reset buffer */
1:	movl r0,filepos[r1]	/* save new position in position table */
	clrl -(sp)		/* whence is start of file */
	pushl r0		/* offset */
	pushl r1		/* fd */
	calls $3,_lseek		/* seek */
	brw next

/* CREAT		( addr[string] pmode --- fd ) */
	.byte 5; .ascii "CREAT"
	.word seek-8
creat:	.word creat+2

	movzwl (r8)+,-(sp)	/* stack protection mode */
	movzwl (r8),-(sp)	/* stack address of file name string */
	calls $2,_creat		/* creat system call */
	movw r0,(r8)		/* return file descriptor */
	blss 1f			/* skip if creation failed */
	clrl filepos[r0]	/* set file position to zero */
1:	brw next

/* OPEN			( addr[strin] mode --- fd )   */
	.byte 4; .ascii "OPEN "
	.word creat-8
open:	.word open+2

	movzwl (r8)+,-(sp)	/* stack mode */
	movzwl (r8),-(sp)	/* stack address of file name */
	calls $2,_open		/* open */
	movw r0,(r8)		/* return file descriptor */
	blss 1f			/* skip of open faled */
	clrl filepos[r0]	/* reset file positions */
1:	brw next

/* CLOSE		( fd --- )		      */
	.byte 5; .ascii "CLOSE"
	.word open-8
close:	.word close+2

	movzwl (r8)+,-(sp)	/* stack file descriptor */
	calls $1,_close		/* close */
	brw next

/* TERMINATE		( --- )			      */
	.byte 9; .ascii "TERMI"
	.word close-8
terminate:	.word terminate+2

	clrl -(sp)		/* return good status */
	calls $1,_exit		/* exit */

/*	high level utilities written in assembly language for speed */

/* (FIND)		( addr[word] addr[vocab] --- 0 <or> nfa )  */
	.byte 6; .ascii "(FIND"
	.word terminate-8
pfind:	.word pfind+2

	movzwl (r8)+,r0
	beql 3f
	movzwl (r8),r1
	movl (r1),r2
1:	bicl3 $128,(r0),r3
	cmpl r2,r3
	bneq 2f
	cmpw 4(r1),4(r0)
	beql 3f
2:	movzwl 6(r0),r0
	bneq 1b
3:	movw r0,(r8)
	brw next

/* WORD					*/
	.byte 4; .ascii "WORD "
	.word pfind-8
word:	.word word+2

	clrl r1
	addw3 $inbuf,*$IN,r1
	skpc (r8),$1000,(r1)
	movzwl (r8),r0
	movzwl *$DP,r2
	movw r2,(r8)
	movzwl r1,r3
1:	cmpb r0,(r3)
	beql 2f
	cmpb $012,(r3)
	beql 2f
	incw r3
	brb 1b
2:	subw2 r1,r3
	movb r3,(r2)+
	beql 4f
3:	movb (r1)+,(r2)+
	sobgtr r3,3b
4:	cmpb $012,(r1)
	beql 5f
	incw r1
5:	subw3 $inbuf,r1,*$IN
	movb $040,(r2)
	brw next

/*	VAX-FORTH stack primitives	*/

/* !					*/
	.byte 1; .ascii "!    "
	.word word-8
store:	.word store+2
	movzwl (r8)+,r0
	movw (r8)+,(r0)
	brw next

/* !SP					*/
	.byte 3; .ascii "!SP  "
	.word store-8
storesp:	.word storesp+2
	movzwl (r8),r8
	brw next

/* +					*/
	.byte 1; .ascii "+    "
	.word storesp-8
plus:	.word plus+2
	addw2 (r8)+,(r8)
	brw next

/* +!					*/
	.byte 2; .ascii "+!   "
	.word plus-8
plusstore:	.word plusstore+2

	movzwl (r8)+,r0
	addw2 (r8)+,(r0)
	brw next

/* -					*/
	.byte 1; .ascii "-    "
	.word plusstore-8
minus:	.word minus+2

	subw2 (r8)+,(r8)
	brw next

/* -1					*/
	.byte 2; .ascii "-1   "
	.word minus-8
minusone:	.word minusone+2

	movw $-1,-(r8)
	brw next

/* 0					*/
	.byte 1; .ascii "0    "
	.word minusone-8
zero:	.word zero+2

	clrw -(r8)
	brw next

/* 0<					*/
	.byte 2; .ascii "0<   "
	.word zero-8
zeroless:	.word zeroless+2

	clrw r0
	tstw (r8)
	bgeq 1f
	movw $-1,r0
1:	movw r0,(r8)
	brw next

/* 0=					*/
	.byte 2; .ascii "0=   "
	.word zeroless-8
zeroeq:	.word zeroeq+2

	clrw r0
	tstw (r8)
	bneq 1f
	movw $-1,r0
1:	movw r0,(r8)
	brw next

/* 1					*/
	.byte 1; .ascii "1    "
	.word zeroeq-8
one:	.word one+2

	movw $1,-(r8)
	brw next

/* 1+					*/
	.byte 2; .ascii "1+   "
	.word one-8
oneplus:	.word oneplus+2

	incw (r8)
	brw next

/* 1-					*/
	.byte 2; .ascii "1-   "
	.word oneplus-8
oneminus:	.word oneminus+2

	decw (r8)
	brw next

/* 2					*/
	.byte 1; .ascii "2    "
	.word oneminus-8
two:	.word two+2

	movw $2,-(r8)
	brw next

/* 2+					*/
	.byte 2; .ascii "2+   "
	.word two-8
twoplus:	.word twoplus+2

	addw2 $2,(r8)
	brw next

/* 2-					*/
	.byte 2; .ascii "2-   "
	.word twoplus-8
twominus:	.word twominus+2

	subw2 $2,(r8)
	brw next

/* 2*					*/
	.byte 2; .ascii "2*   "
	.word twominus-8
twostar:	.word twostar+2

	movw (r8),r0
	ashl $1,r0,r0
	movw r0,(r8)
	brw next

/* 2/					*/
	.byte 2; .ascii "2/   "
	.word twostar-8
twoslash:	.word twoslash+2

	cvtwl (r8),r0
	ashl $-1,r0,r0
	movw r0,(r8)
	brw next

/* <					*/
	.byte 1; .ascii "<    "
	.word twoslash-8
less:	.word less+2

	clrw r0
	cmpw (r8)+,(r8)
	bleq 1f
	movw $-1,r0
1:	movw r0,(r8)
	brw next

/* =					*/
	.byte 1; .ascii "=    "
	.word less-8
equal:	.word equal+2

	clrw r0
	cmpw (r8)+,(r8)
	bneq 1f
	movw $-1,r0
1:	movw r0,(r8)
	brw next

/* >					*/
	.byte 1; .ascii ">    "
	.word equal-8
greater:	.word greater+2

	clrw r0
	cmpw (r8)+,(r8)
	bgeq 1f
	movw $-1,r0
1:	movw r0,(r8)
	brw next

/* >R					*/
	.byte 2; .ascii ">R   "
	.word greater-8
tor:	.word tor+2

	movw (r8)+,-(sp)
	brw next

/* @					*/
	.byte 1; .ascii "@    "
	.word tor-8
at:	.word at+2

	movzwl (r8),r0
	movw (r0),(r8)
	brw next

/* @SP					*/
	.byte 3; .ascii "@SP  "
	.word at-8
atsp:	.word atsp+2

	movw r8,r0
	movw r0,-(r8)
	brw next

/* AND					*/
	.byte 3; .ascii "AND  "
	.word atsp-8
and:	.word and+2

	mcomw (r8)+,r0
	bicw2 r0,(r8)
	brw next

/* C!					*/
	.byte 2; .ascii "C!   "
	.word and-8
cstore:	.word cstore+2

	movzwl (r8)+,r0
	movb (r8)+,(r0)
	incw r8
	brw next

/* C@					*/
	.byte 2; .ascii "C@   "
	.word cstore-8
cat:	.word cat+2

	movzwl (r8),r0
	movzbw (r0),(r8)
	brw next

/* CMOVE				*/
	.byte 5; .ascii "CMOVE"
	.word cat-8
cmove:	.word cmove+2

	movzwl (r8)+,r2
	beql 2f
	movzwl (r8),r0
	movzwl 2(r8),r1
1:	movb (r1)+,(r0)+
	sobgtr r2,1b
2:	addl2 $4,r8
	brw next

/* D+					*/
	.byte 2; .ascii "D+   "
	.word cmove-8
dplus:	.word dplus+2

	movw 2(r8),-(r8)
	movw 8(r8),4(r8)
	addl2 (r8)+,(r8)
	movw (r8)+,2(r8)
	brw next

/* DNEGATE				*/
	.byte 7; .ascii "DNEGA"
	.word dplus-8
dnegate:	.word dnegate+2

	movw 2(r8),-(r8)
	mnegl (r8),(r8)
	movw (r8)+,2(r8)
	brw next

/* D<					*/
	.byte 2; .ascii "D<   "
	.word dnegate-8
dless:	.word dless+2

	movw 2(r8),-(r8)
	movw 8(r8),4(r8)
	clrw r0
	cmpl (r8)+,(r8)+
	bleq 1f
	movw $-1,r0
1:	movw r0,(r8)
	brw next

/* DROP					*/
	.byte 4; .ascii "DROP "
	.word dless-8
drop:	.word drop+2

	addw2 $2,r8
	brw next

/* DUP					*/
	.byte 3; .ascii "DUP  "
	.word drop-8
dup:	.word dup+2

	movw (r8),-(r8)
	brw next

/* M*					*/
	.byte 2; .ascii "M*   "
	.word dup-8
mstar:	.word mstar+2

	cvtwl (r8)+,r0
	cvtwl (r8),r1
	mull3 r0,r1,-(r8)
	movw (r8)+,2(r8)
	brw next

/* M/					*/
	.byte 2; .ascii "M/   "
	.word mstar-8
mslash:	.word mslash+2

	cvtwl (r8),r0		/* divisor in r0 */
	movw 4(r8),(r8)
	clrl r2
	movl (r8)+,r1
	bgeq 1f
	decl r2			/* signed quadword dividend in r1,r2 */
1:	xorl3 r2,r0,r3		/* expected sign in r3 */
	ediv r0,r1,r4,r5
	tstl r3
	bgeq 2f			/* branch if sign not negative */
	tstl r1
	beql 2f			/* branch if remainder is zero */
	decl r4			/* subtract one from quotient */
	addl2 r0,r5		/* add divisor to remainder */
2:	movw r5,(r8)		/* remainder */
	movw r4,-(r8)		/* quotient */
	brw next

/* NEGATE				*/
	.byte 6; .ascii "NEGAT"
	.word mslash-8
negate:	.word negate+2

	mnegw (r8),(r8)
	brw next

/* NOT					*/
	.byte 3; .ascii "NOT  "
	.word negate-8
not:	.word not+2

	mcomw (r8),(r8)
	brw next

/* OR					*/
	.byte 2; .ascii "OR   "
	.word not-8
or:	.word or+2

	bisw2 (r8)+,(r8)
	brw next

/* OVER					*/
	.byte 4; .ascii "OVER "
	.word or-8
over:	.word over+2

	movw 2(r8),-(r8)
	brw next

/* R>					*/
	.byte 2; .ascii "R>   "
	.word over-8
fromr:	.word fromr+2

	movw (sp)+,-(r8)
	brw next

/* R@					*/
	.byte 2; .ascii "R@   "
	.word fromr-8
rat:	.word rat+2

	movw (sp),-(r8)
	brw next

/* ROT					*/
	.byte 3; .ascii "ROT  "
	.word rat-8
rot:	.word rot+2

	movw 4(r8),r0
	movw 2(r8),4(r8)
	movw (r8),2(r8)
	movw r0,(r8)
	brw next

/* ROTATE				*/
	.byte 6; .ascii "ROTAT"
	.word rot-8
rotate:	.word rotate+2

	bicw3 $0177760,(r8),r0
	movw 2(r8),(r8)
	movl (r8),r1
	addw2 $2,r8
	rotl r0,r1,r1
	movw r1,(r8)
	brw next

/* SWAP					*/
	.byte 4; .ascii "SWAP "
	.word rotate-8
swap:	.word swap+2

	movw 2(r8),r0
	movw (r8),2(r8)
	movw r0,(r8)
	brw next

/* U<					*/
	.byte 2; .ascii "U<   "
	.word swap-8
uless:	.word uless+2

	clrw r0
	cmpw (r8)+,(r8)
	blequ 1f
	movw $-1,r0
1:	movw r0,(r8)
	brw next

/* U>					*/
	.byte 2; .ascii "U>   "
	.word uless-8
ugreater:	.word ugreater+2

	clrw r0
	cmpw (r8)+,(r8)
	bgequ 1f
	movw $-1,r0
1:	movw r0,(r8)
	brw next

/* UM*					*/
	.byte 3; .ascii "UM*  "
	.word ugreater-8
umstar:	.word umstar+2

	movzwl (r8)+,r0
	movzwl (r8),r1
	mull2 r1,r0
	movl r0,-(r8)
	movw (r8)+,2(r8)
	brw next

/* UM/					*/
	.byte 3; .ascii "UM/  "
	.word umstar-8
umslash:	.word umslash+2

	movzwl (r8),r2
	movw 4(r8),(r8)
	movl (r8)+,r3
	clrl r4
	ediv r2,r3,r0,r1
	movw r1,(r8)
	movw r0,-(r8)
	brw next

/* XOR					*/
	.byte 3; .ascii "XOR  "
	.word umslash-8
exor:	.word exor+2

	xorw2 (r8)+,(r8)
	brw next
!E!O!F