moved entity management functions to a separate file
This commit is contained in:
parent
31ae7440a5
commit
1d478104b3
@ -164,7 +164,7 @@ int scm_main (int argc, qse_char_t* argv[])
|
|||||||
qse_scm_attachio (scm, &io);
|
qse_scm_attachio (scm, &io);
|
||||||
}
|
}
|
||||||
|
|
||||||
qse_scm_read (scm);
|
qse_scm_print (scm, qse_scm_read (scm));
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
while (1)
|
while (1)
|
||||||
|
@ -129,6 +129,24 @@ typedef qse_scm_ent_t* (*qse_scm_prim_t) (
|
|||||||
qse_scm_ent_t* obj
|
qse_scm_ent_t* obj
|
||||||
);
|
);
|
||||||
|
|
||||||
|
#define QSE_SCM_ENT_ISNIL(scm,ent) ((ent) == (scm)->nil)
|
||||||
|
|
||||||
|
#define QSE_SCM_ENT_ISSMALLINT(scm,ent) ((qse_uintptr_t)(ent) & 1)
|
||||||
|
|
||||||
|
/* TODO: need more typecasting to something like int? how to i determine
|
||||||
|
* the best type for the range in CAN_BE_SMALLINT()?
|
||||||
|
#define QSE_SCM_ENT_FROMSMALLINT(x) ((int)((qse_uintptr_t)(x) >> 1))
|
||||||
|
*/
|
||||||
|
#define QSE_SCM_ENT_FROMSMALLINT(scm,ent) \
|
||||||
|
((qse_uintptr_t)(ent) >> 1)
|
||||||
|
|
||||||
|
/* TODO: change the smallint range... */
|
||||||
|
#define QSE_SCM_ENT_TOSMALLINT(scm,num) \
|
||||||
|
((qse_scm_ent_t*)(qse_uintptr_t)(((num) << 1) | 1))
|
||||||
|
|
||||||
|
#define QSE_SCM_ENT_CANBESMALLINT(scm,num) \
|
||||||
|
(((num) >= -16384) && ((num) <= 16383))
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
@ -250,6 +268,51 @@ int qse_scm_removeprim (
|
|||||||
const qse_char_t* name
|
const qse_char_t* name
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
qse_scm_ent_t* qse_scm_makepairent (
|
||||||
|
qse_scm_t* scm,
|
||||||
|
qse_scm_ent_t* car,
|
||||||
|
qse_scm_ent_t* cdr
|
||||||
|
);
|
||||||
|
|
||||||
|
qse_scm_ent_t* qse_scm_makenument (
|
||||||
|
qse_scm_t* scm,
|
||||||
|
qse_long_t val
|
||||||
|
);
|
||||||
|
|
||||||
|
qse_scm_ent_t* qse_scm_makerealent (
|
||||||
|
qse_scm_t* scm,
|
||||||
|
qse_long_t val
|
||||||
|
);
|
||||||
|
|
||||||
|
qse_scm_ent_t* qse_scm_makestrent (
|
||||||
|
qse_scm_t* scm,
|
||||||
|
const qse_char_t* str,
|
||||||
|
qse_size_t len
|
||||||
|
);
|
||||||
|
|
||||||
|
qse_scm_ent_t* qse_scm_makenamentity (
|
||||||
|
qse_scm_t* scm,
|
||||||
|
const qse_char_t* str
|
||||||
|
);
|
||||||
|
|
||||||
|
qse_scm_ent_t* qse_scm_makesyment (
|
||||||
|
qse_scm_t* scm,
|
||||||
|
const qse_char_t* name
|
||||||
|
);
|
||||||
|
|
||||||
|
qse_scm_ent_t* qse_scm_makesyntent (
|
||||||
|
qse_scm_t* scm,
|
||||||
|
const qse_char_t* name,
|
||||||
|
int code
|
||||||
|
);
|
||||||
|
|
||||||
|
qse_scm_ent_t* qse_scm_makeprocent (
|
||||||
|
qse_scm_t* scm,
|
||||||
|
const qse_char_t* name,
|
||||||
|
int code
|
||||||
|
);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -8,6 +8,6 @@ AM_CPPFLAGS = \
|
|||||||
|
|
||||||
lib_LTLIBRARIES = libqsescm.la
|
lib_LTLIBRARIES = libqsescm.la
|
||||||
|
|
||||||
libqsescm_la_SOURCES = scm.h scm.c print.c err.c
|
libqsescm_la_SOURCES = scm.h scm.c mem.c print.c err.c
|
||||||
libqsescm_la_LDFLAGS = -L../cmn -L$(libdir) -version-info 1:0:0 -no-undefined
|
libqsescm_la_LDFLAGS = -L../cmn -L$(libdir) -version-info 1:0:0 -no-undefined
|
||||||
libqsescm_la_LIBADD = -lqsecmn
|
libqsescm_la_LIBADD = -lqsecmn
|
||||||
|
@ -71,7 +71,7 @@ am__base_list = \
|
|||||||
am__installdirs = "$(DESTDIR)$(libdir)"
|
am__installdirs = "$(DESTDIR)$(libdir)"
|
||||||
LTLIBRARIES = $(lib_LTLIBRARIES)
|
LTLIBRARIES = $(lib_LTLIBRARIES)
|
||||||
libqsescm_la_DEPENDENCIES =
|
libqsescm_la_DEPENDENCIES =
|
||||||
am_libqsescm_la_OBJECTS = scm.lo print.lo err.lo
|
am_libqsescm_la_OBJECTS = scm.lo mem.lo print.lo err.lo
|
||||||
libqsescm_la_OBJECTS = $(am_libqsescm_la_OBJECTS)
|
libqsescm_la_OBJECTS = $(am_libqsescm_la_OBJECTS)
|
||||||
libqsescm_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
|
libqsescm_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
|
||||||
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
|
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
|
||||||
@ -238,7 +238,7 @@ AM_CPPFLAGS = \
|
|||||||
-I$(includedir)
|
-I$(includedir)
|
||||||
|
|
||||||
lib_LTLIBRARIES = libqsescm.la
|
lib_LTLIBRARIES = libqsescm.la
|
||||||
libqsescm_la_SOURCES = scm.h scm.c print.c err.c
|
libqsescm_la_SOURCES = scm.h scm.c mem.c print.c err.c
|
||||||
libqsescm_la_LDFLAGS = -L../cmn -L$(libdir) -version-info 1:0:0 -no-undefined
|
libqsescm_la_LDFLAGS = -L../cmn -L$(libdir) -version-info 1:0:0 -no-undefined
|
||||||
libqsescm_la_LIBADD = -lqsecmn
|
libqsescm_la_LIBADD = -lqsecmn
|
||||||
all: all-am
|
all: all-am
|
||||||
@ -316,6 +316,7 @@ distclean-compile:
|
|||||||
-rm -f *.tab.c
|
-rm -f *.tab.c
|
||||||
|
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/err.Plo@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/err.Plo@am__quote@
|
||||||
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mem.Plo@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/print.Plo@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/print.Plo@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/scm.Plo@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/scm.Plo@am__quote@
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,100 +0,0 @@
|
|||||||
/*
|
|
||||||
* $Id$
|
|
||||||
*
|
|
||||||
Copyright 2006-2009 Chung, Hyung-Hwan.
|
|
||||||
This file is part of QSE.
|
|
||||||
|
|
||||||
QSE is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU Lesser General Public License as
|
|
||||||
published by the Free Software Foundation, either version 3 of
|
|
||||||
the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
QSE 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 Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with QSE. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _QSE_LIB_SCM_MEM_H_
|
|
||||||
#define _QSE_LIB_SCM_MEM_H_
|
|
||||||
|
|
||||||
#ifndef _QSE_SCM_SCM_H_
|
|
||||||
#error Never include this file directly. Include <qse/scm/scm.h> instead
|
|
||||||
#endif
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
QSE_SCM_OBJ_NIL = 0,
|
|
||||||
QSE_SCM_OBJ_TRUE,
|
|
||||||
QSE_SCM_OBJ_INT,
|
|
||||||
QSE_SCM_OBJ_REAL,
|
|
||||||
QSE_SCM_OBJ_SYM,
|
|
||||||
QSE_SCM_OBJ_STR,
|
|
||||||
QSE_SCM_OBJ_CONS,
|
|
||||||
QSE_SCM_OBJ_FUNC,
|
|
||||||
QSE_SCM_OBJ_MACRO,
|
|
||||||
QSE_SCM_OBJ_PRIM,
|
|
||||||
|
|
||||||
QSE_SCM_TYPE_COUNT /* the number of lsp object types */
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct qse_scm_mem_t qse_scm_mem_t;
|
|
||||||
|
|
||||||
struct qse_scm_mem_t
|
|
||||||
{
|
|
||||||
qse_scm_t* scm;
|
|
||||||
|
|
||||||
/* object allocation list */
|
|
||||||
qse_size_t ubound; /* upper bounds of the maximum number of objects */
|
|
||||||
qse_size_t ubound_inc; /* increment of the upper bounds */
|
|
||||||
qse_size_t count; /* the number of objects currently allocated */
|
|
||||||
qse_scm_obj_t* used[QSE_SCM_TYPE_COUNT];
|
|
||||||
qse_scm_obj_t* free[QSE_SCM_TYPE_COUNT];
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
qse_scm_obj_t* obj;
|
|
||||||
qse_scm_obj_t* tmp; /* temporary datum to protect from gc in read() */
|
|
||||||
qse_scm_obj_t* stack;
|
|
||||||
} r;
|
|
||||||
|
|
||||||
/* commonly accessed objects */
|
|
||||||
qse_scm_obj_t* nil; /* qse_scm_obj_nil_t */
|
|
||||||
qse_scm_obj_t* t; /* qse_scm_obj_true_t */
|
|
||||||
qse_scm_obj_t* quote; /* qse_scm_obj_sym_t */
|
|
||||||
qse_scm_obj_t* lambda; /* qse_scm_obj_sym_t */
|
|
||||||
qse_scm_obj_t* macro; /* qse_scm_obj_sym_t */
|
|
||||||
qse_scm_obj_t* num[10]; /* qse_scm_obj_int_t */
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
/* run-time environment frame */
|
|
||||||
qse_scm_frame_t* frame;
|
|
||||||
/* pointer to a global-level frame */
|
|
||||||
qse_scm_frame_t* root_frame;
|
|
||||||
/* pointer to an interim frame not yet added to "frame" */
|
|
||||||
qse_scm_frame_t* brooding_frame;
|
|
||||||
|
|
||||||
/* links for temporary objects */
|
|
||||||
qse_scm_tlink_t* tlink;
|
|
||||||
qse_size_t tlink_count;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
qse_scm_mem_t* qse_scm_initmem (
|
|
||||||
qse_scm_mem_t* mem, qse_scm_t* scm,
|
|
||||||
qse_size_t ubound, qse_size_t ubound_inc);
|
|
||||||
void qse_scm_finimem (qse_scm_mem_t* mem);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
@ -36,13 +36,94 @@
|
|||||||
} \
|
} \
|
||||||
)
|
)
|
||||||
|
|
||||||
|
static qse_size_t long_to_str (
|
||||||
|
qse_long_t value, int radix,
|
||||||
|
const qse_char_t* prefix, qse_char_t* buf, qse_size_t size)
|
||||||
|
{
|
||||||
|
qse_long_t t, rem;
|
||||||
|
qse_size_t len, ret, i;
|
||||||
|
qse_size_t prefix_len;
|
||||||
|
|
||||||
|
prefix_len = (prefix != QSE_NULL)? qse_strlen(prefix): 0;
|
||||||
|
|
||||||
|
t = value;
|
||||||
|
if (t == 0)
|
||||||
|
{
|
||||||
|
/* zero */
|
||||||
|
if (buf == QSE_NULL)
|
||||||
|
{
|
||||||
|
/* if buf is not given,
|
||||||
|
* return the number of bytes required */
|
||||||
|
return prefix_len + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size < prefix_len+1)
|
||||||
|
{
|
||||||
|
/* buffer too small */
|
||||||
|
return (qse_size_t)-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < prefix_len; i++) buf[i] = prefix[i];
|
||||||
|
buf[prefix_len] = QSE_T('0');
|
||||||
|
if (size > prefix_len+1) buf[prefix_len+1] = QSE_T('\0');
|
||||||
|
return prefix_len+1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* non-zero values */
|
||||||
|
len = prefix_len;
|
||||||
|
if (t < 0) { t = -t; len++; }
|
||||||
|
while (t > 0) { len++; t /= radix; }
|
||||||
|
|
||||||
|
if (buf == QSE_NULL)
|
||||||
|
{
|
||||||
|
/* if buf is not given, return the number of bytes required */
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size < len) return (qse_size_t)-1; /* buffer too small */
|
||||||
|
if (size > len) buf[len] = QSE_T('\0');
|
||||||
|
ret = len;
|
||||||
|
|
||||||
|
t = value;
|
||||||
|
if (t < 0) t = -t;
|
||||||
|
|
||||||
|
while (t > 0)
|
||||||
|
{
|
||||||
|
rem = t % radix;
|
||||||
|
if (rem >= 10)
|
||||||
|
buf[--len] = (qse_char_t)rem + QSE_T('a') - 10;
|
||||||
|
else
|
||||||
|
buf[--len] = (qse_char_t)rem + QSE_T('0');
|
||||||
|
t /= radix;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value < 0)
|
||||||
|
{
|
||||||
|
for (i = 1; i <= prefix_len; i++)
|
||||||
|
{
|
||||||
|
buf[i] = prefix[i-1];
|
||||||
|
len--;
|
||||||
|
}
|
||||||
|
buf[--len] = QSE_T('-');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (i = 0; i < prefix_len; i++) buf[i] = prefix[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int print_entity (
|
static int print_entity (
|
||||||
qse_scm_t* scm, const qse_scm_ent_t* obj, int prt_cons_par)
|
qse_scm_t* scm, const qse_scm_ent_t* obj, int prt_cons_par)
|
||||||
{
|
{
|
||||||
qse_char_t buf[256];
|
qse_char_t buf[256];
|
||||||
|
qse_long_t nval;
|
||||||
|
|
||||||
if (IS_SMALLINT(obj))
|
if (IS_SMALLINT(scm,obj))
|
||||||
{
|
{
|
||||||
|
nval = FROM_SMALLINT(scm,obj);
|
||||||
|
goto printnum;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (TYPE(obj))
|
switch (TYPE(obj))
|
||||||
@ -60,31 +141,17 @@ static int print_entity (
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case QSE_SCM_ENT_NUM:
|
case QSE_SCM_ENT_NUM:
|
||||||
#if QSE_SIZEOF_LONG_LONG > 0
|
{
|
||||||
scm->prm.sprintf (
|
qse_char_t tmp[QSE_SIZEOF(qse_long_t)*8+2];
|
||||||
scm->prm.udd,
|
qse_size_t len;
|
||||||
buf, QSE_COUNTOF(buf),
|
|
||||||
QSE_T("%lld"), (long long)NUM_VALUE(obj));
|
nval = NUM_VALUE(obj);
|
||||||
#elif QSE_SIZEOF___INT64 > 0
|
|
||||||
scm->prm.sprintf (
|
printnum:
|
||||||
scm->prm.udd,
|
len = long_to_str (nval, 10, QSE_NULL, tmp, QSE_COUNTOF(tmp));
|
||||||
buf, QSE_COUNTOF(buf),
|
OUTPUT_STRX (scm, tmp, len);
|
||||||
QSE_T("%I64d"), (__int64)NUM_VALUE(obj));
|
|
||||||
#elif QSE_SIZEOF_LONG > 0
|
|
||||||
scm->prm.sprintf (
|
|
||||||
scm->prm.udd,
|
|
||||||
buf, QSE_COUNTOF(buf),
|
|
||||||
QSE_T("%ld"), (long)NUM_VALUE(obj));
|
|
||||||
#elif QSE_SIZEOF_INT > 0
|
|
||||||
scm->prm.sprintf (
|
|
||||||
scm->prm.udd,
|
|
||||||
buf, QSE_COUNTOF(buf),
|
|
||||||
QSE_T("%d"), (int)NUM_VALUE(obj));
|
|
||||||
#else
|
|
||||||
#error unsupported size
|
|
||||||
#endif
|
|
||||||
OUTPUT_STR (scm, buf);
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
case QSE_SCM_ENT_REAL:
|
case QSE_SCM_ENT_REAL:
|
||||||
@ -122,7 +189,7 @@ static int print_entity (
|
|||||||
{
|
{
|
||||||
qse_scm_print (scm, PAIR_CAR(p));
|
qse_scm_print (scm, PAIR_CAR(p));
|
||||||
p = PAIR_CDR(p);
|
p = PAIR_CDR(p);
|
||||||
if (!IS_NIL(p))
|
if (!IS_NIL(scm,p))
|
||||||
{
|
{
|
||||||
OUTPUT_STR (scm, QSE_T(" "));
|
OUTPUT_STR (scm, QSE_T(" "));
|
||||||
if (TYPE(p) != QSE_SCM_ENT_PAIR)
|
if (TYPE(p) != QSE_SCM_ENT_PAIR)
|
||||||
|
@ -22,18 +22,6 @@
|
|||||||
|
|
||||||
QSE_IMPLEMENT_COMMON_FUNCTIONS (scm)
|
QSE_IMPLEMENT_COMMON_FUNCTIONS (scm)
|
||||||
|
|
||||||
#define IS_NIL(x) ((x) == scm->nil)
|
|
||||||
|
|
||||||
#define IS_SMALLINT(x) ((qse_uintptr_t)(x) & 1)
|
|
||||||
#define TO_SMALLINT(x) ((qse_scm_ent_t*)(qse_uintptr_t)(((x) << 1) | 1))
|
|
||||||
/* TODO: need more typecasting to something like int? how to i determine
|
|
||||||
* the best type for the range in CAN_BE_SMALLINT()?
|
|
||||||
#define FROM_SMALLINT(x) ((int)((qse_uintptr_t)(x) >> 1))
|
|
||||||
*/
|
|
||||||
#define FROM_SMALLINT(x) ((qse_uintptr_t)(x) >> 1)
|
|
||||||
/* TODO: change the smallint range... */
|
|
||||||
#define CAN_BE_SMALLINT(x) (((x) >= -16384) && ((x) <= 16383))
|
|
||||||
|
|
||||||
static qse_scm_t* qse_scm_init (
|
static qse_scm_t* qse_scm_init (
|
||||||
qse_scm_t* scm,
|
qse_scm_t* scm,
|
||||||
qse_mmgr_t* mmgr,
|
qse_mmgr_t* mmgr,
|
||||||
@ -45,12 +33,6 @@ static void qse_scm_fini (
|
|||||||
qse_scm_t* scm
|
qse_scm_t* scm
|
||||||
);
|
);
|
||||||
|
|
||||||
static qse_scm_ent_t* make_pair_entity (
|
|
||||||
qse_scm_t* scm,
|
|
||||||
qse_scm_ent_t* car,
|
|
||||||
qse_scm_ent_t* cdr
|
|
||||||
);
|
|
||||||
|
|
||||||
qse_scm_t* qse_scm_open (
|
qse_scm_t* qse_scm_open (
|
||||||
qse_mmgr_t* mmgr, qse_size_t xtnsize,
|
qse_mmgr_t* mmgr, qse_size_t xtnsize,
|
||||||
qse_size_t mem_ubound, qse_size_t mem_ubound_inc)
|
qse_size_t mem_ubound, qse_size_t mem_ubound_inc)
|
||||||
@ -146,530 +128,19 @@ int qse_scm_attachio (qse_scm_t* scm, qse_scm_io_t* io)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static qse_scm_enb_t* new_entity_block (qse_scm_t* scm, qse_size_t len)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Create a new value block containing as 'len' slots.
|
|
||||||
*/
|
|
||||||
|
|
||||||
void* raw;
|
|
||||||
qse_scm_enb_t* blk;
|
|
||||||
qse_scm_ent_t* v;
|
|
||||||
qse_size_t i;
|
|
||||||
|
|
||||||
/* Let me assume that an aligned memory pointer is an even address.
|
|
||||||
* malloc() returns an aligned memory pointer on most systems.
|
|
||||||
* However, I can't simply ignore oddball systems that returns
|
|
||||||
* an unaligned memory pointer. (Is there any?) A user may provide
|
|
||||||
* a custom memory allocator that does not return unaligned memory
|
|
||||||
* pointer. I make the pointer to an entity block 2-byte aligned
|
|
||||||
* hoping that the entity pointer alloc_entity() returns is also an
|
|
||||||
* even number. This, of couurse, requires that the size of
|
|
||||||
* qse_scm_enb_t and qse_scm_ent_t is the multiple of 2.
|
|
||||||
* I do this for SMALLINT, not for memory alignemnt.The test for
|
|
||||||
* SMALLINT can simply check the lowest bit. Am i doing too much?
|
|
||||||
*/
|
|
||||||
QSE_ASSERTX (
|
|
||||||
QSE_SIZEOF(qse_scm_enb_t) % 2 == 0,
|
|
||||||
"This function is written assuming the size of qse_scm_enb_t is even"
|
|
||||||
);
|
|
||||||
QSE_ASSERTX (
|
|
||||||
QSE_SIZEOF(qse_scm_ent_t) % 2 == 0,
|
|
||||||
"This function is written assuming the size of qse_scm_ent_t is even"
|
|
||||||
);
|
|
||||||
|
|
||||||
/* The actual memory block size is calculated as shown here:
|
|
||||||
* QSE_SIZEOF(void*) to store the actual memory block pointer
|
|
||||||
* 1 to secure extra 1 byte required for 2-byte alignement.
|
|
||||||
* QSE_SIZEOF(qse_scm_enb_t) to store the block header.
|
|
||||||
* QSE_SIZEOF(qse_Scm_ent_t) * len to store the actual entities.
|
|
||||||
*/
|
|
||||||
raw = (qse_scm_enb_t*) QSE_MMGR_ALLOC (
|
|
||||||
scm->mmgr,
|
|
||||||
QSE_SIZEOF(void*) + 1 +
|
|
||||||
QSE_SIZEOF(qse_scm_enb_t) +
|
|
||||||
QSE_SIZEOF(qse_scm_ent_t) * len
|
|
||||||
);
|
|
||||||
if (raw == QSE_NULL)
|
|
||||||
{
|
|
||||||
qse_scm_seterror (scm, QSE_SCM_ENOMEM, QSE_NULL, QSE_NULL);
|
|
||||||
return QSE_NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The entity block begins after the memory block pointer. */
|
|
||||||
blk = (qse_scm_enb_t*)((qse_byte_t*)raw + QSE_SIZEOF(void*) + 1);
|
|
||||||
|
|
||||||
/* Adjust the block pointer to an even number.
|
|
||||||
* the resulting address is:
|
|
||||||
* either the old address
|
|
||||||
* or the old address - 1
|
|
||||||
*/
|
|
||||||
blk = (qse_scm_enb_t*)((qse_uintptr_t)blk & ~(qse_uintptr_t)1);
|
|
||||||
|
|
||||||
/* Remember the raw block pointer.
|
|
||||||
* ((void**)blk)[-1] gets naturally aligned as blk is aligned.
|
|
||||||
* It can be raw + 1 or the same as raw. */
|
|
||||||
((void**)blk)[-1] = raw;
|
|
||||||
|
|
||||||
/* Initialize the block fields */
|
|
||||||
blk->ptr = (qse_scm_ent_t*)(blk + 1);
|
|
||||||
blk->len = len;
|
|
||||||
|
|
||||||
/* Chain the value block to the block list */
|
|
||||||
blk->next = scm->mem.ebl;
|
|
||||||
scm->mem.ebl = blk;
|
|
||||||
|
|
||||||
/* Chain each slot to the free slot list using
|
|
||||||
* the CDR field of an entity */
|
|
||||||
v = &blk->ptr[0];
|
|
||||||
for (i = 0; i < len -1; i++)
|
|
||||||
{
|
|
||||||
qse_scm_ent_t* tmp = v++;
|
|
||||||
PAIR_CDR(tmp) = v;
|
|
||||||
}
|
|
||||||
PAIR_CDR(v) = scm->mem.free;
|
|
||||||
scm->mem.free = &blk->ptr[0];
|
|
||||||
|
|
||||||
return blk;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void mark (qse_scm_t* scm, qse_scm_ent_t* v)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Mark values non-recursively with Deutsch-Schorr-Waite(DSW) algorithm.
|
|
||||||
* This algorithm builds backtraces directly into the value chain
|
|
||||||
* with the help of additional variables.
|
|
||||||
*/
|
|
||||||
|
|
||||||
qse_scm_ent_t* parent, * me;
|
|
||||||
|
|
||||||
if (IS_SMALLINT(v)) return;
|
|
||||||
|
|
||||||
/* Initialization */
|
|
||||||
parent = QSE_NULL;
|
|
||||||
me = v;
|
|
||||||
|
|
||||||
MARK(me) = 1;
|
|
||||||
/*if (!ATOM(me))*/ DSWCOUNT(me) = 0;
|
|
||||||
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
if (ATOM(me) || DSWCOUNT(me) >= QSE_COUNTOF(me->u.ref.ent))
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Backtrack to the parent node
|
|
||||||
*/
|
|
||||||
qse_scm_ent_t* child;
|
|
||||||
|
|
||||||
/* Nothing more to backtrack? end of marking */
|
|
||||||
if (parent == QSE_NULL) return;
|
|
||||||
|
|
||||||
/* Remember me temporarily for restoration below */
|
|
||||||
child = me;
|
|
||||||
|
|
||||||
/* The current parent becomes me */
|
|
||||||
me = parent;
|
|
||||||
|
|
||||||
/* Change the parent to the parent of parent */
|
|
||||||
parent = me->u.ref.ent[DSWCOUNT(me)];
|
|
||||||
|
|
||||||
/* Restore the cell contents */
|
|
||||||
me->u.ref.ent[DSWCOUNT(me)] = child;
|
|
||||||
|
|
||||||
/* Increment the counter to indicate that the
|
|
||||||
* 'count'th field has been processed. */
|
|
||||||
DSWCOUNT(me)++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Move on to an unprocessed child
|
|
||||||
*/
|
|
||||||
qse_scm_ent_t* child;
|
|
||||||
|
|
||||||
child = me->u.ref.ent[DSWCOUNT(me)];
|
|
||||||
|
|
||||||
/* Process the field */
|
|
||||||
QSE_ASSERT (child != QSE_NULL);
|
|
||||||
|
|
||||||
if (IS_SMALLINT(child) || MARK(child))
|
|
||||||
{
|
|
||||||
/* Already marked. Increment the count */
|
|
||||||
DSWCOUNT(me)++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Change the contents of the child chosen
|
|
||||||
* to point to the current parent */
|
|
||||||
me->u.ref.ent[DSWCOUNT(me)] = parent;
|
|
||||||
|
|
||||||
/* Link me to the head of parent list */
|
|
||||||
parent = me;
|
|
||||||
|
|
||||||
/* Let me point to the child chosen */
|
|
||||||
me = child;
|
|
||||||
|
|
||||||
MARK(me) = 1;
|
|
||||||
/*if (!ATOM(me))*/ DSWCOUNT(me) = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void gc (qse_scm_t* scm, qse_scm_ent_t* x, qse_scm_ent_t* y)
|
|
||||||
{
|
|
||||||
/* TODO: How can i GC away those symbols not actually meaningful?
|
|
||||||
* marking objects referenced in symbol table prevent me from
|
|
||||||
* finding unused symbols... you keep on evaluating expressions
|
|
||||||
* with different symbols. you'll get out of memory. */
|
|
||||||
mark (scm, scm->symtab);
|
|
||||||
mark (scm, scm->gloenv);
|
|
||||||
|
|
||||||
mark (scm, scm->reg.arg);
|
|
||||||
mark (scm, scm->reg.env);
|
|
||||||
mark (scm, scm->reg.cod);
|
|
||||||
mark (scm, scm->reg.dmp);
|
|
||||||
|
|
||||||
/* mark the temporaries */
|
|
||||||
if (x) mark (scm, x);
|
|
||||||
if (y) mark (scm, y);
|
|
||||||
|
|
||||||
|
|
||||||
/* scan the allocated values */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
rsr4
|
|
||||||
|
|
||||||
the following identifiers are syntactic keywors and should not be
|
|
||||||
used as variables.
|
|
||||||
|
|
||||||
=> do or
|
|
||||||
and else quasiquote
|
|
||||||
begin if quote
|
|
||||||
case lambda set!
|
|
||||||
cond let unquote
|
|
||||||
define let* unquote-splicing
|
|
||||||
delay letrec
|
|
||||||
|
|
||||||
however, you can allow for these keywords to be used as variables...
|
|
||||||
|
|
||||||
biniding, unbound...
|
|
||||||
environment.. a set of visible bindings at some point in a program.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
type atom cons
|
|
||||||
number NUMBER Y
|
|
||||||
string STRING Y
|
|
||||||
symbol SYMBOL name,NIL
|
|
||||||
syntax SYNTAX|SYMBOL name,NIL
|
|
||||||
proc PROC Y
|
|
||||||
pair PAIR Y
|
|
||||||
closure
|
|
||||||
continuation
|
|
||||||
|
|
||||||
an atom does not reference any other values.
|
|
||||||
a symbol can be assoicated with property list
|
|
||||||
(put 'a 'name "brian")
|
|
||||||
(put 'a 'city "daegu")
|
|
||||||
-------------------------
|
|
||||||
(define a1 'a)
|
|
||||||
(put a1 'name "brian")
|
|
||||||
(put a1 'city "daegu")
|
|
||||||
-------------------------
|
|
||||||
(get a1 'name)
|
|
||||||
(get a1 'city)
|
|
||||||
|
|
||||||
a procedure is a privimitive routine built-in to scheme.
|
|
||||||
a closure is an anonymous routine defined with lambda.
|
|
||||||
both can be bound to a variable in the environment.
|
|
||||||
|
|
||||||
a syntax is more primitive than a procedure.
|
|
||||||
a syntax is created as if it is a symbol but not registerd
|
|
||||||
into an environment
|
|
||||||
|
|
||||||
car cdr
|
|
||||||
| STR | PTR CHR ARR | -1 |
|
|
||||||
| PROC | PROCNUM | |
|
|
||||||
| SYM | REF STR | REF PROP LIST |
|
|
||||||
| SYN | REF STR | REF PROP LIST |
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
static qse_scm_ent_t* alloc_entity (
|
|
||||||
qse_scm_t* scm, qse_scm_ent_t* x, qse_scm_ent_t* y)
|
|
||||||
{
|
|
||||||
/* find a free value slot and return it.
|
|
||||||
* two parameters x and y are saved from garbage collection */
|
|
||||||
|
|
||||||
qse_scm_ent_t* v;
|
|
||||||
|
|
||||||
if (IS_NIL(scm->mem.free))
|
|
||||||
{
|
|
||||||
/* if no free slot is available */
|
|
||||||
gc (scm, x, y); /* perform garbage collection */
|
|
||||||
if (IS_NIL(scm->mem.free))
|
|
||||||
{
|
|
||||||
/* if no free slot is available after garbage collection,
|
|
||||||
* make new value blocks containing more free slots */
|
|
||||||
|
|
||||||
/* TODO: make the value block size configurable */
|
|
||||||
if (new_entity_block (scm, 1000) == QSE_NULL) return QSE_NULL;
|
|
||||||
QSE_ASSERT (scm->mem.free != scm->nil);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
v = scm->mem.free;
|
|
||||||
scm->mem.free = PAIR_CDR(v);
|
|
||||||
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
static qse_scm_ent_t* make_pair_entity (
|
|
||||||
qse_scm_t* scm, qse_scm_ent_t* car, qse_scm_ent_t* cdr)
|
|
||||||
{
|
|
||||||
qse_scm_ent_t* v;
|
|
||||||
|
|
||||||
v = alloc_entity (scm, car, cdr);
|
|
||||||
if (v == QSE_NULL) return QSE_NULL;
|
|
||||||
|
|
||||||
TYPE(v) = QSE_SCM_ENT_PAIR;
|
|
||||||
ATOM(v) = 0; /* a pair is not an atom as it references other entities */
|
|
||||||
PAIR_CAR(v) = car;
|
|
||||||
PAIR_CDR(v) = cdr;
|
|
||||||
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
static qse_scm_ent_t* make_number_entity (qse_scm_t* scm, qse_long_t val)
|
|
||||||
{
|
|
||||||
qse_scm_ent_t* v;
|
|
||||||
|
|
||||||
if (CAN_BE_SMALLINT(val)) return TO_SMALLINT(val);
|
|
||||||
|
|
||||||
v = alloc_entity (scm, QSE_NULL, QSE_NULL);
|
|
||||||
if (v == QSE_NULL) return QSE_NULL;
|
|
||||||
|
|
||||||
TYPE(v) = QSE_SCM_ENT_NUM;
|
|
||||||
ATOM(v) = 1;
|
|
||||||
NUM_VALUE(v) = val;
|
|
||||||
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
static qse_scm_ent_t* make_real_entity (qse_scm_t* scm, qse_long_t val)
|
|
||||||
{
|
|
||||||
qse_scm_ent_t* v;
|
|
||||||
|
|
||||||
v = alloc_entity (scm, QSE_NULL, QSE_NULL);
|
|
||||||
if (v == QSE_NULL) return QSE_NULL;
|
|
||||||
|
|
||||||
TYPE(v) = QSE_SCM_ENT_REAL;
|
|
||||||
ATOM(v) = 1;
|
|
||||||
REAL_VALUE(v) = val;
|
|
||||||
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
static qse_scm_ent_t* make_string_entity (
|
|
||||||
qse_scm_t* scm, const qse_char_t* str, qse_size_t len)
|
|
||||||
{
|
|
||||||
qse_scm_ent_t* v;
|
|
||||||
|
|
||||||
v = alloc_entity (scm, QSE_NULL, QSE_NULL);
|
|
||||||
if (v == QSE_NULL) return QSE_NULL;
|
|
||||||
|
|
||||||
TYPE(v) = QSE_SCM_ENT_STR;
|
|
||||||
ATOM(v) = 1;
|
|
||||||
/* TODO: allocate a string from internal managed region .
|
|
||||||
Calling strdup is not an option as it is not managed...
|
|
||||||
*/
|
|
||||||
STR_PTR(v) = qse_strxdup (str, len, QSE_MMGR(scm));
|
|
||||||
if (STR_PTR(v) == QSE_NULL)
|
|
||||||
{
|
|
||||||
qse_scm_seterror (scm, QSE_SCM_ENOMEM, QSE_NULL, QSE_NULL);
|
|
||||||
return QSE_NULL;
|
|
||||||
}
|
|
||||||
STR_LEN(v) = len;
|
|
||||||
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
static qse_scm_ent_t* make_name_entity (qse_scm_t* scm, const qse_char_t* str)
|
|
||||||
{
|
|
||||||
qse_scm_ent_t* v;
|
|
||||||
|
|
||||||
v = alloc_entity (scm, QSE_NULL, QSE_NULL);
|
|
||||||
if (v == QSE_NULL) return QSE_NULL;
|
|
||||||
|
|
||||||
TYPE(v) = QSE_SCM_ENT_NAM;
|
|
||||||
ATOM(v) = 1;
|
|
||||||
/* TODO: allocate a string from internal managed region .
|
|
||||||
Calling strdup is not an option as it is not managed...
|
|
||||||
*/
|
|
||||||
LAB_PTR(v) = qse_strdup (str, QSE_MMGR(scm));
|
|
||||||
if (LAB_PTR(v) == QSE_NULL)
|
|
||||||
{
|
|
||||||
qse_scm_seterror (scm, QSE_SCM_ENOMEM, QSE_NULL, QSE_NULL);
|
|
||||||
return QSE_NULL;
|
|
||||||
}
|
|
||||||
LAB_CODE(v) = 0;
|
|
||||||
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
static qse_scm_ent_t* make_symbol_entity (qse_scm_t* scm, const qse_char_t* name)
|
|
||||||
{
|
|
||||||
qse_scm_ent_t* pair, * sym, * nam;
|
|
||||||
|
|
||||||
/* TODO: use a hash table, red-black tree to maintain symbol table
|
|
||||||
* The current linear search algo is not performance friendly...
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* find if the symbol already exists by traversing the pair list
|
|
||||||
* and inspecting the symbol name pointed to by CAR of each pair.
|
|
||||||
*
|
|
||||||
* the symbol table is a list of pairs whose CAR points to a symbol
|
|
||||||
* and CDR is used for chaining.
|
|
||||||
*
|
|
||||||
* +-----+-----+
|
|
||||||
* | | |
|
|
||||||
* +-----+-----+
|
|
||||||
* car | | cdr +-----+-----+
|
|
||||||
* | +----------> | | |
|
|
||||||
* V +-----+-----+
|
|
||||||
* +--------+ car |
|
|
||||||
* | symbol | V
|
|
||||||
* +--------+ +--------+
|
|
||||||
* | symbol |
|
|
||||||
* +--------+
|
|
||||||
*/
|
|
||||||
for (pair = scm->symtab; !IS_NIL(pair); pair = PAIR_CDR(pair))
|
|
||||||
{
|
|
||||||
sym = PAIR_CAR(pair);
|
|
||||||
if (qse_strcmp(name, LAB_PTR(SYM_NAME(sym))) == 0) return sym;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* no existing symbol with such a name is found.
|
|
||||||
* let's create a new symbol. the first step is to create a
|
|
||||||
* string entity to contain the symbol name */
|
|
||||||
nam = make_name_entity (scm, name);
|
|
||||||
if (nam == QSE_NULL) return QSE_NULL;
|
|
||||||
|
|
||||||
/* let's allocate the actual symbol entity that references the
|
|
||||||
* the symbol name entity created above */
|
|
||||||
sym = alloc_entity (scm, nam, QSE_NULL);
|
|
||||||
if (sym == QSE_NULL) return QSE_NULL;
|
|
||||||
TYPE(sym) = QSE_SCM_ENT_SYM;
|
|
||||||
ATOM(sym) = 0;
|
|
||||||
SYM_NAME(sym) = nam;
|
|
||||||
SYM_PROP(sym) = scm->nil; /* no properties yet */
|
|
||||||
|
|
||||||
/* chain the symbol entity to the symbol table for lookups later */
|
|
||||||
pair = make_pair_entity (scm, sym, scm->symtab);
|
|
||||||
if (pair == QSE_NULL) return QSE_NULL;
|
|
||||||
scm->symtab = pair;
|
|
||||||
|
|
||||||
return sym;
|
|
||||||
}
|
|
||||||
|
|
||||||
static qse_scm_ent_t* make_syntax_entity (
|
|
||||||
qse_scm_t* scm, const qse_char_t* name, int code)
|
|
||||||
{
|
|
||||||
qse_scm_ent_t* v;
|
|
||||||
|
|
||||||
QSE_ASSERTX (code > 0, "Syntax code must be greater than 0");
|
|
||||||
|
|
||||||
v = make_symbol_entity (scm, name);
|
|
||||||
if (v == QSE_NULL) return QSE_NULL;
|
|
||||||
|
|
||||||
/* We piggy-back the syntax code to a symbol name.
|
|
||||||
* The syntax entity is basically a symbol except that the
|
|
||||||
* code field of its label entity is set to non-zero.
|
|
||||||
* Read the comment in make_procedure_entity() for difference between
|
|
||||||
* the syntax entity and the procedure entity.
|
|
||||||
*/
|
|
||||||
TYPE(v) |= QSE_SCM_ENT_SYNT;
|
|
||||||
SYNT_CODE(v) = code;
|
|
||||||
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
static qse_scm_ent_t* make_procedure_entity (
|
|
||||||
qse_scm_t* scm, const qse_char_t* name, int code)
|
|
||||||
{
|
|
||||||
qse_scm_ent_t* sym, * proc, * pair;
|
|
||||||
|
|
||||||
/* A procedure entity is a built-in function that can be
|
|
||||||
* overridden by a user while a syntax entity represents a
|
|
||||||
* lower-level syntactic function that can't be overridden.
|
|
||||||
*
|
|
||||||
* (define lambda 10) is legal but does not change the
|
|
||||||
* meaning of lambda when used as a function name.
|
|
||||||
*
|
|
||||||
* (define tail 10) changes the meaning of eval totally.
|
|
||||||
* (tail '(1 2 3)) is not legal from now on.
|
|
||||||
*
|
|
||||||
* (define x lambda) is illegal as the lambda symbol
|
|
||||||
*
|
|
||||||
* (define lambda 10) followed by (define x lambda) lets the x symbol
|
|
||||||
* to be associated with 10 but you still can use lambda to create
|
|
||||||
* a closure as in ((lambda (x) (+ x 10)) 50)
|
|
||||||
*
|
|
||||||
* (define x tail) lets the 'x' symbol point to the eval procedure.
|
|
||||||
* (x '(1 2 3)) returns (2 3).
|
|
||||||
*
|
|
||||||
* We implement the syntax entity as a symbol itself by ORing
|
|
||||||
* the TYPE field with QSE_SCM_ENT_SYNT and setting the syntax
|
|
||||||
* code in the symbol label entity.
|
|
||||||
*
|
|
||||||
* A procedure entity is an independent entity unlike the syntax
|
|
||||||
* entity. We explicitly create a symbol entity for the procedure name
|
|
||||||
* and associate it with the procedure entity in the global environment.
|
|
||||||
* If you redefine the symbol name to be something else, you won't be
|
|
||||||
* able to reference the procedure entity with the name. Worst case,
|
|
||||||
* it may be GCed out.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* create a symbol containing the name */
|
|
||||||
sym = make_symbol_entity (scm, name);
|
|
||||||
if (sym == QSE_NULL) return QSE_NULL;
|
|
||||||
|
|
||||||
/* create an actual procedure value which is a number containing
|
|
||||||
* the opcode for the procedure */
|
|
||||||
proc = alloc_entity (scm, sym, QSE_NULL);
|
|
||||||
if (proc == QSE_NULL) return QSE_NULL;
|
|
||||||
TYPE(proc) = QSE_SCM_ENT_PROC;
|
|
||||||
ATOM(proc) = 1;
|
|
||||||
PROC_CODE(proc) = code;
|
|
||||||
|
|
||||||
/* create a pair containing the name symbol and the procedure value */
|
|
||||||
pair = make_pair_entity (scm, sym, proc);
|
|
||||||
if (pair == QSE_NULL) return QSE_NULL;
|
|
||||||
|
|
||||||
/* link it to the global environment */
|
|
||||||
pair = make_pair_entity (scm, pair, PAIR_CAR(scm->gloenv));
|
|
||||||
if (pair == QSE_NULL) return QSE_NULL;
|
|
||||||
PAIR_CAR(scm->gloenv) = pair;
|
|
||||||
|
|
||||||
return proc;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define MAKE_SYNTAX_ENTITY(scm,name,code) QSE_BLOCK( \
|
#define MAKE_SYNTAX_ENTITY(scm,name,code) QSE_BLOCK( \
|
||||||
if (make_syntax_entity (scm, name, code) == QSE_NULL) return -1; \
|
if (qse_scm_makesyntent (scm, name, code) == QSE_NULL) return -1; \
|
||||||
)
|
)
|
||||||
|
|
||||||
static int build_syntax_entities (qse_scm_t* scm)
|
static int build_syntax_entities (qse_scm_t* scm)
|
||||||
{
|
{
|
||||||
qse_scm_ent_t* v;
|
qse_scm_ent_t* v;
|
||||||
|
|
||||||
v = make_syntax_entity (scm, QSE_T("lambda"), 1);
|
v = qse_scm_makesyntent (scm, QSE_T("lambda"), 1);
|
||||||
if (v == QSE_NULL) return -1;
|
if (v == QSE_NULL) return -1;
|
||||||
scm->lambda = v;
|
scm->lambda = v;
|
||||||
|
|
||||||
v = make_syntax_entity (scm, QSE_T("quote"), 2);
|
v = qse_scm_makesyntent (scm, QSE_T("quote"), 2);
|
||||||
if (v == QSE_NULL) return -1;
|
if (v == QSE_NULL) return -1;
|
||||||
scm->quote = v;
|
scm->quote = v;
|
||||||
|
|
||||||
@ -726,8 +197,8 @@ static qse_scm_t* qse_scm_init (
|
|||||||
scm->mem.ebl = QSE_NULL;
|
scm->mem.ebl = QSE_NULL;
|
||||||
scm->mem.free = scm->nil;
|
scm->mem.free = scm->nil;
|
||||||
|
|
||||||
/* initialize all the key data to nil before make_pair_entity()
|
/* initialize all the key data to nil before qse_scm_makepairent()
|
||||||
* below. make_pair_entity() calls alloc_entity() that invokes
|
* below. qse_scm_makepairent() calls alloc_entity() that invokes
|
||||||
* gc() as this is the first time. As gc() marks all the key data,
|
* gc() as this is the first time. As gc() marks all the key data,
|
||||||
* we need to initialize these to nil. */
|
* we need to initialize these to nil. */
|
||||||
scm->reg.arg = scm->nil;
|
scm->reg.arg = scm->nil;
|
||||||
@ -741,7 +212,7 @@ static qse_scm_t* qse_scm_init (
|
|||||||
scm->r.e = scm->nil;
|
scm->r.e = scm->nil;
|
||||||
|
|
||||||
/* build the global environment entity as a pair */
|
/* build the global environment entity as a pair */
|
||||||
scm->gloenv = make_pair_entity (scm, scm->nil, scm->nil);
|
scm->gloenv = qse_scm_makepairent (scm, scm->nil, scm->nil);
|
||||||
if (scm->gloenv == QSE_NULL) goto oops;
|
if (scm->gloenv == QSE_NULL) goto oops;
|
||||||
|
|
||||||
/* update the current environment to the global environment */
|
/* update the current environment to the global environment */
|
||||||
@ -1259,7 +730,7 @@ static QSE_INLINE qse_scm_ent_t* push (qse_scm_t* scm, qse_scm_ent_t* obj)
|
|||||||
{
|
{
|
||||||
qse_scm_ent_t* pair;
|
qse_scm_ent_t* pair;
|
||||||
|
|
||||||
pair = make_pair_entity (scm, obj, scm->r.s);
|
pair = qse_scm_makepairent (scm, obj, scm->r.s);
|
||||||
if (pair == QSE_NULL) return QSE_NULL;
|
if (pair == QSE_NULL) return QSE_NULL;
|
||||||
|
|
||||||
scm->r.s = pair;
|
scm->r.s = pair;
|
||||||
@ -1271,7 +742,7 @@ static QSE_INLINE qse_scm_ent_t* push (qse_scm_t* scm, qse_scm_ent_t* obj)
|
|||||||
static QSE_INLINE_ALWAYS void pop (qse_scm_t* scm)
|
static QSE_INLINE_ALWAYS void pop (qse_scm_t* scm)
|
||||||
{
|
{
|
||||||
QSE_ASSERTX (
|
QSE_ASSERTX (
|
||||||
!IS_NIL(scm->r.s),
|
!IS_NIL(scm,scm->r.s),
|
||||||
"You've called pop() more times than push()"
|
"You've called pop() more times than push()"
|
||||||
);
|
);
|
||||||
scm->r.s = PAIR_CDR(scm->r.s);
|
scm->r.s = PAIR_CDR(scm->r.s);
|
||||||
@ -1304,7 +775,7 @@ static QSE_INLINE qse_scm_ent_t* enter_list (qse_scm_t* scm, int flagv)
|
|||||||
* nil#2 to store the last element in the list.
|
* nil#2 to store the last element in the list.
|
||||||
* both to be updated in chain_to_list() as items are added.
|
* both to be updated in chain_to_list() as items are added.
|
||||||
*/
|
*/
|
||||||
return (push (scm, TO_SMALLINT(flagv)) == QSE_NULL ||
|
return (push (scm, TO_SMALLINT(scm,flagv)) == QSE_NULL ||
|
||||||
push (scm, scm->nil) == QSE_NULL ||
|
push (scm, scm->nil) == QSE_NULL ||
|
||||||
push (scm, scm->nil) == QSE_NULL)? QSE_NULL: scm->r.s;
|
push (scm, scm->nil) == QSE_NULL)? QSE_NULL: scm->r.s;
|
||||||
}
|
}
|
||||||
@ -1315,7 +786,7 @@ static QSE_INLINE_ALWAYS qse_scm_ent_t* leave_list (qse_scm_t* scm, int* flagv)
|
|||||||
|
|
||||||
/* the stack must not be empty */
|
/* the stack must not be empty */
|
||||||
QSE_ASSERTX (
|
QSE_ASSERTX (
|
||||||
!IS_NIL(scm->r.s),
|
!IS_NIL(scm,scm->r.s),
|
||||||
"You cannot leave a list without entering it"
|
"You cannot leave a list without entering it"
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -1327,7 +798,7 @@ static QSE_INLINE_ALWAYS qse_scm_ent_t* leave_list (qse_scm_t* scm, int* flagv)
|
|||||||
pop (scm);
|
pop (scm);
|
||||||
pop (scm);
|
pop (scm);
|
||||||
|
|
||||||
if (IS_NIL(scm->r.s))
|
if (IS_NIL(scm,scm->r.s))
|
||||||
{
|
{
|
||||||
/* the stack is empty after popping.
|
/* the stack is empty after popping.
|
||||||
* it is back to the top level.
|
* it is back to the top level.
|
||||||
@ -1351,12 +822,12 @@ static QSE_INLINE_ALWAYS void dot_list (qse_scm_t* scm)
|
|||||||
qse_scm_ent_t* pair;
|
qse_scm_ent_t* pair;
|
||||||
int flagv;
|
int flagv;
|
||||||
|
|
||||||
QSE_ASSERT (!IS_NIL(scm->r.s));
|
QSE_ASSERT (!IS_NIL(scm,scm->r.s));
|
||||||
|
|
||||||
/* mark the state that a dot has appeared in the list */
|
/* mark the state that a dot has appeared in the list */
|
||||||
pair = PAIR_CDR(PAIR_CDR(scm->r.s));
|
pair = PAIR_CDR(PAIR_CDR(scm->r.s));
|
||||||
flagv = FROM_SMALLINT(PAIR_CAR(pair));
|
flagv = FROM_SMALLINT(scm,PAIR_CAR(pair));
|
||||||
PAIR_CAR(pair) = TO_SMALLINT(flagv | DOTTED);
|
PAIR_CAR(pair) = TO_SMALLINT(scm,flagv|DOTTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
static qse_scm_ent_t* chain_to_list (qse_scm_t* scm, qse_scm_ent_t* obj)
|
static qse_scm_ent_t* chain_to_list (qse_scm_t* scm, qse_scm_ent_t* obj)
|
||||||
@ -1366,20 +837,20 @@ static qse_scm_ent_t* chain_to_list (qse_scm_t* scm, qse_scm_ent_t* obj)
|
|||||||
|
|
||||||
/* the stack top is the pair pointing to the list tail */
|
/* the stack top is the pair pointing to the list tail */
|
||||||
tail = scm->r.s;
|
tail = scm->r.s;
|
||||||
QSE_ASSERT (!IS_NIL(tail));
|
QSE_ASSERT (!IS_NIL(scm,tail));
|
||||||
|
|
||||||
/* the pair pointing to the list head is below the tail cell
|
/* the pair pointing to the list head is below the tail cell
|
||||||
* connected via cdr. */
|
* connected via cdr. */
|
||||||
head = PAIR_CDR(tail);
|
head = PAIR_CDR(tail);
|
||||||
QSE_ASSERT (!IS_NIL(head));
|
QSE_ASSERT (!IS_NIL(scm,head));
|
||||||
|
|
||||||
/* the pair pointing to the flag is below the head cell
|
/* the pair pointing to the flag is below the head cell
|
||||||
* connected via cdr */
|
* connected via cdr */
|
||||||
flag = PAIR_CDR(head);
|
flag = PAIR_CDR(head);
|
||||||
|
|
||||||
/* retrieve the numeric flag value */
|
/* retrieve the numeric flag value */
|
||||||
QSE_ASSERT(IS_SMALLINT(PAIR_CAR(flag)));
|
QSE_ASSERT(IS_SMALLINT(scm,PAIR_CAR(flag)));
|
||||||
flagv = (int)FROM_SMALLINT(PAIR_CAR(flag));
|
flagv = (int)FROM_SMALLINT(scm,PAIR_CAR(flag));
|
||||||
|
|
||||||
if (flagv & CLOSED)
|
if (flagv & CLOSED)
|
||||||
{
|
{
|
||||||
@ -1390,18 +861,18 @@ static qse_scm_ent_t* chain_to_list (qse_scm_t* scm, qse_scm_ent_t* obj)
|
|||||||
else if (flagv & DOTTED)
|
else if (flagv & DOTTED)
|
||||||
{
|
{
|
||||||
/* the list must not be empty to have reached the dotted state */
|
/* the list must not be empty to have reached the dotted state */
|
||||||
QSE_ASSERT (!IS_NIL(PAIR_CAR(tail)));
|
QSE_ASSERT (!IS_NIL(scm,PAIR_CAR(tail)));
|
||||||
|
|
||||||
/* chain the object via 'cdr' of the tail cell */
|
/* chain the object via 'cdr' of the tail cell */
|
||||||
PAIR_CDR(PAIR_CAR(tail)) = obj;
|
PAIR_CDR(PAIR_CAR(tail)) = obj;
|
||||||
|
|
||||||
/* update the flag to CLOSED so that you can have more than
|
/* update the flag to CLOSED so that you can have more than
|
||||||
* one item after the dot. */
|
* one item after the dot. */
|
||||||
PAIR_CAR(flag) = TO_SMALLINT(flagv | CLOSED);
|
PAIR_CAR(flag) = TO_SMALLINT(scm,flagv|CLOSED);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cell = make_pair_entity (scm, obj, scm->nil);
|
cell = qse_scm_makepairent (scm, obj, scm->nil);
|
||||||
if (cell == QSE_NULL) return QSE_NULL;
|
if (cell == QSE_NULL) return QSE_NULL;
|
||||||
|
|
||||||
if (PAIR_CAR(head) == scm->nil)
|
if (PAIR_CAR(head) == scm->nil)
|
||||||
@ -1429,12 +900,12 @@ static QSE_INLINE_ALWAYS int is_list_empty (qse_scm_t* scm)
|
|||||||
{
|
{
|
||||||
/* the stack must not be empty */
|
/* the stack must not be empty */
|
||||||
QSE_ASSERTX (
|
QSE_ASSERTX (
|
||||||
!IS_NIL(scm->r.s),
|
!IS_NIL(scm,scm->r.s),
|
||||||
"You can not call this function while the stack is empty"
|
"You can not call this function while the stack is empty"
|
||||||
);
|
);
|
||||||
|
|
||||||
/* if the tail pointer is pointing to nil, the list is empty */
|
/* if the tail pointer is pointing to nil, the list is empty */
|
||||||
return IS_NIL(PAIR_CAR(scm->r.s));
|
return IS_NIL(scm,PAIR_CAR(scm->r.s));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int read_entity (qse_scm_t* scm)
|
static int read_entity (qse_scm_t* scm)
|
||||||
@ -1563,20 +1034,20 @@ static int read_entity (qse_scm_t* scm)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case TOK_INT:
|
case TOK_INT:
|
||||||
obj = make_number_entity (scm, TOK_IVAL(scm));
|
obj = qse_scm_makenument (scm, TOK_IVAL(scm));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOK_REAL:
|
case TOK_REAL:
|
||||||
obj = make_real_entity (scm, TOK_RVAL(scm));
|
obj = qse_scm_makerealent (scm, TOK_RVAL(scm));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOK_STRING:
|
case TOK_STRING:
|
||||||
obj = make_string_entity (
|
obj = qse_scm_makestrent (
|
||||||
scm, TOK_NAME_PTR(scm), TOK_NAME_LEN(scm));
|
scm, TOK_NAME_PTR(scm), TOK_NAME_LEN(scm));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOK_SYMBOL:
|
case TOK_SYMBOL:
|
||||||
obj = make_symbol_entity (scm, TOK_NAME_PTR(scm));
|
obj = qse_scm_makesyment (scm, TOK_NAME_PTR(scm));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,6 +208,13 @@ struct qse_scm_t
|
|||||||
} mem;
|
} mem;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define IS_NIL(scm,ent) QSE_SCM_ENT_ISNIL(scm,ent)
|
||||||
|
#define IS_SMALLINT(scm,ent) QSE_SCM_ENT_ISSMALLINT(scm,ent)
|
||||||
|
#define FROM_SMALLINT(scm,ent) QSE_SCM_ENT_FROMSMALLINT(scm,ent)
|
||||||
|
#define TO_SMALLINT(scm,num) QSE_SCM_ENT_TOSMALLINT(scm,num)
|
||||||
|
#define CAN_BE_SMALLINT(scm,num) QSE_SCM_ENT_CANBESMALLINT(scm,num)
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
@ -218,4 +225,5 @@ const qse_char_t* qse_scm_dflerrstr (qse_scm_t* scm, qse_scm_errnum_t errnum);
|
|||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user