home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fresh Fish 8
/
FreshFishVol8-CD1.bin
/
new
/
util
/
edit
/
jade
/
src
/
lisp.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-10-06
|
42KB
|
1,817 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>
#ifdef NEED_MEMORY_H
# include <memory.h>
#endif
_PR VALUE readl(VALUE, int *);
_PR VALUE eval_lambda(VALUE, VALUE, bool);
_PR VALUE load_autoload(VALUE, VALUE);
_PR VALUE funcall(VALUE, VALUE);
_PR VALUE eval_string(u_char *, bool);
_PR VALUE call_lisp0(VALUE);
_PR VALUE call_lisp1(VALUE, VALUE);
_PR VALUE call_lisp2(VALUE, VALUE, VALUE);
_PR void lisp_prin(VALUE, VALUE);
_PR void string_princ(VALUE, VALUE);
_PR void string_print(VALUE, VALUE);
_PR VALUE find_member_by_index(VALUE, int);
_PR VALUE move_down_list(VALUE, int);
_PR int list_length(VALUE);
_PR VALUE copy_list(VALUE);
_PR VALUE handle_var_int(VALUE, long *);
_PR void handle_error(VALUE, VALUE);
_PR VALUE signal_arg_error(VALUE, int);
_PR VALUE mem_error(void);
_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 throw_value;
VALUE throw_value;
/* This cons cell is used for interrupts. We don't know if it's safe to
call cmd_cons() (maybe in gc?) so this is always valid. */
_PR VALUE int_cell;
VALUE int_cell;
_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, sym_no_memory, sym_user_interrupt;
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, sym_no_memory, sym_user_interrupt;
#ifdef MINSTACK
_PR VALUE sym_stack_error;
VALUE sym_stack_error;
#endif
_PR VALUE debug_on_error, sym_error_info;
VALUE debug_on_error, sym_error_info;
/*
* When TRUE cmd_eval() calls the "debug-entry" function
*/
_PR bool single_step_flag;
bool single_step_flag;
_PR struct LispCall *lisp_call_stack;
struct LispCall *lisp_call_stack;
static long lisp_depth, max_lisp_depth = 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...
*/
static VALUE
read_list(VALUE strm, register int *c_p)
{
VALUE result = sym_nil;
VALUE last = NULL;
*c_p = stream_getc(strm);
while(1)
{
switch(*c_p)
{
case EOF:
return(cmd_signal(sym_end_of_stream, LIST_1(strm)));
case ' ':
case '\t':
case '\n':
case '\f':
*c_p = stream_getc(strm);
continue;
case ';':
{
register int c;
while((c = stream_getc(strm)) != EOF && c != '\n' && c != '\f')
;
*c_p = stream_getc(strm);
continue;
}
case '.':
*c_p = stream_getc(strm);
if(last)
{
if(!(VCDR(last) = readl(strm, c_p)))
return(NULL);
}
else
{
return(cmd_signal(sym_invalid_read_syntax,
LIST_1(MKSTR("Nothing to dot second element of cons-cell to"))));
}
case ')':
case ']':
*c_p = stream_getc(strm);
return(result);
default:
{
register VALUE this = cmd_cons(sym_nil, sym_nil);
if(last)
VCDR(last) = this;
else
result = this;
if(!(VCAR(this) = readl(strm, c_p)))
return(NULL);
last = this;
}
}
}
}
/*
* could be number *or* symbol
*/
static VALUE
read_symbol(VALUE strm, int *c_p)
{
#define SYM_BUF_LEN 255
VALUE result;
u_char buff[SYM_BUF_LEN + 1];
register u_char *buf = buff + 1;
int c = *c_p;
register int i = 0;
bool couldbenum = TRUE;
buff[0] = V_StaticString;
while((c != EOF) && (i < SYM_BUF_LEN))
{
switch(c)
{
case ' ':
case '\t':
case '\n':
case '\f':
case '(':
case ')':
case '[':
case ']':
case '\'':
case '"':
case ';':
goto done;
case '\\':
couldbenum = FALSE;
c = stream_getc(strm);
if(c == EOF)
return(cmd_signal(sym_end_of_stream, LIST_1(strm)));
buf[i++] = c;
break;
case '|':
couldbenum = FALSE;
c = stream_getc(strm);
while((c != EOF) && (c != '|') && (i < SYM_BUF_LEN))
{
buf[i++] = c;
c = stream_getc(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 = stream_getc(strm);
}
if(i >= SYM_BUF_LEN)
{
/* Guess I'd better fix this! */
return(cmd_signal(sym_error,
LIST_1(MKSTR("Internal buffer overrun"))));
}
done:
buf[i] = 0;
if(couldbenum && ((i > 1) || isdigit(*buf)))
{
char *dummy;
result = make_number(strtol(buf, &dummy, 0));
}
else
{
if(!(result = cmd_find_symbol(VAL(buff), sym_nil))
|| (NILP(result) && strcmp(buf, "nil")))
{
VALUE name;
if((name = string_dup(buf)) && (result = cmd_make_symbol(name)))
result = cmd_intern_symbol(result, sym_nil);
else
result = NULL;
}
}
*c_p = c;
return(result);
}
static VALUE
read_vector(VALUE strm, int *c_p)
{
VALUE result;
VALUE list = read_list(strm, c_p);
if(list)
{
VALUE cur = list;
int len;
for(len = 0; CONSP(cur); len++)
cur = VCDR(cur);
result = make_vector(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
read_str(VALUE strm, int *c_p)
{
VALUE result;
int buflen = 128;
int c = stream_getc(strm);
u_char *buf = str_alloc(buflen);
register u_char *cur = buf;
u_char *bufend = buf + buflen;
if(buf)
{
while((c != EOF) && (c != '"