diff --git a/ase/configure.ac b/ase/configure.ac index 28a68555..f5460be8 100644 --- a/ase/configure.ac +++ b/ase/configure.ac @@ -1,6 +1,6 @@ -AC_PREREQ(2.59) +AC_PREREQ(2.53) AC_INIT([xpkit], [deb-0.1.0]) -AC_REVISION([$Revision: 1.12 $]) +AC_REVISION([$Revision: 1.13 $]) AC_CONFIG_HEADER([xp/config.h]) # Checks for programs. @@ -35,5 +35,5 @@ AC_CHECK_FILE([/NextDeveloper],[AC_DEFINE([_POSIX_SOURCE],[],[_POSIX_SOURCE])]) AC_CONFIG_FILES([ Makefile build/Makefile xp/Makefile - xp/c/Makefile xp/test/c/Makefile]) + xp/c/Makefile xp/lisp/Makefile xp/test/c/Makefile]) AC_OUTPUT diff --git a/ase/lsp/array.c b/ase/lsp/array.c new file mode 100644 index 00000000..11d97ed7 --- /dev/null +++ b/ase/lsp/array.c @@ -0,0 +1,103 @@ +/* + * $Id: array.c,v 1.1 2005-02-04 15:39:11 bacon Exp $ + */ + +#include "array.h" +#include +#include + +xp_lisp_array_t* xp_lisp_array_new (xp_size_t capacity) +{ + xp_lisp_array_t* array; + + assert (capacity > 0); + array = (xp_lisp_array_t*)malloc (sizeof(xp_lisp_array_t)); + if (array == XP_NULL) return XP_NULL; + + array->buffer = (void**)malloc (capacity + 1); + if (array->buffer == XP_NULL) { + free (array); + return XP_NULL; + } + + array->size = 0; + array->capacity = capacity; + array->buffer[0] = XP_NULL; + return array; +} + +void xp_lisp_array_free (xp_lisp_array_t* array) +{ + while (array->size > 0) + free (array->buffer[--array->size]); + assert (array->size == 0); + + free (array->buffer); + free (array); +} + +int xp_lisp_array_add_item (xp_lisp_array_t* array, void* item) +{ + if (array->size >= array->capacity) { + void* new_buffer = (void**)realloc ( + array->buffer, array->capacity * 2 + 1); + if (new_buffer == XP_NULL) return -1; + array->buffer = new_buffer; + array->capacity = array->capacity * 2; + } + + array->buffer[array->size++] = item; + array->buffer[array->size] = XP_NULL; + return 0; +} + +int xp_lisp_array_insert (xp_lisp_array_t* array, xp_size_t index, void* value) +{ + xp_size_t i; + + if (index >= array->capacity) { + void* new_buffer = (void**)realloc ( + array->buffer, array->capacity * 2 + 1); + if (new_buffer == XP_NULL) return -1; + array->buffer = new_buffer; + array->capacity = array->capacity * 2; + } + + for (i = array->size; i > index; i--) { + array->buffer[i] = array->buffer[i - 1]; + } + array->buffer[index] = value; + array->size = (index > array->size)? index + 1: array->size + 1; + + return 0; +} + +void xp_lisp_array_delete (xp_lisp_array_t* array, xp_size_t index) +{ + assert (index < array->size); + +} + +void xp_lisp_array_clear (xp_lisp_array_t* array) +{ + while (array->size > 0) + free (array->buffer[--array->size]); + assert (array->size == 0); + array->buffer[0] = XP_NULL; +} + +void** xp_lisp_array_transfer (xp_lisp_array_t* array, xp_size_t capacity) +{ + void** old_buffer, ** new_buffer; + + new_buffer = (void**)malloc(capacity + 1); + if (new_buffer == XP_NULL) return XP_NULL; + + old_buffer = array->buffer; + array->buffer = new_buffer; + array->size = 0; + array->capacity = capacity; + array->buffer[0] = XP_NULL; + + return old_buffer; +} diff --git a/ase/lsp/array.h b/ase/lsp/array.h new file mode 100644 index 00000000..86066f53 --- /dev/null +++ b/ase/lsp/array.h @@ -0,0 +1,34 @@ +/* + * $Id: array.h,v 1.1 2005-02-04 15:39:11 bacon Exp $ + */ + +#ifndef _RBL_ARRAY_H_ +#define _RBL_ARRAY_H_ + +#include + +struct xp_lisp_array_t { + void** buffer; + xp_size_t size; + xp_size_t capacity; +}; + +typedef struct xp_lisp_array_t xp_lisp_array_t; + +#ifdef __cplusplus +extern "C" { +#endif + +xp_lisp_array_t* xp_lisp_array_new (xp_size_t capacity); +void xp_lisp_array_free (xp_lisp_array_t* array); +int xp_lisp_array_add_item (xp_lisp_array_t* array, void* item); +int xp_lisp_array_insert (xp_lisp_array_t* array, xp_size_t index, void* value); +void xp_lisp_array_delete (xp_lisp_array_t* array, xp_size_t index); +void xp_lisp_array_clear (xp_lisp_array_t* array); +void** xp_lisp_array_transfer (xp_lisp_array_t* array, xp_size_t capacity); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ase/lsp/env.c b/ase/lsp/env.c new file mode 100644 index 00000000..733eb539 --- /dev/null +++ b/ase/lsp/env.c @@ -0,0 +1,82 @@ +/* + * $Id: env.c,v 1.1 2005-02-04 15:39:11 bacon Exp $ + */ + +#include "environment.h" +#include + +xp_lisp_assoc_t* xp_lisp_assoc_new (xp_lisp_obj_t* name, xp_lisp_obj_t* value) +{ + xp_lisp_assoc_t* assoc; + + assoc = (xp_lisp_assoc_t*) xp_malloc (sizeof(xp_lisp_assoc_t)); + if (assoc == XP_NULL) return XP_NULL; + + assoc->name = name; + assoc->value = value; + assoc->link = XP_NULL; + + return assoc; +} + +void xp_lisp_assoc_free (xp_lisp_assoc_t* assoc) +{ + xp_free (assoc); +} + +xp_lisp_frame_t* xp_lisp_frame_new (void) +{ + xp_lisp_frame_t* frame; + + frame = (xp_lisp_frame_t*) xp_malloc (sizeof(xp_lisp_frame_t)); + if (frame == XP_NULL) return XP_NULL; + + frame->assoc = XP_NULL; + frame->link = XP_NULL; + + return frame; +} + +void xp_lisp_frame_free (xp_lisp_frame_t* frame) +{ + xp_lisp_assoc_t* assoc, * link; + + // destroy the associations + assoc = frame->assoc; + while (assoc != XP_NULL) { + link = assoc->link; + xp_lisp_assoc_free (assoc); + assoc = link; + } + + xp_free (frame); +} + +xp_lisp_assoc_t* xp_lisp_frame_lookup (xp_lisp_frame_t* frame, xp_lisp_obj_t* name) +{ + xp_lisp_assoc_t* assoc; + + xp_lisp_assert (RBL_TYPE(name) == RBL_OBJ_SYMBOL); + + assoc = frame->assoc; + while (assoc != XP_NULL) { + if (name == assoc->name) return assoc; + assoc = assoc->link; + } + return XP_NULL; +} + +xp_lisp_assoc_t* xp_lisp_frame_insert ( + xp_lisp_frame_t* frame, xp_lisp_obj_t* name, xp_lisp_obj_t* value) +{ + xp_lisp_assoc_t* assoc; + + xp_lisp_assert (RBL_TYPE(name) == RBL_OBJ_SYMBOL); + + assoc = xp_lisp_assoc_new (name, value); + if (assoc == XP_NULL) return XP_NULL; + assoc->link = frame->assoc; + frame->assoc = assoc; + return assoc; +} + diff --git a/ase/lsp/env.h b/ase/lsp/env.h new file mode 100644 index 00000000..6209e076 --- /dev/null +++ b/ase/lsp/env.h @@ -0,0 +1,42 @@ +/* + * $Id: env.h,v 1.1 2005-02-04 15:39:11 bacon Exp $ + */ + +#ifndef _RBL_ENV_H_ +#define _RBL_ENV_H_ + +#include "object.h" + +struct xp_lisp_assoc_t +{ + xp_lisp_obj_t* name; // xp_lisp_obj_symbol_t + xp_lisp_obj_t* value; + struct xp_lisp_assoc_t* link; +}; + +struct xp_lisp_frame_t +{ + struct xp_lisp_assoc_t* assoc; + struct xp_lisp_frame_t* link; +}; + +typedef struct xp_lisp_assoc_t xp_lisp_assoc_t; +typedef struct xp_lisp_frame_t xp_lisp_frame_t; + +#ifdef __cplusplus +extern "C" { +#endif + +xp_lisp_assoc_t* xp_lisp_assoc_new (xp_lisp_obj_t* name, xp_lisp_obj_t* value); +void xp_lisp_assoc_free (xp_lisp_assoc_t* assoc); + +xp_lisp_frame_t* xp_lisp_frame_new (void); +void xp_lisp_frame_free (xp_lisp_frame_t* frame); +xp_lisp_assoc_t* xp_lisp_frame_lookup (xp_lisp_frame_t* frame, xp_lisp_obj_t* name); +xp_lisp_assoc_t* xp_lisp_frame_insert (xp_lisp_frame_t* frame, xp_lisp_obj_t* name, xp_lisp_obj_t* value); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ase/lsp/eval.c b/ase/lsp/eval.c new file mode 100644 index 00000000..a1d3dcfb --- /dev/null +++ b/ase/lsp/eval.c @@ -0,0 +1,275 @@ +/* + * $Id: eval.c,v 1.1 2005-02-04 15:39:11 bacon Exp $ + */ + +#include "lsp.h" +#include "env.h" +#include "prim.h" + +#ifdef __cplusplus +extern "C" { +#endif + +static xp_lisp_obj_t* make_func (xp_lisp_t* lsp, xp_lisp_obj_t* cdr, int is_macro); +static xp_lisp_obj_t* eval_cons (xp_lisp_t* lsp, xp_lisp_obj_t* cons); +static xp_lisp_obj_t* apply (xp_lisp_t* lsp, xp_lisp_obj_t* func, xp_lisp_obj_t* actual); + +#ifdef __cplusplus +} +#endif + +xp_lisp_obj_t* xp_lisp_eval (xp_lisp_t* lsp, xp_lisp_obj_t* obj) +{ + lsp->error = RBL_ERR_NONE; + + if (RBL_TYPE(obj) == RBL_OBJ_CONS) + return eval_cons (lsp, obj); + else if (RBL_TYPE(obj) == RBL_OBJ_SYMBOL) { + xp_lisp_assoc_t* assoc; + + /* + if (obj == lsp->mem->lambda || obj == lsp->mem->macro) { + printf ("lambda or macro can't be used as a normal symbol\n"); + lsp->error = RBL_ERR_BAD_SYMBOL; + return XP_NULL; + } + */ + + if ((assoc = xp_lisp_lookup (lsp->mem, obj)) == XP_NULL) { + if (lsp->opt_undef_symbol) { + lsp->error = RBL_ERR_UNDEF_SYMBOL; + return XP_NULL; + } + return lsp->mem->nil; + } + + obj = assoc->value; + } + + return obj; +} + +static xp_lisp_obj_t* make_func (xp_lisp_t* lsp, xp_lisp_obj_t* cdr, int is_macro) +{ + // TODO: lambda expression syntax check. + xp_lisp_obj_t* func, * formal, * body; + + printf ("about to create a function or a macro ....\n"); + + if (cdr == lsp->mem->nil) { + lsp->error = RBL_ERR_TOO_FEW_ARGS; + return XP_NULL; + } + + if (RBL_TYPE(cdr) != RBL_OBJ_CONS) { + lsp->error = RBL_ERR_BAD_ARG; + return XP_NULL; + } + + formal = RBL_CAR(cdr); + body = RBL_CDR(cdr); + + if (body == lsp->mem->nil) { + lsp->error = RBL_ERR_EMPTY_BODY; + return XP_NULL; + } + + func = (is_macro)? + xp_lisp_make_macro (lsp->mem, formal, body): + xp_lisp_make_func (lsp->mem, formal, body); + if (func == XP_NULL) { + lsp->error = RBL_ERR_MEM; + return XP_NULL; + } + + return func; +} + +static xp_lisp_obj_t* eval_cons (xp_lisp_t* lsp, xp_lisp_obj_t* cons) +{ + xp_lisp_obj_t* car, * cdr; + + xp_lisp_assert (RBL_TYPE(cons) == RBL_OBJ_CONS); + + car = RBL_CAR(cons); + cdr = RBL_CDR(cons); + + if (car == lsp->mem->lambda) { + return make_func (lsp, cdr, 0); + } + else if (car == lsp->mem->macro) { + return make_func (lsp, cdr, 1); + } + else if (RBL_TYPE(car) == RBL_OBJ_SYMBOL) { + xp_lisp_assoc_t* assoc; + + if ((assoc = xp_lisp_lookup (lsp->mem, car)) != XP_NULL) { + xp_lisp_obj_t* func = assoc->value; + if (RBL_TYPE(func) == RBL_OBJ_FUNC || + RBL_TYPE(func) == RBL_OBJ_MACRO) { + return apply (lsp, func, cdr); + } + else if (RBL_TYPE(func) == RBL_OBJ_PRIM) { + // primitive function + return RBL_PIMPL(func) (lsp, cdr); + } + else { + printf ("undefined function: "); + xp_lisp_print (lsp, car); + printf ("\n"); + lsp->error = RBL_ERR_UNDEF_FUNC; + return XP_NULL; + } + } + else { + //TODO: better error handling. + printf ("undefined function: "); + xp_lisp_print (lsp, car); + printf ("\n"); + lsp->error = RBL_ERR_UNDEF_FUNC; + return XP_NULL; + } + } + else if (RBL_TYPE(car) == RBL_OBJ_FUNC || + RBL_TYPE(car) == RBL_OBJ_MACRO) { + return apply (lsp, car, cdr); + } + else if (RBL_TYPE(car) == RBL_OBJ_CONS) { + if (RBL_CAR(car) == lsp->mem->lambda) { + xp_lisp_obj_t* func = make_func (lsp, RBL_CDR(car), 0); + if (func == XP_NULL) return XP_NULL; + return apply (lsp, func, cdr); + } + else if (RBL_CAR(car) == lsp->mem->macro) { + xp_lisp_obj_t* func = make_func (lsp, RBL_CDR(car), 1); + if (func == XP_NULL) return XP_NULL; + return apply (lsp, func, cdr); + } + } + + rb_printf (RBL_TEXT("bad function: ")); + xp_lisp_print (lsp, car); + rb_printf (RBL_TEXT("\n")); + lsp->error = RBL_ERR_BAD_FUNC; + return XP_NULL; +} + +static xp_lisp_obj_t* apply (xp_lisp_t* lsp, xp_lisp_obj_t* func, xp_lisp_obj_t* actual) +{ + xp_lisp_frame_t* frame; + xp_lisp_obj_t* formal; + xp_lisp_obj_t* body; + xp_lisp_obj_t* value; + xp_lisp_mem_t* mem; + + xp_lisp_assert ( + RBL_TYPE(func) == RBL_OBJ_FUNC || + RBL_TYPE(func) == RBL_OBJ_MACRO); + + xp_lisp_assert (RBL_TYPE(RBL_CDR(func)) == RBL_OBJ_CONS); + + mem = lsp->mem; + + if (RBL_TYPE(func) == RBL_OBJ_MACRO) { + formal = RBL_MFORMAL (func); + body = RBL_MBODY (func); + } + else { + formal = RBL_FFORMAL (func); + body = RBL_FBODY (func); + } + + // make a new frame. + frame = xp_lisp_frame_new (); + if (frame == XP_NULL) { + lsp->error = RBL_ERR_MEM; + return XP_NULL; + } + + // attach it to the brooding frame list to + // make them not to be garbage collected. + frame->link = mem->brooding_frame; + mem->brooding_frame = frame; + + // evaluate arguments and push them into the frame. + while (formal != mem->nil) { + if (actual == mem->nil) { + lsp->error = RBL_ERR_TOO_FEW_ARGS; + mem->brooding_frame = frame->link; + xp_lisp_frame_free (frame); + return XP_NULL; + } + + value = RBL_CAR(actual); + if (RBL_TYPE(func) != RBL_OBJ_MACRO) { + // macro doesn't evaluate actual arguments. + value = xp_lisp_eval (lsp, value); + if (value == XP_NULL) { + mem->brooding_frame = frame->link; + xp_lisp_frame_free (frame); + return XP_NULL; + } + } + + if (xp_lisp_frame_lookup (frame, RBL_CAR(formal)) != XP_NULL) { + lsp->error = RBL_ERR_DUP_FORMAL; + mem->brooding_frame = frame->link; + xp_lisp_frame_free (frame); + return XP_NULL; + } + if (xp_lisp_frame_insert (frame, RBL_CAR(formal), value) == XP_NULL) { + lsp->error = RBL_ERR_MEM; + mem->brooding_frame = frame->link; + xp_lisp_frame_free (frame); + return XP_NULL; + } + + actual = RBL_CDR(actual); + formal = RBL_CDR(formal); + } + + if (RBL_TYPE(actual) == RBL_OBJ_CONS) { + lsp->error = RBL_ERR_TOO_MANY_ARGS; + mem->brooding_frame = frame->link; + xp_lisp_frame_free (frame); + return XP_NULL; + } + else if (actual != mem->nil) { + lsp->error = RBL_ERR_BAD_ARG; + mem->brooding_frame = frame->link; + xp_lisp_frame_free (frame); + return XP_NULL; + } + + // push the frame + mem->brooding_frame = frame->link; + frame->link = mem->frame; + mem->frame = frame; + + // do the evaluation of the body + value = mem->nil; + while (body != mem->nil) { + value = xp_lisp_eval(lsp, RBL_CAR(body)); + if (value == XP_NULL) { + mem->frame = frame->link; + xp_lisp_frame_free (frame); + return XP_NULL; + } + body = RBL_CDR(body); + } + + // pop the frame. + mem->frame = frame->link; + + // destroy the frame. + xp_lisp_frame_free (frame); + + //if (RBL_CAR(func) == mem->macro) { + if (RBL_TYPE(func) == RBL_OBJ_MACRO) { + value = xp_lisp_eval(lsp, value); + if (value == XP_NULL) return XP_NULL; + } + + return value; +} + diff --git a/ase/lsp/lisp.c b/ase/lsp/lisp.c new file mode 100644 index 00000000..a5a0ed0c --- /dev/null +++ b/ase/lsp/lisp.c @@ -0,0 +1,71 @@ +/* + * $Id: lisp.c,v 1.1 2005-02-04 15:39:11 bacon Exp $ + */ + +#include "lsp.h" +#include + +xp_lisp_t* xp_lisp_new (xp_size_t mem_ubound, xp_size_t mem_ubound_inc) +{ + xp_lisp_t* lsp; + + lsp = (xp_lisp_t*)malloc(sizeof(xp_lisp_t)); + if (lsp == XP_NULL) return lsp; + + lsp->token = xp_lisp_token_new (256); + if (lsp->token == XP_NULL) { + free (lsp); + return XP_NULL; + } + + lsp->error = RBL_ERR_NONE; + //lsp->opt_undef_symbol = 1; + lsp->opt_undef_symbol = 0; + + lsp->curc = RBL_CHAR_END; + lsp->creader = XP_NULL; + lsp->creader_extra = XP_NULL; + lsp->creader_just_set = 0; + lsp->outstream = stdout; + + lsp->mem = xp_lisp_mem_new (mem_ubound, mem_ubound_inc); + if (lsp->mem == XP_NULL) { + xp_lisp_token_free (lsp->token); + free (lsp); + return XP_NULL; + } + + if (xp_lisp_add_prims (lsp->mem) == -1) { + xp_lisp_mem_free (lsp->mem); + xp_lisp_token_free (lsp->token); + free (lsp); + return XP_NULL; + } + + return lsp; +} + +void xp_lisp_free (xp_lisp_t* lsp) +{ + xp_lisp_assert (lsp != XP_NULL); + + xp_lisp_mem_free (lsp->mem); + xp_lisp_token_free (lsp->token); + free (lsp); +} + +int xp_lisp_error (xp_lisp_t* lsp, xp_lisp_char* buf, xp_size_t size) +{ + if (buf != XP_NULL || size == 0) return lsp->error; + + // TODO:... + /* + switch (lsp->error) { + + default: + xp_lisp_copy_string (buf, size, "unknown error"); + } + */ + + return lsp->error; +} diff --git a/ase/lsp/lisp.h b/ase/lsp/lisp.h new file mode 100644 index 00000000..9d96fe20 --- /dev/null +++ b/ase/lsp/lisp.h @@ -0,0 +1,87 @@ +/* + * $Id: lisp.h,v 1.1 2005-02-04 15:39:11 bacon Exp $ + */ + +#ifndef _RBL_LISP_H_ +#define _RBL_LISP_H_ + +#include +#include +#include +#include + +// NOTICE: the function of xp_lisp_creader_t must return -1 on error +// and 0 on success. the first argument must be set to +// RBL_END_CHAR at the end of input. +typedef int (*xp_lisp_creader_t) (xp_lisp_cint*, void*); + +#define RBL_ERR(lsp) ((lsp)->error) +#define RBL_ERR_NONE 0 +#define RBL_ERR_ABORT 1 +#define RBL_ERR_END 2 +#define RBL_ERR_MEM 3 +#define RBL_ERR_READ 4 +#define RBL_ERR_SYNTAX 5 +#define RBL_ERR_BAD_ARG 6 +#define RBL_ERR_WRONG_ARG 7 +#define RBL_ERR_TOO_FEW_ARGS 8 +#define RBL_ERR_TOO_MANY_ARGS 9 +#define RBL_ERR_UNDEF_FUNC 10 +#define RBL_ERR_BAD_FUNC 11 +#define RBL_ERR_DUP_FORMAL 12 +#define RBL_ERR_BAD_SYMBOL 13 +#define RBL_ERR_UNDEF_SYMBOL 14 +#define RBL_ERR_EMPTY_BODY 15 +#define RBL_ERR_BAD_VALUE 16 + +struct xp_lisp_t +{ + /* error number */ + int error; + int opt_undef_symbol; + + /* for read */ + xp_lisp_cint curc; + xp_lisp_creader_t creader; + void* creader_extra; + int creader_just_set; + xp_lisp_token_t* token; + + /* for eval */ + xp_size_t max_eval_depth; // TODO:.... + xp_size_t eval_depth; + + /* for print */ + FILE* outstream; + + /* memory manager */ + xp_lisp_mem_t* mem; +}; + +typedef struct xp_lisp_t xp_lisp_t; + +#ifdef __cplusplus +extern "C" { +#endif + +/* lsp.c */ +xp_lisp_t* xp_lisp_new (xp_size_t mem_ubound, xp_size_t mem_ubound_inc); +void xp_lisp_free (xp_lisp_t* lsp); +int xp_lisp_error (xp_lisp_t* lsp, xp_lisp_char* buf, xp_size_t size); + +/* read.c */ +// TODO: move xp_lisp_set_creader to lsp.c +void xp_lisp_set_creader (xp_lisp_t* lsp, xp_lisp_creader_t func, void* extra); +xp_lisp_obj_t* xp_lisp_read (xp_lisp_t* lsp); + +/* eval.c */ +xp_lisp_obj_t* xp_lisp_eval (xp_lisp_t* lsp, xp_lisp_obj_t* obj); + +/* print.c */ +void xp_lisp_print (xp_lisp_t* lsp, xp_lisp_obj_t* obj); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ase/lsp/makefile.in b/ase/lsp/makefile.in new file mode 100644 index 00000000..87e91a94 --- /dev/null +++ b/ase/lsp/makefile.in @@ -0,0 +1,20 @@ +SRCS = env.c token.c mem.c lsp.c prim.c read.c eval.c print.c array.c +OBJS = $(SRCS:.c=.o) +OUT = libxplisp.a + +CC = @CC@ +RANLIB = @RANLIB@ +CFLAGS = @CFLAGS@ -I@abs_top_builddir@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ + +all: $(OBJS) + ar cr $(OUT) $(OBJS) + ranlib $(OUT) + +clean: + rm -rf $(OBJS) $(OUT) *.o + +.SUFFIXES: .c .o +.c.o: + $(CC) $(CFLAGS) -c $< diff --git a/ase/lsp/memory.c b/ase/lsp/memory.c new file mode 100644 index 00000000..98146f71 --- /dev/null +++ b/ase/lsp/memory.c @@ -0,0 +1,658 @@ +/* + * $Id: memory.c,v 1.1 2005-02-04 15:39:11 bacon Exp $ + */ + +#include +#include +#include + +xp_lisp_mem_t* xp_lisp_mem_new (xp_size_t ubound, xp_size_t ubound_inc) +{ + xp_lisp_mem_t* mem; + xp_size_t i; + + // allocate memory + mem = (xp_lisp_mem_t*)xp_malloc (sizeof(xp_lisp_mem_t)); + if (mem == XP_NULL) return XP_NULL; + + // create a new root environment frame + mem->frame = xp_lisp_frame_new (); + if (mem->frame == XP_NULL) { + xp_free (mem); + return XP_NULL; + } + mem->root_frame = mem->frame; + mem->brooding_frame = XP_NULL; + + // create an array to hold temporary objects + mem->temp_array = xp_lisp_array_new (512); + if (mem->temp_array == XP_NULL) { + xp_lisp_frame_free (mem->frame); + xp_free (mem); + return XP_NULL; + } + + // initialize object allocation list + mem->ubound = ubound; + mem->ubound_inc = ubound_inc; + mem->count = 0; + for (i = 0; i < RBL_TYPE_COUNT; i++) { + mem->used[i] = XP_NULL; + mem->free[i] = XP_NULL; + } + mem->locked = XP_NULL; + + // when "ubound" is too small, the garbage collection can + // be performed while making the common objects. + mem->nil = XP_NULL; + mem->t = XP_NULL; + mem->quote = XP_NULL; + mem->lambda = XP_NULL; + mem->macro = XP_NULL; + + // initialize common object pointers + mem->nil = xp_lisp_make_nil (mem); + mem->t = xp_lisp_make_true (mem); + mem->quote = xp_lisp_make_symbol (mem, RBL_TEXT("quote"), 5); + mem->lambda = xp_lisp_make_symbol (mem, RBL_TEXT("lambda"), 6); + mem->macro = xp_lisp_make_symbol (mem, RBL_TEXT("macro"), 5); + + if (mem->nil == XP_NULL || + mem->t == XP_NULL || + mem->quote == XP_NULL || + mem->lambda == XP_NULL || + mem->macro == XP_NULL) { + xp_lisp_dispose_all (mem); + xp_lisp_array_free (mem->temp_array); + xp_lisp_frame_free (mem->frame); + xp_free (mem); + return XP_NULL; + } + + return mem; +} + +void xp_lisp_mem_free (xp_lisp_mem_t* mem) +{ + xp_lisp_assert (mem != XP_NULL); + + // dispose of the allocated objects + xp_lisp_dispose_all (mem); + + // dispose of the temporary object arrays + xp_lisp_array_free (mem->temp_array); + + // dispose of environment frames + xp_lisp_frame_free (mem->frame); + + // free the memory + xp_free (mem); +} + +static int xp_lisp_add_prim ( + xp_lisp_mem_t* mem, const xp_lisp_char* name, xp_size_t len, xp_lisp_pimpl_t prim) +{ + xp_lisp_obj_t* n, * p; + + n = xp_lisp_make_symbol (mem, name, len); + if (n == XP_NULL) return -1; + + xp_lisp_lock (n); + + p = xp_lisp_make_prim (mem, prim); + if (p == XP_NULL) return -1; + + xp_lisp_unlock (n); + + if (xp_lisp_set (mem, n, p) == XP_NULL) return -1; + + return 0; +} + + +int xp_lisp_add_prims (xp_lisp_mem_t* mem) +{ + +#define ADD_PRIM(mem,name,len,prim) \ + if (xp_lisp_add_prim(mem,name,len,prim) == -1) return -1; + + ADD_PRIM (mem, RB_TEXT("abort"), 5, xp_lisp_prim_abort); + ADD_PRIM (mem, RB_TEXT("eval"), 4, xp_lisp_prim_eval); + ADD_PRIM (mem, RB_TEXT("prog1"), 5, xp_lisp_prim_prog1); + ADD_PRIM (mem, RB_TEXT("progn"), 5, xp_lisp_prim_progn); + ADD_PRIM (mem, RB_TEXT("gc"), 2, xp_lisp_prim_gc); + + ADD_PRIM (mem, RB_TEXT("cond"), 4, xp_lisp_prim_cond); + ADD_PRIM (mem, RB_TEXT("if"), 2, xp_lisp_prim_if); + ADD_PRIM (mem, RB_TEXT("while"), 5, xp_lisp_prim_while); + + ADD_PRIM (mem, RB_TEXT("car"), 3, xp_lisp_prim_car); + ADD_PRIM (mem, RB_TEXT("cdr"), 3, xp_lisp_prim_cdr); + ADD_PRIM (mem, RB_TEXT("cons"), 4, xp_lisp_prim_cons); + ADD_PRIM (mem, RB_TEXT("set"), 3, xp_lisp_prim_set); + ADD_PRIM (mem, RB_TEXT("setq"), 4, xp_lisp_prim_setq); + ADD_PRIM (mem, RB_TEXT("quote"), 5, xp_lisp_prim_quote); + ADD_PRIM (mem, RB_TEXT("defun"), 5, xp_lisp_prim_defun); + ADD_PRIM (mem, RB_TEXT("demac"), 5, xp_lisp_prim_demac); + ADD_PRIM (mem, RB_TEXT("let"), 3, xp_lisp_prim_let); + ADD_PRIM (mem, RB_TEXT("let*"), 4, xp_lisp_prim_letx); + + ADD_PRIM (mem, RB_TEXT("+"), 1, xp_lisp_prim_plus); + ADD_PRIM (mem, RB_TEXT(">"), 1, xp_lisp_prim_gt); + ADD_PRIM (mem, RB_TEXT("<"), 1, xp_lisp_prim_lt); + + return 0; +} + + +xp_lisp_obj_t* xp_lisp_allocate (xp_lisp_mem_t* mem, int type, xp_size_t size) +{ + xp_lisp_obj_t* obj; + + if (mem->count >= mem->ubound) xp_lisp_garbage_collect (mem); + if (mem->count >= mem->ubound) { + mem->ubound += mem->ubound_inc; + if (mem->count >= mem->ubound) return XP_NULL; + } + + obj = (xp_lisp_obj_t*)xp_malloc (size); + if (obj == XP_NULL) { + xp_lisp_garbage_collect (mem); + + obj = (xp_lisp_obj_t*)xp_malloc (size); + if (obj == XP_NULL) return XP_NULL; + } + + RBL_TYPE(obj) = type; + RBL_SIZE(obj) = size; + RBL_MARK(obj) = 0; + RBL_LOCK(obj) = 0; + + // insert the object at the head of the used list + RBL_LINK(obj) = mem->used[type]; + mem->used[type] = obj; + mem->count++; + RB_DEBUG1 (RB_TEXT("mem->count: %u\n"), mem->count); + + return obj; +} + +void xp_lisp_dispose (xp_lisp_mem_t* mem, xp_lisp_obj_t* prev, xp_lisp_obj_t* obj) +{ + xp_lisp_assert (mem != XP_NULL); + xp_lisp_assert (obj != XP_NULL); + xp_lisp_assert (mem->count > 0); + + // TODO: push the object to the free list for more + // efficient memory management + + if (prev == XP_NULL) + mem->used[RBL_TYPE(obj)] = RBL_LINK(obj); + else RBL_LINK(prev) = RBL_LINK(obj); + + mem->count--; + RB_DEBUG1 (RB_TEXT("mem->count: %u\n"), mem->count); + + xp_free (obj); +} + +void xp_lisp_dispose_all (xp_lisp_mem_t* mem) +{ + xp_lisp_obj_t* obj, * next; + xp_size_t i; + + for (i = 0; i < RBL_TYPE_COUNT; i++) { + obj = mem->used[i]; + + while (obj != XP_NULL) { + next = RBL_LINK(obj); + xp_lisp_dispose (mem, XP_NULL, obj); + obj = next; + } + } +} + +static void xp_lisp_mark_obj (xp_lisp_obj_t* obj) +{ + xp_lisp_assert (obj != XP_NULL); + + // TODO:.... + // can it be recursive? + if (RBL_MARK(obj) != 0) return; + + RBL_MARK(obj) = 1; + + if (RBL_TYPE(obj) == RBL_OBJ_CONS) { + xp_lisp_mark_obj (RBL_CAR(obj)); + xp_lisp_mark_obj (RBL_CDR(obj)); + } + else if (RBL_TYPE(obj) == RBL_OBJ_FUNC) { + xp_lisp_mark_obj (RBL_FFORMAL(obj)); + xp_lisp_mark_obj (RBL_FBODY(obj)); + } + else if (RBL_TYPE(obj) == RBL_OBJ_MACRO) { + xp_lisp_mark_obj (RBL_MFORMAL(obj)); + xp_lisp_mark_obj (RBL_MBODY(obj)); + } +} + +/* + * xp_lisp_lock and xp_lisp_unlock_all are just called by xp_lisp_read. + */ +void xp_lisp_lock (xp_lisp_obj_t* obj) +{ + xp_lisp_assert (obj != XP_NULL); + RBL_LOCK(obj) = 1; + //RBL_MARK(obj) = 1; +} + +void xp_lisp_unlock (xp_lisp_obj_t* obj) +{ + xp_lisp_assert (obj != XP_NULL); + RBL_LOCK(obj) = 0; +} + +void xp_lisp_unlock_all (xp_lisp_obj_t* obj) +{ + xp_lisp_assert (obj != XP_NULL); + + RBL_LOCK(obj) = 0; + + if (RBL_TYPE(obj) == RBL_OBJ_CONS) { + xp_lisp_unlock_all (RBL_CAR(obj)); + xp_lisp_unlock_all (RBL_CDR(obj)); + } + else if (RBL_TYPE(obj) == RBL_OBJ_FUNC) { + xp_lisp_unlock_all (RBL_FFORMAL(obj)); + xp_lisp_unlock_all (RBL_FBODY(obj)); + } + else if (RBL_TYPE(obj) == RBL_OBJ_MACRO) { + xp_lisp_unlock_all (RBL_MFORMAL(obj)); + xp_lisp_unlock_all (RBL_MBODY(obj)); + } +} + +static void xp_lisp_mark (xp_lisp_mem_t* mem) +{ + xp_lisp_frame_t* frame; + xp_lisp_assoc_t* assoc; + xp_lisp_array_t* array; + xp_size_t i; + + RB_DEBUG0 (RB_TEXT("marking environment frames\n")); + // mark objects in the environment frames + frame = mem->frame; + while (frame != XP_NULL) { + assoc = frame->assoc; + while (assoc != XP_NULL) { + xp_lisp_mark_obj (assoc->name); + xp_lisp_mark_obj (assoc->value); + assoc = assoc->link; + } + + frame = frame->link; + } + + RB_DEBUG0 (RB_TEXT("marking interim frames\n")); + + // mark objects in the interim frames + frame = mem->brooding_frame; + while (frame != XP_NULL) { + + assoc = frame->assoc; + while (assoc != XP_NULL) { + xp_lisp_mark_obj (assoc->name); + xp_lisp_mark_obj (assoc->value); + assoc = assoc->link; + } + + frame = frame->link; + } + + /* + RB_DEBUG0 (RB_TEXT("marking the locked object\n")); + if (mem->locked != XP_NULL) xp_lisp_mark_obj (mem->locked); + */ + + RB_DEBUG0 (RB_TEXT("marking termporary objects\n")); + array = mem->temp_array; + for (i = 0; i < array->size; i++) { + xp_lisp_mark_obj (array->buffer[i]); + } + + RB_DEBUG0 (RB_TEXT("marking builtin objects\n")); + // mark common objects + if (mem->t != XP_NULL) xp_lisp_mark_obj (mem->t); + if (mem->nil != XP_NULL) xp_lisp_mark_obj (mem->nil); + if (mem->quote != XP_NULL) xp_lisp_mark_obj (mem->quote); + if (mem->lambda != XP_NULL) xp_lisp_mark_obj (mem->lambda); + if (mem->macro != XP_NULL) xp_lisp_mark_obj (mem->macro); +} + +static void xp_lisp_sweep (xp_lisp_mem_t* mem) +{ + xp_lisp_obj_t* obj, * prev, * next; + xp_size_t i; + + // scan all the allocated objects and get rid of unused objects + for (i = 0; i < RBL_TYPE_COUNT; i++) { + //for (i = RBL_TYPE_COUNT; i > 0; /*i--*/) { + prev = XP_NULL; + obj = mem->used[i]; + //obj = mem->used[--i]; + + RB_DEBUG1 (RB_TEXT("sweeping objects of type: %u\n"), i); + + while (obj != XP_NULL) { + next = RBL_LINK(obj); + + if (RBL_LOCK(obj) == 0 && RBL_MARK(obj) == 0) { + // dispose of unused objects + xp_lisp_dispose (mem, prev, obj); + } + else { + // unmark the object in use + RBL_MARK(obj) = 0; + prev = obj; + } + + obj = next; + } + } +} + +void xp_lisp_garbage_collect (xp_lisp_mem_t* mem) +{ + xp_lisp_mark (mem); + xp_lisp_sweep (mem); +} + +xp_lisp_obj_t* xp_lisp_make_nil (xp_lisp_mem_t* mem) +{ + if (mem->nil != XP_NULL) return mem->nil; + mem->nil = xp_lisp_allocate (mem, RBL_OBJ_NIL, sizeof(xp_lisp_obj_nil_t)); + return mem->nil; +} + +xp_lisp_obj_t* xp_lisp_make_true (xp_lisp_mem_t* mem) +{ + if (mem->t != XP_NULL) return mem->t; + mem->t = xp_lisp_allocate (mem, RBL_OBJ_TRUE, sizeof(xp_lisp_obj_true_t)); + return mem->t; +} + +xp_lisp_obj_t* xp_lisp_make_int (xp_lisp_mem_t* mem, xp_lisp_int value) +{ + xp_lisp_obj_t* obj; + + obj = xp_lisp_allocate (mem, RBL_OBJ_INT, sizeof(xp_lisp_obj_int_t)); + if (obj == XP_NULL) return XP_NULL; + + RBL_IVALUE(obj) = value; + + return obj; +} + +xp_lisp_obj_t* xp_lisp_make_float (xp_lisp_mem_t* mem, xp_lisp_float value) +{ + xp_lisp_obj_t* obj; + + obj = xp_lisp_allocate (mem, RBL_OBJ_FLOAT, sizeof(xp_lisp_obj_float_t)); + if (obj == XP_NULL) return XP_NULL; + + RBL_FVALUE(obj) = value; + + return obj; +} + +xp_lisp_obj_t* xp_lisp_make_symbol (xp_lisp_mem_t* mem, const xp_lisp_char* str, xp_size_t len) +{ + xp_lisp_obj_t* obj; + + // look for a sysmbol with the given name + obj = mem->used[RBL_OBJ_SYMBOL]; + while (obj != XP_NULL) { + // if there is a symbol with the same name, it is just used. + if (xp_lisp_comp_symbol2 (obj, str, len) == 0) return obj; + obj = RBL_LINK(obj); + } + + // no such symbol found. create a new one + obj = xp_lisp_allocate (mem, RBL_OBJ_SYMBOL, + sizeof(xp_lisp_obj_symbol_t) + (len + 1) * sizeof(xp_lisp_char)); + if (obj == XP_NULL) return XP_NULL; + + // fill in the symbol buffer + xp_lisp_copy_string2 (RBL_SYMVALUE(obj), str, len); + + return obj; +} + +xp_lisp_obj_t* xp_lisp_make_string (xp_lisp_mem_t* mem, const xp_lisp_char* str, xp_size_t len) +{ + xp_lisp_obj_t* obj; + + // allocate memory for the string + obj = xp_lisp_allocate (mem, RBL_OBJ_STRING, + sizeof(xp_lisp_obj_string_t) + (len + 1) * sizeof(xp_lisp_char)); + if (obj == XP_NULL) return XP_NULL; + + // fill in the string buffer + xp_lisp_copy_string2 (RBL_STRVALUE(obj), str, len); + + return obj; +} + +xp_lisp_obj_t* xp_lisp_make_cons (xp_lisp_mem_t* mem, xp_lisp_obj_t* car, xp_lisp_obj_t* cdr) +{ + xp_lisp_obj_t* obj; + + obj = xp_lisp_allocate (mem, RBL_OBJ_CONS, sizeof(xp_lisp_obj_cons_t)); + if (obj == XP_NULL) return XP_NULL; + + RBL_CAR(obj) = car; + RBL_CDR(obj) = cdr; + + return obj; +} + +xp_lisp_obj_t* xp_lisp_make_func (xp_lisp_mem_t* mem, xp_lisp_obj_t* formal, xp_lisp_obj_t* body) +{ + xp_lisp_obj_t* obj; + + obj = xp_lisp_allocate (mem, RBL_OBJ_FUNC, sizeof(xp_lisp_obj_func_t)); + if (obj == XP_NULL) return XP_NULL; + + RBL_FFORMAL(obj) = formal; + RBL_FBODY(obj) = body; + + return obj; +} + +xp_lisp_obj_t* xp_lisp_make_macro (xp_lisp_mem_t* mem, xp_lisp_obj_t* formal, xp_lisp_obj_t* body) +{ + xp_lisp_obj_t* obj; + + obj = xp_lisp_allocate (mem, RBL_OBJ_MACRO, sizeof(xp_lisp_obj_macro_t)); + if (obj == XP_NULL) return XP_NULL; + + RBL_MFORMAL(obj) = formal; + RBL_MBODY(obj) = body; + + return obj; +} + +xp_lisp_obj_t* xp_lisp_make_prim (xp_lisp_mem_t* mem, void* impl) +{ + xp_lisp_obj_t* obj; + + obj = xp_lisp_allocate (mem, RBL_OBJ_PRIM, sizeof(xp_lisp_obj_prim_t)); + if (obj == XP_NULL) return XP_NULL; + + RBL_PIMPL(obj) = impl; + + return obj; +} + +xp_lisp_assoc_t* xp_lisp_lookup (xp_lisp_mem_t* mem, xp_lisp_obj_t* name) +{ + xp_lisp_frame_t* frame; + xp_lisp_assoc_t* assoc; + + xp_lisp_assert (RBL_TYPE(name) == RBL_OBJ_SYMBOL); + + frame = mem->frame; + + while (frame != XP_NULL) { + assoc = xp_lisp_frame_lookup (frame, name); + if (assoc != XP_NULL) return assoc; + frame = frame->link; + } + + return XP_NULL; +} + +xp_lisp_assoc_t* xp_lisp_set (xp_lisp_mem_t* mem, xp_lisp_obj_t* name, xp_lisp_obj_t* value) +{ + xp_lisp_assoc_t* assoc; + + assoc = xp_lisp_lookup (mem, name); + if (assoc == XP_NULL) { + assoc = xp_lisp_frame_insert (mem->root_frame, name, value); + if (assoc == XP_NULL) return XP_NULL; + } + else assoc->value = value; + + return assoc; +} + +xp_size_t xp_lisp_cons_len (xp_lisp_mem_t* mem, xp_lisp_obj_t* obj) +{ + xp_size_t count; + + xp_lisp_assert (obj == mem->nil || RBL_TYPE(obj) == RBL_OBJ_CONS); + + count = 0; + //while (obj != mem->nil) { + while (RBL_TYPE(obj) == RBL_OBJ_CONS) { + count++; + obj = RBL_CDR(obj); + } + + return count; +} + +int xp_lisp_probe_args (xp_lisp_mem_t* mem, xp_lisp_obj_t* obj, xp_size_t* len) +{ + xp_size_t count = 0; + + while (RBL_TYPE(obj) == RBL_OBJ_CONS) { + count++; + obj = RBL_CDR(obj); + } + + if (obj != mem->nil) return -1; + + *len = count; + return 0; +} + +int xp_lisp_comp_symbol (xp_lisp_obj_t* obj, const xp_lisp_char* str) +{ + xp_lisp_char* p; + xp_size_t index, length; + + xp_lisp_assert (RBL_TYPE(obj) == RBL_OBJ_SYMBOL); + + index = 0; + length = RBL_SYMLEN(obj); + + p = RBL_SYMVALUE(obj); + while (index < length) { + if (*p > *str) return 1; + if (*p < *str) return -1; + index++; p++; str++; + } + + return (*str == RBL_CHAR('\0'))? 0: -1; +} + +int xp_lisp_comp_symbol2 (xp_lisp_obj_t* obj, const xp_lisp_char* str, xp_size_t len) +{ + xp_lisp_char* p; + xp_size_t index, length; + + xp_lisp_assert (RBL_TYPE(obj) == RBL_OBJ_SYMBOL); + + index = 0; + length = RBL_SYMLEN(obj); + p = RBL_SYMVALUE(obj); + + while (index < length && index < len) { + if (*p > *str) return 1; + if (*p < *str) return -1; + index++; p++; str++; + } + + return (length < len)? -1: + (length > len)? 1: 0; +} + +int xp_lisp_comp_string (xp_lisp_obj_t* obj, const xp_lisp_char* str) +{ + xp_lisp_char* p; + xp_size_t index, length; + + xp_lisp_assert (RBL_TYPE(obj) == RBL_OBJ_STRING); + + index = 0; + length = RBL_STRLEN(obj); + + p = RBL_STRVALUE(obj); + while (index < length) { + if (*p > *str) return 1; + if (*p < *str) return -1; + index++; p++; str++; + } + + return (*str == RBL_CHAR('\0'))? 0: -1; +} + +int xp_lisp_comp_string2 (xp_lisp_obj_t* obj, const xp_lisp_char* str, xp_size_t len) +{ + xp_lisp_char* p; + xp_size_t index, length; + + xp_lisp_assert (RBL_TYPE(obj) == RBL_OBJ_STRING); + + index = 0; + length = RBL_STRLEN(obj); + p = RBL_STRVALUE(obj); + + while (index < length && index < len) { + if (*p > *str) return 1; + if (*p < *str) return -1; + index++; p++; str++; + } + + return (length < len)? -1: + (length > len)? 1: 0; +} + +void xp_lisp_copy_string (xp_lisp_char* dst, const xp_lisp_char* str) +{ + // the buffer pointed by dst should be big enough to hold str + while (*str != RBL_CHAR('\0')) *dst++ = *str++; + *dst = RBL_CHAR('\0'); +} + +void xp_lisp_copy_string2 (xp_lisp_char* dst, const xp_lisp_char* str, xp_size_t len) +{ + // the buffer pointed by dst should be big enough to hold str + while (len > 0) { + *dst++ = *str++; + len--; + } + *dst = RBL_CHAR('\0'); +} + diff --git a/ase/lsp/memory.h b/ase/lsp/memory.h new file mode 100644 index 00000000..7e288e4e --- /dev/null +++ b/ase/lsp/memory.h @@ -0,0 +1,100 @@ +/* + * $Id: memory.h,v 1.1 2005-02-04 15:39:11 bacon Exp $ + */ + +#ifndef _RBL_MEM_H_ +#define _RBL_MEM_H_ + +#include "obj.h" +#include "env.h" +#include "array.h" + +struct xp_lisp_mem_t +{ + /* + * object allocation list + */ + xp_size_t ubound; // upper bounds of the maximum number of objects + xp_size_t ubound_inc; // increment of the upper bounds + xp_size_t count; // the number of objects currently allocated + xp_lisp_obj_t* used[RBL_TYPE_COUNT]; + xp_lisp_obj_t* free[RBL_TYPE_COUNT]; + xp_lisp_obj_t* locked; + + /* + * commonly accessed objects + */ + xp_lisp_obj_t* nil; // xp_lisp_obj_nil_t + xp_lisp_obj_t* t; // xp_lisp_obj_true_t + xp_lisp_obj_t* quote; // xp_lisp_obj_symbol_t + xp_lisp_obj_t* lambda; // xp_lisp_obj_symbol_t + xp_lisp_obj_t* macro; // xp_lisp_obj_symbol_t + + /* + * run-time environment frame + */ + xp_lisp_frame_t* frame; + // pointer to a global-level frame + xp_lisp_frame_t* root_frame; + // pointer to an interim frame not yet added to "frame" + xp_lisp_frame_t* brooding_frame; + + /* + * temporary objects + */ + xp_lisp_array_t* temp_array; +}; + +typedef struct xp_lisp_mem_t xp_lisp_mem_t; + +#ifdef __cplusplus +extern "C" { +#endif + +xp_lisp_mem_t* xp_lisp_mem_new (xp_size_t ubound, xp_size_t ubound_inc); +void xp_lisp_mem_free (xp_lisp_mem_t* mem); + +int xp_lisp_add_prims (xp_lisp_mem_t* mem); + +xp_lisp_obj_t* xp_lisp_allocate (xp_lisp_mem_t* mem, int type, xp_size_t size); +void xp_lisp_dispose (xp_lisp_mem_t* mem, xp_lisp_obj_t* prev, xp_lisp_obj_t* obj); +void xp_lisp_dispose_all (xp_lisp_mem_t* mem); +void xp_lisp_garbage_collect (xp_lisp_mem_t* mem); + +void xp_lisp_lock (xp_lisp_obj_t* obj); +void xp_lisp_unlock (xp_lisp_obj_t* obj); +void xp_lisp_unlock_all (xp_lisp_obj_t* obj); + +// object creation of standard types +xp_lisp_obj_t* xp_lisp_make_nil (xp_lisp_mem_t* mem); +xp_lisp_obj_t* xp_lisp_make_true (xp_lisp_mem_t* mem); +xp_lisp_obj_t* xp_lisp_make_int (xp_lisp_mem_t* mem, xp_lisp_int value); +xp_lisp_obj_t* xp_lisp_make_float (xp_lisp_mem_t* mem, xp_lisp_float value); +xp_lisp_obj_t* xp_lisp_make_symbol (xp_lisp_mem_t* mem, const xp_lisp_char* str, xp_size_t len); +xp_lisp_obj_t* xp_lisp_make_string (xp_lisp_mem_t* mem, const xp_lisp_char* str, xp_size_t len); +xp_lisp_obj_t* xp_lisp_make_cons (xp_lisp_mem_t* mem, xp_lisp_obj_t* car, xp_lisp_obj_t* cdr); +xp_lisp_obj_t* xp_lisp_make_func (xp_lisp_mem_t* mem, xp_lisp_obj_t* formal, xp_lisp_obj_t* body); +xp_lisp_obj_t* xp_lisp_make_macro (xp_lisp_mem_t* mem, xp_lisp_obj_t* formal, xp_lisp_obj_t* body); +xp_lisp_obj_t* xp_lisp_make_prim (xp_lisp_mem_t* mem, void* impl); + +// frame lookup +xp_lisp_assoc_t* xp_lisp_lookup (xp_lisp_mem_t* mem, xp_lisp_obj_t* name); +xp_lisp_assoc_t* xp_lisp_set (xp_lisp_mem_t* mem, xp_lisp_obj_t* name, xp_lisp_obj_t* value); + +// cons operations +xp_size_t xp_lisp_cons_len (xp_lisp_mem_t* mem, xp_lisp_obj_t* obj); +int xp_lisp_probe_args (xp_lisp_mem_t* mem, xp_lisp_obj_t* obj, xp_size_t* len); + +// symbol and string operations +int xp_lisp_comp_symbol (xp_lisp_obj_t* obj, const xp_lisp_char* str); +int xp_lisp_comp_symbol2 (xp_lisp_obj_t* obj, const xp_lisp_char* str, xp_size_t len); +int xp_lisp_comp_string (xp_lisp_obj_t* obj, const xp_lisp_char* str); +int xp_lisp_comp_string2 (xp_lisp_obj_t* obj, const xp_lisp_char* str, xp_size_t len); +void xp_lisp_copy_string (xp_lisp_char* dst, const xp_lisp_char* str); +void xp_lisp_copy_string2 (xp_lisp_char* dst, const xp_lisp_char* str, xp_size_t len); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ase/lsp/object.h b/ase/lsp/object.h new file mode 100644 index 00000000..4c51d9e5 --- /dev/null +++ b/ase/lsp/object.h @@ -0,0 +1,151 @@ +/* + * $Id: object.h,v 1.1 2005-02-04 15:39:11 bacon Exp $ + */ + +#ifndef _RBL_OBJECT_H_ +#define _RBL_OBJECT_H_ + +#include "types.h" + +// object types +enum +{ + RBL_OBJ_NIL = 0, + RBL_OBJ_TRUE, + RBL_OBJ_INT, + RBL_OBJ_FLOAT, + RBL_OBJ_SYMBOL, + RBL_OBJ_STRING, + RBL_OBJ_CONS, + RBL_OBJ_FUNC, + RBL_OBJ_MACRO, + RBL_OBJ_PRIM, + + RBL_TYPE_COUNT // the number of lisp object types +}; + +#define RBL_OBJ_HEADER \ + rb_uint32 type: 24; \ + rb_uint32 mark: 4; \ + rb_uint32 lock: 4; \ + xp_size_t size; \ + struct xp_lisp_obj_t* link + +struct xp_lisp_obj_t +{ + RBL_OBJ_HEADER; +}; + +struct xp_lisp_obj_nil_t +{ + RBL_OBJ_HEADER; +}; + +struct xp_lisp_obj_true_t +{ + RBL_OBJ_HEADER; +}; + +struct xp_lisp_obj_int_t +{ + RBL_OBJ_HEADER; + xp_lisp_int value; +}; + +struct xp_lisp_obj_float_t +{ + RBL_OBJ_HEADER; + xp_lisp_float value; +}; + +struct xp_lisp_obj_symbol_t +{ + RBL_OBJ_HEADER; +#ifdef __BORLANDC__ +#else + xp_lisp_char buffer[0]; +#endif +}; + +struct xp_lisp_obj_string_t +{ + RBL_OBJ_HEADER; +#ifdef __BORLANDC__ +#else + xp_lisp_char buffer[0]; +#endif +}; + +struct xp_lisp_obj_cons_t +{ + RBL_OBJ_HEADER; + struct xp_lisp_obj_t* car; + struct xp_lisp_obj_t* cdr; +}; + +struct xp_lisp_obj_func_t +{ + RBL_OBJ_HEADER; + struct xp_lisp_obj_t* formal; + struct xp_lisp_obj_t* body; +}; + +struct xp_lisp_obj_macro_t +{ + RBL_OBJ_HEADER; + struct xp_lisp_obj_t* formal; + struct xp_lisp_obj_t* body; +}; + +struct xp_lisp_obj_prim_t +{ + RBL_OBJ_HEADER; + void* impl; // xp_lisp_prim_t +}; + +typedef struct xp_lisp_obj_t xp_lisp_obj_t; +typedef struct xp_lisp_obj_nil_t xp_lisp_obj_nil_t; +typedef struct xp_lisp_obj_true_t xp_lisp_obj_true_t; +typedef struct xp_lisp_obj_int_t xp_lisp_obj_int_t; +typedef struct xp_lisp_obj_float_t xp_lisp_obj_float_t; +typedef struct xp_lisp_obj_symbol_t xp_lisp_obj_symbol_t; +typedef struct xp_lisp_obj_string_t xp_lisp_obj_string_t; +typedef struct xp_lisp_obj_cons_t xp_lisp_obj_cons_t; +typedef struct xp_lisp_obj_func_t xp_lisp_obj_func_t; +typedef struct xp_lisp_obj_macro_t xp_lisp_obj_macro_t; +typedef struct xp_lisp_obj_prim_t xp_lisp_obj_prim_t; + +// header access +#define RBL_TYPE(x) (((xp_lisp_obj_t*)x)->type) +#define RBL_SIZE(x) (((xp_lisp_obj_t*)x)->size) +#define RBL_MARK(x) (((xp_lisp_obj_t*)x)->mark) +#define RBL_LOCK(x) (((xp_lisp_obj_t*)x)->lock) +#define RBL_LINK(x) (((xp_lisp_obj_t*)x)->link) + +// value access +#define RBL_IVALUE(x) (((xp_lisp_obj_int_t*)x)->value) +#define RBL_FVALUE(x) (((xp_lisp_obj_float_t*)x)->value) + +#ifdef __BORLANDC__ +#define RBL_SYMVALUE(x) ((xp_lisp_char*)(((xp_lisp_obj_symbol_t*)x) + 1)) +#else +#define RBL_SYMVALUE(x) (((xp_lisp_obj_symbol_t*)x)->buffer) +#endif +#define RBL_SYMLEN(x) ((((xp_lisp_obj_symbol_t*)x)->size - sizeof(xp_lisp_obj_t)) / sizeof(xp_lisp_char) - 1) + +#ifdef __BORLANDC__ +#define RBL_STRVALUE(x) ((xp_lisp_char*)(((xp_lisp_obj_string_t*)x) + 1)) +#else +#define RBL_STRVALUE(x) (((xp_lisp_obj_string_t*)x)->buffer) +#endif +#define RBL_STRLEN(x) ((((xp_lisp_obj_string_t*)x)->size - sizeof(xp_lisp_obj_t)) / sizeof(xp_lisp_char) - 1) + +#define RBL_CAR(x) (((xp_lisp_obj_cons_t*)x)->car) +#define RBL_CDR(x) (((xp_lisp_obj_cons_t*)x)->cdr) +#define RBL_FFORMAL(x) (((xp_lisp_obj_func_t*)x)->formal) +#define RBL_FBODY(x) (((xp_lisp_obj_func_t*)x)->body) +#define RBL_MFORMAL(x) (((xp_lisp_obj_macro_t*)x)->formal) +#define RBL_MBODY(x) (((xp_lisp_obj_macro_t*)x)->body) +#define RBL_PIMPL(x) ((xp_lisp_pimpl_t)(((xp_lisp_obj_prim_t*)x)->impl)) + +#endif diff --git a/ase/lsp/primitive.c b/ase/lsp/primitive.c new file mode 100644 index 00000000..e2df5e3d --- /dev/null +++ b/ase/lsp/primitive.c @@ -0,0 +1,686 @@ +/* + * $Id: primitive.c,v 1.1 2005-02-04 15:39:11 bacon Exp $ + */ + +#include "lisp.h" +#include "memory.h" +#include "primitive.h" + +xp_lisp_obj_t* xp_lisp_prim_abort (xp_lisp_t* lsp, xp_lisp_obj_t* args) +{ + RBL_PRIM_CHECK_ARG_COUNT (lsp, args, 0, 0); + lsp->error = RBL_ERR_ABORT; + return XP_NULL; +} + +xp_lisp_obj_t* xp_lisp_prim_eval (xp_lisp_t* lsp, xp_lisp_obj_t* args) +{ + xp_lisp_obj_t* tmp; + + RBL_PRIM_CHECK_ARG_COUNT (lsp, args, 1, 1); + xp_lisp_assert (RBL_TYPE(args) == RBL_OBJ_CONS); + + tmp = xp_lisp_eval (lsp, RBL_CAR(args)); + if (tmp == XP_NULL) return XP_NULL; + + tmp = xp_lisp_eval (lsp, tmp); + if (tmp == XP_NULL) return XP_NULL; + + return tmp; +} + +xp_lisp_obj_t* xp_lisp_prim_prog1 (xp_lisp_t* lsp, xp_lisp_obj_t* args) +{ + xp_lisp_obj_t* res = XP_NULL, * tmp; + + RBL_PRIM_CHECK_ARG_COUNT (lsp, args, 1, RBL_PRIM_MAX_ARG_COUNT); + + //while (args != lsp->mem->nil) { + while (RBL_TYPE(args) == RBL_OBJ_CONS) { + + tmp = xp_lisp_eval (lsp, RBL_CAR(args)); + if (tmp == XP_NULL) return XP_NULL; + + if (res == XP_NULL) { + /* + xp_lisp_array_t* ta = lsp->mem->temp_array; + xp_lisp_array_insert (ta, ta->size, tmp); + */ + res = tmp; + } + args = RBL_CDR(args); + } + + return res; +} + +xp_lisp_obj_t* xp_lisp_prim_progn (xp_lisp_t* lsp, xp_lisp_obj_t* args) +{ + xp_lisp_obj_t* res, * tmp; + + RBL_PRIM_CHECK_ARG_COUNT (lsp, args, 1, RBL_PRIM_MAX_ARG_COUNT); + + res = lsp->mem->nil; + //while (args != lsp->mem->nil) { + while (RBL_TYPE(args) == RBL_OBJ_CONS) { + + tmp = xp_lisp_eval (lsp, RBL_CAR(args)); + if (tmp == XP_NULL) return XP_NULL; + + res = tmp; + args = RBL_CDR(args); + } + + return res; +} + +xp_lisp_obj_t* xp_lisp_prim_gc (xp_lisp_t* lsp, xp_lisp_obj_t* args) +{ + RBL_PRIM_CHECK_ARG_COUNT (lsp, args, 0, 0); + xp_lisp_garbage_collect (lsp->mem); + return lsp->mem->nil; +} + +xp_lisp_obj_t* xp_lisp_prim_cond (xp_lisp_t* lsp, xp_lisp_obj_t* args) +{ + /* + * (cond + * (condition1 result1) + * (consition2 result2) + * ... + * (t resultN)) + */ + + xp_lisp_obj_t* tmp, * ret; + + RBL_PRIM_CHECK_ARG_COUNT (lsp, args, 0, RBL_PRIM_MAX_ARG_COUNT); + + while (RBL_TYPE(args) == RBL_OBJ_CONS) { + if (RBL_TYPE(RBL_CAR(args)) != RBL_OBJ_CONS) { + lsp->error = RBL_ERR_BAD_ARG; + return XP_NULL; + } + + tmp = xp_lisp_eval (lsp, RBL_CAR(RBL_CAR(args))); + if (tmp == XP_NULL) return XP_NULL; + + if (tmp != lsp->mem->nil) { + tmp = RBL_CDR(RBL_CAR(args)); + ret = lsp->mem->nil; + while (RBL_TYPE(tmp) == RBL_OBJ_CONS) { + ret = xp_lisp_eval (lsp, RBL_CAR(tmp)); + if (ret == XP_NULL) return XP_NULL; + tmp = RBL_CDR(tmp); + } + if (tmp != lsp->mem->nil) { + lsp->error = RBL_ERR_BAD_ARG; + return XP_NULL; + } + return ret; + } + + args = RBL_CDR(args); + } + + return lsp->mem->nil; +} + +xp_lisp_obj_t* xp_lisp_prim_if (xp_lisp_t* lsp, xp_lisp_obj_t* args) +{ + xp_lisp_obj_t* tmp; + + RBL_PRIM_CHECK_ARG_COUNT (lsp, args, 2, RBL_PRIM_MAX_ARG_COUNT); + xp_lisp_assert (RBL_TYPE(args) == RBL_OBJ_CONS); + + tmp = xp_lisp_eval (lsp, RBL_CAR(args)); + if (tmp == XP_NULL) return XP_NULL; + + if (tmp != lsp->mem->nil) { + tmp = xp_lisp_eval (lsp, RBL_CAR(RBL_CDR(args))); + if (tmp == XP_NULL) return XP_NULL; + return tmp; + } + else { + xp_lisp_obj_t* res = lsp->mem->nil; + + tmp = RBL_CDR(RBL_CDR(args)); + + while (RBL_TYPE(tmp) == RBL_OBJ_CONS) { + res = xp_lisp_eval (lsp, RBL_CAR(tmp)); + if (res == XP_NULL) return XP_NULL; + tmp = RBL_CDR(tmp); + } + if (tmp != lsp->mem->nil) { + lsp->error = RBL_ERR_BAD_ARG; + return XP_NULL; + } + + return res; + } +} + +xp_lisp_obj_t* xp_lisp_prim_while (xp_lisp_t* lsp, xp_lisp_obj_t* args) +{ + /* + * (setq a 1) + * (while (< a 100) (setq a (+ a 1))) + */ + + xp_lisp_obj_t* tmp; + + RBL_PRIM_CHECK_ARG_COUNT (lsp, args, 1, RBL_PRIM_MAX_ARG_COUNT); + xp_lisp_assert (RBL_TYPE(args) == RBL_OBJ_CONS); + + for (;;) { + tmp = xp_lisp_eval (lsp, RBL_CAR(args)); + if (tmp == XP_NULL) return XP_NULL; + if (tmp == lsp->mem->nil) break; + + tmp = RBL_CDR(args); + while (RBL_TYPE(tmp) == RBL_OBJ_CONS) { + if (xp_lisp_eval (lsp, RBL_CAR(tmp)) == XP_NULL) return XP_NULL; + tmp = RBL_CDR(tmp); + } + if (tmp != lsp->mem->nil) { + lsp->error = RBL_ERR_BAD_ARG; + return XP_NULL; + } + } + + return lsp->mem->nil; +} + +xp_lisp_obj_t* xp_lisp_prim_car (xp_lisp_t* lsp, xp_lisp_obj_t* args) +{ + xp_lisp_obj_t* tmp; + + RBL_PRIM_CHECK_ARG_COUNT (lsp, args, 1, 1); + xp_lisp_assert (RBL_TYPE(args) == RBL_OBJ_CONS); + + tmp = xp_lisp_eval (lsp, RBL_CAR(args)); + if (tmp == XP_NULL) return XP_NULL; + if (tmp == lsp->mem->nil) return lsp->mem->nil; + + if (RBL_TYPE(tmp) != RBL_OBJ_CONS) { + lsp->error = RBL_ERR_BAD_ARG; + return XP_NULL; + } + + return RBL_CAR(tmp); +} + +xp_lisp_obj_t* xp_lisp_prim_cdr (xp_lisp_t* lsp, xp_lisp_obj_t* args) +{ + xp_lisp_obj_t* tmp; + + RBL_PRIM_CHECK_ARG_COUNT (lsp, args, 1, 1); + xp_lisp_assert (RBL_TYPE(args) == RBL_OBJ_CONS); + + tmp = xp_lisp_eval (lsp, RBL_CAR(args)); + if (tmp == XP_NULL) return XP_NULL; + if (tmp == lsp->mem->nil) return lsp->mem->nil; + + if (RBL_TYPE(tmp) != RBL_OBJ_CONS) { + lsp->error = RBL_ERR_BAD_ARG; + return XP_NULL; + } + + return RBL_CDR(tmp); +} + +xp_lisp_obj_t* xp_lisp_prim_cons (xp_lisp_t* lsp, xp_lisp_obj_t* args) +{ + xp_lisp_obj_t* car, * cdr, * cons; + + RBL_PRIM_CHECK_ARG_COUNT (lsp, args, 2, 2); + xp_lisp_assert (RBL_TYPE(args) == RBL_OBJ_CONS); + + car = xp_lisp_eval (lsp, RBL_CAR(args)); + if (car == XP_NULL) return XP_NULL; + + cdr = xp_lisp_eval (lsp, RBL_CAR(RBL_CDR(args))); + if (cdr == XP_NULL) return XP_NULL; + + cons = xp_lisp_make_cons (lsp->mem, car, cdr); + if (cons == XP_NULL) { + lsp->error = RBL_ERR_MEM; + return XP_NULL; + } + + return cons; +} + +xp_lisp_obj_t* xp_lisp_prim_set (xp_lisp_t* lsp, xp_lisp_obj_t* args) +{ + xp_lisp_obj_t* p1, * p2; + + RBL_PRIM_CHECK_ARG_COUNT (lsp, args, 2, 2); + xp_lisp_assert (RBL_TYPE(args) == RBL_OBJ_CONS); + + p1 = xp_lisp_eval (lsp, RBL_CAR(args)); + if (p1 == XP_NULL) return XP_NULL; + + if (RBL_TYPE(p1) != RBL_OBJ_SYMBOL) { + lsp->error = RBL_ERR_BAD_ARG; + return XP_NULL; + } + + p2 = xp_lisp_eval (lsp, RBL_CAR(RBL_CDR(args))); + if (p2 == XP_NULL) return XP_NULL; + + if (xp_lisp_set (lsp->mem, p1, p2) == XP_NULL) { + lsp->error = RBL_ERR_MEM; + return XP_NULL; + } + + return p2; +} + +xp_lisp_obj_t* xp_lisp_prim_setq (xp_lisp_t* lsp, xp_lisp_obj_t* args) +{ + xp_lisp_obj_t* p = args, * p1, * p2 = lsp->mem->nil; + + while (p != lsp->mem->nil) { + xp_lisp_assert (RBL_TYPE(p) == RBL_OBJ_CONS); + + p1 = RBL_CAR(p); + if (RBL_TYPE(p1) != RBL_OBJ_SYMBOL) { + lsp->error = RBL_ERR_BAD_ARG; + return XP_NULL; + } + + if (RBL_TYPE(RBL_CDR(p)) != RBL_OBJ_CONS) { + lsp->error = RBL_ERR_TOO_FEW_ARGS; + return XP_NULL; + } + + p2 = xp_lisp_eval (lsp, RBL_CAR(RBL_CDR(p))); + if (p2 == XP_NULL) return XP_NULL; + + if (xp_lisp_set (lsp->mem, p1, p2) == XP_NULL) { + lsp->error = RBL_ERR_MEM; + return XP_NULL; + } + + p = RBL_CDR(RBL_CDR(p)); + } + + return p2; +} + +xp_lisp_obj_t* xp_lisp_prim_quote (xp_lisp_t* lsp, xp_lisp_obj_t* args) +{ + RBL_PRIM_CHECK_ARG_COUNT (lsp, args, 1, 1); + xp_lisp_assert (RBL_TYPE(args) == RBL_OBJ_CONS); + return RBL_CAR(args); +} + +xp_lisp_obj_t* xp_lisp_prim_defun (xp_lisp_t* lsp, xp_lisp_obj_t* args) +{ + /* + * (defun x (abc) x y z) + * (setq x (lambda (abc) x y z)) + */ + + xp_lisp_obj_t* name, * fun; + + RBL_PRIM_CHECK_ARG_COUNT (lsp, args, 3, RBL_PRIM_MAX_ARG_COUNT); + + name = RBL_CAR(args); + if (RBL_TYPE(name) != RBL_OBJ_SYMBOL) { + lsp->error = RBL_ERR_BAD_ARG; + return XP_NULL; + } + + fun = xp_lisp_make_func (lsp->mem, + RBL_CAR(RBL_CDR(args)), RBL_CDR(RBL_CDR(args))); + if (fun == XP_NULL) return XP_NULL; + + if (xp_lisp_set (lsp->mem, RBL_CAR(args), fun) == XP_NULL) { + lsp->error = RBL_ERR_MEM; + return XP_NULL; + } + return fun; +} + +xp_lisp_obj_t* xp_lisp_prim_demac (xp_lisp_t* lsp, xp_lisp_obj_t* args) +{ + /* + * (demac x (abc) x y z) + *(setq x (macro (abc) x y z)) + */ + + xp_lisp_obj_t* name, * mac; + + RBL_PRIM_CHECK_ARG_COUNT (lsp, args, 3, RBL_PRIM_MAX_ARG_COUNT); + + name = RBL_CAR(args); + if (RBL_TYPE(name) != RBL_OBJ_SYMBOL) { + lsp->error = RBL_ERR_BAD_ARG; + return XP_NULL; + } + + mac = xp_lisp_make_macro (lsp->mem, + RBL_CAR(RBL_CDR(args)), RBL_CDR(RBL_CDR(args))); + if (mac == XP_NULL) return XP_NULL; + + if (xp_lisp_set (lsp->mem, RBL_CAR(args), mac) == XP_NULL) { + lsp->error = RBL_ERR_MEM; + return XP_NULL; + } + return mac; +} + +static xp_lisp_obj_t* xp_lisp_prim_let_impl ( + xp_lisp_t* lsp, xp_lisp_obj_t* args, int sequential) +{ + xp_lisp_frame_t* frame; + xp_lisp_obj_t* assoc; + xp_lisp_obj_t* body; + xp_lisp_obj_t* value; + + RBL_PRIM_CHECK_ARG_COUNT (lsp, args, 1, RBL_PRIM_MAX_ARG_COUNT); + + // create a new frame + frame = xp_lisp_frame_new (); + if (frame == XP_NULL) { + lsp->error = RBL_ERR_MEM; + return XP_NULL; + } + //frame->link = lsp->mem->frame; + + if (sequential) { + frame->link = lsp->mem->frame; + lsp->mem->frame = frame; + } + else { + frame->link = lsp->mem->brooding_frame; + lsp->mem->brooding_frame = frame; + } + + assoc = RBL_CAR(args); + + //while (assoc != lsp->mem->nil) { + while (RBL_TYPE(assoc) == RBL_OBJ_CONS) { + xp_lisp_obj_t* ass = RBL_CAR(assoc); + if (RBL_TYPE(ass) == RBL_OBJ_CONS) { + xp_lisp_obj_t* n = RBL_CAR(ass); + xp_lisp_obj_t* v = RBL_CDR(ass); + + if (RBL_TYPE(n) != RBL_OBJ_SYMBOL) { + lsp->error = RBL_ERR_BAD_ARG; // must be a symbol + if (sequential) lsp->mem->frame = frame->link; + else lsp->mem->brooding_frame = frame->link; + xp_lisp_frame_free (frame); + return XP_NULL; + } + + if (v != lsp->mem->nil) { + if (RBL_CDR(v) != lsp->mem->nil) { + lsp->error = RBL_ERR_TOO_MANY_ARGS; // must be a symbol + if (sequential) lsp->mem->frame = frame->link; + else lsp->mem->brooding_frame = frame->link; + xp_lisp_frame_free (frame); + return XP_NULL; + } + if ((v = xp_lisp_eval(lsp, RBL_CAR(v))) == XP_NULL) { + if (sequential) lsp->mem->frame = frame->link; + else lsp->mem->brooding_frame = frame->link; + xp_lisp_frame_free (frame); + return XP_NULL; + } + } + + if (xp_lisp_frame_lookup (frame, n) != XP_NULL) { + lsp->error = RBL_ERR_DUP_FORMAL; + if (sequential) lsp->mem->frame = frame->link; + else lsp->mem->brooding_frame = frame->link; + xp_lisp_frame_free (frame); + return XP_NULL; + } + if (xp_lisp_frame_insert (frame, n, v) == XP_NULL) { + lsp->error = RBL_ERR_MEM; + if (sequential) lsp->mem->frame = frame->link; + else lsp->mem->brooding_frame = frame->link; + xp_lisp_frame_free (frame); + return XP_NULL; + } + } + else if (RBL_TYPE(ass) == RBL_OBJ_SYMBOL) { + if (xp_lisp_frame_lookup (frame, ass) != XP_NULL) { + lsp->error = RBL_ERR_DUP_FORMAL; + if (sequential) lsp->mem->frame = frame->link; + else lsp->mem->brooding_frame = frame->link; + xp_lisp_frame_free (frame); + return XP_NULL; + } + if (xp_lisp_frame_insert (frame, ass, lsp->mem->nil) == XP_NULL) { + lsp->error = RBL_ERR_MEM; + if (sequential) lsp->mem->frame = frame->link; + else lsp->mem->brooding_frame = frame->link; + xp_lisp_frame_free (frame); + return XP_NULL; + } + } + else { + lsp->error = RBL_ERR_BAD_ARG; + if (sequential) lsp->mem->frame = frame->link; + else lsp->mem->brooding_frame = frame->link; + xp_lisp_frame_free (frame); + return XP_NULL; + } + + assoc = RBL_CDR(assoc); + } + + if (assoc != lsp->mem->nil) { + lsp->error = RBL_ERR_BAD_ARG; + if (sequential) lsp->mem->frame = frame->link; + else lsp->mem->brooding_frame = frame->link; + xp_lisp_frame_free (frame); + return XP_NULL; + } + + // push the frame + if (!sequential) { + lsp->mem->brooding_frame = frame->link; + frame->link = lsp->mem->frame; + lsp->mem->frame = frame; + } + + // evaluate forms in the body + value = lsp->mem->nil; + body = RBL_CDR(args); + while (body != lsp->mem->nil) { + value = xp_lisp_eval (lsp, RBL_CAR(body)); + if (value == XP_NULL) { + lsp->mem->frame = frame->link; + xp_lisp_frame_free (frame); + return XP_NULL; + } + body = RBL_CDR(body); + } + + // pop the frame + lsp->mem->frame = frame->link; + + // destroy the frame + xp_lisp_frame_free (frame); + return value; +} + +xp_lisp_obj_t* xp_lisp_prim_let (xp_lisp_t* lsp, xp_lisp_obj_t* args) +{ + return xp_lisp_prim_let_impl (lsp, args, 0); +} + +xp_lisp_obj_t* xp_lisp_prim_letx (xp_lisp_t* lsp, xp_lisp_obj_t* args) +{ + return xp_lisp_prim_let_impl (lsp, args, 1); +} + +xp_lisp_obj_t* xp_lisp_prim_plus (xp_lisp_t* lsp, xp_lisp_obj_t* args) +{ + xp_lisp_obj_t* body, * tmp; + xp_lisp_int value = 0; + + RBL_PRIM_CHECK_ARG_COUNT (lsp, args, 1, RBL_PRIM_MAX_ARG_COUNT); + xp_lisp_assert (RBL_TYPE(args) == RBL_OBJ_CONS); + + body = args; + //while (body != lsp->mem->nil) { + while (RBL_TYPE(body) == RBL_OBJ_CONS) { + tmp = xp_lisp_eval (lsp, RBL_CAR(body)); + if (tmp == XP_NULL) return XP_NULL; + + if (RBL_TYPE(tmp) != RBL_OBJ_INT) { + lsp->error = RBL_ERR_BAD_VALUE; + return XP_NULL; + } + + value = value + RBL_IVALUE(tmp); + body = RBL_CDR(body); + } + + tmp = xp_lisp_make_int (lsp->mem, value); + if (tmp == XP_NULL) { + lsp->error = RBL_ERR_MEM; + return XP_NULL; + } + + return tmp; +} + +xp_lisp_obj_t* xp_lisp_prim_gt (xp_lisp_t* lsp, xp_lisp_obj_t* args) +{ + xp_lisp_obj_t* p1, * p2; + int res; + + RBL_PRIM_CHECK_ARG_COUNT (lsp, args, 2, 2); + xp_lisp_assert (RBL_TYPE(args) == RBL_OBJ_CONS); + + p1 = xp_lisp_eval (lsp, RBL_CAR(args)); + if (p1 == XP_NULL) return XP_NULL; + // TODO: lock p1.... + + p2 = xp_lisp_eval (lsp, RBL_CAR(RBL_CDR(args))); + if (p2 == XP_NULL) return XP_NULL; + + if (RBL_TYPE(p1) == RBL_OBJ_INT) { + if (RBL_TYPE(p2) == RBL_OBJ_INT) { + res = RBL_IVALUE(p1) > RBL_IVALUE(p2); + } + else if (RBL_TYPE(p2) == RBL_OBJ_FLOAT) { + res = RBL_IVALUE(p1) > RBL_FVALUE(p2); + } + else { + lsp->error = RBL_ERR_BAD_VALUE; + return XP_NULL; + } + } + else if (RBL_TYPE(p1) == RBL_OBJ_FLOAT) { + if (RBL_TYPE(p2) == RBL_OBJ_INT) { + res = RBL_FVALUE(p1) > RBL_IVALUE(p2); + } + else if (RBL_TYPE(p2) == RBL_OBJ_FLOAT) { + res = RBL_FVALUE(p1) > RBL_FVALUE(p2); + } + else { + lsp->error = RBL_ERR_BAD_VALUE; + return XP_NULL; + } + } + else if (RBL_TYPE(p1) == RBL_OBJ_SYMBOL) { + if (RBL_TYPE(p2) == RBL_OBJ_SYMBOL) { + res = xp_lisp_comp_symbol2 ( + p1, RBL_SYMVALUE(p2), RBL_SYMLEN(p2)) > 0; + } + else { + lsp->error = RBL_ERR_BAD_VALUE; + return XP_NULL; + } + } + else if (RBL_TYPE(p1) == RBL_OBJ_STRING) { + if (RBL_TYPE(p2) == RBL_OBJ_STRING) { + res = xp_lisp_comp_string2 ( + p1, RBL_STRVALUE(p2), RBL_STRLEN(p2)) > 0; + } + else { + lsp->error = RBL_ERR_BAD_VALUE; + return XP_NULL; + } + } + else { + lsp->error = RBL_ERR_BAD_VALUE; + return XP_NULL; + } + + return (res)? lsp->mem->t: lsp->mem->nil; +} + +xp_lisp_obj_t* xp_lisp_prim_lt (xp_lisp_t* lsp, xp_lisp_obj_t* args) +{ + xp_lisp_obj_t* p1, * p2; + int res; + + RBL_PRIM_CHECK_ARG_COUNT (lsp, args, 2, 2); + xp_lisp_assert (RBL_TYPE(args) == RBL_OBJ_CONS); + + p1 = xp_lisp_eval (lsp, RBL_CAR(args)); + if (p1 == XP_NULL) return XP_NULL; + // TODO: lock p1.... + + p2 = xp_lisp_eval (lsp, RBL_CAR(RBL_CDR(args))); + if (p2 == XP_NULL) return XP_NULL; + + if (RBL_TYPE(p1) == RBL_OBJ_INT) { + if (RBL_TYPE(p2) == RBL_OBJ_INT) { + res = RBL_IVALUE(p1) < RBL_IVALUE(p2); + } + else if (RBL_TYPE(p2) == RBL_OBJ_FLOAT) { + res = RBL_IVALUE(p1) < RBL_FVALUE(p2); + } + else { + lsp->error = RBL_ERR_BAD_VALUE; + return XP_NULL; + } + } + else if (RBL_TYPE(p1) == RBL_OBJ_FLOAT) { + if (RBL_TYPE(p2) == RBL_OBJ_INT) { + res = RBL_FVALUE(p1) < RBL_IVALUE(p2); + } + else if (RBL_TYPE(p2) == RBL_OBJ_FLOAT) { + res = RBL_FVALUE(p1) < RBL_FVALUE(p2); + } + else { + lsp->error = RBL_ERR_BAD_VALUE; + return XP_NULL; + } + } + else if (RBL_TYPE(p1) == RBL_OBJ_SYMBOL) { + if (RBL_TYPE(p2) == RBL_OBJ_SYMBOL) { + res = xp_lisp_comp_symbol2 ( + p1, RBL_SYMVALUE(p2), RBL_SYMLEN(p2)) < 0; + } + else { + lsp->error = RBL_ERR_BAD_VALUE; + return XP_NULL; + } + } + else if (RBL_TYPE(p1) == RBL_OBJ_STRING) { + if (RBL_TYPE(p2) == RBL_OBJ_STRING) { + res = xp_lisp_comp_string2 ( + p1, RBL_STRVALUE(p2), RBL_STRLEN(p2)) < 0; + } + else { + lsp->error = RBL_ERR_BAD_VALUE; + return XP_NULL; + } + } + else { + lsp->error = RBL_ERR_BAD_VALUE; + return XP_NULL; + } + + return (res)? lsp->mem->t: lsp->mem->nil; +} diff --git a/ase/lsp/primitive.h b/ase/lsp/primitive.h new file mode 100644 index 00000000..8a5b1e6e --- /dev/null +++ b/ase/lsp/primitive.h @@ -0,0 +1,64 @@ +/* + * $Id: primitive.h,v 1.1 2005-02-04 15:39:11 bacon Exp $ + */ + +#ifndef _RBL_PRIM_H_ +#define _RBL_PRIM_H_ + +#include "types.h" +#include "lsp.h" + +typedef xp_lisp_obj_t* (*xp_lisp_pimpl_t) (xp_lisp_t*, xp_lisp_obj_t*); + +#ifdef __cplusplus +extern "C" { +#endif + +xp_lisp_obj_t* xp_lisp_prim_abort (xp_lisp_t*, xp_lisp_obj_t* args); +xp_lisp_obj_t* xp_lisp_prim_eval (xp_lisp_t*, xp_lisp_obj_t* args); +xp_lisp_obj_t* xp_lisp_prim_prog1 (xp_lisp_t*, xp_lisp_obj_t* args); +xp_lisp_obj_t* xp_lisp_prim_progn (xp_lisp_t*, xp_lisp_obj_t* args); +xp_lisp_obj_t* xp_lisp_prim_gc (xp_lisp_t*, xp_lisp_obj_t* args); +xp_lisp_obj_t* xp_lisp_prim_cond (xp_lisp_t*, xp_lisp_obj_t* args); +xp_lisp_obj_t* xp_lisp_prim_if (xp_lisp_t*, xp_lisp_obj_t* args); +xp_lisp_obj_t* xp_lisp_prim_while (xp_lisp_t*, xp_lisp_obj_t* args); + +xp_lisp_obj_t* xp_lisp_prim_car (xp_lisp_t*, xp_lisp_obj_t* args); +xp_lisp_obj_t* xp_lisp_prim_cdr (xp_lisp_t*, xp_lisp_obj_t* args); +xp_lisp_obj_t* xp_lisp_prim_cons (xp_lisp_t*, xp_lisp_obj_t* args); +xp_lisp_obj_t* xp_lisp_prim_set (xp_lisp_t*, xp_lisp_obj_t* args); +xp_lisp_obj_t* xp_lisp_prim_setq (xp_lisp_t*, xp_lisp_obj_t* args); +xp_lisp_obj_t* xp_lisp_prim_quote (xp_lisp_t*, xp_lisp_obj_t* args); +xp_lisp_obj_t* xp_lisp_prim_defun (xp_lisp_t*, xp_lisp_obj_t* args); +xp_lisp_obj_t* xp_lisp_prim_demac (xp_lisp_t*, xp_lisp_obj_t* args); +xp_lisp_obj_t* xp_lisp_prim_let (xp_lisp_t*, xp_lisp_obj_t* args); +xp_lisp_obj_t* xp_lisp_prim_letx (xp_lisp_t*, xp_lisp_obj_t* args); + +xp_lisp_obj_t* xp_lisp_prim_plus (xp_lisp_t*, xp_lisp_obj_t* args); +xp_lisp_obj_t* xp_lisp_prim_gt (xp_lisp_t*, xp_lisp_obj_t* args); +xp_lisp_obj_t* xp_lisp_prim_lt (xp_lisp_t*, xp_lisp_obj_t* args); + +#ifdef __cplusplus +} +#endif + +#define RBL_PRIM_CHECK_ARG_COUNT(lsp,args,min,max) \ +{ \ + xp_size_t count; \ + if (xp_lisp_probe_args(lsp->mem, args, &count) == -1) { \ + lsp->error = RBL_ERR_BAD_ARG; \ + return XP_NULL; \ + } \ + if (count < min) { \ + lsp->error = RBL_ERR_TOO_FEW_ARGS; \ + return XP_NULL; \ + } \ + if (count > max) { \ + lsp->error = RBL_ERR_TOO_MANY_ARGS; \ + return XP_NULL; \ + } \ +} + +#define RBL_PRIM_MAX_ARG_COUNT ((xp_size_t)~(xp_size_t)0) + +#endif diff --git a/ase/lsp/print.c b/ase/lsp/print.c new file mode 100644 index 00000000..44e977a6 --- /dev/null +++ b/ase/lsp/print.c @@ -0,0 +1,113 @@ +/* + * $Id: print.c,v 1.1 2005-02-04 15:39:11 bacon Exp $ + */ + +#include "lsp.h" + +void xp_lisp_print_debug (xp_lisp_obj_t* obj) +{ + switch (RBL_TYPE(obj)) { + case RBL_OBJ_NIL: + rb_printf ( RBL_TEXT("nil")); + break; + case RBL_OBJ_TRUE: + rb_printf ( RBL_TEXT("t")); + break; + case RBL_OBJ_INT: + rb_printf ( RBL_TEXT("%d"), RBL_IVALUE(obj)); + break; + case RBL_OBJ_FLOAT: + rb_printf ( RBL_TEXT("%f"), RBL_FVALUE(obj)); + break; + case RBL_OBJ_SYMBOL: + rb_printf ( RBL_TEXT("%s"), RBL_SYMVALUE(obj)); + break; + case RBL_OBJ_STRING: + rb_printf ( RBL_TEXT("%s"), RBL_STRVALUE(obj)); + break; + case RBL_OBJ_CONS: + { + xp_lisp_obj_t* p = obj; + rb_printf ( RBL_TEXT("(")); + do { + xp_lisp_print_debug (RBL_CAR(p)); + p = RBL_CDR(p); + if (RBL_TYPE(p) != RBL_OBJ_NIL) { + rb_printf ( RBL_TEXT(" ")); + if (RBL_TYPE(p) != RBL_OBJ_CONS) { + rb_printf ( RBL_TEXT(". ")); + xp_lisp_print_debug (p); + } + } + } while (RBL_TYPE(p) != RBL_OBJ_NIL && RBL_TYPE(p) == RBL_OBJ_CONS); + rb_printf ( RBL_TEXT(")")); + } + break; + case RBL_OBJ_FUNC: + rb_printf ( RBL_TEXT("func")); + break; + case RBL_OBJ_MACRO: + rb_printf (RBL_TEXT("macro")); + break; + case RBL_OBJ_PRIM: + rb_printf (RBL_TEXT("prim")); + break; + default: + rb_printf (RBL_TEXT("unknown object type: %d"), RBL_TYPE(obj)); + } +} + +void xp_lisp_print (xp_lisp_t* lsp, xp_lisp_obj_t* obj) +{ + switch (RBL_TYPE(obj)) { + case RBL_OBJ_NIL: + rb_fprintf (lsp->outstream, RBL_TEXT("nil")); + break; + case RBL_OBJ_TRUE: + rb_fprintf (lsp->outstream, RBL_TEXT("t")); + break; + case RBL_OBJ_INT: + rb_fprintf (lsp->outstream, RBL_TEXT("%d"), RBL_IVALUE(obj)); + break; + case RBL_OBJ_FLOAT: + rb_fprintf (lsp->outstream, RBL_TEXT("%f"), RBL_FVALUE(obj)); + break; + case RBL_OBJ_SYMBOL: + rb_fprintf (lsp->outstream, RBL_TEXT("%s"), RBL_SYMVALUE(obj)); + break; + case RBL_OBJ_STRING: + rb_fprintf (lsp->outstream, RBL_TEXT("\"%s\""), RBL_STRVALUE(obj)); + break; + case RBL_OBJ_CONS: + { + xp_lisp_obj_t* p = obj; + rb_fprintf (lsp->outstream, RBL_TEXT("(")); + do { + xp_lisp_print (lsp, RBL_CAR(p)); + p = RBL_CDR(p); + if (p != lsp->mem->nil) { + rb_fprintf (lsp->outstream, RBL_TEXT(" ")); + if (RBL_TYPE(p) != RBL_OBJ_CONS) { + rb_fprintf (lsp->outstream, RBL_TEXT(". ")); + xp_lisp_print (lsp, p); + } + } + } while (p != lsp->mem->nil && RBL_TYPE(p) == RBL_OBJ_CONS); + rb_fprintf (lsp->outstream, RBL_TEXT(")")); + } + break; + case RBL_OBJ_FUNC: + rb_fprintf (lsp->outstream, RBL_TEXT("func")); + break; + case RBL_OBJ_MACRO: + rb_fprintf (lsp->outstream, RBL_TEXT("macro")); + break; + case RBL_OBJ_PRIM: + rb_fprintf (lsp->outstream, RBL_TEXT("prim")); + break; + default: + rb_fprintf (lsp->outstream, + RBL_TEXT("unknown object type: %d"), RBL_TYPE(obj)); + } +} + diff --git a/ase/lsp/read.c b/ase/lsp/read.c new file mode 100644 index 00000000..ccd6c66a --- /dev/null +++ b/ase/lsp/read.c @@ -0,0 +1,413 @@ +/* + * $Id: read.c,v 1.1 2005-02-04 15:39:11 bacon Exp $ + */ + +#include "lsp.h" +#include "token.h" + +#define IS_SPACE(x) rb_isspace(x) +#define IS_DIGIT(x) rb_isdigit(x) +#define IS_ALPHA(x) rb_isalpha(x) +#define IS_ALNUM(x) rb_isalnum(x) + +#define IS_IDENT(c) \ + ((c) == RBL_CHAR('+') || (c) == RBL_CHAR('-') || \ + (c) == RBL_CHAR('*') || (c) == RBL_CHAR('/') || \ + (c) == RBL_CHAR('%') || (c) == RBL_CHAR('&') || \ + (c) == RBL_CHAR('<') || (c) == RBL_CHAR('>') || \ + (c) == RBL_CHAR('=') || (c) == RBL_CHAR('_') || \ + (c) == RBL_CHAR('?')) + +#define TOKEN_CLEAR(lsp) xp_lisp_token_clear (lsp->token) +#define TOKEN_TYPE(lsp) lsp->token->type +#define TOKEN_IVALUE(lsp) lsp->token->ivalue +#define TOKEN_FVALUE(lsp) lsp->token->fvalue +#define TOKEN_SVALUE(lsp) lsp->token->buffer +#define TOKEN_SLENGTH(lsp) lsp->token->size +#define TOKEN_ADD_CHAR(lsp,ch) \ + do { \ + if (xp_lisp_token_addc (lsp->token, ch) == -1) { \ + lsp->error = RBL_ERR_MEM; \ + return -1; \ + } \ + } while (0) +#define TOKEN_COMPARE(lsp,str) xp_lisp_token_compare (lsp->token, str) + + +#define TOKEN_END 0 +#define TOKEN_INT 1 +#define TOKEN_FLOAT 2 +#define TOKEN_STRING 3 +#define TOKEN_LPAREN 4 +#define TOKEN_RPAREN 5 +#define TOKEN_IDENT 6 +#define TOKEN_QUOTE 7 +#define TOKEN_DOT 8 +#define TOKEN_INVALID 50 +#define TOKEN_UNTERM_STRING 51 + +#ifdef __cplusplus +extern "C" { +#endif + +static xp_lisp_obj_t* read_obj (xp_lisp_t* lsp); +static xp_lisp_obj_t* read_list (xp_lisp_t* lsp); +static xp_lisp_obj_t* read_quote (xp_lisp_t* lsp); + +static int read_token (xp_lisp_t* lsp); +static int read_number (xp_lisp_t* lsp, int negative); +static int read_ident (xp_lisp_t* lsp); +static int read_string (xp_lisp_t* lsp); + +#ifdef __cplusplus +} +#endif + +#define NEXT_CHAR(lsp) \ + do { \ + if (lsp->creader (&lsp->curc, lsp->creader_extra) == -1) { \ + lsp->error = RBL_ERR_READ; \ + return -1; \ + } \ + } while (0) + +#define NEXT_TOKEN(lsp) \ + do { \ + if (read_token(lsp) == -1) return XP_NULL; \ + } while (0) + + +void xp_lisp_set_creader (xp_lisp_t* lsp, xp_lisp_creader_t func, void* extra) +{ + xp_lisp_assert (lsp != XP_NULL); + + lsp->creader = func; + lsp->creader_extra = extra; + lsp->creader_just_set = 1; +} + +xp_lisp_obj_t* xp_lisp_read (xp_lisp_t* lsp) +{ + xp_lisp_assert (lsp != XP_NULL && lsp->creader != XP_NULL); + + if (lsp->creader_just_set) { + // NEXT_CHAR (lsp); + if (lsp->creader (&lsp->curc, lsp->creader_extra) == -1) { + lsp->error = RBL_ERR_READ; + return XP_NULL; + } + lsp->creader_just_set = 0; + } + + lsp->error = RBL_ERR_NONE; + NEXT_TOKEN (lsp); + + if (lsp->mem->locked != XP_NULL) { + xp_lisp_unlock_all (lsp->mem->locked); + lsp->mem->locked = XP_NULL; + } + lsp->mem->locked = read_obj (lsp); + return lsp->mem->locked; +} + +static xp_lisp_obj_t* read_obj (xp_lisp_t* lsp) +{ + xp_lisp_obj_t* obj; + + switch (TOKEN_TYPE(lsp)) { + case TOKEN_END: + lsp->error = RBL_ERR_END; + return XP_NULL; + case TOKEN_LPAREN: + NEXT_TOKEN (lsp); + return read_list (lsp); + case TOKEN_QUOTE: + NEXT_TOKEN (lsp); + return read_quote (lsp); + case TOKEN_INT: + obj = xp_lisp_make_int (lsp->mem, TOKEN_IVALUE(lsp)); + if (obj == XP_NULL) lsp->error = RBL_ERR_MEM; + xp_lisp_lock (obj); + return obj; + case TOKEN_FLOAT: + obj = xp_lisp_make_float (lsp->mem, TOKEN_FVALUE(lsp)); + if (obj == XP_NULL) lsp->error = RBL_ERR_MEM; + xp_lisp_lock (obj); + return obj; + case TOKEN_STRING: + obj = xp_lisp_make_string ( + lsp->mem, TOKEN_SVALUE(lsp), TOKEN_SLENGTH(lsp)); + if (obj == XP_NULL) lsp->error = RBL_ERR_MEM; + xp_lisp_lock (obj); + return obj; + case TOKEN_IDENT: + xp_lisp_assert (lsp->mem->nil != XP_NULL && lsp->mem->t != XP_NULL); + if (TOKEN_COMPARE(lsp, RBL_TEXT("nil")) == 0) obj = lsp->mem->nil; + else if (TOKEN_COMPARE(lsp, RBL_TEXT("t")) == 0) obj = lsp->mem->t; + else { + obj = xp_lisp_make_symbol ( + lsp->mem, TOKEN_SVALUE(lsp), TOKEN_SLENGTH(lsp)); + if (obj == XP_NULL) lsp->error = RBL_ERR_MEM; + xp_lisp_lock (obj); + } + return obj; + } + + lsp->error = RBL_ERR_SYNTAX; + return XP_NULL; +} + +static xp_lisp_obj_t* read_list (xp_lisp_t* lsp) +{ + xp_lisp_obj_t* obj; + xp_lisp_obj_cons_t* p, * first = XP_NULL, * prev = XP_NULL; + + while (TOKEN_TYPE(lsp) != TOKEN_RPAREN) { + if (TOKEN_TYPE(lsp) == TOKEN_END) { + lsp->error = RBL_ERR_SYNTAX; // unexpected end of input + return XP_NULL; + } + + if (TOKEN_TYPE(lsp) == TOKEN_DOT) { + if (prev == XP_NULL) { + lsp->error = RBL_ERR_SYNTAX; // unexpected . + return XP_NULL; + } + + NEXT_TOKEN (lsp); + obj = read_obj (lsp); + if (obj == XP_NULL) { + if (lsp->error == RBL_ERR_END) { + //unexpected end of input + lsp->error = RBL_ERR_SYNTAX; + } + return XP_NULL; + } + prev->cdr = obj; + + NEXT_TOKEN (lsp); + if (TOKEN_TYPE(lsp) != TOKEN_RPAREN) { + lsp->error = RBL_ERR_SYNTAX; // ) expected + return XP_NULL; + } + + break; + } + + obj = read_obj (lsp); + if (obj == XP_NULL) { + if (lsp->error == RBL_ERR_END) { + // unexpected end of input + lsp->error = RBL_ERR_SYNTAX; + } + return XP_NULL; + } + + p = (xp_lisp_obj_cons_t*)xp_lisp_make_cons ( + lsp->mem, lsp->mem->nil, lsp->mem->nil); + if (p == XP_NULL) { + lsp->error = RBL_ERR_MEM; + return XP_NULL; + } + xp_lisp_lock ((xp_lisp_obj_t*)p); + + if (first == XP_NULL) first = p; + if (prev != XP_NULL) prev->cdr = (xp_lisp_obj_t*)p; + + p->car = obj; + prev = p; + + NEXT_TOKEN (lsp); + } + + return (first == XP_NULL)? lsp->mem->nil: (xp_lisp_obj_t*)first; +} + +static xp_lisp_obj_t* read_quote (xp_lisp_t* lsp) +{ + xp_lisp_obj_t* cons, * tmp; + + tmp = read_obj (lsp); + if (tmp == XP_NULL) { + if (lsp->error == RBL_ERR_END) { + // unexpected end of input + lsp->error = RBL_ERR_SYNTAX; + } + return XP_NULL; + } + + cons = xp_lisp_make_cons (lsp->mem, tmp, lsp->mem->nil); + if (cons == XP_NULL) { + lsp->error = RBL_ERR_MEM; + return XP_NULL; + } + xp_lisp_lock (cons); + + cons = xp_lisp_make_cons (lsp->mem, lsp->mem->quote, cons); + if (cons == XP_NULL) { + lsp->error = RBL_ERR_MEM; + return XP_NULL; + } + xp_lisp_lock (cons); + + return cons; +} + +static int read_token (xp_lisp_t* lsp) +{ + xp_lisp_assert (lsp->creader != XP_NULL); + + TOKEN_CLEAR (lsp); + + for (;;) { + // skip white spaces + while (IS_SPACE(lsp->curc)) NEXT_CHAR (lsp); + + // skip the comments here + if (lsp->curc == RBL_CHAR(';')) { + do { + NEXT_CHAR (lsp); + } while (lsp->curc != RBL_CHAR('\n') && lsp->curc != RBL_CHAR_END); + } + else break; + } + + if (lsp->curc == RBL_CHAR_END) { + TOKEN_TYPE(lsp) = TOKEN_END; + return 0; + } + else if (lsp->curc == RBL_CHAR('(')) { + TOKEN_ADD_CHAR (lsp, lsp->curc); + TOKEN_TYPE(lsp) = TOKEN_LPAREN; + NEXT_CHAR (lsp); + return 0; + } + else if (lsp->curc == RBL_CHAR(')')) { + TOKEN_ADD_CHAR (lsp, lsp->curc); + TOKEN_TYPE(lsp) = TOKEN_RPAREN; + NEXT_CHAR (lsp); + return 0; + } + else if (lsp->curc == RBL_CHAR('\'')) { + TOKEN_ADD_CHAR (lsp, lsp->curc); + TOKEN_TYPE(lsp) = TOKEN_QUOTE; + NEXT_CHAR (lsp); + return 0; + } + else if (lsp->curc == RBL_CHAR('.')) { + TOKEN_ADD_CHAR (lsp, lsp->curc); + TOKEN_TYPE(lsp) = TOKEN_DOT; + NEXT_CHAR (lsp); + return 0; + } + else if (lsp->curc == RBL_CHAR('-')) { + TOKEN_ADD_CHAR (lsp, lsp->curc); + NEXT_CHAR (lsp); + return (IS_DIGIT(lsp->curc))? + read_number (lsp, 1): read_ident (lsp); + } + else if (IS_DIGIT(lsp->curc)) { + return read_number (lsp, 0); + } + else if (IS_ALPHA(lsp->curc) || IS_IDENT(lsp->curc)) { + return read_ident (lsp); + } + else if (lsp->curc == RBL_CHAR('\"')) { + NEXT_CHAR (lsp); + return read_string (lsp); + } + + TOKEN_TYPE(lsp) = TOKEN_INVALID; + NEXT_CHAR (lsp); // consume + return 0; +} + +static int read_number (xp_lisp_t* lsp, int negative) +{ + do { + TOKEN_IVALUE(lsp) = + TOKEN_IVALUE(lsp) * 10 + lsp->curc - RBL_CHAR('0'); + TOKEN_ADD_CHAR (lsp, lsp->curc); + NEXT_CHAR (lsp); + } while (IS_DIGIT(lsp->curc)); + + if (negative) TOKEN_IVALUE(lsp) *= -1; + TOKEN_TYPE(lsp) = TOKEN_INT; + + // TODO: read floating point numbers + + return 0; +} + +static int read_ident (xp_lisp_t* lsp) +{ + do { + TOKEN_ADD_CHAR (lsp, lsp->curc); + NEXT_CHAR (lsp); + } while (IS_ALNUM(lsp->curc) || IS_IDENT(lsp->curc)); + TOKEN_TYPE(lsp) = TOKEN_IDENT; + return 0; +} + +static int read_string (xp_lisp_t* lsp) +{ + int escaped = 0; + xp_lisp_cint code = 0; + + do { + if (lsp->curc == RBL_CHAR_END) { + TOKEN_TYPE(lsp) = TOKEN_UNTERM_STRING; + return 0; + } + + // TODO: + if (escaped == 3) { + /* \xNN */ + } + else if (escaped == 2) { + /* \000 */ + } + else if (escaped == 1) { + /* backslash + character */ + if (lsp->curc == RBL_CHAR('a')) + lsp->curc = RBL_CHAR('\a'); + else if (lsp->curc == RBL_CHAR('b')) + lsp->curc = RBL_CHAR('\b'); + else if (lsp->curc == RBL_CHAR('f')) + lsp->curc = RBL_CHAR('\f'); + else if (lsp->curc == RBL_CHAR('n')) + lsp->curc = RBL_CHAR('\n'); + else if (lsp->curc == RBL_CHAR('r')) + lsp->curc = RBL_CHAR('\r'); + else if (lsp->curc == RBL_CHAR('t')) + lsp->curc = RBL_CHAR('\t'); + else if (lsp->curc == RBL_CHAR('v')) + lsp->curc = RBL_CHAR('\v'); + else if (lsp->curc == RBL_CHAR('0')) { + escaped = 2; + code = 0; + NEXT_CHAR (lsp); + continue; + } + else if (lsp->curc == RBL_CHAR('x')) { + escaped = 3; + code = 0; + NEXT_CHAR (lsp); + continue; + } + } + else if (lsp->curc == RBL_CHAR('\\')) { + escaped = 1; + NEXT_CHAR (lsp); + continue; + } + + TOKEN_ADD_CHAR (lsp, lsp->curc); + NEXT_CHAR (lsp); + } while (lsp->curc != RBL_CHAR('\"')); + + TOKEN_TYPE(lsp) = TOKEN_STRING; + NEXT_CHAR (lsp); + + return 0; +} diff --git a/ase/lsp/token.c b/ase/lsp/token.c new file mode 100644 index 00000000..cd351f88 --- /dev/null +++ b/ase/lsp/token.c @@ -0,0 +1,92 @@ +/* + * $Id: token.c,v 1.1 2005-02-04 15:39:11 bacon Exp $ + */ + +#include "token.h" +#include + +xp_lisp_token_t* xp_lisp_token_new (xp_size_t capacity) +{ + xp_lisp_token_t* token; + + xp_lisp_assert (capacity > 0); + + token = (xp_lisp_token_t*)malloc (sizeof(xp_lisp_token_t)); + if (token == XP_NULL) return XP_NULL; + + token->buffer = (xp_lisp_char*)malloc ((capacity + 1) * sizeof(xp_lisp_char)); + if (token->buffer == XP_NULL) { + free (token); + return XP_NULL; + } + + token->ivalue = 0; + token->fvalue = .0; + + token->size = 0; + token->capacity = capacity; + token->buffer[0] = RBL_CHAR('\0'); + + return token; +} + +void xp_lisp_token_free (xp_lisp_token_t* token) +{ + free (token->buffer); + free (token); +} + +int xp_lisp_token_addc (xp_lisp_token_t* token, xp_lisp_cint c) +{ + if (token->size >= token->capacity) { + // double the capacity. + xp_lisp_char* new_buffer = (xp_lisp_char*)realloc ( + token->buffer, (token->capacity * 2 + 1) * sizeof(xp_lisp_char)); + if (new_buffer == XP_NULL) return -1; + token->buffer = new_buffer; + token->capacity = token->capacity * 2; + } + + token->buffer[token->size++] = c; + token->buffer[token->size] = RBL_CHAR('\0'); + return 0; +} + +void xp_lisp_token_clear (xp_lisp_token_t* token) +{ + token->ivalue = 0; + token->fvalue = .0; + + token->size = 0; + token->buffer[0] = RBL_CHAR('\0'); +} + +xp_lisp_char* xp_lisp_token_transfer (xp_lisp_token_t* token, xp_size_t capacity) +{ + xp_lisp_char* old_buffer, * new_buffer; + + new_buffer = (xp_lisp_char*)malloc((capacity + 1) * sizeof(xp_lisp_char)); + if (new_buffer == XP_NULL) return XP_NULL; + + old_buffer = token->buffer; + token->buffer = new_buffer; + token->size = 0; + token->capacity = capacity; + token->buffer[0] = RBL_CHAR('\0'); + + return old_buffer; +} + +int xp_lisp_token_compare (xp_lisp_token_t* token, const xp_lisp_char* str) +{ + xp_lisp_char* p = token->buffer; + xp_size_t index = 0; + + while (index < token->size) { + if (*p > *str) return 1; + if (*p < *str) return -1; + index++; p++; str++; + } + + return (*str == RBL_CHAR('\0'))? 0: -1; +} diff --git a/ase/lsp/token.h b/ase/lsp/token.h new file mode 100644 index 00000000..4b916fce --- /dev/null +++ b/ase/lsp/token.h @@ -0,0 +1,39 @@ +/* + * $Id: token.h,v 1.1 2005-02-04 15:39:11 bacon Exp $ + */ + +#ifndef _RBL_TOKEN_H_ +#define _RBL_TOKEN_H_ + +#include "types.h" + +struct xp_lisp_token_t +{ + int type; + + xp_lisp_int ivalue; + xp_lisp_float fvalue; + + xp_size_t capacity; + xp_size_t size; + xp_lisp_char* buffer; +}; + +typedef struct xp_lisp_token_t xp_lisp_token_t; + +#ifdef __cplusplus +extern "C" { +#endif + +xp_lisp_token_t* xp_lisp_token_new (xp_size_t capacity); +void xp_lisp_token_free (xp_lisp_token_t* token); +int xp_lisp_token_addc (xp_lisp_token_t* token, xp_lisp_cint c); +void xp_lisp_token_clear (xp_lisp_token_t* token); +xp_lisp_char* xp_lisp_token_transfer (xp_lisp_token_t* token, xp_size_t capacity); +int xp_lisp_token_compare (xp_lisp_token_t* token, const xp_lisp_char* str); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ase/lsp/types.h b/ase/lsp/types.h new file mode 100644 index 00000000..6f707612 --- /dev/null +++ b/ase/lsp/types.h @@ -0,0 +1,23 @@ +/* + * $Id: types.h,v 1.1 2005-02-04 15:39:11 bacon Exp $ + */ + +#ifndef _RBL_TYPES_H_ +#define _RBL_TYPES_H_ + +#include +#include + +typedef rb_char xp_lisp_char; +typedef rb_cint xp_lisp_cint; +typedef int xp_lisp_int; +typedef float xp_lisp_float; + +#define RBL_CHAR(x) RB_CHAR(x) +#define RBL_TEXT(x) RB_TEXT(x) +#define RBL_CHAR_END RB_EOF + +#define xp_lisp_ensure(x) RB_ENSURE(x) +#define xp_lisp_assert(x) RB_ASSERT(x) + +#endif