home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fresh Fish 4
/
FreshFish_May-June1994.bin
/
bbs
/
may94
/
util
/
edit
/
jade.lha
/
Jade
/
src
/
lispmach.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-04-19
|
19KB
|
888 lines
/* lispmach.c -- Interpreter for compiled Lisp forms
Copyright (C) 1993, 1994 John Harper <jsh@ukc.ac.uk>
This file is part of Jade.
Jade is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
Jade is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Jade; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "jade.h"
#include "jade_protos.h"
#ifdef HAVE_ALLOCA
# include <alloca.h>
#endif
_PR void lispmach_init(void);
#define OP_CALL 0x08
#define OP_PUSH 0x10
#define OP_VREFC 0x18
#define OP_VSETC 0x20
#define OP_LIST 0x28
#define OP_BIND 0x30
#define OP_LAST_WITH_ARGS 0x38
#define OP_VREF 0x40
#define OP_VSET 0x41
#define OP_FREF 0x42
#define OP_FSET 0x43
#define OP_INIT_BIND 0x44
#define OP_UNBIND 0x45
#define OP_DUP 0x46
#define OP_SWAP 0x47
#define OP_POP 0x48
#define OP_NIL 0x49
#define OP_T 0x4a
#define OP_CONS 0x4b
#define OP_CAR 0x4c
#define OP_CDR 0x4d
#define OP_RPLACA 0x4e
#define OP_RPLACD 0x4f
#define OP_NTH 0x50
#define OP_NTHCDR 0x51
#define OP_ASET 0x52
#define OP_AREF 0x53
#define OP_LENGTH 0x54
#define OP_EVAL 0x55
#define OP_PLUS_2 0x56
#define OP_NEGATE 0x57
#define OP_MINUS_2 0x58
#define OP_PRODUCT_2 0x59
#define OP_DIVIDE_2 0x5a
#define OP_MOD_2 0x5b
#define OP_BIT_NOT 0x5c
#define OP_NOT 0x5d
#define OP_BIT_OR_2 0x5e
#define OP_BIT_AND_2 0x5f
#define OP_EQUAL 0x60
#define OP_EQ 0x61
#define OP_NUM_EQ 0x62
#define OP_NUM_NOTEQ 0x63
#define OP_GTTHAN 0x64
#define OP_GETHAN 0x65
#define OP_LTTHAN 0x66
#define OP_LETHAN 0x67
#define OP_INC 0x68
#define OP_DEC 0x69
#define OP_LSH 0x6a
#define OP_ZEROP 0x6b
#define OP_NULL 0x6c
#define OP_ATOM 0x6d
#define OP_CONSP 0x6e
#define OP_LISTP 0x6f
#define OP_NUMBERP 0x70
#define OP_STRINGP 0x71
#define OP_VECTORP 0x72
#define OP_CATCH_KLUDGE 0x73
#define OP_THROW 0x74
#define OP_UNWIND_PRO 0x75
#define OP_UN_UNWIND_PRO 0x76
#define OP_FBOUNDP 0x77
#define OP_BOUNDP 0x78
#define OP_SYMBOLP 0x79
#define OP_GET 0x7a
#define OP_PUT 0x7b
#define OP_ERROR_PRO 0x7c
#define OP_SIGNAL 0x7d
#define OP_SET_CURRENT_BUFFER 0xb0
#define OP_SWAP_BUFFER 0xb1
#define OP_CURRENT_BUFFER 0xb2
#define OP_BUFFERP 0xb3
#define OP_MARK_P 0xb4
#define OP_WINDOWP 0xb5
#define OP_SWAP_WINDOW 0xb6
#define OP_LAST_BEFORE_JMPS 0xfa
#define OP_JMP 0xfb
#define OP_JMP_NIL 0xfc
#define OP_JMP_T 0xfd
#define OP_JMP_NIL_ELSE_POP 0xfe
#define OP_JMP_T_ELSE_POP 0xff
#define TOP (*stackp)
#define RET_POP (*stackp--)
#define POP (stackp--)
#define POPN(n) (stackp -= n)
#define PUSH(v) (*(++stackp) = (v))
#define STK_USE (stackp - (stackbase - 1))
#define ARG_MASK 0x7f
#define ARG_SHIFT 7
#define OP_ARG_MASK 0x07
#define OP_OP_MASK 0xf8
#define OP_ARG_1BYTE 6
#define OP_ARG_2BYTE 7
_PR VALUE cmd_lisp_code(VALUE code, VALUE consts, VALUE stkreq);
DEFUN("lisp-code", cmd_lisp_code, subr_lisp_code, (VALUE code, VALUE consts, VALUE stkreq), V_Subr3, DOC_lisp_code) /*
::doc:lisp_code::
(lisp-code CODE-STRING CONST-VEC MAX-STACK)
Evaluates the string of byte codes CODE-STRING, the constants that it
references are contained in the vector CONST-VEC. MAX-STACK is a number
defining how much stack space is required to evaluate the code.
Do *not* attempt to call this function manually, the lisp file `compiler.jl'
contains a simple compiler which translates files of lisp forms into files
of byte code. See the functions `compile-file', `compile-directory' and
`compile-lisp-lib' for more details.
::end:: */
{
VALUE *stackbase;
register VALUE *stackp;
/* This holds a list of sets of bindings, it can also hold the form of
an unwind-protect that always gets eval'd (when the car is t). */
VALUE bindstack = sym_nil;
register u_char *pc;
u_char c;
GCVAL gcv_code, gcv_consts, gcv_bindstack;
/* The `gcv_N' field is only filled in with the stack-size when there's
a chance of gc. */
GCVALN gcv_stackbase;
DECLARE1(code, STRINGP);
DECLARE2(consts, VECTORP);
DECLARE3(stkreq, NUMBERP);
#ifdef HAVE_ALLOCA
stackbase = alloca(sizeof(VALUE) * VNUM(stkreq));
#else
if(!(stackbase = mystralloc(sizeof(VALUE) * VNUM(stkreq))))
return(NULL);
#endif
stackp = stackbase - 1;
PUSHGC(gcv_code, code);
PUSHGC(gcv_consts, consts);
PUSHGC(gcv_bindstack, bindstack);
PUSHGCN(gcv_stackbase, stackbase, 0);
pc = VSTR(code);
while((c = *pc++) != 0)
{
if(c < OP_LAST_WITH_ARGS)
{
register short arg;
switch(c & OP_ARG_MASK)
{
case OP_ARG_1BYTE:
arg = *pc++ & ARG_MASK;
break;
case OP_ARG_2BYTE:
arg = ((pc[0] & ARG_MASK) << ARG_SHIFT) | (pc[1] & ARG_MASK);
pc += 2;
break;
default:
arg = c & OP_ARG_MASK;
}
switch(c & OP_OP_MASK)
{
register VALUE tmp;
VALUE tmp2;
case OP_CALL:
#ifdef MINSTACK
if(STK_SIZE <= MINSTACK)
{
STK_WARN("lisp-code");
TOP = cmd_signal(sym_stack_error, sym_nil);
goto quit;
}
#endif
if((DataAfterGC >= DataBeforeGC) && !GCinhibit)
{
gcv_stackbase.gcv_N = STK_USE;
cmd_garbage_collect(sym_t);
}
/* args are still available above the top of the stack,
this just makes things a bit easier. */
POPN(arg);
tmp = TOP;
if(SYMBOLP(tmp))
{
if(VSYM(tmp)->sym_Flags & SF_DEBUG)
SingleStepFlag = TRUE;
/* The `+ arg' is to make sure that our args (which were
sort of popped) are protected from gc as well. */
if(!(tmp = cmd_symbol_function(tmp)))
{
cmd_signal(sym_void_function, LIST_1(TOP));
goto error;
}
}
gcv_stackbase.gcv_N = STK_USE;
switch(VTYPE(tmp))
{
case V_Subr0:
TOP = VSUBR0FUN(tmp)();
break;
case V_Subr1:
TOP = VSUBR1FUN(tmp)(arg >= 1 ? stackp[1] : sym_nil);
break;
case V_Subr2:
switch(arg)
{
case 0:
TOP = VSUBR2FUN(tmp)(sym_nil, sym_nil);
break;
case 1:
TOP = VSUBR2FUN(tmp)(stackp[1], sym_nil);
break;
default:
TOP = VSUBR2FUN(tmp)(stackp[1], stackp[2]);
break;
}
break;
case V_Subr3:
switch(arg)
{
case 0:
TOP = VSUBR3FUN(tmp)(sym_nil, sym_nil, sym_nil);
break;
case 1:
TOP = VSUBR3FUN(tmp)(stackp[1], sym_nil, sym_nil);
break;
case 2:
TOP = VSUBR3FUN(tmp)(stackp[1], stackp[2], sym_nil);
break;
default:
TOP = VSUBR3FUN(tmp)(stackp[1], stackp[2], stackp[3]);
break;
}
break;
case V_Subr4:
switch(arg)
{
case 0:
TOP = VSUBR4FUN(tmp)(sym_nil, sym_nil,
sym_nil, sym_nil);
break;
case 1:
TOP = VSUBR4FUN(tmp)(stackp[1], sym_nil,
sym_nil, sym_nil);
break;
case 2:
TOP = VSUBR4FUN(tmp)(stackp[1], stackp[2],
sym_nil, sym_nil);
break;
case 3:
TOP = VSUBR4FUN(tmp)(stackp[1], stackp[2],
stackp[3], sym_nil);
break;
default:
TOP = VSUBR4FUN(tmp)(stackp[1], stackp[2],
stackp[3], stackp[4]);
break;
}
break;
case V_Subr5:
switch(arg)
{
case 0:
TOP = VSUBR5FUN(tmp)(sym_nil, sym_nil, sym_nil,
sym_nil, sym_nil);
break;
case 1:
TOP = VSUBR5FUN(tmp)(stackp[1], sym_nil, sym_nil,
sym_nil, sym_nil);
break;
case 2:
TOP = VSUBR5FUN(tmp)(stackp[1], stackp[2], sym_nil,
sym_nil, sym_nil);
break;
case 3:
TOP = VSUBR5FUN(tmp)(stackp[1], stackp[2], stackp[3],
sym_nil, sym_nil);
break;
case 4:
TOP = VSUBR5FUN(tmp)(stackp[1], stackp[2], stackp[3],
stackp[4], sym_nil);
default:
TOP = VSUBR5FUN(tmp)(stackp[1], stackp[2], stackp[3],
stackp[4], stackp[5]);
break;
}
break;
case V_SubrN:
tmp2 = sym_nil;
POPN(-arg); /* reclaim my args */
while(ar