[alt.sources] TILE FORTH PACKAGE 7

mip@massormetrix.ida.liu.se (Mikael Patel) (12/19/89)

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 7 (of 7)."
# Contents:  kernel.c
# Wrapped by mip@massormetrix on Mon Dec 18 18:40:14 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f kernel.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"kernel.c\"
else
echo shar: Extracting \"kernel.c\" \(57109 characters\)
sed "s/^X//" >kernel.c <<'END_OF_kernel.c'
X/*
X  C BASED FORTH-83 MULTI-TASKING KERNEL
X
X  Copyright (c) 1989 by Mikael R.K. Patel
X
X  Computer Aided Design Laboratory (CADLAB)
X  Department of Computer and Information Science
X  Linkoping University
X  S-581 83 LINKOPING
X  SWEDEN
X
X  Email: mip@ida.liu.se
X
X  Started on: 30 June 1988
X
X  Last updated on: 11 December 1989
X
X  Dependencies:
X       (cc) kernel.h, error.h, memory.h and io.c
X
X  Description:
X       Virtual Forth machine and kernel code supporting multi-tasking of
X       light weight processes. A pure 32-bit Forth-83 Standard implementation.
X
X       Extended with argument binding and local variables, exception
X       handling, queue data management, multi-tasking, symbol hiding and
X       casting, forwarding, null terminated string and memory allocation,
X       file search paths, and source library module loading.
X  
X       The kernel does not implement the block word set. All code is
X       stored as text files.
X
X  Copying:
X       This program is free software; you can redistribute it and/or modify
X       it under the terms of the GNU General Public License as published by
X       the Free Software Foundation; either version 1, or (at your option)
X       any later version.
X
X       This program is distributed in the hope that it will be useful,
X       but WITHOUT ANY WARRANTY; without even the implied warranty of
X       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X       GNU General Public License for more details.
X
X       You should have received a copy of the GNU General Public License
X       along with this program; see the file COPYING.  If not, write to
X       the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
X
X*/
X
X#include "kernel.h"
X#include "memory.h"
X#include "error.h"
X#include "io.h"
X
X
X/* EXTERNAL DECLARATIONS */
X
Xextern void io_dispatch();
X
X
X/* INTERNAL FORWARD DECLARATIONS */
X
Xextern ENTRY terminate;
Xextern ENTRY toexception;
Xextern ENTRY kernel_abort;
Xextern ENTRY span;
Xextern ENTRY state;
Xextern ENTRY vocabulary;
Xextern char  thepad[];
Xextern char  thetib[];
X
X
X/* VOCABULARY LISTING PARAMETERS */
X
X#define COLUMNWIDTH 15
X#define LINEWIDTH 75
X
X
X/* CONTROL STRUCTURE MARKERS */
X
X#define ELSE 1
X#define THEN 2
X#define AGAIN 4
X#define UNTIL 8
X#define WHILE 16
X#define REPEAT 32
X#define LOOP 64
X#define PLUSLOOP 128
X#define OF 256
X#define ENDOF 512
X#define ENDCASE 1024
X#define SEMICOLON 2048
X
X
X/* MULTI-TASKING MACHINE REGISTERS */
X
Xlong verbose;			/* Application or programming mode */
Xlong quited;			/* Interpreter toploop state */
Xlong running;			/* Task switch flag */
Xlong tasking;			/* Multi-tasking flag */
X
XTASK *tp;			/* Task pointer */
XTASK *foreground;		/* Foreground task pointer */
X
X
X/* FORTH MACHINE REGISTERS */
X
Xlong tos;			/* Top of stack register */
Xlong *sp;			/* Parameter stack pointer */
Xlong *s0;			/* Bottom of parameter stack pointer */
X
Xlong *ip;			/* Instruction pointer */
Xlong *rp;			/* Return stack pointer */
Xlong *r0;			/* Bottom of return stack pointer */
X
Xlong *fp;			/* Argument frame pointer */
Xlong *ep;			/* Exception frame pointer */
X
X
X/* VOCABULARY SEARCH LISTS */
X
X#define CONTEXTSIZE 32
X
Xstatic ENTRY *current = &forth;
Xstatic ENTRY *context[CONTEXTSIZE] = {&forth};
X
X
X/* ENTRY LOOKUP CACHE, SIZE AND HASH FUNCTION */
X
X#define CACHESIZE 256
X#define hash(s) ((s[0] + (s[1] << 4)) & (CACHESIZE - 1))
X
Xstatic ENTRY *cache[CACHESIZE];
X
X
X/* DICTIONARY AREA FOR THREADED CODE AND DATA */
X
Xlong *dictionary;
Xlong *dp;
X
X
X/* INTERNAL STRUCTURE SIZES */
X
X#define PADSIZE 84
X#define TIBSIZE 256
X    
X
X/* INNER MULTI-TASKING FORTH VIRTUAL MACHINE */
X
Xvoid doinner()
X{
X    long e;
X
X    /* Exception marking and handler */
X    if (e = setjmp(restart)) {
X	spush(e);
X	doraise();
X    }
X    
X    /* Run virtual machine until task switch */
X    running = TRUE;
X    while (running) {
X
X	/* Fetch next thread to execute */
X	ENTRY *p = (ENTRY *) *ip++;
X
X	/* Select on type of entry */
X	switch (p -> code) {
X	  case CODE:
X	    ((void (*)()) (p -> parameter))(); 
X	    break;
X	  case COLON:
X	    rpush(ip);
X	    jump(p -> parameter);
X	    break;
X	  case VARIABLE:
X	    spush(&(p -> parameter));
X	    break;
X	  case CONSTANT:
X	    spush(p -> parameter);
X	    break;
X	  case VOCABULARY:
X	    doappend(p);
X	    break;
X	  case CREATE:
X	    spush(p -> parameter);
X	    break;
X	  case USER:
X	    spush(tp + p -> parameter);
X	    break;
X	  case LOCAL:
X	    spush(*((long *) (long) fp - p -> parameter));
X	    break;
X	  case FORWARD:
X	    if (p -> parameter)
X		docall((ENTRY *) p -> parameter);
X	    else {
X		(void) printf("%s: unresolved forward entry\n", p -> name);
X		doabort();
X	    }
X	    break;
X	  case EXCEPTION:
X	    spush(p);
X	    break;
X	  case FIELD:
X	    tos = p -> parameter + tos;
X	    break;
X	  default: /* DOES: FORTH LEVEL INTERPRETATION */
X	    rpush(ip);
X	    spush(p -> parameter);
X	    jump(p -> code);
X	    break;
X	}
X    }
X}
X
Xvoid docommand()
X{
X    long e;
X
X    /* Exception marking and handler */
X    if (e = setjmp(restart)) {
X	spush(e);
X	doraise();
X	return;
X    }
X
X    /* Execute command on top of stack */
X    doexecute();
X
X    /* Check if this affects the virtual machine */
X    if (rp != r0) {
X	tasking = TRUE;
X
X	/* Run the virtual machine and allow user extension */
X	while (tasking) {
X	    doinner();
X	    io_dispatch();
X	}
X    }
X}
X
Xvoid docall(p)
X    ENTRY *p;
X{
X    /* Select on type of entry */
X    switch (p -> code) {
X      case CODE:
X	((void (*)()) (p -> parameter))(); 
X	return;	
X      case COLON:
X	rpush(ip);
X	jump(p -> parameter);
X	return;
X      case VARIABLE:
X	spush(&(p -> parameter));
X	return;
X      case CONSTANT:
X	spush(p -> parameter);
X	return;
X      case VOCABULARY:
X	doappend(p);
X	return;
X      case CREATE:
X	spush(p -> parameter);
X	return;
X      case USER:
X	spush(tp + p -> parameter);
X	return;
X      case LOCAL:
X	spush(*((long *) (long) fp - p -> parameter));
X	return;
X      case FORWARD:
X	if (p -> parameter)
X	    docall((ENTRY *) p -> parameter);
X	else {
X	    (void) printf("%s: unresolved forward entry\n", p -> name);
X	    doabort();
X	}
X	return;
X      case EXCEPTION:
X	spush(p);
X	return;
X      case FIELD:
X	tos = p -> parameter + tos;
X	return;
X      default: /* DOES: FORTH LEVEL INTERPRETATION */
X	rpush(ip);
X	spush(p -> parameter);
X	jump(p -> code);
X	return;
X    }
X}
X
Xvoid doappend(p)
X    ENTRY *p;
X{
X    long v;
X    
X    /* Flush the entry cache */
X    spush(FALSE);
X    dorestore();
X
X    /* Check if the vocabulary is a member of the current search set */
X    for (v = 0; v < CONTEXTSIZE; v++)
X
X	/* If a member then rotate the vocabulary first */
X	if (p == context[v]) {
X	    for (; v; v--) context[v] = context[v - 1];
X	    context[0] = p;
X	    return;
X	}
X
X    /* If not a member, then insert first into the search set */
X    for (v = CONTEXTSIZE - 1; v > 0; v--) context[v] = context[v - 1];
X    context[0] = p;
X}    
X
X
X/* VOCABULARY ROOT */
X
XENTRY forth = {(ENTRY *) NIL, "forth", NORMAL, VOCABULARY, (long) &vocabulary};
X
X
X/* CONTROL: EXTENSION LEVEL DEFINITIONS */
X
Xvoid doparenbranch()
X{
X    branch(*ip);
X}
X
XCOMPILATION_CODE(parenbranch, forth, "(branch)", doparenbranch);
X
Xvoid doparenqbranch()
X{
X    long flag = spop;
X    
X    /* Check flag on top of stack and branch if false */
X    if (flag)
X	skip;
X    else
X	branch(*ip);
X}
X
XCOMPILATION_CODE(parenqbranch, parenbranch, "(?branch)", doparenqbranch);
X
Xvoid doparendo()
X{
X    /* Build a loop frame on return stack */
X    rpush(ip++);
X    rpush(spop);
X    rpush(spop);
X}
X
XCOMPILATION_CODE(parendo, parenqbranch, "(do)", doparendo);
X
Xvoid doparenqdo()
X{
X    /* Check if the start and stop value are equal */
X    if (tos == snth(0)) {
X
X	/* If equal then branch over the loop block */
X	sdrop(1);
X	branch(*ip);
X    }
X    else {
X
X	/* else build a loop frame on the return stack */
X	rpush(ip++);
X	rpush(spop);
X	rpush(spop);
X    }
X}
X
XCOMPILATION_CODE(parenqdo, parendo, "(?do)", doparenqdo);
X
Xvoid doparenloop()
X{
X    /* Increment the index by one and check if within loop range */
X    rnth(1) += 1;
X    if (rnth(0) > rnth(1)) {
X
X	/* Branch if still within range */
X	branch(*ip);
X	return;
X    }
X
X    /* Else remove the loop frame from the return stack and skip */
X    rdrop(3);
X    skip;
X
X}
X
XCOMPILATION_CODE(parenloop, parenqdo, "(loop)", doparenloop);
X
Xvoid doparenplusloop()
X{
X    long d = spop;
X
X    /* Increment the index with the top of stack value */
X    rnth(1) += d;
X
X    /* Check direction and if the index is still within the loop range */
X    if (d > 0) {
X	if (rnth(0) > rnth(1)) {
X	    branch(*ip);
X	    return;
X	}
X    }
X    else {
X	if (rnth(0) < rnth(1)) {
X	    branch(*ip);
X	    return;
X	}
X    }
X
X    /* Else remove the loop frame from the return stack and skip */
X    rdrop(3);
X    skip;
X}
X
XCOMPILATION_CODE(parenplusloop, parenloop, "(+loop)", doparenplusloop);
X
X
X/* COMPILATION LITERALS */
X
Xvoid doparenliteral()
X{ 
X    spush(*ip++);
X}
X
XCOMPILATION_CODE(parenliteral, parenplusloop, "(literal)", doparenliteral);
X
Xvoid doparendotquote()
X{
X    (void) printf("%s", *ip++);
X}
X
XCOMPILATION_CODE(parendotquote, parenliteral, "(.\")", doparendotquote);
X
Xvoid doparenabortquote()
X{
X    long flag = spop;
X    
X    /* Check flag on top of stack. If true then abort and give inline message */
X    if (flag) {
X	doparendotquote();
X	doabort();
X    }
X    else skip;
X}
X
XCOMPILATION_CODE(parenabortquote, parendotquote, "(abort\")", doparenabortquote);
X
Xvoid doparensemicolon()
X{
X    jump(rpop);
X}
X
XCOMPILATION_CODE(parensemicolon, parendotquote, "(;)", doparensemicolon);
X
Xvoid doparendoes()
X{
X    ((ENTRY *) (current -> parameter)) -> code = (long) ip;
X    jump(rpop);
X}
X
XCOMPILATION_CODE(parendoes, parensemicolon, "(does>)", doparendoes);
X
X
X/* THREADING PRIMITIVES */
X
Xvoid dothread()
X{
X    *dp++ = spop;
X}
X
XNORMAL_CODE(thread, parendoes, "thread", dothread);
X
Xvoid dounthread()
X{
X    unary(*(long *));
X}
X
XNORMAL_CODE(unthread, thread, "unthread", dounthread);
X
X
X/* COMPILATION: STANDARD EXTENSION LEVEL DEFINITIONS */
X
Xvoid doforwardmark()
X{
X    dohere();
X    spush(0);
X    docomma();
X}
X
XCOMPILATION_CODE(forwardmark, unthread, ">mark", doforwardmark);
X
Xvoid dobackwardmark()
X{
X    dohere();
X}
X
XCOMPILATION_CODE(backwardmark, forwardmark, "<mark", dobackwardmark);
X
Xvoid doforwardresolve()
X{
X    dohere();
X    doover();
X    dominus();
X    doswap();
X    dostore();
X}
X
XCOMPILATION_CODE(forwardresolve, backwardmark, ">resolve", doforwardresolve);
X
Xvoid dobackwardresolve()
X{
X    dohere();
X    dominus();
X    docomma();
X}
X
XCOMPILATION_CODE(backwardresolve, forwardresolve, "<resolve", dobackwardresolve);
X
XNORMAL_VOCABULARY(compiler, forth, "compiler", backwardresolve);
X
X
X/* LOCAL VARIABLES AND ARGUMENT BINDING */
X
Xstatic ENTRY *theframed = (ENTRY *) NIL;
X
Xvoid doremovelocals()
X{
X    /* Check if the last definition used an argument definition */
X    if (theframed) {
X	
X	/* Restore the vocabulary structure */
X	spush(theframed);
X	dorestore();
X	theframed = (ENTRY *) NIL;
X    }
X}
X
Xvoid doparenlink()  
X{
X    /* Build an argument and local variable frame */
X    spush(tos);
X    rpush(fp);
X
X    /* Using the two inline values: arguments and local variables */
X    fp = sp + *ip++;
X    sp = sp - *ip++;
X
X    /* Save entry stack pointer to allow result movement on exit */
X    rpush(sp);
X}
X
XCOMPILATION_CODE(parenlink, forth, "(link)", doparenlink);
X
Xvoid doparenunlink()  
X{    
X    long *t;
X
X    /* Remove the argument and local variable frame */
X    t = (long *) rpop;
X    spush(tos);
X
X    /* And move results to new top of stack */
X    for (--t; t > sp; *--fp = *--t);
X    sp = fp;
X    spop;
X
X    /* Restore old frame pointer */
X    fp = (long *) rpop;
X}
X
XCOMPILATION_CODE(parenunlink, parenlink, "(unlink)", doparenunlink);
X
Xvoid doparenunlinksemicolon() 
X{
X    long *t;
X
X    /* Remove the argument and local variable frame */
X    t = (long *) rpop;
X    spush(tos);
X
X    /* And move results to new top of stack */
X    for (--t; t > sp; *--fp = *--t);
X    sp = fp;
X    spop;
X
X    /* Restore old frame pointer */
X    fp = (long *) rpop;
X
X    /* Return from this colon definition */
X    jump(rpop);
X}
X
XCOMPILATION_CODE(parenunlinksemicolon, parenunlink, "(unlink;)", doparenunlinksemicolon);
X
Xvoid doparenunlinkdoes()
X{
X    long *t;
X
X    /* Remove the argument and local variable frame */
X    t = (long *) rpop;
X    spush(tos);
X
X    /* And move results to new top of stack */
X    for (--t; t > sp; *--fp = *--t);
X    sp = fp;
X    spop;
X
X    /* Restore old frame pointer */
X    fp = (long *) rpop;
X
X    /* Make the last definition of the following does code */
X    ((ENTRY *) ((ENTRY *) current -> parameter)) -> code = (long) ip;
X
X    /* Return from this colon definition */
X    jump(rpop);
X}
X
XCOMPILATION_CODE(parenunlinkdoes, parenunlinksemicolon, "(unlinkdoes>)", doparenunlinkdoes);
X
Xvoid doparenlocal()
X{
X    spush(((long *) (long) fp - *ip++));
X}
X
XCOMPILATION_CODE(parenlocal, parenunlinkdoes, "(local)", doparenlocal);
X
Xvoid doparenlocalstore()
X{
X    *((long *) (long) fp - *ip++) = spop;
X}
X
XCOMPILATION_CODE(parenlocalstore, parenlocal, "(local!)", doparenlocalstore);
X
Xvoid doparenlocalfetch()
X{
X    spush(*((long *) (long) fp - *ip++));
X}
X
XCOMPILATION_CODE(parenlocalfetch, parenlocalstore, "(local@)", doparenlocalfetch);
X
Xvoid doassignlocal()
X{
X    *((long *) (long) fp - ((ENTRY *) *ip++) -> parameter) = spop;
X}
X
XCOMPILATION_CODE(assignlocal, parenlocalfetch, "->", doassignlocal);
X
XCOMPILATION_CODE(localexit, assignlocal, "exit", doparenunlinksemicolon);
X
Xvoid docurlebracket()
X{
X    long frameflag = 1;
X    long argflag   = 1;
X    long arguments = 0;
X    long locals    = 0;
X
X    /* Check only one active lexical levels allowed */
X    if (theframed) {
X	(void) printf("%s: illegal argument binding\n", theframed -> name);
X	doremovelocals();
X	doabort();
X	return;
X    }
X
X    /* Save pointer to latest defintion to allow removal of local names */
X    theframed = (ENTRY *) current -> parameter;
X
X    /* While the end of the frame description is not found */
X    while (frameflag) {
X
X	/* Scan the next symbol */
X    	spush(' ');
X	doword();
X	if (io_eof()) {
X	    (void) printf("locals: end of file during scan of parameter list\n");
X	    doabort();
X	    return;
X	}
X
X	/* Check if it marks the end of the argument section */
X	if (STREQ(tos, "|")) {
X	    argflag = 0;
X	}
X	else {
X	    /* else check if its the end of the frame description */
X            if (STREQ(tos, "}")) {
X	    	frameflag = 0;
X	    }
X	    else {
X		/* Or the beginning of the return description */
X	    	if (STREQ(tos, "--")) {
X		    spop;
X		    spush('}');
X		    doword();
X		    frameflag = 0;
X		}
X		else {
X		    /* If not then make the symbol a local variable */
X		    if (argflag)
X			arguments++;
X		    else
X			locals++;
X		    (void) makeentry((char *) tos,
X				     (long) LOCAL,
X				     (long) COMPILATION,
X				     arguments + locals);
X		}
X	    }
X	}
X	spop;
X    }
X
X    /* Compile the parameter binding linkage */
X    spush(&parenlink);
X    dothread();
X
X    /* And the appropriate frame size */
X    spush(arguments);
X    docomma();
X    spush(locals);
X    docomma();
X}
X
XCOMPILATION_IMMEDIATE_CODE(curlebracket, localexit, "{", docurlebracket);
X
XNORMAL_VOCABULARY(locals, compiler, "locals", curlebracket);
X
X
X/* NULL TERMINATED STRINGS */
X
Xvoid doparenquote()
X{
X    spush(*ip++);
X}
X
XCOMPILATION_CODE(parenquote, forth, "(\")", doparenquote);
X
Xvoid doquote()
X{
X    /* Scan for the string if not end of input */
X    (void) io_scan(thetib, '"');
X
X    /* Make a copy of it */
X    spush(thetib);
X    dostringcopy();
X
X    /* If compilation mode then thread a string literal */
X    if (state.parameter) {
X	spush(&parenquote);
X	dothread();
X	docomma();
X    }
X}
X
XIMMEDIATE_CODE(quote, parenquote, "\"", doquote);
X
Xvoid dostringlength()
X{
X    tos = (long) strlen((char *) tos);
X}
X
XNORMAL_CODE(stringlength, quote, "length", dostringlength);
X
Xvoid dostringcopy()
X{
X    tos = (long) strcpy(malloc((unsigned) strlen((char *) tos) + 1), (char *) tos);
X}
X
XNORMAL_CODE(stringcopy, stringlength, "copy", dostringcopy);
X
Xvoid dostringequal()
X{
X    char *s = (char *) spop;
X    
X    tos = ((STREQ(tos, s) ? TRUE : FALSE));
X}
X
XNORMAL_CODE(stringequal, stringcopy, "=", dostringequal);
X
Xvoid dostringcat()
X{
X    char *s = (char *) spop;
X    
X    tos = (long) strcat((char *) tos, s);
X}
X
XNORMAL_CODE(stringcat, stringequal, "+", dostringcat);
X
Xvoid dostringprint()
X{
X    char *s = (char *) spop;
X    
X    (void) printf("%s", s);
X}
X
XNORMAL_CODE(stringprint, stringcat, "print", dostringprint);
X
XNORMAL_VOCABULARY(string, locals, "string", stringprint); 
X
X
X/* MEMORY ALLOCATION */
X
Xvoid domalloc()
X{
X    tos = (long) malloc((unsigned) tos);
X}
X
XNORMAL_CODE(kernel_malloc, forth, "malloc", domalloc);
X
Xvoid dorealloc()
X{
X    char *m = (char *) spop;
X    
X    tos = (long) realloc(m, (unsigned) tos);
X}
X
XNORMAL_CODE(kernel_realloc, kernel_malloc, "realloc", dorealloc);
X
Xvoid dofree()
X{
X    char *m = (char *) spop;
X    
X    free(m);
X}
X
XNORMAL_CODE(kernel_free, kernel_realloc, "free", dofree);
X
XNORMAL_VOCABULARY(memory, string, "memory", kernel_free); 
X
X
X/* DOUBLE LINKED LIST */
X
Xvoid doqemptyqueue()
X{
X    compare(== (long) (((QUEUE *) tos) -> succ));
X}
X
XNORMAL_CODE(qemptyqueue, forth, "?empty", doqemptyqueue);
X
Xvoid dointoqueue()
X{
X    QUEUE *t, *q;
X
X    q = (QUEUE *) spop;
X    t = (QUEUE *) spop;
X
X    t -> pred = q -> pred;
X    t -> succ = q;
X
X    q -> pred -> succ = t;
X    q -> pred = t;
X}
X
XNORMAL_CODE(intoqueue, qemptyqueue, "into", dointoqueue);
X
Xvoid dooutqueue()
X{
X    QUEUE *t = (QUEUE *) spop;
X
X    t -> succ -> pred = t -> pred;
X    t -> pred -> succ = t -> succ;
X
X    t -> succ = t -> pred = t;
X}
X
XNORMAL_CODE(outqueue, intoqueue, "out", dooutqueue);
X
XNORMAL_VOCABULARY(queues, memory, "queues", outqueue);
X
X
X/* MULTI-TASKING */
X
Xstatic long toterminate = (long) &terminate;
X
XNORMAL_CONSTANT(kernel_foreground, forth, "foreground", (long) &foreground);
X
XNORMAL_CONSTANT(kernel_running, kernel_foreground, "running", (long) &tp);
X
Xvoid douser()
X{
X    spush(NORMAL);
X    spush(USER);
X    spush(' ');
X    doword();
X    doentry();
X}
X
XNORMAL_CODE(user, kernel_running, "user", douser);
X
XTASK *maketask(users, params, returns, action)
X    long users, params, returns, action;
X{
X    long size = sizeof(TASK_HEADER) + users + params + returns;
X    TASK *t = (TASK *) malloc((unsigned) size);
X
X    /* Initiate queues structure, status and environment */
X    t -> queue.succ = t -> queue.pred = (QUEUE *) t;
X    t -> status = READY;
X
X    t -> s0 = t -> sp = (long *) ((char *) t + size - returns);
X    t -> r0 = t -> rp = (long *) ((char *) t + size);
X    t -> ip = (action ? (long *) action : (long *) &toterminate);
X    t -> fp = NIL;
X    t -> ep = NIL;
X
X    /* Return task pointer */
X    return t;
X}
X
Xvoid dotask()
X{
X    long users, params, returns, action;
X
X    action  = spop;
X    returns = spop;
X    params  = spop;
X    users   = spop;
X    spush(maketask(users, params, returns, action));
X}
X
XNORMAL_CODE(task, user, "task", dotask);
X
Xvoid doresume()
X{
X    TASK *t = (TASK *) tos;
X
X    /* Check if the task to resume is the current task and active */
X    if (t -> status && t != tp) {
X
X	/* Store the state of the current task */
X	tp -> sp = sp;
X	tp -> s0 = s0;
X	tp -> ip = ip;
X	tp -> rp = rp;
X	tp -> r0 = r0;
X	tp -> fp = fp;
X	tp -> ep = ep;
X
X	/* Indicate task switch to the virtual machine */
X	running = FALSE;
X    
X	/* Restore the parameter task */
X	sp = t -> sp;
X	s0 = t -> s0;
X	ip = t -> ip;
X	rp = t -> rp;
X	r0 = t -> r0;
X	fp = t -> fp;
X	ep = t -> ep;
X	tp = t;
X    }
X
X    /* Load top of stack again */
X    spop;
X}
X
XNORMAL_CODE(resume, task, "resume", doresume);
X
Xvoid doschedule()
X{
X    /* Put the task after the current task */
X    spush(tp -> queue.succ);
X    dointoqueue();
X
X    /* Resume the task now */
X    dodetach();
X
X    /* Restore parameter and return stack */
X    spush(tp);
X    rpush(&toterminate);
X
X    /* Mark the task as running */
X    tp -> status = RUNNING;
X}
X
XNORMAL_CODE(schedule, resume, "schedule", doschedule);
X
Xvoid dodetach()
X{
X    /* Resume the next task in the system task queue */
X    spush(tp -> queue.succ);
X    doresume();
X}
X
XNORMAL_CODE(detach, schedule , "detach", dodetach);
X
Xvoid doterminate()
X{
X    TASK *t = tp;
X
X    /* Check if the task is the foreground task */
X    if (tp == foreground) {
X
X	/* Empty the return stack and signal end of execution to inner loop */
X	rinit;
X	running = FALSE;
X	tasking = FALSE;
X
X	/* Foreground should always terminate on last exit */
X	ip = (long *) &toterminate;
X    }
X    else {
X
X	/* else remove the current task from the system task queue */
X	dodetach();
X	t -> status = TERMINATED;
X	spush(t);
X	dooutqueue();
X    }
X}
X
XNORMAL_CODE(terminate, detach, "terminate", doterminate);
X
XNORMAL_VOCABULARY(multitasking, queues, "multi-tasking", terminate);
X
X
X/* EXCEPTION MANAGEMENT */
X
Xvoid donewexception()
X{
X    spush(NIL);
X    spush(NORMAL);
X    spush(EXCEPTION);
X    spush(' ');
X    doword();
X    doentry();
X}
X
XNORMAL_CODE(newexception, forth, "exception", donewexception);
X
Xvoid doparenexceptionsemicolon()
X{  
X    /* Restore the old exception frame pointer */
X    ep = (long *) rpop;
X
X    /* Remove the exception frame */
X    rdrop(4);
X    
X    /* Return from the current definition */
X    jump(rpop);
X}
X
XCOMPILATION_CODE(parenexceptionsemicolon, newexception, "(exception;)", doparenexceptionsemicolon);
X
Xvoid doparenexceptionunlinksemicolon()
X{  
X    long *t;
X
X    /* Remove the argument and local variable frame */
X    t = (long *) rpop;
X    spush(tos);
X
X    /* And move results to new top of stack */
X    for (--t; t > sp; *--fp = *--t);
X    sp = fp;
X    spop;
X
X    /* Restore old frame pointer */
X    fp = (long *) rpop;
X
X    /* Restore the old exception frame pointer */
X    ep = (long *) rpop;
X
X    /* Remove the exception frame */
X    rdrop(4);
X    
X    /* Return from the current definition */
X    jump(rpop);
X}
X
XCOMPILATION_CODE(parenexceptionunlinksemicolon, parenexceptionsemicolon, "(exceptionunlink;)", doparenexceptionunlinksemicolon);
X
Xvoid doparenexception()
X{   
X    long body;
X
X    /* Capture pointer to body */
X    body = spop;
X   
X    /* Build an exception frame */
X    rpush(tos);
X    rpush(sp);
X    rpush(ip);
X    rpush(fp);
X    rpush(ep);
X    ep = rp;
X    
X    /* Jump to the body of the definition */
X    jump(body);
X}
X
XCOMPILATION_CODE(parenexception, parenexceptionunlinksemicolon, "(exception>)", doparenexception);
X
Xvoid doexception()
X{  
X    ENTRY *t;
X
X    /* Set up pointer to last definition */
X    dolast();
X    t = (ENTRY *) spop;
X    
X    /* Compile an exit of the current definition */
X    spush((theframed ? &parenexceptionunlinksemicolon : &parenexceptionsemicolon));
X    dothread();
X    doremovelocals();
X    
X    /* Redefine the code type of the last definition */
X    t -> code = (long) dp;
X    
X    /* Compile the run time exception management definition */
X    spush(&parenexception);
X    dothread();
X}
X
XCOMPILATION_IMMEDIATE_CODE(exception, parenexception, "exception>", doexception);
X
Xvoid doraise()
X{  
X    long s = spop;
X    
X    /* Check if there is an exception block available */
X    if (ep) {
X
X	/* Restore the call environment */
X	rp = ep;
X	ep = (long *) rpop;
X	fp = (long *) rpop;
X	ip = (long *) rpop;
X	sp = (long *) rpop;
X	tos = rpop;
X
X	/* Pass on the signal or exception to the exception block */
X	spush(s);
X    }
X    else {
X	
X	/* Call low level management of signal */
X	(void) error_signal(s);
X    }
X}
X
XNORMAL_CODE(raise, exception, "raise", doraise);
X
XNORMAL_VOCABULARY(exceptions, multitasking, "exceptions", raise);
X
X
X/* LOGIC: FORTH-83 VOCABULARY */
X
XNORMAL_CONSTANT(false, exceptions, "false", FALSE);
X
XNORMAL_CONSTANT(true, false, "true", TRUE);
X
Xvoid doboolean()
X{
X    compare(!= 0);
X}
X
XNORMAL_CODE(boolean, true, "boolean", doboolean);
X
Xvoid donot()
X{
X    unary(~);
X}
X
XNORMAL_CODE(not, boolean, "not", donot);
X
Xvoid doand()
X{
X    binary(&);
X}
X
XNORMAL_CODE(and, not, "and", doand);
X
Xvoid door()
X{
X    binary(|);
X}
X
XNORMAL_CODE(or, and, "or", door);
X
Xvoid doxor()
X{
X    binary(^);
X}
X
XNORMAL_CODE(xor, or, "xor", doxor);
X
Xvoid doqwithin()
X{
X    long value;
X    long upper;
X    long lower;
X    
X    upper = spop;
X    lower = spop;
X    value = spop;
X    
X    spush((value > upper) || (value < lower) ? FALSE : TRUE);
X}
X    
XNORMAL_CODE(qwithin, xor, "?within", doqwithin);
X
X
X/* STACK MANIPULATION */
X
Xvoid dodup()
X{
X    spush(tos);
X}
X
XNORMAL_CODE(kernel_dup, qwithin, "dup", dodup);
X
Xvoid dodrop()
X{
X    spop;
X}
X
XNORMAL_CODE(drop, kernel_dup, "drop", dodrop);
X
Xvoid doswap()
X{
X    long t = tos;
X
X    tos = snth(0);
X    snth(0) = t;
X}
X
XNORMAL_CODE(swap, drop, "swap", doswap);
X
Xvoid doover()
X{
X    spush(snth(1));
X}
X
XNORMAL_CODE(over, swap, "over", doover);
X
Xvoid dorot()
X{
X    long t = tos;
X
X    tos = snth(1);
X    snth(1) = snth(0);
X    snth(0) = t;
X}
X
XNORMAL_CODE(rot, over, "rot", dorot);
X
Xvoid dopick()
X{
X    tos = snth(tos);
X}
X
XNORMAL_CODE(pick, rot, "pick", dopick);
X
Xvoid doroll()
X{
X    long e;
X    long *s;
X
X    /* Fetch roll parameters: number and element */
X    e = snth(tos);
X
X    /* Roll the stack */
X    for (s = sp + tos; s > sp; s--) *s = *(s - 1);
X    sp++;
X    
X    /* And assign the new top of stack */
X    tos = e;
X}
X
XNORMAL_CODE(roll, pick, "roll", doroll);
X
Xvoid doqdup()
X{
X    if (tos) spush(tos);
X}
X
XNORMAL_CODE(qdup, roll, "?dup", doqdup);
X
Xvoid dotor()
X{
X    rpush(spop);
X}
X
XCOMPILATION_CODE(tor, qdup, ">r", dotor);
X
Xvoid dofromr()
X{
X    spush(rpop);
X}
X
XCOMPILATION_CODE(fromr, tor, "r>", dofromr);
X
Xvoid docopyr()
X{
X    spush(*rp);
X}
X
XCOMPILATION_CODE(copyr, fromr, "r@", docopyr);
X
Xvoid dodepth()
X{
X    long *t = sp;
X
X    spush((s0 - t));
X}
X
XNORMAL_CODE(depth, copyr, "depth", dodepth);
X
Xvoid dodots()
X{
X    /* Print the stack depth */
X    (void) printf("[%d] ", s0 - sp);
X
X    /* Check if there are any elements on the stack */
X    if (s0 - sp > 0) {
X	long *s;
X
X	/* Print them and don't forget top of stack */
X	for (s = s0 - 2; s >= sp; s--) {
X	    (void) printf("\\");
X	    spush(*s);
X	    if (tos < 0) {
X		(void) putchar('-');
X		tos = -tos;
X	    }
X	    dolesssharp();
X	    dosharps();
X	    dosharpgreater();
X	    dotype();
X	}
X	(void) printf("\\");
X	dodup();
X	dodot();
X    }
X}
X
XNORMAL_CODE(dots, depth, ".s", dodots);
X
X
X/* COMPARISON */
X
Xvoid dolessthan()
X{
X    relation(<);
X}
X
XNORMAL_CODE(lessthan, dots, "<", dolessthan);
X
Xvoid doequals()
X{
X    relation(==);
X}
X
XNORMAL_CODE(equals, lessthan, "=", doequals);
X
Xvoid dogreaterthan()
X{
X    relation(>);
X}
X
XNORMAL_CODE(greaterthan, equals, ">", dogreaterthan);
X
Xvoid dozeroless()
X{
X    compare(< 0);
X}
X
XNORMAL_CODE(zeroless, greaterthan, "0<", dozeroless);
X
Xvoid dozeroequals()
X{
X    compare(== 0);
X}
X
XNORMAL_CODE(zeroequals, zeroless, "0=", dozeroequals);
X
Xvoid dozerogreater()
X{
X    compare(> 0);
X}
X
XNORMAL_CODE(zerogreater, zeroequals, "0>", dozerogreater);
X
Xvoid doulessthan()
X{
X    urelation(<);
X}
X
XNORMAL_CODE(ulessthan, zerogreater, "u<", doulessthan);
X
X
X/* CONSTANTS */
X
XNORMAL_CONSTANT(nil, ulessthan, "nil", NIL);
X
XNORMAL_CONSTANT(minustwo, nil, "-2", -2);
X
XNORMAL_CONSTANT(minusone, minustwo, "-1", -1);
X
XNORMAL_CONSTANT(zero, minusone, "0", 0);
X
XNORMAL_CONSTANT(one, zero, "1", 1);
X
XNORMAL_CONSTANT(two, one, "2", 2);
X
X
X/* ARITHMETRIC */
X
Xvoid doplus()
X{
X    binary(+);
X}
X
XNORMAL_CODE(plus, two, "+", doplus);
X
Xvoid dominus()
X{
X    binary(-);
X}
X
XNORMAL_CODE(minus, plus, "-", dominus);
X
Xvoid dooneplus()
X{
X    unary(++);
X}
X
XNORMAL_CODE(oneplus, minus, "1+", dooneplus);
X
Xvoid dooneminus()
X{
X    unary(--);
X}
X
XNORMAL_CODE(oneminus, oneplus, "1-", dooneminus);
X
Xvoid dotwoplus()
X{
X    unary(2 +);
X}
X
XNORMAL_CODE(twoplus, oneminus, "2+", dotwoplus);
X
Xvoid dotwominus()
X{
X    unary(-2 +);
X}
X
XNORMAL_CODE(twominus, twoplus, "2-", dotwominus);
X
Xvoid dotwotimes()
X{
X    tos <<= 1;
X}
X
XNORMAL_CODE(twotimes, twominus, "2*", dotwotimes);
X
Xvoid doleftshift()
X{
X    binary(<<);
X}
X
XNORMAL_CODE(leftshift, twotimes, "<<", doleftshift);
X
Xvoid dotimes()
X{
X    binary(*);
X}
X
XNORMAL_CODE(kernel_times, leftshift, "*", dotimes);
X
Xvoid doumtimes()
X{
X    ubinary(*);
X}
X
XNORMAL_CODE(kernel_utimes, kernel_times, "um*", doumtimes);
X
Xvoid doumdividemod()
X{
X    long t = snth(0);
X
X    snth(0) = (unsigned long) t % (unsigned long) tos;
X    tos = (unsigned long) t / (unsigned long) tos;
X}
X
XNORMAL_CODE(umdividemod, kernel_utimes, "um/mod", doumdividemod);
X
Xvoid dotwodivide()
X{
X    tos >>= 1;
X}
X
XNORMAL_CODE(twodivide, umdividemod, "2/", dotwodivide);
X
Xvoid dorightshift()
X{
X    binary(>>);
X}
X
XNORMAL_CODE(rightshift, twodivide, ">>", dorightshift);
X
Xvoid dodivide()
X{
X    binary(/);
X}
X
XNORMAL_CODE(divide, rightshift, "/", dodivide);
X
Xvoid domod()
X{
X    binary(%);
X}
X
XNORMAL_CODE(mod, divide, "mod", domod);
X
Xvoid dodividemod()
X{
X    long t = snth(0);
X
X    snth(0) = t % tos;
X    tos = t / tos;
X}
X
XNORMAL_CODE(dividemod, mod, "/mod", dodividemod);
X
Xvoid dotimesdividemod()
X{
X    long t = spop;
X
X    tos = tos * snth(0);
X    snth(0) = tos % t;
X    tos = tos / t;
X}
X
XNORMAL_CODE(timesdividemod, dividemod, "*/mod", dotimesdividemod);
X
Xvoid dotimesdivide()
X{
X    long t = spop;
X
X    binary(*);
X    spush(t);
X    binary(/);
X}
X
XNORMAL_CODE(timesdivide, timesdividemod, "*/", dotimesdivide);
X
Xvoid domin()
X{
X    long t = spop;
X    
X    tos = (t < tos ? t : tos);
X}
X
XNORMAL_CODE(min, timesdivide, "min", domin);
X
Xvoid domax()
X{
X    long t = spop;
X    
X    tos = (t > tos ? t : tos);
X}
X
XNORMAL_CODE(max, min, "max", domax);
X
Xvoid doabs()
X{
X    tos = (tos < 0 ? -tos : tos);
X}
X
XNORMAL_CODE(kernel_abs, max, "abs", doabs);
X
Xvoid donegate()
X{
X    unary(-);
X}
X
XNORMAL_CODE(negate, kernel_abs, "negate", donegate);
X
X
X/* MEMORY */
X
Xvoid dofetch()
X{
X    unary(*(long *));
X}
X
XNORMAL_CODE(fetch, negate, "@", dofetch);
X
Xvoid dostore()
X{
X    *((long *) tos) = snth(0);
X    sdrop(1);
X}
X
XNORMAL_CODE(store, fetch, "!", dostore);
X
Xvoid dowfetch()
X{
X    unary(*(word *));
X}
X
XNORMAL_CODE(wfetch, store, "w@", dowfetch);
X
Xvoid dowstore()
X{
X    *((word *) tos) = snth(0);
X    sdrop(1);
X}
X
XNORMAL_CODE(wstore, wfetch, "w!", dowstore);
X
Xvoid docfetch()
X{
X    unary(*(char *));
X}
X
XNORMAL_CODE(cfetch, wstore, "c@", docfetch);
X
Xvoid docstore()
X{
X    *((char *) tos) = snth(0);
X    sdrop(1);
X}
X
XNORMAL_CODE(cstore, cfetch, "c!", docstore);
X
Xvoid doffetch()
X{
X    long pos;
X    long width;
X
X    width = spop;
X    pos = spop;
X    tos = (tos >> pos) & ~(-1 << width);
X}
X
XNORMAL_CODE(ffetch, cstore, "f@", doffetch);
X
Xvoid dofstore()
X{
X    long pos;
X    long width;
X    long value;
X
X    width = spop;
X    pos = spop;
X    value = spop;
X    tos = ((tos & ~(-1 << width)) << pos) | (value & ~((~(-1 << width)) << pos));
X}
X
XNORMAL_CODE(fstore, ffetch, "f!", dofstore);
X
Xvoid dobfetch()
X{
X    long bit = spop;
X
X    tos = (((tos >> bit) & 1) ? TRUE : FALSE);
X}
X
XNORMAL_CODE(bfetch, fstore, "b@", dobfetch);
X
Xvoid dobstore()
X{
X    long bit;
X    long value;
X
X    bit = spop;
X    value = spop;
X
X    tos = (tos ? (value | (1 << bit)) : (value & ~(1 << bit)));
X}
X
XNORMAL_CODE(bstore, bfetch, "b!", dobstore);
X
Xvoid doplusstore()
X{
X    *((long *) tos) += snth(0);
X    sdrop(1);
X}
X
XNORMAL_CODE(plusstore, bstore, "+!", doplusstore);
X
X
X/* STRINGS */
X
Xvoid docmove()
X{
X    register long n;
X    register char *to;
X    register char *from;
X
X    n = spop;
X    to = (char *) spop;
X    from = (char *) spop;
X
X    while (--n != -1) *to++ = *from++;
X}
X
XNORMAL_CODE(cmove, plusstore, "cmove", docmove);
X
Xvoid docmoveup()
X{
X    register long n;
X    register char *to;
X    register char *from;
X
X    n = spop;
X    to = (char *) spop;
X    from = (char *) spop;
X
X    to += n;
X    from += n;
X    while (--n != -1) *--to = *--from;
X}
X
XNORMAL_CODE(cmoveup, cmove, "cmove>", docmoveup);
X
Xvoid dofill()
X{
X    register char with;
X    register long n;
X    register char *from;
X
X    with = (char) spop;
X    n = spop;
X    from = (char *) spop;
X
X    while (--n != -1) *from++ = with;
X}
X
XNORMAL_CODE(fill, cmoveup, "fill", dofill);
X
Xvoid docount()
X{
X    spush(*((char *) tos));
X    snth(0)++;
X}
X
XNORMAL_CODE(count, fill, "count", docount);
X
Xvoid dodashtrailing()
X{
X    char *p = (char *) (snth(0) + tos);
X    
X    tos += 1;
X    while (--tos && (*--p == ' '));
X}
X
XNORMAL_CODE(dashtrailing, count, "-trailing", dodashtrailing);
X
X
X/* NUMERICAL CONVERSION */
X
XNORMAL_VARIABLE(base, dashtrailing, "base", 10);
X
Xvoid dobinary()
X{
X    base.parameter = 2;
X}
X
XNORMAL_CODE(kernel_binary, base, "binary", dobinary);
X
Xvoid dooctal()
X{
X    base.parameter = 8;
X}
X
XNORMAL_CODE(octal, kernel_binary, "octal", dooctal);
X
Xvoid dodecimal()
X{
X    base.parameter = 10;
X}
X
XNORMAL_CODE(decimal, octal, "decimal", dodecimal);
X
Xvoid dohex()
X{
X    base.parameter = 16;
X}
X
XNORMAL_CODE(hex, decimal, "hex", dohex);
X
Xvoid doconvert()
X{
X    register char c;
X    register long b;
X    register long n;
X    
X    b = base.parameter;
X    n = snth(0);			
X
X    for (;;) {
X	c = *(char *) tos;
X	if (c < '0' || c > 'z' || (c > '9' && c < 'a')) {
X	    snth(0) = n;
X	    return;
X	}
X	else {
X	    if (c > '9') c = c - 'a' + ':';
X	    c = c - '0';
X	    if (c < 0 || c >= b) {
X		snth(0) = n;
X		return;
X	    }
X	    n = (n * b) + c;
X	    tos += 1;
X	}
X    }
X}
X
XNORMAL_CODE(convert, hex, "convert", doconvert);
X
Xstatic long hld;
X
Xvoid dolesssharp()
X{
X    hld = (long) thepad + PADSIZE;
X}
X
XNORMAL_CODE(lesssharp, convert, "<#", dolesssharp);
X
Xvoid dosharp()
X{
X    long n = tos;
X    
X    tos = (unsigned long) n / (unsigned long) base.parameter;
X    n = (unsigned long) n % (unsigned long) base.parameter;
X    *(char *) --hld = n + ((n > 9) ? 'a' - 10 : '0');
X}
X
XNORMAL_CODE(sharp, lesssharp, "#", dosharp);
X
Xvoid dosharps()
X{
X    do { dosharp(); } while (tos);
X}
X
XNORMAL_CODE(sharps, sharp, "#s", dosharps);
X
Xvoid dohold()
X{
X    *(char *) --hld = spop;
X}
X
XNORMAL_CODE(hold, sharps, "hold", dohold);
X
Xvoid dosign()
X{
X    long flag = spop;
X    
X    if (flag < 0) *(char *) --hld = '-';
X}
X
XNORMAL_CODE(sign, hold, "sign", dosign);
X
Xvoid dosharpgreater()
X{
X    tos = hld;
X    spush(thepad + PADSIZE - hld);
X}
X
XNORMAL_CODE(sharpgreater, sign, "#>", dosharpgreater);
X
Xvoid doqnumber()
X{
X    char *s0;
X    char *s1;
X    
X    s0 = (char *) spop;
X    spush(0);
X    if (*s0 == '-') {
X	spush(s0 + 1);
X    }
X    else {
X	spush(s0);
X    }
X    doconvert();
X    s1 = (char *) spop;
X    if (*s1 == '\0') {
X	if (*s0 == '-') unary(-);
X	spush(TRUE);
X    }
X    else {
X	tos = (long) s0;
X	spush(FALSE);
X    }
X}
X
XNORMAL_CODE(qnumber, sharpgreater, "?number", doqnumber);
X
X
X/* CONTROL STRUCTURES */
X
Xlong docheck(this)
X    int this;
X{
X    ENTRY *last;
X    long follow = spop;
X
X    /* Check if the symbol is in the follow set */
X    if (this & follow) {
X
X	/* Return true is so */
X	return TRUE;
X    }
X    else {
X
X	/* Else report a control structure error */
X	dolast();
X	last = (ENTRY *) spop;
X	(void) printf("%s: illegal control structure\n", last -> name);
X	doabort();
X
X	return FALSE;
X    }
X}
X
Xvoid dodo()
X{
X    spush(&parendo);
X    dothread();
X    doforwardmark();
X    dobackwardmark();
X    spush(LOOP+PLUSLOOP);
X}
X
XCOMPILATION_IMMEDIATE_CODE(kernel_do, qnumber, "do", dodo);
X
Xvoid doqdo()
X{
X    spush(&parenqdo);
X    dothread();
X    doforwardmark();
X    dobackwardmark();
X    spush(LOOP+PLUSLOOP);
X}
X
XCOMPILATION_IMMEDIATE_CODE(kernel_qdo, kernel_do, "?do", doqdo);
X
Xvoid doloop()
X{
X    if (docheck(LOOP)) {
X	spush(&parenloop);
X	dothread();
X	dobackwardresolve();
X	doforwardresolve();
X    }
X}
X
XCOMPILATION_IMMEDIATE_CODE(loop, kernel_qdo, "loop", doloop);
X
Xvoid doplusloop()
X{
X    if (docheck(PLUSLOOP)) {
X	spush(&parenplusloop);
X	dothread();
X	dobackwardresolve();
X	doforwardresolve();
X    }
X}
X
XCOMPILATION_IMMEDIATE_CODE(plusloop, loop, "+loop", doplusloop);
X
Xvoid doleave()
X{
X    rdrop(2);
X    jump(rpop);
X    branch(*ip);
X}
X
XCOMPILATION_CODE(leave, plusloop, "leave", doleave);
X
Xvoid doi()
X{
X    spush(rnth(1));
X}
X
XCOMPILATION_CODE(kernel_i, leave,"i", doi);
X
Xvoid doj()
X{
X    spush(rnth(4));
X}
X
XCOMPILATION_CODE(kernel_j, kernel_i, "j", doj);
X
Xvoid doif()
X{
X    spush(&parenqbranch);
X    dothread();
X    doforwardmark();
X    spush(ELSE+THEN);
X}
X
XCOMPILATION_IMMEDIATE_CODE(kernel_if, kernel_j, "if", doif);
X
Xvoid doelse()
X{
X    if (docheck(ELSE)) {
X	spush(&parenbranch);
X	dothread();
X	doforwardmark();
X	doswap();
X	doforwardresolve();
X	spush(THEN);
X    }
X}
X
XCOMPILATION_IMMEDIATE_CODE(kernel_else, kernel_if, "else", doelse);
X
Xvoid dothen()
X{
X    if (docheck(THEN)) {
X	doforwardresolve();
X    }
X}
X
XCOMPILATION_IMMEDIATE_CODE(kernel_then, kernel_else, "then", dothen);
X
Xvoid docase()
X{
X    spush(0);
X    spush(OF+ENDCASE);
X}
X
XCOMPILATION_IMMEDIATE_CODE(kernel_case, kernel_then, "case", docase);
X
Xvoid doof()
X{
X    if (docheck(OF)) {
X	spush(&over);
X	dothread();
X	spush(&equals);
X	dothread();
X	spush(&parenqbranch);
X	dothread();
X	doforwardmark();
X	spush(&drop);
X	dothread();
X	spush(ENDOF);
X    }
X}
X
XCOMPILATION_IMMEDIATE_CODE(kernel_of, kernel_case, "of", doof);
X
Xvoid doendof()
X{
X    if (docheck(ENDOF)) {
X	spush(&parenbranch);
X	dothread();
X	doforwardmark();
X	doswap();
X	doforwardresolve();
X	spush(OF+ENDCASE);
X    }
X}
X
XCOMPILATION_IMMEDIATE_CODE(endof, kernel_of, "endof", doendof);
X
Xvoid doendcase()
X{
X    if (docheck(ENDCASE)) {
X	spush(&drop);
X	dothread();
X	while (tos) doforwardresolve();
X	dodrop();
X    }
X}
X
XCOMPILATION_IMMEDIATE_CODE(endcase, endof, "endcase", doendcase);
X
Xvoid dobegin()
X{
X    dobackwardmark();
X    spush(AGAIN+UNTIL+WHILE);
X}
X
XCOMPILATION_IMMEDIATE_CODE(begin, endcase, "begin", dobegin);
X
Xvoid dountil()
X{
X    if (docheck(UNTIL)) {
X	spush(&parenqbranch);
X	dothread();
X	dobackwardresolve();
X    }
X}
X
XCOMPILATION_IMMEDIATE_CODE(until, begin, "until", dountil);
X
Xvoid dowhile()
X{
X    if (docheck(WHILE)) {
X	spush(&parenqbranch);
X	dothread();
X	doforwardmark();
X	spush(REPEAT);
X    }
X}
X
XCOMPILATION_IMMEDIATE_CODE(kernel_while, until, "while", dowhile);
X
Xvoid dorepeat()
X{
X    if (docheck(REPEAT)) {
X	spush(&parenbranch);
X	dothread();
X	doswap();
X	dobackwardresolve();
X	doforwardresolve();
X    }
X}
X
XCOMPILATION_IMMEDIATE_CODE(repeat, kernel_while, "repeat", dorepeat);
X
Xvoid doagain()
X{
X    if (docheck(AGAIN)) {
X	spush(&parenbranch);
X	dothread();
X	dobackwardresolve();
X    }
X}
X
XCOMPILATION_IMMEDIATE_CODE(again, repeat, "again", doagain);
X
Xvoid dorecurse()
X{
X    dolast();
X    dothread();
X}
X
XCOMPILATION_IMMEDIATE_CODE(recurse, again, "recurse", dorecurse);
X
Xvoid dotailrecurse()
X{
X    if (theframed) {
X 	spush(&parenunlink);
X	dothread();
X    }
X    dolast();
X    dotobody();
X    spush(&parenbranch);
X    dothread();
X    dobackwardresolve();
X}
X
XCOMPILATION_IMMEDIATE_CODE(tailrecurse, recurse, "tail-recurse", dotailrecurse);
X
Xvoid doexit()
X{
X    jump(rpop);
X}
X
XCOMPILATION_CODE(kernel_exit, tailrecurse, "exit", doexit);
X
Xvoid doexecute()
X{
X    long t = spop;
X
X    docall((ENTRY *) t);
X}
X
XNORMAL_CODE(execute, kernel_exit, "execute", doexecute);
X
Xvoid dobye()
X{
X    quited = FALSE;
X}
X
XNORMAL_CODE(bye, execute, "bye", dobye);
X
X
X/* TERMINAL INPUT-OUTPUT */
X
Xvoid dodot()
X{
X    if (tos < 0) {
X	(void) putchar('-');
X	tos = -tos;
X    }
X    doudot();
X}
X
XNORMAL_CODE(dot, bye, ".", dodot);
X
Xvoid doudot()
X{
X    dolesssharp();
X    dosharps();
X    dosharpgreater();
X    dotype();
X    dospace();
X}
X
XNORMAL_CODE(udot, dot, "u.", doudot);
X
Xvoid doascii()
X{
X    spush(' ');
X    doword();
X    docfetch();
X    doliteral();
X}
X
XIMMEDIATE_CODE(ascii, udot, "ascii", doascii);
X
Xvoid dodotquote()
X{
X    (void) io_scan(thetib, '"');
X    spush(thetib);
X    dostringcopy();
X    spush(&parendotquote);
X    dothread();
X    docomma();
X}
X
XCOMPILATION_IMMEDIATE_CODE(dotquote, ascii, ".\"", dodotquote);
X
Xvoid dodotparen()
X{
X    (void) io_scan(thetib, ')'); 
X    spush(thetib);
X    dostringprint();
X}
X
XIMMEDIATE_CODE(dotparen, dotquote, ".(", dodotparen);
X
Xvoid docr()
X{
X    (void) putchar('\n');
X}
X
XNORMAL_CODE(cr, dotparen, "cr", docr);
X
Xvoid doemit()
X{
X    char c = (char) spop;
X    
X    (void) putchar(c);
X}
X
XNORMAL_CODE(emit, cr, "emit", doemit);
X
Xvoid dotype()
X{
X    long n;
X    char *s;
X
X    n = spop;
X    s = (char *) spop;
X    while (n--) (void) putchar(*s++);
X}
X
XNORMAL_CODE(type, emit, "type", dotype);
X
Xvoid dospace()
X{
X    (void) putchar(' ');
X}
X
XNORMAL_CODE(space, type, "space", dospace);
X
Xvoid dospaces()
X{
X    long n = spop;
X
X    while (n--) (void) putchar(' ');
X}
X
XNORMAL_CODE(spaces, space, "spaces", dospaces);
X
Xvoid dokey()
X{
X    spush(io_getchar());
X}
X
XNORMAL_CODE(key, spaces, "key", dokey);
X
Xvoid doexpect()
X{
X    char *s0;
X    char *s1;
X    char  c;
X    long  n;
X    
X    /* Pop buffer pointer and size */
X    n = spop;
X    s0 = s1 = (char *) spop;
X    
X    /* Fill buffer until end of line or buffer */
X    while (io_not_eof() && (n-- > 0) && ((c = io_getchar()) != '\n')) *s1++ = c;
X
X    /* Set span to number of characters received */
X    span.parameter = (long) (s1 - s0);
X}
X
XNORMAL_CODE(expect, key, "expect", doexpect);
X
XNORMAL_VARIABLE(span, expect, "span", 0);
X
X
X/* PROGRAM BEGINNING AND TERMINATION */
X
Xvoid doforth83()
X{ }
X
XNORMAL_CODE(forth83, span, "forth-83", doforth83);
X    
Xvoid dointerpret()
X{
X    long flag;			/* Flag value returned by for words */
X    long cast;			/* Casting operation flag */
X
X    quited = TRUE;		/* Iterate until bye or end of input */
X
X    while (quited) {
X
X	/* Check stack underflow */
X	if (s0 < sp) {
X	    (void) printf("interpret: stack underflow\n");
X	    doabort();
X	}
X
X	/* Scan for the next symbol */
X	spush(' ');
X	doword();
X
X	/* Exit top loop if end of input stream */
X	if (io_eof()) {
X	    spop;
X	    return;
X	}
X
X	/* Search for the symbol in the current vocabulary search set*/
X	dofind();
X	flag = spop;
X
X	/* Check for vocabulary casting prefix */
X	for (cast = flag; !cast;) {
X	    char *s = (char *) tos;
X	    long l = strlen(s) - 1;
X
X	    /* Assume casting prefix */
X	    cast = TRUE;
X
X	    /* Check casting syntax, vocabulary name within parethesis */ 
X	    if ((s[0] == '(') && (s[l] == ')')) {
X
X		/* Remove the parenthesis from the input string */
X		s[l] = 0;
X		tos++;
X
X		/* Search for the symbol again */
X		dofind();
X		flag = spop;
X		
X		/* If found check that its a vocabulary */
X		if (flag) {
X		    ENTRY *v = (ENTRY *) spop;
X
X		    /* Check that the symbol is really a vocabulary */
X		    if (v -> code == VOCABULARY) {
X
X			/* Scan for a new symbol */
X			spush(' ');
X			doword();
X
X			/* Exit top loop if end of input stream */
X			if (io_eof()) {
X			    spop;
X			    return;
X			}
X
X			/* And look for it in the given vocabulary */
X			spush(v);
X			dolookup();
X			flag = spop;
X			cast = flag;
X		    }
X		}
X	    }
X	}
X	
X	/* If found then execute or thread the symbol */
X	if (flag) {
X	    if (state.parameter == flag)
X		dothread();
X	    else
X		docommand();
X	}
X	else {
X	    /* Else check if it is a number */
X	    doqnumber();
X	    flag = spop;
X	    if (flag) {
X		doliteral();
X	    }
X	    else {
X		/* If not print error message and abort */
X		(void) printf("%s ??\n", tos);
X		doabort();
X	    }
X	}
X    }
X    quited = TRUE;
X}
X
XNORMAL_CODE(interpret, forth83, "interpret", dointerpret);
X
Xvoid doquit()
X{
X    rinit;
X    doleftbracket();
X    dointerpret();
X}
X
XNORMAL_CODE(quit, interpret, "quit", doquit);
X
Xvoid doabort()
X{
X    /* Check if it is the foreground task */
X    if (tp == foreground) {
X	sinit; 
X	doleftbracket();
X	io_flush();
X    }
X
X    /* Terminate aborted tasks */
X    doterminate();
X}
X
XNORMAL_CODE(kernel_abort, quit, "abort", doabort);
X
Xvoid doabortquote()
X{
X    spush('"');
X    doword();
X    dostringcopy();
X    spush(&parenabortquote);
X    dothread();
X    docomma();
X}
X
XCOMPILATION_IMMEDIATE_CODE(abortquote, kernel_abort, "abort\"", doabortquote);
X    
X
X/* DICTIONARY ADDRESSES */
X
Xvoid dohere()
X{
X    spush(dp);
X}
X
XNORMAL_CODE(here, abortquote, "here", dohere);
X
Xstatic char thepad[PADSIZE];
X
XNORMAL_CONSTANT(pad, here, "pad", (long) thepad);
X
Xstatic char thetib[TIBSIZE];
X
XNORMAL_CONSTANT( tib, pad, "tib", (long) thetib);
X
Xvoid dotobody()
X{
X    tos = ((ENTRY *) tos) -> parameter;
X}
X
XNORMAL_CODE(tobody, tib, ">body", dotobody);
X
Xvoid dodotname()
X{
X    ENTRY *e = (ENTRY *) spop;
X    
X    (void) printf("%s", e -> name);
X}
X
XNORMAL_CODE(dotname, tobody, ".name", dodotname);
X
X
X/* COMPILER AND INTERPRETER WORDS */
X
Xvoid dosharpif()
X{
X    long symbol;
X    long flag = spop;
X
X    if (!flag) {
X	do {
X	    spush(' ');
X	    doword();
X	    symbol = spop;
X	    if (STREQ(symbol, "#if")) {
X		dosharpelse();
X		spush(' ');
X		doword();
X		symbol = spop;
X	    }
X	} while (!((STREQ(symbol, "#else") || STREQ(symbol, "#then"))));
X    }
X}
X
XIMMEDIATE_CODE(sharpif, dotname, "#if", dosharpif);
X
Xvoid dosharpelse()
X{
X    long symbol;
X    
X    do {
X	spush(' ');
X	doword();
X	symbol = spop;
X	if (STREQ(symbol, "#if")) {
X	    dosharpelse();
X	    spush(' ');
X	    doword();
X	    symbol = spop;
X	}
X    } while (!STREQ(symbol, "#then"));
X}
X
XIMMEDIATE_CODE(sharpelse, sharpif, "#else", dosharpelse);
X
Xvoid dosharpthen()
X{
X
X}
X
XIMMEDIATE_CODE(sharpthen, sharpelse, "#then", dosharpthen);
X
Xvoid dosharpifdef()
X{
X    spush(' ');
X    doword();
X    dofind();
X    doswap();
X    spop;
X    dosharpif();
X}
X
XIMMEDIATE_CODE(sharpifdef, sharpthen, "#ifdef", dosharpifdef);
X
Xvoid dosharpifundef()
X{
X    spush(' ');
X    doword();
X    dofind();
X    doswap();
X    spop;
X    dozeroequals();
X    dosharpif();
X}
X
XIMMEDIATE_CODE(sharpifundef, sharpifdef, "#ifundef", dosharpifundef);
X
Xvoid dosharpinclude()
X{
X    int  flag;
X    char *fname;
X    
X    spush(' ');
X    doword();
X    fname = (char *) spop;
X    if (flag = io_infile(fname) == IO_UNKNOWN_FILE)
X	(void) printf("%s: file not found\n", fname);
X    else if (flag == IO_TOO_MANY_FILES)
X	(void) printf("%s: too many files open\n", fname);
X}
X
XNORMAL_CODE(sharpinclude, sharpifundef, "#include", dosharpinclude);
X
Xvoid dosharppath()
X{
X    int flag;
X    
X    spush(' ');
X    doword();
X    if (flag = io_path((char *) tos, IO_PATH_FIRST) == IO_UNKNOWN_PATH)
X	(void) printf("%s: unknown environment variable\n", tos);
X    else if (flag == IO_TOO_MANY_PATHS)
X	(void) printf("%s: too many paths defined\n", tos);
X    spop;
X}
X
XNORMAL_CODE(sharppath, sharpinclude, "#path", dosharppath);
X
Xvoid doparen()
X{
X    char c;
X    
X    while (c = io_getchar())
X	if (c == ')') return;
X	else if (c == '(') doparen();
X	else if (io_eof()) return;
X}
X
XIMMEDIATE_CODE(paren, sharppath, "(", doparen);
X
Xvoid dobackslash()
X{
X    io_skip('\n');
X}
X
XIMMEDIATE_CODE(backslash, paren, "\\", dobackslash);
X
Xvoid docomma()
X{
X    *dp++ = spop;
X}
X
XNORMAL_CODE(comma, backslash, ",", docomma);
X
Xvoid doallot()
X{
X    long n = spop;
X
X    dp = (long *) ((char *) dp + n);
X}
X
XNORMAL_CODE(allot, comma, "allot", doallot);
X
Xvoid dodoes()
X{
X    spush((theframed ? &parenunlinkdoes: &parendoes));
X    dothread();
X    doremovelocals();
X}
X
XCOMPILATION_IMMEDIATE_CODE(does, allot, "does>", dodoes);
X
Xvoid doimmediate()
X{
X    ((ENTRY *) current -> parameter) -> mode |= IMMEDIATE;
X}
X
XNORMAL_CODE(immediate, does, "immediate", doimmediate);
X
Xvoid doexecution()
X{
X    ((ENTRY *) current -> parameter) -> mode |= EXECUTION;
X}
X
XNORMAL_CODE(execution, immediate, "execution", doexecution);
X
Xvoid docompilation()
X{
X    ((ENTRY *) current -> parameter) -> mode |= COMPILATION;
X}
X
XNORMAL_CODE(compilation, execution, "compilation", docompilation);
X
Xvoid doprivate()
X{
X    ((ENTRY *) current -> parameter) -> mode |= PRIVATE;
X}
X
XNORMAL_CODE(private, compilation, "private", doprivate);
X
Xvoid dobracketcompile()
X{
X    dotick();
X    dothread();
X}
X
XCOMPILATION_IMMEDIATE_CODE(bracketcompile, private, "[compile]", dobracketcompile);
X
Xvoid docompile()
X{
X    spush(*ip++);
X    dothread();
X}
X
XCOMPILATION_CODE(compile, bracketcompile, "compile", docompile);
X
Xvoid doqcompile()
X{
X    if (state.parameter) docompile();
X}
X
XCOMPILATION_CODE(qcompile, compile, "?compile", doqcompile);
X
XNORMAL_VARIABLE(state, qcompile, "state", FALSE);
X
Xvoid docompiling()
X{
X    spush(state.parameter);
X}
X
XNORMAL_CODE(compiling, state, "compiling", docompiling);
X
Xvoid doliteral()
X{
X    if (state.parameter) {
X	spush(&parenliteral);
X	dothread();
X	docomma();
X    }
X}
X
XCOMPILATION_IMMEDIATE_CODE(literal, compiling, "literal", doliteral);
X
Xvoid doleftbracket()
X{
X    state.parameter = FALSE;
X}
X
XIMMEDIATE_CODE(leftbracket, literal, "[", doleftbracket);
X
Xvoid dorightbracket()
X{
X    state.parameter = TRUE;
X}
X
XNORMAL_CODE(rightbracket, leftbracket, "]", dorightbracket);
X
Xvoid doword()
X{
X    char brkchr = (char) spop;
X    
X    (void) io_skipspace();
X    (void) io_scan(thetib, brkchr);
X    spush(thetib);
X}
X
XNORMAL_CODE(kernel_word, rightbracket, "word", doword);
X
X
X/* VOCABULARIES */
X
XNORMAL_CONSTANT(kernel_context, kernel_word, "context", (long) context);
X
XNORMAL_CONSTANT(kernel_current, kernel_context, "current", (long) &current);
X
Xvoid dolast()
X{
X    spush((theframed ? (long) theframed : current -> parameter));
X}
X
XNORMAL_CODE(last, kernel_current, "last", dolast);
X
Xvoid dodefinitions()
X{
X    current = context[0];
X}
X
XNORMAL_CODE(definitions, last, "definitions", dodefinitions);
X
Xvoid doonly()
X{
X    long v;
X
X    /* Flush the entry cache */
X    spush(FALSE);
X    dorestore();
X
X    /* Remove all vocabularies except the first */
X    for (v = 1; v < CONTEXTSIZE; v++) context[v] = (ENTRY *) NIL;
X
X    /* And make it definition vocabulary */
X    current = context[0];
X}
X
XNORMAL_CODE(only, definitions, "only", doonly);
X
Xvoid dorestore()
X{
X    register long i;		/* Iteration variable */
X    register ENTRY *e;		/* Pointer to parameter entry */
X    register ENTRY *p;		/* Pointer to current entry */
X
X    /* Access parameter and check if an entry */
X    e = (ENTRY *) spop;
X    if (e) {
X
X	/* Flush all enties until the parameter symbol */
X	for (p = (ENTRY *) current -> parameter; p && (p != e); p = p -> link)
X	    cache[hash(p -> name)] = (ENTRY *) NIL;
X
X	/* If the entry was found remove all symbols until this entry */
X	if (p == e) current -> parameter = (long) e;
X    }
X    else {
X	
X	/* Flush the entry cache */
X	for (i = 0; i < CACHESIZE; i++) cache[i] = (ENTRY *) NIL;
X    }
X}
X
XNORMAL_CODE(restore, only, "restore", dorestore);
X
Xvoid dotick()
X{
X    long flag;
X
X    spush(' ');
X    doword();
X    dofind();
X    flag = spop;
X    if (!flag) {
X	(void) printf("%s: unknown symbol\n", tos);
X	doabort();
X    }
X}
X
XNORMAL_CODE(tick, restore, "'", dotick);
X
Xvoid dobrackettick()
X{
X    dotick();
X    doliteral();
X}
X
XCOMPILATION_IMMEDIATE_CODE(brackettick, tick, "[']", dobrackettick);
X
Xvoid dolookup() 
X{
X    register ENTRY *v;		/* Vocabulary pointer */
X    register ENTRY *e;		/* Entry pointer */
X    register char  *s;		/* Symbol to be found */
X    
X    /* Fetch parameters and initate entry pointer */
X    v = (ENTRY *) spop;
X    s = (char *) tos;
X    
X    /* Iterate over the linked list of entries */
X    for (e = (ENTRY *) v -> parameter; e; e = e -> link)
X
X	/* Compare the symbol and entry string */
X	if (STREQ(s, e -> name)) {
X
X	    /* Check if the entry is currently visible */
X	    if (!(((e -> mode & COMPILATION) && (!state.parameter)) ||
X		  ((e -> mode & EXECUTION) && (state.parameter))  ||
X		  ((e -> mode & PRIVATE) && (v != current)))) {
X
X		/* Return the entry and compilation mode */
X		tos = (long) e;
X		spush((e -> mode & IMMEDIATE ? 1 : -1));
X		return;
X	    }
X	}
X    spush(FALSE);
X}
X
XNORMAL_CODE(lookup, brackettick, "lookup", dolookup);
X
X#ifdef PROFILE
Xvoid docollision()
X{
X    /* Add collision statistics to profile information */
X}
X#endif
X
Xvoid dofind()
X{
X    ENTRY *e;			/* Entry in the entry cache */
X    char  *n;			/* Name string of entry to be found */
X    long  v;			/* Index into vocabulary set */
X    
X    /* Access the string to be found */
X    n = (char *) tos;
X
X    /* Check for cached entry */
X    if (e = cache[hash(n)]) {
X
X	/* Compare the string and the entry name */
X	if (STREQ(tos, e -> name)) {
X
X	    /* Check if the entry is currently visible */
X	    if (!(((e -> mode & COMPILATION) && (!state.parameter)) ||
X		  ((e -> mode & EXECUTION) && (state.parameter)))) {
X		tos = (long) e;
X		spush((e -> mode & IMMEDIATE ? 1 : -1));
X		return;
X	    }
X	}
X#ifdef PROFILE
X	else {
X	    docollision();
X	}
X#endif	
X    }
X    
X    /* For each vocabulary in the current search chain */
X    for (v = 0; context[v] && v < CONTEXTSIZE; v++) {
X	spush(context[v]);
X	dolookup();
X	if (tos) {
X	    cache[hash(n)] = (ENTRY *) snth(0);
X	    return;
X	}
X	else {
X	    spop;
X	}
X    }
X    spush(FALSE);
X}
X
XNORMAL_CODE(find, lookup, "find", dofind);
X
Xvoid doforget()
X{
X    dotick();
X    tos = (long) ((ENTRY *) tos) -> link; 
X    dorestore();
X}
X
XNORMAL_CODE(forget, find, "forget", doforget);
X
Xvoid dowords()
X{
X    ENTRY *e;			/* Pointer to entries */
X    long   v;			/* Index into vocabulary set */
X    long   l;			/* String length */
X    long   s;			/* Spaces between words */
X    long   c;			/* Column counter */
X    long   i;			/* Loop index */
X    
X    /* Iterate over all vocabularies in the search set */
X    for (v = 0; v < CONTEXTSIZE && context[v]; v++) {
X
X	/* Print vocabulary name */
X	(void) printf("VOCABULARY %s", context[v] -> name);
X	if (context[v] == current) (void) printf(" DEFINITIONS");
X	(void) putchar('\n');
X
X	/* Access linked list of enties and initiate column counter */
X	c = 0;
X
X	/* Iterate over all entries in the vocabulary */
X	for (e = (ENTRY *) context[v] -> parameter; e; e = e -> link) {
X
X	    /* Check if the entry is current visible */
X	    if (!(((e -> mode & COMPILATION) && (!state.parameter)) ||
X		  ((e -> mode & EXECUTION) && (state.parameter))  ||
X		  ((e -> mode & PRIVATE) && (context[v] != current)))) {
X		
X		/* Print the entry string. Check that space is available */
X		l = strlen(e -> name);
X		s = (c ? (COLUMNWIDTH - (c % COLUMNWIDTH)) : 0);
X		c = c + s + l;
X		if (c < LINEWIDTH) {
X		    for (i = 0; i < s; i++) (void) putchar(' '); 
X		}
X		else {
X		    (void) putchar('\n');
X		    c = l;
X		}
X		(void) printf("%s", e -> name);
X	    }
X	}
X
X	/* End the list of words and separate the vocabularies */
X	(void) putchar('\n');
X	(void) putchar('\n');
X    }
X}
X
XIMMEDIATE_CODE(words, forget, "words", dowords);
X
X
X/* DEFINING NEW VOCABULARY ENTRIES */
X
XENTRY *makeentry(name, code, mode, parameter)
X    char *name;			/* String for the new entry */
X    long code, mode, parameter; /* Entry parameters */
X{
X    /* Allocate space for the entry */
X    ENTRY *e = (ENTRY *) malloc(sizeof(ENTRY));
X
X    /* Insert into the current vocabulary and set parameters */
X    e -> link = (ENTRY *) current -> parameter;
X    current -> parameter = (long) e;
X
X    /* Set entry parameters */
X    e -> name = strcpy(malloc((unsigned) strlen(name) + 1), name);
X    e -> code = code;
X    e -> mode = mode;
X    e -> parameter = parameter;
X
X    /* Cache entry */
X    cache[hash(name)] = e;
X    
X    /* Return pointer to the new entry */
X    return e;
X}
X
Xvoid doentry()
X{
X    long flag, name, code, mode, parameter;
X    ENTRY *forward;
X    
X    /* Try to find entry to check for forward declarations */
X    forward = (ENTRY *) NIL;
X    dodup();
X    dofind();
X    flag = spop;
X    if (flag) {
X	forward = (ENTRY *) spop;
X    }
X    else {
X	spop;
X    }
X    
X    /* Access name, code, mode and parameter field parameters */
X    name = spop;
X    code = spop;
X    mode = spop;
X    parameter = spop;
X
X    /* Create the new entry */
X    (void) makeentry((char *) name, code, mode, parameter);
X
X    /* If found and forward the redirect parameter field of initial entry */
X    if (forward && forward -> code == FORWARD) {
X	forward -> parameter = current -> parameter;
X	if (verbose)
X	    (void) printf("%s: forward definition resolved\n", forward -> name);
X    }
X}
X
XNORMAL_CODE(kernel_entry, words, "entry", doentry);
X
Xvoid doforward()
X{
X    spush(0);
X    spush(NORMAL);
X    spush(FORWARD);
X    spush(' ');
X    doword();
X    doentry();
X}
X
XNORMAL_CODE(forward, kernel_entry, "forward", doforward);
X
Xstatic ENTRY *thelast = (ENTRY *) NIL;
X
Xvoid docolon()
X{
X    align(dp);
X    dohere();
X    spush(HIDDEN);
X    spush(COLON);
X    spush(' ');
X    doword();
X    doentry();
X    dorightbracket();
X    thelast = (ENTRY *) current -> parameter;
X}
X
XNORMAL_CODE(colon, forward, ":", docolon);
X
Xvoid dosemicolon()
X{
X    spush((theframed ? &parenunlinksemicolon : &parensemicolon));
X    dothread();
X    doleftbracket();
X    doremovelocals();
X    if (thelast) {
X	thelast -> mode = NORMAL;
X	cache[hash(thelast -> name)] = thelast;
X	thelast = (ENTRY *) NIL;
X    }
X}
X
XCOMPILATION_IMMEDIATE_CODE(semicolon, colon, ";", dosemicolon);
X
Xvoid docreate()
X{
X    align(dp);
X    dohere();
X    spush(NORMAL);
X    spush(CREATE);
X    spush(' ');
X    doword();
X    doentry();
X}
X
XNORMAL_CODE(create, semicolon, "create", docreate);
X
Xvoid dovariable()
X{
X    spush(0);
X    spush(NORMAL);
X    spush(VARIABLE);
X    spush(' ');
X    doword();
X    doentry();
X}
X
XNORMAL_CODE(variable, create, "variable", dovariable);
X
Xvoid doconstant()
X{
X    spush(NORMAL);
X    spush(CONSTANT);
X    spush(' ');
X    doword();
X    doentry();
X}
X
XNORMAL_CODE(constant, variable, "constant", doconstant);
X
Xvoid dovocabulary()
X{
X    spush(&forth);
X    spush(NORMAL);
X    spush(VOCABULARY);
X    spush(' ');
X    doword();
X    doentry();
X}
X
XNORMAL_CODE(vocabulary, constant, "vocabulary", dovocabulary);
X
Xvoid dofield()
X{
X    spush(NORMAL);
X    spush(FIELD);
X    spush(' ');
X    doword();
X    doentry();
X}
X
XNORMAL_CODE(field, vocabulary, "field", dofield);
X
X
X/* INITIALIZATION OF THE KERNEL */
X
Xvoid kernel_initiate(first, last, users, parameters, returns)
X    ENTRY *first, *last;
X    int users, parameters, returns;
X{
X    /* Link user symbols into vocabulary chain if given */
X    if (first && last) {
X	forth.parameter = (long) first;
X	last -> link = (ENTRY *) &field;
X    }
X    
X    /* Create the foreground task object */
X    foreground = maketask((long) users, (long) parameters, (long) returns, NIL);
X    
X    s0 = foreground -> s0;
X    sp = foreground -> sp;
X    r0 = foreground -> r0;
X    rp = foreground -> rp;
X    ip = foreground -> ip;
X    fp = foreground -> fp;
X    ep = foreground -> ep;
X
X    /* Make the foreground task the current task */
X    tp = foreground;
X
X}
X
Xvoid kernel_finish()
X{
X    /* Future clean up function for kernel */
X}
END_OF_kernel.c
if test 57109 -ne `wc -c <kernel.c`; then
    echo shar: \"kernel.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of archive 7 \(of 7\).
cp /dev/null ark7isdone
MISSING=""
for I in 1 2 3 4 5 6 7 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 7 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0