home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fresh Fish 4
/
FreshFish_May-June1994.bin
/
bbs
/
may94
/
util
/
edit
/
jade.lha
/
Jade
/
src
/
lisp.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-04-19
|
40KB
|
1,686 lines
/* lisp.c -- Core of the Lisp, reading and evaluating...
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"
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
_PR VALUE readlispexp(VALUE, int *);
_PR VALUE evallambda(VALUE, VALUE, bool);
_PR VALUE funcall(VALUE, VALUE);
_PR VALUE evalstring(u_char *, bool);
_PR VALUE calllisp0(VALUE);
_PR VALUE calllisp1(VALUE, VALUE);
_PR VALUE calllisp2(VALUE, VALUE, VALUE);
_PR void lisp_prin(VALUE, VALUE);
_PR void string_princ(VALUE, VALUE);
_PR void string_print(VALUE, VALUE);
_PR VALUE findmemberbyindex(VALUE, int);
_PR VALUE movedownlist(VALUE, int);
_PR int listlen(VALUE);
_PR VALUE copylist(VALUE);
_PR VALUE handlevarint(VALUE, long *);
_PR void handleerror(VALUE, VALUE);
_PR void signalargerror(VALUE, int);
_PR void lisp_init(void);
_PR VALUE sym_debug_entry, sym_debug_exit, sym_debug_error_entry;
VALUE sym_debug_entry, sym_debug_exit, sym_debug_error_entry;
_PR VALUE sym_quote, sym_lambda, sym_macro, sym_autoload, sym_function;
VALUE sym_quote, sym_lambda, sym_macro, sym_autoload, sym_function;
_PR VALUE sym_standard_input, sym_standard_output, sym_defun;
VALUE sym_standard_input, sym_standard_output, sym_defun;
_PR VALUE sym_amp_optional, sym_amp_rest, sym_amp_aux;
VALUE sym_amp_optional, sym_amp_rest, sym_amp_aux;
/*
* When a `throw' happens a function stuffs a cons-cell in here with,
* (TAG . VALUE).
* An error is the above with TAG=sym_error and VALUE a list of relevant
* data.
*/
_PR VALUE ThrowValue;
VALUE ThrowValue;
_PR VALUE sym_error, sym_error_message, sym_invalid_function;
_PR VALUE sym_void_function, sym_void_value, sym_bad_arg, sym_invalid_read_syntax;
_PR VALUE sym_end_of_stream, sym_invalid_lambda_list, sym_missing_arg;
_PR VALUE sym_invalid_macro, sym_invalid_autoload, sym_no_catcher;
_PR VALUE sym_buffer_read_only, sym_bad_event_desc, sym_file_error;
_PR VALUE sym_invalid_stream, sym_setting_constant, sym_process_error;
_PR VALUE sym_invalid_area;
VALUE sym_error, sym_error_message, sym_invalid_function,
sym_void_function, sym_void_value, sym_bad_arg, sym_invalid_read_syntax,
sym_end_of_stream, sym_invalid_lambda_list, sym_missing_arg,
sym_invalid_macro, sym_invalid_autoload, sym_no_catcher,
sym_buffer_read_only, sym_bad_event_desc, sym_file_error,
sym_invalid_stream, sym_setting_constant, sym_process_error,
sym_invalid_area;
#ifdef MINSTACK
_PR VALUE sym_stack_error;
VALUE sym_stack_error;
#endif
_PR VALUE DebugOnError, sym_error_info;
VALUE DebugOnError, sym_error_info;
/*
* When TRUE cmd_eval() calls the "debug-entry" function
*/
_PR bool SingleStepFlag;
bool SingleStepFlag;
_PR struct LispCall *LispCallStack;
struct LispCall *LispCallStack;
static long LispDepth, MaxLispDepth = 250;
/*
* All of the read-related functions are now stream based. This will
* probably add some (much?) overhead but I think it's worth it?
*
* The `c' variable which keeps coming up is the lookahead character,
* since each read*() routine normally has to look at the next character
* to see if it's what it wants. If not, this char is given to someone
* else...
*/
/*
* Steps over white space, if a semi-colon is found the rest of the line
* is ignored.
*/
static int
nextlispexp(VALUE strm, int c)
{
while(c != EOF)
{
switch(c)
{
case ' ':
case '\t':
case '\n':
case '\f':
break;
case ';':
while((c = streamgetc(strm)) != EOF)
{
if((c == '\n') || (c == '\f'))
break;
}
break;
default:
return(c);
}
c = streamgetc(strm);
}
return(c);
}
static VALUE
readlisplist(VALUE strm, int *c_p)
{
VALUE result = sym_nil;
VALUE last = NULL;
int c = streamgetc(strm);
c = nextlispexp(strm, c);
while((c != EOF) && (c != ')') && (c != ']'))
{
if(c == '.')
{
c = streamgetc(strm);
if(last)
{
if(!(VCDR(last) = readlispexp(strm, &c)))
return(NULL);
}
else
{
cmd_signal(sym_invalid_read_syntax,
LIST_1(MKSTR("Nothing to dot second element of cons-cell to")));
return(NULL);
}
}
else
{
VALUE this;
if(!(this = cmd_cons(sym_nil, sym_nil)))
return(NULL);
if(last)
VCDR(last) = this;
else
result = this;
if(!(VCAR(this) = readlispexp(strm, &c)))
return(NULL);
last = this;
}
c = nextlispexp(strm, c);
}
if(c == EOF)
return(cmd_signal(sym_end_of_stream, LIST_1(strm)));
*c_p = streamgetc(strm);
return(result);
}
/*
* could be number *or* symbol
*/
static VALUE
readlispsymbol(VALUE strm, int *c_p)
{
VALUE result;
u_char buff[256];
u_char *buf = buff + 1;
int c = *c_p;
int i = 0;
bool couldbenum = TRUE;
buff[0] = V_StaticString;
while(c != EOF)
{
switch(c)
{
case ' ':
case '\t':
case '\n':
case '\f':
case '(':
case ')':
case '[':
case ']':
case '\'':
case '"':
case ';':
goto done;
case '\\':
couldbenum = FALSE;
c = streamgetc(strm);
if(c == EOF)
return(cmd_signal(sym_end_of_stream, LIST_1(strm)));
buf[i++] = c;
break;
case '|':
couldbenum = FALSE;
c = streamgetc(strm);
while((c != EOF) && (c != '|'))
{
buf[i++] = c;
c = streamgetc(strm);
}
if(c == EOF)
return(cmd_signal(sym_end_of_stream, LIST_1(strm)));
break;
default:
if(couldbenum)
{
/*
* if c isn't a digit (decimal or hex) and c isn't a sign
* at the start of the string then it's not a number!
*/
if(!(isdigit(c) || ((i >= 2) && isxdigit(c)) || ((i == 1) && (toupper(c) == 'X'))))
{
if(!((i == 0) && ((c == '+') || (c == '-'))))
couldbenum = FALSE;
}
}
buf[i++] = c;
}
c = streamgetc(strm);
}
done:
buf[i] = 0;
if(couldbenum && ((i > 1) || isdigit(*buf)))
{
char *dummy;
result = newnumber(strtol(buf, &dummy, 0));
}
else
{
if(!(result = cmd_find_symbol(buff, sym_nil))
|| (NILP(result) && strcmp(buf, "nil")))
{
VALUE name;
if((name = valstrdup(buf)) && (result = cmd_make_symbol(name)))
result = cmd_intern_symbol(result, sym_nil);
else
result = NULL;
}
}
*c_p = c;
return(result);
}
static VALUE
readlispvector(VALUE strm, int *c_p)
{
VALUE result;
VALUE list = readlisplist(strm, c_p);
if(list)
{
VALUE cur = list;
int len;
for(len = 0; CONSP(cur); len++)
cur = VCDR(cur);
result = newvector(len);
if(result)
{
int i;
cur = list;
for(i = 0; i < len; i++)
{
VALUE nxt = VCDR(cur);
VVECT(result)->vc_Array[i] = VCAR(cur);
#if 1
/* I think it's okay to put the cons cells back onto their
freelist. There can't be any references to them?? */
cons_free(cur);
#endif
cur = nxt;
}
}
else
result = NULL;
}
else
result = NULL;
return(result);
}
static VALUE
readlispstr(VALUE strm, int *c_p)
{
VALUE result;
int buflen = 128, i = 0;
int c = streamgetc(strm);
u_char *buf = mystralloc(buflen);
if(buf)
{
while((c != EOF) && (c != '"'))
{
if(i == buflen)
{
int newbuflen = buflen * 2;
u_char *newbuf = mystralloc(newbuflen);
if(newbuf)
{
memcpy(newbuf, buf, i);
mystrfree(buf);
buf = newbuf;
buflen = newbuflen;
}
else
{
settitle(NoMemMsg);
return(NULL);
}
}
if(c == '\\')
{
c = streamgetc(strm);
buf[i++] = escstreamchar(strm, &c);
}
else
{
buf[i++] = c;
c = streamgetc(strm);
}
}
if(c == EOF)