[alt.sources] TILE Forth Release 2.0, package 6 of 6

news@majestix.ida.liu.se (News Subsystem) (06/29/90)

--
Mikael R.K. Patel
Researcher and Lecturer
Computer Aided Design Laboratory (CADLAB)
Department of Computer and Information Science
Linkoping University, S-581 83  LINKOPING, SWEDEN

Phone: +46 13281821
Telex: 8155076 LIUIDA S			Telefax: +46 13142231
Internet: mip@ida.liu.se		UUCP: {uunet,mcsun,...}!liuida!mip
Bitnet: MIP@SELIUIDA			SUNET: LIUIDA::MIP

mip@IDA.LiU.SE (Mikael Patel) (07/17/90)

#! /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 6 (of 6)."
# Contents:  src/kernel.c
# Wrapped by mip@mina on Fri Jun 29 16:49:14 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f src/kernel.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"src/kernel.c\"
else
echo shar: Extracting \"src/kernel.c\" \(49941 characters\)
sed "s/^X//" >src/kernel.c <<'END_OF_src/kernel.c'
X/*
X  C BASED FORTH-83 MULTI-TASKING KERNEL
X
X  Copyright (c) 1988-1990 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: 25 June 1990
X
X  Dependencies:
X  	(cc) kernel.h, error.h, memory.h, io.c, compiler.v,
X	     locals.v, string.v, float.v, memory.v, queues.v,
X	     multi-tasking.v, and exceptions.v.
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 floating point numbers, argument binding and local
X       variables, exception handling, queue data management, multi-tasking,
X       symbol hiding and casting, forwarding, null terminated string,
X       memory allocation, file search paths, and source library module
X       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 code_entry qnumber;
Xextern code_entry terminate;
Xextern code_entry abort_entry;
Xextern entry toexception;
Xextern entry span;
Xextern entry state;
Xextern code_entry vocabulary;
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
XINT32 verbose;			/* Application or programming mode */
XINT32 quited;			/* Interpreter toploop state */
XINT32 running;			/* Task switch flag */
XINT32 tasking;			/* Multi-tasking flag */
X
XTASK tp;			/* Task pointer */
XTASK foreground;		/* Foreground task pointer */
X
X
X/* FORTH MACHINE REGISTERS */
X
XUNIV tos;			/* Top of stack register */
XPTR sp;				/* Parameter stack pointer */
XPTR s0;				/* Bottom of parameter stack pointer */
X
XPTR32 ip;			/* Instruction pointer */
XPTR32 rp;			/* Return stack pointer */
XPTR32 r0;			/* Bottom of return stack pointer */
X
XPTR32 fp;			/* Argument frame pointer */
XPTR32 ep;			/* Exception frame pointer */
X
X
X/* VOCABULARY SEARCH LISTS */
X
X#define CONTEXTSIZE 64
X
Xstatic VOCABULARY_ENTRY current = &forth;
Xstatic VOCABULARY_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
XPTR32 dictionary;
XPTR32 dp;
X
X
X/* INTERNAL STRUCTURE AND SIZES */
X
Xstatic INT32 hld;
Xstatic ENTRY thelast = NIL;
X
X#define PADSIZE 84
Xstatic CHAR thepad[PADSIZE];
X
X#define TIBSIZE 256
Xstatic CHAR thetib[TIBSIZE];
X    
X
X/* INNER MULTI-TASKING FORTH VIRTUAL MACHINE */
X
XVOID doinner()
X{
X    INT32 e;
X
X    /* Exception marking and handler */
X    if (e = setjmp(restart)) {
X	spush(e, INT32);
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	register ENTRY p = (ENTRY) *ip++;
X
X	/* Select on type of entry */
X	switch (p -> code) {
X	  case CODE:
X	    ((SUBR) (p -> parameter))(); 
X	    break;
X	  case COLON:
X	    rpush(ip);
X	    fjump(p -> parameter);
X	    break;
X	  case VARIABLE:
X	    spush(&(p -> parameter), PTR32);
X	    break;
X	  case CONSTANT:
X	    spush(p -> parameter, INT32);
X	    break;
X	  case VOCABULARY:
X	    doappend((VOCABULARY_ENTRY) p);
X	    break;
X	  case CREATE:
X	    spush(p -> parameter, INT32);
X	    break;
X	  case USER:
X	    spush(((INT32) tp) + p -> parameter, INT32);
X	    break;
X	  case LOCAL:
X	    spush(*((PTR32) (INT32) fp - p -> parameter), INT32);
X	    break;
X	  case FORWARD:
X	    if (p -> parameter)
X		docall((ENTRY) p -> parameter);
X	    else {
X		if (io_source())
X		    (VOID) fprintf(io_errf, "%s:%i:", io_source(), io_line());
X		(VOID) fprintf(io_errf, "%s: unresolved forward entry\n", p -> name);
X		doabort();
X	    }
X	    break;
X	  case EXCEPTION:
X	    spush(p, ENTRY);
X	    break;
X	  case FIELD:
X	    unary(p -> parameter +, INT32);
X	    break;
X	  default: /* DOES: FORTH LEVEL INTERPRETATION */
X	    rpush(ip);
X	    spush(p -> parameter, INT32);
X	    fjump(p -> code);
X	    break;
X	}
X    }
X}
X
XVOID docommand()
X{
X    INT32 e;
X
X    /* Exception marking and handler */
X    if (e = setjmp(restart)) {
X	spush(e, INT32);
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	((SUBR) (p -> parameter))(); 
X	return;	
X      case COLON:
X	rpush(ip);
X	fjump(p -> parameter);
X	return;
X      case VARIABLE:
X	spush(&(p -> parameter), PTR32);
X	return;
X      case CONSTANT:
X	spush(p -> parameter, INT32);
X	return;
X      case VOCABULARY:
X	doappend((VOCABULARY_ENTRY) p);
X	return;
X      case CREATE:
X	spush(p -> parameter, INT32);
X	return;
X      case USER:
X	spush(((INT32) tp) + p -> parameter, INT32);
X	return;
X      case LOCAL:
X	spush(*((PTR32) (INT32) fp - p -> parameter), INT32);
X	return;
X      case FORWARD:
X	if (p -> parameter)
X	    docall((ENTRY) p -> parameter);
X	else {
X	    if (io_source())
X		(VOID) fprintf(io_errf, "%s:%i:", io_source(), io_line());
X	    (VOID) fprintf(io_errf, "%s: unresolved forward entry\n", p -> name);
X	    doabort();
X	}
X	return;
X      case EXCEPTION:
X	spush(p, ENTRY);
X	return;
X      case FIELD:
X	unary(p -> parameter +, INT32);
X	return;
X      default: /* DOES: FORTH LEVEL INTERPRETATION */
X	rpush(ip);
X	spush(p -> parameter, INT32);
X	fjump(p -> code);
X	return;
X    }
X}
X
XVOID doappend(p)
X    VOCABULARY_ENTRY p;
X{
X    INT32 v;
X    
X    /* Flush the entry cache */
X    spush(FALSE, BOOL);
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 AND EXTERNAL VOCABULARIES */
X
Xvocabulary_entry forth = {NIL, "forth", NORMAL, VOCABULARY, (ENTRY) &vocabulary, (ENTRY) &qnumber};
X
X
X/* COMPILER EXTENSIONS */
X
X#include "compiler.v"
X  
XNORMAL_VOCABULARY(compiler, forth, "compiler", &backwardresolve, NIL);
X
X
X/* LOCAL VARIABLES AND ARGUMENT BINDING */
X
X#include "locals.v"
X
XNORMAL_VOCABULARY(locals, compiler, "locals", &curlebracket, NIL);
X
X
X/* NULL TERMINATED STRING */
X
X#include "string.v"
X
XNORMAL_VOCABULARY(string, locals, "string", &sprint, NIL); 
X
X
X/* FLOATING POINT */
X
X#include "float.v"
X
XNORMAL_VOCABULARY(float_entry, string, "float", &qfloat, &qfloat); 
X
X
X/* MEMORY MANAGEMENT */
X
X#include "memory.v"
X
XNORMAL_VOCABULARY(memory, float_entry, "memory", &free_entry, NIL); 
X
X
X/* DOUBLE LINKED LISTS */
X
X#include "queues.v"
X
XNORMAL_VOCABULARY(queues, memory, "queues", &dequeue, NIL);
X
X
X/* MULTI-TASKING EXTENSIONS */
X
X#include "multi-tasking.v"
X
XNORMAL_VOCABULARY(multitasking, queues, "multi-tasking", &terminate, NIL);
X
X
X/* SIGNAL AND EXCEPTION MANAGEMENT */
X
X#include "exceptions.v"
X
XNORMAL_VOCABULARY(exceptions, multitasking, "exceptions", &raise, NIL);
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, INT32);
X}
X
XNORMAL_CODE(boolean, true, "boolean", doboolean);
X
XVOID donot()
X{
X    unary(~, INT32);
X}
X
XNORMAL_CODE(not, boolean, "not", donot);
X
XVOID doand()
X{
X    binary(&, INT32);
X}
X
XNORMAL_CODE(and, not, "and", doand);
X
XVOID door()
X{
X    binary(|, INT32);
X}
X
XNORMAL_CODE(or, and, "or", door);
X
XVOID doxor()
X{
X    binary(^, INT32);
X}
X
XNORMAL_CODE(xor, or, "xor", doxor);
X
XVOID doqwithin()
X{
X    register INT32 value;
X    register INT32 upper;
X    register INT32 lower;
X    
X    upper = spop(INT32);
X    lower = spop(INT32);
X    value = spop(INT32);
X    
X    spush((value > upper) || (value < lower) ? FALSE : TRUE, BOOL);
X}
X    
XNORMAL_CODE(qwithin, xor, "?within", doqwithin);
X
X
X/* STACK MANIPULATION */
X
XVOID dodepth()
X{
X    register PTR32 t;
X
X    t = (PTR32) sp;
X    spush(((PTR32) s0 - t), INT32);
X}
X
XNORMAL_CODE(depth, qwithin, "depth", dodepth);
X
XVOID dodrop()
X{
X    sdrop();
X}
X
XNORMAL_CODE(drop, depth, "drop", dodrop);
X
XVOID donip()
X{
X    snip();
X}
X
XNORMAL_CODE(nip, drop, "nip", donip);
X
XVOID doswap()
X{
X    sswap();
X}
X
XNORMAL_CODE(swap, nip, "swap", doswap);
X
XVOID dorot()
X{
X    srot();
X}
X
XNORMAL_CODE(rot, swap, "rot", dorot);
X
XVOID dodashrot()
X{
X    sdashrot();
X}
X
XNORMAL_CODE(dashrot, rot, "-rot", dodashrot);
X
XVOID doroll()
X{
X    register UNIV e;
X    register PTR s;
X
X    /* Fetch roll parameters: number and element */
X    e = snth(tos.INT32);
X
X    /* Roll the stack */
X    for (s = sp + tos.INT32; 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, dashrot, "roll", doroll);
X
XVOID doqdup()
X{
X    if (tos.INT32) sdup();
X}
X
XNORMAL_CODE(qdup, roll, "?dup", doqdup);
X
XVOID dodup()
X{
X    sdup();
X}
X
XNORMAL_CODE(dup_entry, qdup, "dup", dodup);
X
XVOID doover()
X{
X    sover();
X}
X
XNORMAL_CODE(over, dup_entry, "over", doover);
X
XVOID dotuck()
X{
X    stuck();
X}
X
XNORMAL_CODE(tuck, over, "tuck", dotuck);
X
XVOID dopick()
X{
X    tos = snth(tos.INT32);
X}
X
XCOMPILATION_CODE(pick, tuck, "pick", dopick);
X
XVOID dotor()
X{
X    rpush(spop(INT32));
X}
X
XCOMPILATION_CODE(tor, pick, ">r", dotor);
X
XVOID dofromr()
X{
X    spush(rpop(), INT32);
X}
X
XCOMPILATION_CODE(fromr, tor, "r>", dofromr);
X
XVOID docopyr()
X{
X    spush(*rp, INT32);
X}
X
XCOMPILATION_CODE(copyr, fromr, "r@", docopyr);
X
XVOID dotwotor()
X{
X    rpush(spop(INT32));
X    rpush(spop(INT32));
X}
X
XCOMPILATION_CODE(twotor, copyr, "2>r", dotwotor);
X
XVOID dotwofromr()
X{
X    spush(rpop(), INT32);
X    spush(rpop(), INT32);
X}
X
XCOMPILATION_CODE(twofromr, twotor, "2r>", dotwofromr);
X
XVOID dotwodrop()
X{
X    sndrop(1);
X}
X
XNORMAL_CODE(twodrop, twofromr, "2drop", dotwodrop);
X
XVOID dotwoswap()
X{
X    register UNIV t;
X
X    t = tos;
X    tos = snth(1);
X    snth(1) = t;
X
X    t = snth(0);
X    snth(0) = snth(2);
X    snth(2) = t;
X}
X
XNORMAL_CODE(twoswap, twodrop, "2swap", dotwoswap);
X
XVOID dotworot()
X{
X    register UNIV t;
X
X    t = tos;
X    tos = snth(3);
X    snth(3) = snth(1);
X    snth(1) = t;
X    
X    t = snth(0);
X    snth(0) = snth(4);
X    snth(4) = snth(2);
X    snth(2) = t;
X}
X
XNORMAL_CODE(tworot, twoswap, "2rot", dotworot);
X
XVOID dotwodup()
X{
X    spush(snth(1).INT32, INT32);
X    spush(snth(1).INT32, INT32);
X}
X
XNORMAL_CODE(twodup, tworot, "2dup", dotwodup);
X
XVOID dotwoover()
X{
X    spush(snth(3).INT32, INT32);
X    spush(snth(3).INT32, INT32);
X}
X
XNORMAL_CODE(twoover, twodup, "2over", dotwoover);
X
X
X/* COMPARISON */
X
XVOID dolessthan()
X{
X    relation(<, INT32);
X}
X
XNORMAL_CODE(lessthan, twoover, "<", dolessthan);
X
XVOID doequals()
X{
X    relation(==, INT32);
X}
X
XNORMAL_CODE(equals, lessthan, "=", doequals);
X
XVOID dogreaterthan()
X{
X    relation(>, INT32);
X}
X
XNORMAL_CODE(greaterthan, equals, ">", dogreaterthan);
X
XVOID dozeroless()
X{
X    compare(< 0, INT32);
X}
X
XNORMAL_CODE(zeroless, greaterthan, "0<", dozeroless);
X
XVOID dozeroequals()
X{
X    compare(== 0, INT32);
X}
X
XNORMAL_CODE(zeroequals, zeroless, "0=", dozeroequals);
X
XVOID dozerogreater()
X{
X    compare(> 0, INT32);
X}
X
XNORMAL_CODE(zerogreater, zeroequals, "0>", dozerogreater);
X
XVOID doulessthan()
X{
X    relation(<, NUM32);
X}
X
XNORMAL_CODE(ulessthan, zerogreater, "u<", doulessthan);
X
X
X/* CONSTANTS */
X
XNORMAL_CONSTANT(nil, ulessthan, "nil", NIL);
X
XNORMAL_CONSTANT(minusfour, nil, "-4", -4);
X
XNORMAL_CONSTANT(minustwo, minusfour, "-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
XNORMAL_CONSTANT(four, two, "4", 4);
X
X
X/* ARITHMETRIC */
X
XVOID doplus()
X{
X    binary(+, INT32);
X}
X
XNORMAL_CODE(plus, four, "+", doplus);
X
XVOID dominus()
X{
X    binary(-, INT32);
X}
X
XNORMAL_CODE(minus, plus, "-", dominus);
X
XVOID dooneplus()
X{
X    unary(++, INT32);
X}
X
XNORMAL_CODE(oneplus, minus, "1+", dooneplus);
X
XVOID dooneminus()
X{
X    unary(--, INT32);
X}
X
XNORMAL_CODE(oneminus, oneplus, "1-", dooneminus);
X
XVOID dotwoplus()
X{
X    unary(2 +, INT32);
X}
X
XNORMAL_CODE(twoplus, oneminus, "2+", dotwoplus);
X
XVOID dotwominus()
X{
X    unary(-2 +, INT32);
X}
X
XNORMAL_CODE(twominus, twoplus, "2-", dotwominus);
X
XVOID dotwotimes()
X{
X    tos.INT32 <<= 1;
X}
X
XNORMAL_CODE(twotimes, twominus, "2*", dotwotimes);
X
XVOID doleftshift()
X{
X    binary(<<, INT32);
X}
X
XNORMAL_CODE(leftshift, twotimes, "<<", doleftshift);
X
XVOID dotimes()
X{
X    binary(*, INT32);
X}
X
XNORMAL_CODE(times_entry, leftshift, "*", dotimes);
X
XVOID doumtimes()
X{
X    binary(*, NUM32);
X}
X
XNORMAL_CODE(utimes_entry, times_entry, "um*", doumtimes);
X
XVOID doumdividemod()
X{
X    register NUM32 t;
X
X    t = snth(0).NUM32;
X    snth(0).NUM32 = t % tos.NUM32;
X    tos.NUM32 = t / tos.NUM32;
X}
X
XNORMAL_CODE(umdividemod, utimes_entry, "um/mod", doumdividemod);
X
XVOID dotwodivide()
X{
X    tos.INT32 >>= 1;
X}
X
XNORMAL_CODE(twodivide, umdividemod, "2/", dotwodivide);
X
XVOID dorightshift()
X{
X    binary(>>, INT32);
X}
X
XNORMAL_CODE(rightshift, twodivide, ">>", dorightshift);
X
XVOID dodivide()
X{
X    binary(/, INT32);
X}
X
XNORMAL_CODE(divide, rightshift, "/", dodivide);
X
XVOID domod()
X{
X    binary(%, INT32);
X}
X
XNORMAL_CODE(mod, divide, "mod", domod);
X
XVOID dodividemod()
X{
X    register INT32 t;
X
X    t = snth(0).INT32;
X    snth(0).INT32 = t % tos.INT32;
X    tos.INT32 = t / tos.INT32;
X}
X
XNORMAL_CODE(dividemod, mod, "/mod", dodividemod);
X
XVOID dotimesdividemod()
X{
X    register INT32 t;
X
X    t = spop(INT32);
X    tos.INT32 = tos.INT32 * snth(0).INT32;
X    snth(0).INT32 = tos.INT32 % t;
X    tos.INT32 = tos.INT32 / t;
X}
X
XNORMAL_CODE(timesdividemod, dividemod, "*/mod", dotimesdividemod);
X
XVOID dotimesdivide()
X{
X    register INT32 t;
X
X    t = spop(INT32);
X    binary(*, INT32);
X    spush(t, INT32);
X    binary(/, INT32);
X}
X
XNORMAL_CODE(timesdivide, timesdividemod, "*/", dotimesdivide);
X
XVOID domin()
X{
X    register INT32 t;
X
X    t = spop(INT32);
X    tos.INT32 = (t < tos.INT32 ? t : tos.INT32);
X}
X
XNORMAL_CODE(min, timesdivide, "min", domin);
X
XVOID domax()
X{
X    register INT32 t;
X
X    t = spop(INT32);
X    tos.INT32 = (t > tos.INT32 ? t : tos.INT32);
X}
X
XNORMAL_CODE(max, min, "max", domax);
X
XVOID doabs()
X{
X    tos.INT32 = (tos.INT32 < 0 ? - tos.INT32 : tos.INT32);
X}
X
XNORMAL_CODE(abs_entry, max, "abs", doabs);
X
XVOID donegate()
X{
X    unary(-, INT32);
X}
X
XNORMAL_CODE(negate, abs_entry, "negate", donegate);
X
X
X/* MEMORY */
X
XVOID dofetch()
X{
X    unary(*(PTR32), INT32);
X}
X
XNORMAL_CODE(fetch, negate, "@", dofetch);
X
XVOID dostore()
X{
X    register PTR32 t;
X
X    t = spop(PTR32);
X    *t = spop(INT32);
X}
X
XNORMAL_CODE(store, fetch, "!", dostore);
X
XVOID dowfetch()
X{
X    unary(*(PTR16), INT32);
X}
X
XNORMAL_CODE(wfetch, store, "w@", dowfetch);
X
XVOID dowstore()
X{
X    register PTR16 t;
X
X    t = spop(PTR16);
X    *t = spop(INT32);
X}
X
XNORMAL_CODE(wstore, wfetch, "w!", dowstore);
X
XVOID docfetch()
X{
X    unary(*(CSTR), INT32);
X}
X
XNORMAL_CODE(cfetch, wstore, "c@", docfetch);
X
XVOID docstore()
X{
X    register CSTR t;
X
X    t = spop(CSTR);
X    *t = spop(INT32);
X}
X
XNORMAL_CODE(cstore, cfetch, "c!", docstore);
X
XVOID doffetch()
X{
X    register INT32 pos;
X    register INT32 width;
X
X    width = spop(INT32);
X    pos = spop(INT32);
X    tos.INT32 = (tos.INT32 >> pos) & ~(-1 << width);
X}
X
XNORMAL_CODE(ffetch, cstore, "f@", doffetch);
X
XVOID dolessffetch()
X{
X    register INT32 pos;
X    register INT32 width;
X
X    width = spop(INT32);
X    pos = spop(INT32);
X    tos.INT32 = (tos.INT32 >> pos) & ~(-1 << width);
X    if ((1 << (width - 1)) & tos.INT32) {
X	tos.INT32 = (tos.INT32) | (-1 << width);
X    }
X}
X
XNORMAL_CODE(lessffetch, ffetch, "<f@", dolessffetch);
X
XVOID dofstore()
X{
X    register INT32 pos;
X    register INT32 width;
X    register INT32 value;
X
X    width = spop(INT32);
X    pos = spop(INT32);
X    value = spop(INT32);
X    tos.INT32 = ((tos.INT32 & ~(-1 << width)) << pos) | (value & ~((~(-1 << width)) << pos));
X}
X
XNORMAL_CODE(fstore, lessffetch, "f!", dofstore);
X
XVOID dobfetch()
X{
X    register INT32 bit;
X
X    bit = spop(INT32);
X    tos.INT32 = (((tos.INT32 >> bit) & 1) ? TRUE : FALSE);
X}
X
XNORMAL_CODE(bfetch, fstore, "b@", dobfetch);
X
XVOID dobstore()
X{
X    register INT32 bit;
X    register INT32 value;
X
X    bit = spop(INT32);
X    value = spop(INT32);
X    tos.INT32 = (tos.INT32 ? (value | (1 << bit)) : (value & ~(1 << bit)));
X}
X
XNORMAL_CODE(bstore, bfetch, "b!", dobstore);
X
XVOID doplusstore()
X{
X    register PTR32 t;
X
X    t = spop(PTR32);
X    *t += spop(INT32);
X}
X
XNORMAL_CODE(plusstore, bstore, "+!", doplusstore);
X
XVOID dotwofetch()
X{
X    register PTR32 t;
X
X    t = tos.PTR32;
X    spush(*t++, INT32);
X    snth(0).INT32 = *t;
X}
X
XNORMAL_CODE(twofetch, plusstore, "2@", dotwofetch);
X
XVOID dotwostore()
X{
X    register PTR32 t;
X
X    t = spop(PTR32);
X    *t++ = spop(INT32);
X    *t = spop(INT32);
X}
X
XNORMAL_CODE(twostore, twofetch, "2!", dotwostore);
X
X
X/* STRINGS */
X
XVOID docmove()
X{
X    register INT32 n;
X    register CSTR to;
X    register CSTR from;
X
X    n = spop(INT32);
X    to = spop(CSTR);
X    from = spop(CSTR);
X
X    while (--n != -1) *to++ = *from++;
X}
X
XNORMAL_CODE(cmove, twostore, "cmove", docmove);
X
XVOID docmoveup()
X{
X    register INT32 n;
X    register CSTR to;
X    register CSTR from;
X
X    n = spop(INT32);
X    to = spop(CSTR);
X    from = spop(CSTR);
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 INT32 with;
X    register INT32 n;
X    register CSTR from;
X
X    with = spop(INT32);
X    n = spop(INT32);
X    from = spop(CSTR);
X
X    while (--n != -1) *from++ = with;
X}
X
XNORMAL_CODE(fill, cmoveup, "fill", dofill);
X
XVOID docount()
X{
X    register CSTR t;
X
X    t = spop(CSTR);
X    spush(*t++, INT32);
X    spush(t, CSTR);
X}
X
XNORMAL_CODE(count, fill, "count", docount);
X
XVOID dobounds()
X{
X    register CSTR n;
X
X    n = snth(0).CSTR;
X    snth(0).CSTR = snth(0).CSTR + tos.INT32;
X    tos.CSTR = n;
X}
X
XNORMAL_CODE(bounds, count, "bounds", dobounds);
X
XVOID dodashtrailing()
X{
X    register CSTR p;
X
X    p = snth(0).CSTR + tos.INT32;
X    tos.INT32 += 1;
X    while (--tos.INT32 && (*--p == ' '));
X}
X
XNORMAL_CODE(dashtrailing, bounds, "-trailing", dodashtrailing);
X
XVOID dodashmatch()
X{
X    register INT32 n;
X    register CSTR s;
X    register CSTR t;
X    
X    n = spop(INT32);
X    s = spop(CSTR);
X    t = spop(CSTR);
X
X    if (n) {
X	while ((n) && (*s++ == *t++)) n--;
X	spush(n ? TRUE : FALSE, BOOL);
X    }
X    else {
X	spush(TRUE, BOOL);
X    }
X}
X
XNORMAL_CODE(dashmatch, dashtrailing, "-match", dodashmatch);
X
X
X/* NUMERICAL CONVERSION */
X
XNORMAL_VARIABLE(base, dashmatch, "base", 10);
X
XVOID dobinary()
X{
X    base.parameter = 2;
X}
X
XNORMAL_CODE(binary_entry, base, "binary", dobinary);
X
XVOID dooctal()
X{
X    base.parameter = 8;
X}
X
XNORMAL_CODE(octal, binary_entry, "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 INT32 b;
X    register INT32 n;
X    
X    b = base.parameter;
X    n = snth(0).INT32;
X
X    for (;;) {
X	c = *tos.CSTR;
X	if (c < '0' || c > 'z' || (c > '9' && c < 'a')) {
X	    snth(0).INT32 = 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).INT32 = n;
X		return;
X	    }
X	    n = (n * b) + c;
X	    tos.INT32 += 1;
X	}
X    }
X}
X
XNORMAL_CODE(convert, hex, "convert", doconvert);
X
XVOID dolesssharp()
X{
X    hld = (INT32) thepad + PADSIZE;
X}
X
XNORMAL_CODE(lesssharp, convert, "<#", dolesssharp);
X
XVOID dosharp()
X{
X    register NUM32 n;
X
X    n = tos.NUM32;
X    tos.NUM32 = n / (unsigned INT32) base.parameter;
X    n = n % (unsigned INT32) base.parameter;
X    *(CSTR) --hld = n + ((n > 9) ? 'a' - 10 : '0');
X}
X
XNORMAL_CODE(sharp, lesssharp, "#", dosharp);
X
XVOID dosharps()
X{
X    do { dosharp(); } while (tos.INT32);
X}
X
XNORMAL_CODE(sharps, sharp, "#s", dosharps);
X
XVOID dohold()
X{
X    *(CSTR) --hld = spop(INT32);
X}
X
XNORMAL_CODE(hold, sharps, "hold", dohold);
X
XVOID dosign()
X{
X    INT32 flag;
X
X    flag = spop(INT32);
X    if (flag < 0) *(CSTR) --hld = '-';
X}
X
XNORMAL_CODE(sign, hold, "sign", dosign);
X
XVOID dosharpgreater()
X{
X    tos.INT32 = hld;
X    spush((INT32) thepad + PADSIZE - hld, INT32);
X}
X
XNORMAL_CODE(sharpgreater, sign, "#>", dosharpgreater);
X
XVOID doqnumber()
X{
X    CSTR s0;
X    CSTR s1;
X    
X    s0 = spop(CSTR);
X    spush(0, INT32);
X    if (*s0 == '-') {
X	spush(s0 + 1, CSTR);
X    }
X    else {
X	spush(s0, CSTR);
X    }
X    doconvert();
X    s1 = spop(CSTR);
X    if (*s1 == '\0') {
X	if (*s0 == '-') unary(-, INT32);
X	spush(TRUE, BOOL);
X    }
X    else {
X	tos.CSTR = s0;
X	spush(FALSE, BOOL);
X    }
X}
X
XNORMAL_CODE(qnumber, sharpgreater, "?number", doqnumber);
X
X
X/* CONTROL STRUCTURES */
X
XINT32 docheck(this)
X    int this;
X{
X    ENTRY last;
X    INT32 follow = spop(INT32);
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 = spop(ENTRY);
X	if (io_source())
X	    (VOID) fprintf(io_errf, "%s:%i:", io_source(), io_line());
X	(VOID) fprintf(io_errf, "%s: illegal control structure\n", last -> name);
X	doabort();
X
X	return FALSE;
X    }
X}
X
XVOID dodo()
X{
X    spush(&parendo, CODE_ENTRY);
X    dothread();
X    doforwardmark();
X    dobackwardmark();
X    spush(LOOP+PLUSLOOP, INT32);
X}
X
XCOMPILATION_IMMEDIATE_CODE(do_entry, qnumber, "do", dodo);
X
XVOID doqdo()
X{
X    spush(&parenqdo, CODE_ENTRY);
X    dothread();
X    doforwardmark();
X    dobackwardmark();
X    spush(LOOP+PLUSLOOP, INT32);
X}
X
XCOMPILATION_IMMEDIATE_CODE(qdo_entry, do_entry, "?do", doqdo);
X
XVOID doloop()
X{
X    if (docheck(LOOP)) {
X	spush(&parenloop, CODE_ENTRY);
X	dothread();
X	dobackwardresolve();
X	doforwardresolve();
X    }
X}
X
XCOMPILATION_IMMEDIATE_CODE(loop, qdo_entry, "loop", doloop);
X
XVOID doplusloop()
X{
X    if (docheck(PLUSLOOP)) {
X	spush(&parenplusloop, CODE_ENTRY);
X	dothread();
X	dobackwardresolve();
X	doforwardresolve();
X    }
X}
X
XCOMPILATION_IMMEDIATE_CODE(plusloop, loop, "+loop", doplusloop);
X
XVOID doleave()
X{
X    rndrop(2);
X    fjump(rpop());
X    fbranch(*ip);
X}
X
XCOMPILATION_CODE(leave, plusloop, "leave", doleave);
X
XVOID doi()
X{
X    spush(rnth(1), INT32);
X}
X
XCOMPILATION_CODE(i_entry, leave,"i", doi);
X
XVOID doj()
X{
X    spush(rnth(4), INT32);
X}
X
XCOMPILATION_CODE(j_entry, i_entry, "j", doj);
X
XVOID doif()
X{
X    spush(&parenqbranch, CODE_ENTRY);
X    dothread();
X    doforwardmark();
X    spush(ELSE+THEN, INT32);
X}
X
XCOMPILATION_IMMEDIATE_CODE(if_entry, j_entry, "if", doif);
X
XVOID doelse()
X{
X    if (docheck(ELSE)) {
X	spush(&parenbranch, CODE_ENTRY);
X	dothread();
X	doforwardmark();
X	doswap();
X	doforwardresolve();
X	spush(THEN, INT32);
X    }
X}
X
XCOMPILATION_IMMEDIATE_CODE(else_entry, if_entry, "else", doelse);
X
XVOID dothen()
X{
X    if (docheck(THEN)) {
X	doforwardresolve();
X    }
X}
X
XCOMPILATION_IMMEDIATE_CODE(then_entry, else_entry, "then", dothen);
X
XVOID docase()
X{
X    spush(0, INT32);
X    spush(OF+ENDCASE, INT32);
X}
X
XCOMPILATION_IMMEDIATE_CODE(case_entry, then_entry, "case", docase);
X
XVOID doof()
X{
X    if (docheck(OF)) {
X	spush(&over, CODE_ENTRY);
X	dothread();
X	spush(&equals, CODE_ENTRY);
X	dothread();
X	spush(&parenqbranch, CODE_ENTRY);
X	dothread();
X	doforwardmark();
X	spush(&drop, CODE_ENTRY);
X	dothread();
X	spush(ENDOF, INT32);
X    }
X}
X
XCOMPILATION_IMMEDIATE_CODE(of_entry, case_entry, "of", doof);
X
XVOID doendof()
X{
X    if (docheck(ENDOF)) {
X	spush(&parenbranch, CODE_ENTRY);
X	dothread();
X	doforwardmark();
X	doswap();
X	doforwardresolve();
X	spush(OF+ENDCASE, INT32);
X    }
X}
X
XCOMPILATION_IMMEDIATE_CODE(endof, of_entry, "endof", doendof);
X
XVOID doendcase()
X{
X    if (docheck(ENDCASE)) {
X	spush(&drop, CODE_ENTRY);
X	dothread();
X	while (tos.INT32) doforwardresolve();
X	dodrop();
X    }
X}
X
XCOMPILATION_IMMEDIATE_CODE(endcase, endof, "endcase", doendcase);
X
XVOID dobegin()
X{
X    dobackwardmark();
X    spush(AGAIN+UNTIL+WHILE, INT32);
X}
X
XCOMPILATION_IMMEDIATE_CODE(begin, endcase, "begin", dobegin);
X
XVOID dountil()
X{
X    if (docheck(UNTIL)) {
X	spush(&parenqbranch, CODE_ENTRY);
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, CODE_ENTRY);
X	dothread();
X	doforwardmark();
X	spush(REPEAT, INT32);
X    }
X}
X
XCOMPILATION_IMMEDIATE_CODE(while_entry, until, "while", dowhile);
X
XVOID dorepeat()
X{
X    if (docheck(REPEAT)) {
X	spush(&parenbranch, CODE_ENTRY);
X	dothread();
X	doswap();
X	dobackwardresolve();
X	doforwardresolve();
X    }
X}
X
XCOMPILATION_IMMEDIATE_CODE(repeat, while_entry, "repeat", dorepeat);
X
XVOID doagain()
X{
X    if (docheck(AGAIN)) { 
X	spush(&parenbranch, CODE_ENTRY);
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, CODE_ENTRY);
X	dothread();
X    }
X    dolast();
X    dotobody();
X    spush(&parenbranch, CODE_ENTRY);
X    dothread();
X    dobackwardresolve();
X}
X
XCOMPILATION_IMMEDIATE_CODE(tailrecurse, recurse, "tail-recurse", dotailrecurse);
X
XVOID doexit()
X{
X    fsemicolon();
X}
X
XCOMPILATION_CODE(exit_entry, tailrecurse, "exit", doexit);
X
XVOID doexecute()
X{
X    ENTRY t;
X
X    t = spop(ENTRY);
X    docall(t);
X}
X
XNORMAL_CODE(execute, exit_entry, "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.INT32 < 0) {
X	(VOID) fputc('-', io_outf);
X	unary(-, INT32);
X    }
X    doudot();
X}
X
XNORMAL_CODE(dot, bye, ".", dodot);
X
XVOID dodotr()
X{
X    INT32 s, t;
X
X    t = spop(INT32);
X    s = tos.INT32;
X    doabs();
X    dolesssharp();
X    dosharps();
X    spush(s, INT32);
X    dosign();
X    dosharpgreater();
X    spush(t, INT32);
X    sover();
X    dominus();
X    dospaces();
X    dotype();
X}
X
XNORMAL_CODE(dotr, dot, ".r", dodotr);
X
XVOID doudot()
X{
X    dolesssharp();
X    dosharps();
X    dosharpgreater();
X    dotype();
X    dospace();
X}
X
XNORMAL_CODE(udot, dotr, "u.", doudot);
X
XVOID doudotr()
X{
X    INT32 t;
X
X    t = spop(INT32);
X    dolesssharp();
X    dosharps();
X    dosharpgreater();
X    spush(t, INT32);
X    sover();
X    dominus();
X    dospaces();
X    dotype();
X}
X
XNORMAL_CODE(udotr, udot, "u.r", doudotr);
X
XVOID doascii()
X{
X    spush(' ', INT32);
X    doword();
X    docfetch();
X    doliteral();
X}
X
XIMMEDIATE_CODE(ascii, udotr, "ascii", doascii);
X
XVOID dodotquote()
X{
X    (VOID) io_scan(thetib, '"');
X    spush(thetib, CSTR);
X    dosdup();
X    spush(&parendotquote, CODE_ENTRY);
X    dothread();
X    docomma();
X}
X
XCOMPILATION_IMMEDIATE_CODE(dotquote, ascii, ".\"", dodotquote);
X
XVOID dodotparen()
X{
X    (VOID) io_scan(thetib, ')'); 
X    spush(thetib, CSTR);
X    dosprint();
X}
X
XIMMEDIATE_CODE(dotparen, dotquote, ".(", dodotparen);
X
XVOID dodots()
X{
X    PTR s;
X
X    /* Print the stack depth */
X    (VOID) fprintf(io_outf, "[%d] ", s0 - sp);
X
X    /* Check if there are any elements on the stack */
X    if (s0 - sp > 0) {
X
X	/* Print them and don't forget top of stack */
X	for (s = s0 - 2; s >= sp; s--) {
X	    (VOID) fprintf(io_outf, "\\");
X	    spush(s -> INT32, INT32);
X	    if (tos.INT32 < 0) {
X		(VOID) fputc('-', io_outf);
X		unary(-, INT32);
X	    }
X	    dolesssharp();
X	    dosharps();
X	    dosharpgreater();
X	    dotype();
X	}
X	(VOID) fprintf(io_outf, "\\");
X	dodup();
X	dodot();
X    }
X}
X
XNORMAL_CODE(dots, dotparen, ".s", dodots);
X
XVOID docr()
X{
X    (VOID) fputc('\n', io_outf);
X}
X
XNORMAL_CODE(cr, dots, "cr", docr);
X
XVOID doemit()
X{
X    CHAR c;
X
X    c = (CHAR) spop(INT32);
X    (VOID) fputc(c, io_outf);
X}
X
XNORMAL_CODE(emit, cr, "emit", doemit);
X
XVOID dotype()
X{
X    INT32 n;
X    CSTR s;
X
X    n = spop(INT32);
X    s = spop(CSTR);
X    while (n--) (VOID) fputc(*s++, io_outf);
X}
X
XNORMAL_CODE(type, emit, "type", dotype);
X
XVOID dospace()
X{
X    (VOID) fputc(' ', io_outf);
X}
X
XNORMAL_CODE(space, type, "space", dospace);
X
XVOID dospaces()
X{
X    INT32 n;
X
X    n = spop(INT32);
X    while (n-- > 0) (VOID) fputc(' ', io_outf);
X}
X
XNORMAL_CODE(spaces, space, "spaces", dospaces);
X
XVOID dokey()
X{
X    spush(io_getchar(), INT32);
X}
X
XNORMAL_CODE(key, spaces, "key", dokey);
X
XVOID doexpect()
X{
X    CHAR  c;
X    CSTR s0;
X    CSTR s1;
X    INT32  n;
X    
X    /* Pop buffer pointer and size */
X    n = spop(INT32);
X    s0 = s1 = spop(CSTR);
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    io_newline();
X
X    /* Set span to number of characters received */
X    span.parameter = (INT32) (s1 - s0);
X}
X
XNORMAL_CODE(expect, key, "expect", doexpect);
X
XNORMAL_VARIABLE(span, expect, "span", 0);
X
XVOID doline()
X{
X    spush(io_line(), INT32);
X}
X
XNORMAL_CODE(line, span, "line", doline);
X
XVOID dosource()
X{
X    spush(io_source(), CSTR);
X}
X
XNORMAL_CODE(source, line, "source", dosource);
X
X
X/* PROGRAM BEGINNING AND TERMINATION */
X
XVOID doforth83()
X{
X
X}
X
XNORMAL_CODE(forth83, source, "forth-83", doforth83);
X    
XVOID dointerpret()
X{
X    INT32 flag;			/* Flag value returned by for words */
X
X#ifdef CASTING
X    INT32 cast;			/* Casting operation flag */
X#endif
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	    if (io_source())
X		(VOID) fprintf(io_errf, "%s:%i:", io_source(), io_line());
X	    (VOID) fprintf(io_errf, "interpret: stack underflow\n");
X	    doabort();
X	}
X
X	/* Scan for the next symbol */
X	spush(' ', INT32);
X	doword();
X
X	/* Exit top loop if end of input stream */
X	if (io_eof()) {
X	    sdrop();
X	    return;
X	}
X
X	/* Search for the symbol in the current vocabulary search set*/
X	dofind();
X	flag = spop(INT32);
X
X#ifdef CASTING
X	/* Check for vocabulary casting prefix */
X	for (cast = flag; !cast;) {
X	    CSTR s = tos.CSTR;
X	    INT32 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		unary(++, INT32);
X
X		/* Search for the symbol again */
X		dofind();
X		flag = spop(INT32);
X		
X		/* If found check that its a vocabulary */
X		if (flag) {
X		    ENTRY v = spop(ENTRY);
X
X		    /* Check that the symbol is really a vocabulary */
X		    if (v -> code == VOCABULARY) {
X
X			/* Scan for a new symbol */
X			spush(' ', INT32);
X			doword();
X
X			/* Exit top loop if end of input stream */
X			if (io_eof()) {
X			    sdrop();
X			    return;
X			}
X
X			/* And look for it in the given vocabulary */
X			spush(v, ENTRY);
X			dolookup();
X			flag = spop(INT32);
X			cast = flag;
X		    }
X		}
X		else {
X		    /* Restore string after vocabulary name test */
X		    s[l] = ')';
X		    unary(--, INT32);
X		}
X	    }
X	}
X#endif
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 literal */
X	    dorecognize();
X	    flag = spop(INT32);
X	    if (flag) {
X		doliteral();
X	    }
X	    else {
X		/* Print source file and line number */
X		if (io_source())
X		    (VOID) fprintf(io_errf, "%s:%i:", io_source(), io_line());
X
X		/* If not print error message and abort */
X		(VOID) fprintf(io_errf, "%s ??\n", tos.CSTR);
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(abort_entry, quit, "abort", doabort);
X
XVOID doabortquote()
X{
X    spush('"', INT32);
X    doword();
X    dosdup();
X    spush(&parenabortquote, CODE_ENTRY);
X    dothread();
X    docomma();
X}
X
XCOMPILATION_IMMEDIATE_CODE(abortquote, abort_entry, "abort\"", doabortquote);
X    
X
X/* DICTIONARY ADDRESSES */
X
XVOID dohere()
X{
X    spush(dp, PTR32);
X}
X
XNORMAL_CODE(here, abortquote, "here", dohere);
X
XNORMAL_CONSTANT(pad, here, "pad", (INT32) thepad);
X
XNORMAL_CONSTANT(tib, pad, "tib", (INT32) thetib);
X
XVOID dotobody()
X{
X    tos.INT32 = tos.ENTRY -> parameter;
X}
X
XNORMAL_CODE(tobody, tib, ">body", dotobody);
X
XVOID dodotname()
X{
X    ENTRY e = spop(ENTRY);
X    
X    (VOID) fprintf(io_outf, "%s", e -> name);
X}
X
XNORMAL_CODE(dotname, tobody, ".name", dodotname);
X
XNORMAL_CONSTANT(cell, dotname, "cell", 4);
X
XVOID docells()
X{
X    tos.INT32 <<= 2;
X}
X
XNORMAL_CODE(cells, cell, "cells", docells);
X
XVOID docellplus()
X{
X    tos.INT32 += 4;
X}
X
XNORMAL_CODE(cellplus, cells, "cell+", docellplus);
X
X
X/* COMPILER AND INTERPRETER WORDS */
X
XVOID dosharpif()
X{
X    INT32 symbol;
X    BOOL flag;
X
X    flag = spop(BOOL);
X
X    if (!flag) {
X	do {
X	    spush(' ', INT32);
X	    doword();
X	    symbol = spop(INT32);
X	    if (STREQ(symbol, "#if")) {
X		dosharpelse();
X		spush(' ', INT32);
X		doword();
X		symbol = spop(INT32);
X	    }
X	} while (!((STREQ(symbol, "#else") || STREQ(symbol, "#then"))));
X    }
X}
X
XIMMEDIATE_CODE(sharpif, cellplus, "#if", dosharpif);
X
XVOID dosharpelse()
X{
X    INT32 symbol;
X    
X    do {
X	spush(' ', INT32);
X	doword();
X	symbol = spop(INT32);
X	if (STREQ(symbol, "#if")) {
X	    dosharpelse();
X	    spush(' ', INT32);
X	    doword();
X	    symbol = spop(INT32);
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(' ', INT32);
X    doword();
X    dofind();
X    doswap();
X    dodrop();
X    dosharpif();
X}
X
XIMMEDIATE_CODE(sharpifdef, sharpthen, "#ifdef", dosharpifdef);
X
XVOID dosharpifundef()
X{
X    spush(' ', INT32);
X    doword();
X    dofind();
X    doswap();
X    dodrop();
X    dozeroequals();
X    dosharpif();
X}
X
XIMMEDIATE_CODE(sharpifundef, sharpifdef, "#ifundef", dosharpifundef);
X
XVOID dosharpinclude()
X{
X    INT32 flag;
X    CSTR  fname;
X    
X    spush(' ', INT32);
X    doword();
X    fname = spop(CSTR);
X    if (flag = io_infile(fname) == IO_UNKNOWN_FILE) {
X	if (io_source())
X	    (VOID) fprintf(io_errf, "%s:%i:", io_source(), io_line());
X	(VOID) fprintf(io_errf, "%s: file not found\n", fname);
X    }
X    else {
X	if (flag == IO_TOO_MANY_FILES) {
X	    if (io_source())
X		(VOID) fprintf(io_errf, "%s:%i:", io_source(), io_line());
X	    (VOID) fprintf(io_errf, "%s: too many files open\n", fname);
X	}
X    }
X}
X
XNORMAL_CODE(sharpinclude, sharpifundef, "#include", dosharpinclude);
X
XVOID dosharppath()
X{
X    INT32 flag;
X    
X    spush(' ', INT32);
X    doword();
X    if (flag = io_path(tos.CSTR, IO_PATH_FIRST) == IO_UNKNOWN_PATH) {
X	if (io_source())
X	    (VOID) fprintf(io_errf, "%s:%i:", io_source(), io_line());
X	(VOID) fprintf(io_errf, "%s: unknown environment variable\n", tos.CSTR);
X    }
X    else {
X	if (flag == IO_TOO_MANY_PATHS) {
X	    if (io_source())
X		(VOID) fprintf(io_errf, "%s:%i:", io_source(), io_line());
X	    (VOID) fprintf(io_errf, "%s: too many paths defined\n", tos.CSTR);
X	}
X    }
X    dodrop();
X}
X
XNORMAL_CODE(sharppath, sharpinclude, "#path", dosharppath);
X
XVOID doparen()
X{
X    CHAR c;
X    
X    while (c = io_getchar())
X	if (io_eof()) {
X	    if (io_source())
X		(VOID) fprintf(io_errf, "%s:%i:", io_source(), io_line());
X	    (VOID) fprintf(io_errf, "kernel: end of file during comment\n");
X	    return;
X	}
X	else
X	    if (c == ')') return;
X	    else
X		if (c == '(') doparen();
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(INT32);
X}
X
XNORMAL_CODE(comma, backslash, ",", docomma);
X
XVOID doallot()
X{
X    INT32 n;
X
X    n = spop(INT32);
X    dp = (PTR32) ((PTR8) dp + n);
X}
X
XNORMAL_CODE(allot, comma, "allot", doallot);
X
XVOID doalign()
X{
X    align(dp);
X}
X
XNORMAL_CODE(align_entry, allot, "align", doalign);
X
XVOID dodoes()
X{
X    if (theframed != NIL) {
X	spush(&parenunlinkdoes, CODE_ENTRY);
X    }
X    else {
X	spush(&parendoes, CODE_ENTRY);
X    }
X    dothread();
X    doremovelocals();
X}
X
XCOMPILATION_IMMEDIATE_CODE(does, align_entry, "does>", dodoes);
X
XVOID doimmediate()
X{
X    current -> last -> mode |= IMMEDIATE;
X}
X
XNORMAL_CODE(immediate, does, "immediate", doimmediate);
X
XVOID doexecution()
X{
X    current -> last -> mode |= EXECUTION;
X}
X
XNORMAL_CODE(execution, immediate, "execution", doexecution);
X
XVOID docompilation()
X{
X    current -> last -> mode |= COMPILATION;
X}
X
XNORMAL_CODE(compilation, execution, "compilation", docompilation);
X
XVOID doprivate()
X{
X    current -> last -> mode |= PRIVATE;
X}
X
XNORMAL_CODE(private_entry, compilation, "private", doprivate);
X
XVOID dorecognizer()
X{
X    current -> recognizer = current -> last;
X}
X
XNORMAL_CODE(recognizer, private_entry, "recognizer", dorecognizer);
X
XVOID dobracketcompile()
X{
X    dotick();
X    dothread();
X}
X
XCOMPILATION_IMMEDIATE_CODE(bracketcompile, recognizer, "[compile]", dobracketcompile);
X
XVOID docompile()
X{
X    spush(*ip++, INT32);
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, INT32);
X}
X
XNORMAL_CODE(compiling, state, "compiling", docompiling);
X
XVOID doliteral()
X{
X    if (state.parameter) {
X	spush(&parenliteral, CODE_ENTRY);
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;
X
X    brkchr = (CHAR) spop(INT32);
X    (VOID) io_skipspace();
X    (VOID) io_scan(thetib, brkchr);
X    spush(thetib, CSTR);
X}
X
XNORMAL_CODE(word_entry, rightbracket, "word", doword);
X
X
X/* VOCABULARIES */
X
XNORMAL_CONSTANT(context_entry, word_entry, "context", (INT32) context);
X
XNORMAL_CONSTANT(current_entry, context_entry, "current", (INT32) &current);
X
XVOID dolast()
X{
X    spush((theframed ? theframed : current -> last), ENTRY);
X}
X
XNORMAL_CODE(last, current_entry, "last", dolast);
X
XVOID dodefinitions()
X{
X    current = context[0];}
X
X
XNORMAL_CODE(definitions, last, "definitions", dodefinitions);
X
XVOID doonly()
X{
X    INT32 v;
X
X    /* Flush the entry cache */
X    spush(FALSE, BOOL);
X    dorestore();
X
X    /* Remove all vocabularies except the first */
X    for (v = 1; v < CONTEXTSIZE; v++) context[v] = 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 INT32 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 = spop(ENTRY);
X    if (e) {
X
X	/* Flush all enties until the parameter symbol */
X	for (p = current -> last; p && (p != e); p = p -> link)
X	    cache[hash(p -> name)] = NIL;
X
X	/* If the entry was found remove all symbols until this entry */
X	if (p == e) current -> last = e;
X    }
X    else {
X	
X	/* Flush the entry cache */
X	for (i = 0; i < CACHESIZE; i++) cache[i] = NIL;
X    }
X}
X
XNORMAL_CODE(restore, only, "restore", dorestore);
X
XVOID dotick()
X{
X    BOOL flag;
X
X    spush(' ', INT32);
X    doword();
X    dofind();
X    flag = spop(BOOL);
X    if (!flag) {
X	/* Print source file and line number */
X	if (io_source())
X	    (VOID) fprintf(io_errf, "%s:%i:", io_source(), io_line());
X
X	/* If not print error message and abort */
X	(VOID) fprintf(io_errf, "%s ??\n", tos.CSTR);
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    VOCABULARY_ENTRY v;		/* Search vocabulary */
X    register ENTRY e;		/* Search entry */
X    register CSTR s;		/* And string */
X    
X    /* Fetch parameters and initate entry pointer */
X    v = (VOCABULARY_ENTRY) spop(PTR32);
X    s = tos.CSTR;
X    
X    /* Iterate over the linked list of entries */
X    for (e = v -> last; 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 (visible(e, v)) {
X		/* Return the entry and compilation mode */
X		tos.ENTRY = e;
X		spush((e -> mode & IMMEDIATE ? 1 : -1), INT32);
X		return;
X	    }
X	}
X    spush(FALSE, BOOL);
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    CSTR  n;			/* Name string of entry to be found */
X    INT32 v;			/* Index into vocabulary set */
X    
X    /* Access the string to be found */
X    n = tos.CSTR;
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.CSTR, 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.ENTRY = e;
X		spush((e -> mode & IMMEDIATE ? 1 : -1), INT32);
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], VOCABULARY_ENTRY);
X	dolookup();
X	if (tos.INT32) {
X	    cache[hash(n)] = snth(0).ENTRY;
X	    return;
X	}
X	else {
X	    sdrop();
X	}
X    }
X    spush(FALSE, BOOL);
X}
X
XNORMAL_CODE(find, lookup, "find", dofind);
X
XVOID dorecognize()
X{
X    INT32 v;			/* Vocabulary index */
X    ENTRY r;			/* Recognizer function */
X
X    for (v = 0; context[v] && v < CONTEXTSIZE; v++) { 
X	
X	/* Check if a recognizer function is available */
X	if (r = context[v] -> recognizer) {
X	    spush(r, ENTRY);
X	    docommand();
X	    if (tos.INT32) {
X		return;
X	    }
X	    else {
X		sdrop();
X	    }
X	}
X    }
X
X    /* The string was not a literal symbol */
X    spush(FALSE, BOOL);
X}
X
XNORMAL_CODE(recognize, find, "recognize", dorecognize);
X
XVOID doforget()
X{
X    dotick();
X    tos.ENTRY = tos.ENTRY -> link; 
X    dorestore();
X}
X
XNORMAL_CODE(forget, recognize, "forget", doforget);
X
XVOID dowords()
X{
X    ENTRY e;			/* Pointer to entries */
X    INT32 v;			/* Index into vocabulary set */
X    INT32 l;			/* String length */
X    INT32 s;			/* Spaces between words */
X    INT32 c;			/* Column counter */
X    INT32 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) fprintf(io_outf, "VOCABULARY %s", context[v] -> name);
X	if (context[v] == current) (VOID) fprintf(io_outf, " DEFINITIONS");
X	(VOID) fputc('\n', io_outf);
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 = context[v] -> last; e; e = e -> link) {
X
X	    /* Check if the entry is current visible */
X	    if (visible(e, context[v])) {
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) fputc(' ', io_outf); 
X		}
X		else {
X		    (VOID) fputc('\n', io_outf);
X		    c = l;
X		}
X		(VOID) fprintf(io_outf, "%s", e -> name);
X	    }
X	}
X
X	/* End the list of words and separate the vocabularies */
X	(VOID) fputc('\n', io_outf);
X	(VOID) fputc('\n', io_outf);
X    }
X}
X
XIMMEDIATE_CODE(words, forget, "words", dowords);
X
X
X/* DEFINING NEW VOCABULARY ENTRIES */
X
XENTRY make_entry(name, code, mode, parameter)
X    CSTR name;			/* String for the new entry */
X    INT32 code, mode, parameter; /* Entry parameters */
X{
X    /* Allocate space for the entry */
X    ENTRY e;
X
X    /* Check type of entry to allocate */
X    if (code == VOCABULARY)
X	e = (ENTRY) malloc(sizeof(vocabulary_entry));
X    else
X	e = (ENTRY) malloc(sizeof(entry));
X
X    /* Insert into the current vocabulary and set parameters */
X    e -> link = current -> last;
X    current -> last = e;
X
X    /* Set entry parameters */
X    e -> name = (CSTR) strcpy(malloc((unsigned) strlen(name) + 1), name);
X    e -> code = code;
X    e -> mode = mode;
X    e -> parameter = parameter;
X    if (code == VOCABULARY)
X	((VOCABULARY_ENTRY) e) -> recognizer = NIL;
X    
X    /* Check for entry caching */
X    if (current == context[0])
X	cache[hash(name)] = e;
X    else
X	cache[hash(name)] = NIL;
X    
X    /* Return pointer to the new entry */
X    return e;
X}
X
XVOID doentry()
X{
X    INT32 flag;
X    CSTR  name;
X    INT32 code, mode, parameter;
X    ENTRY forward;
X    
X    /* Try to find entry to check for forward declarations */
X    forward = NIL;
X    dodup();
X    dofind();
X    flag = spop(INT32);
X    if (flag) {
X	forward = spop(ENTRY);
X    }
X    else {
X	sdrop();
X    }
X    
X    /* Access name, code, mode and parameter field parameters */
X    name = spop(CSTR);
X    code = spop(INT32);
X    mode = spop(INT32);
X    parameter = spop(INT32);
X
X    /* Create the new entry */
X    (VOID) make_entry(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 = (INT32) current -> last;
X	if (verbose) {
X	    if (io_source())
X		(VOID) fprintf(io_errf, "%s:%i:", io_source(), io_line());
X	    (VOID) fprintf(io_errf, "%s: forward definition resolved\n", forward -> name);
X	}
X    }
X}
X
XNORMAL_CODE(entry_entry, words, "entry", doentry);
X
XVOID doforward()
X{
X    spush(0, INT32);
X    spush(NORMAL, INT32);
X    spush(FORWARD, INT32);
X    spush(' ', INT32);
X    doword();
X    doentry();
X}
X
XNORMAL_CODE(forward, entry_entry, "forward", doforward);
X
XVOID docolon()
X{
X    align(dp);
X    dohere();
X    spush(HIDDEN, INT32);
X    spush(COLON, INT32);
X    spush(' ', INT32);
X    doword();
X    doentry();
X    dorightbracket();
X    thelast = current -> last;
X}
X
XNORMAL_CODE(colon, forward, ":", docolon);
X
XVOID dosemicolon()
X{
X    if (theframed != NIL) {
X	spush(&parenunlinksemicolon, CODE_ENTRY);
X    }
X    else {
X	spush(&parensemicolon, CODE_ENTRY);
X    }
X    dothread();
X    doleftbracket();
X    doremovelocals();
X    if (thelast != NIL) {
X	thelast -> mode = NORMAL;
X	if (current == context[0]) cache[hash(thelast -> name)] = thelast;
X	thelast = NIL;
X    }
X}
X
XCOMPILATION_IMMEDIATE_CODE(semicolon, colon, ";", dosemicolon);
X
XVOID docreate()
X{
X    align(dp);
X    dohere();
X    spush(NORMAL, INT32);
X    spush(CREATE, INT32);
X    spush(' ', INT32);
X    doword();
X    doentry();
X}
X
XNORMAL_CODE(create, semicolon, "create", docreate);
X
XVOID dovariable()
X{
X    spush(0, INT32);
X    spush(NORMAL, INT32);
X    spush(VARIABLE, INT32);
X    spush(' ', INT32);
X    doword();
X    doentry();
X}
X
XNORMAL_CODE(variable, create, "variable", dovariable);
X
XVOID doconstant()
X{
X    spush(NORMAL, INT32);
X    spush(CONSTANT, INT32);
X    spush(' ', INT32);
X    doword();
X    doentry();
X}
X
XNORMAL_CODE(constant, variable, "constant", doconstant);
X
XVOID dovocabulary()
X{
X    spush(&forth, VOCABULARY_ENTRY);
X    spush(NORMAL, INT32);
X    spush(VOCABULARY, INT32);
X    spush(' ', INT32);
X    doword();
X    doentry();
X}
X
XNORMAL_CODE(vocabulary, constant, "vocabulary", dovocabulary);
X
XVOID dofield()
X{
X    spush(NORMAL, INT32);
X    spush(FIELD, INT32);
X    spush(' ', INT32);
X    doword();
X    doentry();
X}
X
XNORMAL_CODE(field, vocabulary, "field", dofield);
X
X
X/* INITIALIZATION OF THE KERNEL */
X
XVOID kernel_initiate(last, first, users, parameters, returns)
X    ENTRY first, last;
X    INT32 users, parameters, returns;
X{
X    /* Link user symbols into vocabulary chain if given */
X    if (first && last) {
X	forth.last = last;
X	first -> link = (ENTRY) &field;
X    }
X    
X    /* Create the foreground task object */
X    foreground = make_task(users, parameters, returns, (INT32) NIL);
X    
X    /* Assign task fields */
X    foreground -> status = RUNNING;
X    s0 = (PTR) foreground -> s0;
X    sp = (PTR) 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
XVOID kernel_finish()
X{
X    /* Future clean up function for kernel */
X}
END_OF_src/kernel.c
if test 49941 -ne `wc -c <src/kernel.c`; then
    echo shar: \"src/kernel.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of archive 6 \(of 6\).
cp /dev/null ark6isdone
MISSING=""
for I in 1 2 3 4 5 6 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 6 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