UNIX FORTH for the PDP11 (part 1 of 7)

lwt1 at aplvax.UUCP lwt1 at aplvax.UUCP
Sat Jun 9 05:55:10 AEST 1984


Here is part 1 of the source for FORTH for the PDP-11.
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.

VAX-FORTH should be 'forth'-coming {yuk-yuk} within a couple of weeks.

Have fun!



						-Lloyd W. Taylor
						 ... seismo!umcp-cs!aplvax!lwt1
---I will have had been there before, soon---

---------------------------------- cut here ----------------------------------
echo x - README
cat >README <<'+E+O+F'
.TL
Unix-FORTH for the PDP-11
.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.  One potential problem with this step is the use of the PDP-11 extended
instruction set operations DIV and MUL.  If your machine lacks these 
instructions, you will have to code them yourself.  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
Three more possible portability problems exist.  The first is in the a.out
format used.  Our version of unix uses:
.DS L
struct	exec {		/* a.out header */
	int     	a_magic;	/* magic number */
	unsigned	a_text; 	/* size of text segment */
	unsigned	a_data; 	/* size of initialized data */
	unsigned	a_bss;  	/* size of unitialized data */
	unsigned	a_syms; 	/* size of symbol table */
	unsigned	a_entry; 	/* entry point */
	unsigned	a_unused;	/* not used */
	unsigned	a_flag; 	/* relocation info stripped */
};

#define	A_MAGIC1	0407       	/* normal */
#define	A_MAGIC2	0410       	/* read-only text */
#define	A_MAGIC3	0411       	/* separated I&D */
#define	A_MAGIC4	0412       	/* mapped read-only text */
.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. The final problem
could be in the implementation of system calls.  Our Venix system (similar to
Unix version 7) implements system calls as TRAP instructions and returns an
error flag in the C bit of the condition codes.  If your system behaves
differently, the comments should help you to modify the code appropriately.
.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.
.bp
.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:

	Lloyd W. Taylor
	JHU/Applied Physics Lab
	Johns Hopkins Road
	Laurel, MD 20707
	(301) 953-5000

	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
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.
This utility was developed independently from any UNIX or VENIX source code.
.SH "SEE ALSO"
Unix-FORTH for the TEGSE, TCE-T84-34
.SH AUTHORS
J. Hayes
+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: not 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



More information about the Comp.sources.unix mailing list