UNIX FORTH for the VAX (part 2 of 8)

lwt1 at aplvax.UUCP lwt1 at aplvax.UUCP
Sat Jun 23 04:42:11 AEST 1984


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



More information about the Comp.sources.unix mailing list