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