added more code for scm
This commit is contained in:
		| @ -111,6 +111,7 @@ DEFS = @DEFS@ | ||||
| DEPDIR = @DEPDIR@ | ||||
| DSYMUTIL = @DSYMUTIL@ | ||||
| DUMPBIN = @DUMPBIN@ | ||||
| ECHO = @ECHO@ | ||||
| ECHO_C = @ECHO_C@ | ||||
| ECHO_N = @ECHO_N@ | ||||
| ECHO_T = @ECHO_T@ | ||||
|  | ||||
| @ -138,6 +138,7 @@ DEFS = @DEFS@ | ||||
| DEPDIR = @DEPDIR@ | ||||
| DSYMUTIL = @DSYMUTIL@ | ||||
| DUMPBIN = @DUMPBIN@ | ||||
| ECHO = @ECHO@ | ||||
| ECHO_C = @ECHO_C@ | ||||
| ECHO_N = @ECHO_N@ | ||||
| ECHO_T = @ECHO_T@ | ||||
|  | ||||
| @ -140,6 +140,7 @@ DEFS = @DEFS@ | ||||
| DEPDIR = @DEPDIR@ | ||||
| DSYMUTIL = @DSYMUTIL@ | ||||
| DUMPBIN = @DUMPBIN@ | ||||
| ECHO = @ECHO@ | ||||
| ECHO_C = @ECHO_C@ | ||||
| ECHO_N = @ECHO_N@ | ||||
| ECHO_T = @ECHO_T@ | ||||
|  | ||||
| @ -90,6 +90,20 @@ void qse_assert_failed ( | ||||
|  | ||||
| 	qse_sio_puts (QSE_SIO_ERR, QSE_T("=[ASSERTION FAILURE]============================================================\n")); | ||||
|  | ||||
| #if 1 | ||||
| 	qse_sio_puts (QSE_SIO_ERR, QSE_T("                         __ \n")); | ||||
| 	qse_sio_puts (QSE_SIO_ERR, QSE_T(" _____ _____ _____ _____|  |\n")); | ||||
| 	qse_sio_puts (QSE_SIO_ERR, QSE_T("|     |     |  _  |   __|  |\n")); | ||||
| 	qse_sio_puts (QSE_SIO_ERR, QSE_T("|  |  |  |  |   __|__   |__|\n")); | ||||
| 	qse_sio_puts (QSE_SIO_ERR, QSE_T("|_____|_____|__|  |_____|__|\n")); | ||||
| #else | ||||
| 	qse_sio_puts (QSE_SIO_ERR, QSE_T("                            __ \n")); | ||||
| 	qse_sio_puts (QSE_SIO_ERR, QSE_T(" _____ _____ _____ _____   |  |\n")); | ||||
| 	qse_sio_puts (QSE_SIO_ERR, QSE_T("|     |     |  _  |   __|  |  |\n")); | ||||
| 	qse_sio_puts (QSE_SIO_ERR, QSE_T("|  |  |  |  |   __|__   |  |__|\n")); | ||||
| 	qse_sio_puts (QSE_SIO_ERR, QSE_T("|_____|_____|__|  |_____|  |__|\n")); | ||||
| #endif | ||||
|  | ||||
| 	qse_sio_puts (QSE_SIO_ERR, QSE_T("FILE ")); | ||||
| 	qse_sio_puts (QSE_SIO_ERR, file); | ||||
| 	qse_sio_puts (QSE_SIO_ERR, QSE_T(" LINE ")); | ||||
|  | ||||
| @ -136,6 +136,7 @@ DEFS = @DEFS@ | ||||
| DEPDIR = @DEPDIR@ | ||||
| DSYMUTIL = @DSYMUTIL@ | ||||
| DUMPBIN = @DUMPBIN@ | ||||
| ECHO = @ECHO@ | ||||
| ECHO_C = @ECHO_C@ | ||||
| ECHO_N = @ECHO_N@ | ||||
| ECHO_T = @ECHO_T@ | ||||
|  | ||||
| @ -117,6 +117,7 @@ DEFS = @DEFS@ | ||||
| DEPDIR = @DEPDIR@ | ||||
| DSYMUTIL = @DSYMUTIL@ | ||||
| DUMPBIN = @DUMPBIN@ | ||||
| ECHO = @ECHO@ | ||||
| ECHO_C = @ECHO_C@ | ||||
| ECHO_N = @ECHO_N@ | ||||
| ECHO_T = @ECHO_T@ | ||||
|  | ||||
| @ -18,7 +18,7 @@ | ||||
|     License along with QSE. If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| #include <qse/utl/http.h> | ||||
| #include <qse/http/http.h> | ||||
| #include <qse/cmn/chr.h> | ||||
| #include "../cmn/mem.h" | ||||
|  | ||||
| @ -229,11 +229,13 @@ qse_http_t* qse_http_init (qse_http_t* http, qse_mmgr_t* mmgr) | ||||
|  | ||||
| 	init_buffer (http, &http->reqx.b.raw); | ||||
| 	init_buffer (http, &http->reqx.b.tra); | ||||
| 	init_buffer (http, &http->reqx.b.pen); | ||||
| 	init_buffer (http, &http->req.con); | ||||
|  | ||||
| 	if (qse_htb_init (&http->req.hdrtab, mmgr, 60, 70, 1, 1) == QSE_NULL)  | ||||
| 	{ | ||||
| 		fini_buffer (http, &http->req.con); | ||||
| 		fini_buffer (http, &http->reqx.b.pen); | ||||
| 		fini_buffer (http, &http->reqx.b.tra); | ||||
| 		fini_buffer (http, &http->reqx.b.raw); | ||||
| 		return QSE_NULL; | ||||
| @ -247,6 +249,7 @@ void qse_http_fini (qse_http_t* http) | ||||
| 	qse_htb_fini (&http->req.hdrtab); | ||||
| 	clear_combined_headers (http); | ||||
| 	fini_buffer (http, &http->req.con); | ||||
| 	fini_buffer (http, &http->reqx.b.pen); | ||||
| 	fini_buffer (http, &http->reqx.b.tra); | ||||
| 	fini_buffer (http, &http->reqx.b.raw); | ||||
| } | ||||
| @ -993,8 +996,21 @@ int qse_http_feed (qse_http_t* http, const qse_byte_t* req, qse_size_t len) | ||||
| 	const qse_byte_t* end = req + len; | ||||
| 	const qse_byte_t* ptr = req; | ||||
|  | ||||
| #if 0 | ||||
| 	if (http->reqx.pending) | ||||
| 	{ | ||||
| 	}	 | ||||
| #endif | ||||
|  | ||||
| 	/* does this goto drop code maintainability? */ | ||||
| 	if (http->reqx.s.need > 0) goto content_resume; | ||||
| 	if (http->reqx.s.need > 0)  | ||||
| 	{ | ||||
| 		/* we're in need of as many octets as http->reqx.s.need  | ||||
| 		 * for contents body. make a proper jump to resume | ||||
| 		 * content handling */ | ||||
| 		goto content_resume; | ||||
| 	} | ||||
|  | ||||
| 	switch (http->reqx.s.chunk.phase) | ||||
| 	{ | ||||
| 		case GET_CHUNK_LEN: | ||||
| @ -1099,14 +1115,16 @@ int qse_http_feed (qse_http_t* http, const qse_byte_t* req, qse_size_t len) | ||||
| 					} | ||||
| 					else | ||||
| 					{ | ||||
| 						/* we need to read as many octets as Content-Length */ | ||||
| 						/* we need to read as many octets as | ||||
| 						 * Content-Length */ | ||||
| 						http->reqx.s.need = http->req.attr.content_length; | ||||
| 					} | ||||
|  | ||||
| 					if (http->reqx.s.need > 0) | ||||
| 					{ | ||||
| 						/* content-length or chunked data length specified */ | ||||
| 	 | ||||
| 						/* content-length or chunked data length  | ||||
| 						 * specified */ | ||||
|  | ||||
| 						qse_size_t avail; | ||||
| 	 | ||||
| 					content_resume: | ||||
| @ -1230,3 +1248,19 @@ feedme_more: | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int qse_http_addtext (qse_http_t* http, const qse_byte_t* ptr, qse_size_t len) | ||||
| { | ||||
| } | ||||
|  | ||||
| int qse_http_addresource (qse_http_t* http, const void* ptr, qse_size_t len) | ||||
| { | ||||
| } | ||||
|  | ||||
| int qse_http_addheader ( | ||||
| 	qse_http_t* http, const qse_byte_t* key, const qse_byte_t* val) | ||||
| { | ||||
| } | ||||
|  | ||||
| int qse_http_emit (qse_http_t* http) | ||||
| { | ||||
| } | ||||
|  | ||||
| @ -117,6 +117,7 @@ DEFS = @DEFS@ | ||||
| DEPDIR = @DEPDIR@ | ||||
| DSYMUTIL = @DSYMUTIL@ | ||||
| DUMPBIN = @DUMPBIN@ | ||||
| ECHO = @ECHO@ | ||||
| ECHO_C = @ECHO_C@ | ||||
| ECHO_N = @ECHO_N@ | ||||
| ECHO_T = @ECHO_T@ | ||||
|  | ||||
| @ -22,6 +22,8 @@ | ||||
|  | ||||
| QSE_IMPLEMENT_COMMON_FUNCTIONS (scm) | ||||
|  | ||||
| #define IS_NIL(x) ((x) != scm->nil) | ||||
|  | ||||
| static qse_scm_t* qse_scm_init ( | ||||
| 	qse_scm_t*  scm, | ||||
| 	qse_mmgr_t* mmgr, | ||||
| @ -29,9 +31,15 @@ static qse_scm_t* qse_scm_init ( | ||||
| 	qse_size_t  mem_ubound_inc | ||||
| ); | ||||
|  | ||||
| static void qse_scm_fini (qse_scm_t* scm); | ||||
| static qse_scm_val_t* mkcons ( | ||||
| 	qse_scm_t* scm, qse_scm_val_t* car, qse_scm_val_t* cdr); | ||||
| static void qse_scm_fini ( | ||||
| 	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_mmgr_t* mmgr, qse_size_t xtnsize, | ||||
| @ -71,11 +79,11 @@ void qse_scm_close (qse_scm_t* scm) | ||||
|  | ||||
| static QSE_INLINE void delete_all_value_blocks (qse_scm_t* scm) | ||||
| { | ||||
| 	while (scm->mem.vbl) | ||||
| 	while (scm->mem.ebl) | ||||
| 	{ | ||||
| 		qse_scm_vbl_t* vbl = scm->mem.vbl; | ||||
| 		scm->mem.vbl = scm->mem.vbl->next; | ||||
| 		QSE_MMGR_FREE (scm->mmgr, vbl); | ||||
| 		qse_scm_enb_t* enb = scm->mem.ebl; | ||||
| 		scm->mem.ebl = scm->mem.ebl->next; | ||||
| 		QSE_MMGR_FREE (scm->mmgr, enb); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -83,17 +91,17 @@ static qse_scm_t* qse_scm_init ( | ||||
| 	qse_scm_t* scm, qse_mmgr_t* mmgr,  | ||||
| 	qse_size_t mem_ubound, qse_size_t mem_ubound_inc) | ||||
| { | ||||
| #if 0 | ||||
| 	static qse_scm_val_t static_values[3] = | ||||
| 	static qse_scm_ent_t static_values[3] = | ||||
| 	{ | ||||
| 		/* dswcount, mark, atom, type */ | ||||
|  | ||||
| 		/* nil */ | ||||
| 		{ (QSE_SCM_VAL_ATOM | QSE_SCM_VAL_MARK) }, | ||||
| 		{ 0, 1, 1, QSE_SCM_ENT_NIL }, | ||||
| 		/* f */ | ||||
| 		{ (QSE_SCM_VAL_ATOM | QSE_SCM_VAL_MARK) }, | ||||
| 		{ 0, 1, 1, QSE_SCM_ENT_T },  | ||||
| 		/* t */ | ||||
| 		{ (QSE_SCM_VAL_ATOM | QSE_SCM_VAL_MARK) } | ||||
| 		{ 0, 1, 1, QSE_SCM_ENT_F } | ||||
| 	}; | ||||
| #endif | ||||
|  | ||||
| 	if (mmgr == QSE_NULL) mmgr = QSE_MMGR_GETDFL(); | ||||
|  | ||||
| @ -119,17 +127,15 @@ static qse_scm_t* qse_scm_init ( | ||||
| 		return QSE_NULL; | ||||
| 	} | ||||
|  | ||||
| #if 0 | ||||
| 	/* initialize common values */ | ||||
| 	scm->nil = &static_values[0]; | ||||
| 	scm->f = &static_values[1]; | ||||
| 	scm->t = &static_values[2]; | ||||
| #endif | ||||
| 	scm->f   = &static_values[1]; | ||||
| 	scm->t   = &static_values[2]; | ||||
|  | ||||
| 	scm->mem.vbl = QSE_NULL; | ||||
| 	scm->mem.ebl = QSE_NULL; | ||||
| 	scm->mem.free = scm->nil; | ||||
|  | ||||
| 	scm->genv = mkcons (scm, scm->nil, scm->nil); | ||||
| 	scm->genv = make_pair_entity (scm, scm->nil, scm->nil); | ||||
| 	if (scm->genv == QSE_NULL) | ||||
| 	{ | ||||
| 		delete_all_value_blocks (scm); | ||||
| @ -138,6 +144,8 @@ static qse_scm_t* qse_scm_init ( | ||||
| 		return QSE_NULL; | ||||
| 	} | ||||
|  | ||||
| 	scm->symtab = scm->nil; | ||||
|  | ||||
| 	scm->reg.dmp = scm->nil; | ||||
| 	scm->reg.env = scm->genv; | ||||
|  | ||||
| @ -186,7 +194,7 @@ int qse_scm_attachio (qse_scm_t* scm, qse_scm_io_t* io) | ||||
| 	if (io->out (scm, QSE_SCM_IO_OPEN, &scm->io.arg.out, QSE_NULL, 0) <= -1) | ||||
| 	{ | ||||
| 		if (scm->err.num == QSE_SCM_ENOERR) | ||||
| 			qse_scm_seterror (scm,QSE_SCM_EIO, QSE_NULL, QSE_NULL); | ||||
| 			qse_scm_seterror (scm, QSE_SCM_EIO, QSE_NULL, QSE_NULL); | ||||
| 		io->in (scm, QSE_SCM_IO_CLOSE, &scm->io.arg.in, QSE_NULL, 0); | ||||
| 		return -1; | ||||
| 	} | ||||
| @ -199,60 +207,50 @@ int qse_scm_attachio (qse_scm_t* scm, qse_scm_io_t* io) | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static qse_scm_vbl_t* newvbl (qse_scm_t* scm, qse_size_t len) | ||||
| static qse_scm_enb_t* new_entity_block (qse_scm_t* scm, qse_size_t len) | ||||
| { | ||||
| 	/*  | ||||
| 	 * create a new value block containing as many slots as len | ||||
| 	 */ | ||||
|  | ||||
| 	qse_scm_vbl_t* blk; | ||||
| 	qse_scm_val_t* v; | ||||
| 	qse_scm_enb_t* blk; | ||||
| 	qse_scm_ent_t* v; | ||||
| 	qse_size_t i; | ||||
|  | ||||
| 	blk = (qse_scm_vbl_t*) QSE_MMGR_ALLOC ( | ||||
| 	blk = (qse_scm_enb_t*) QSE_MMGR_ALLOC ( | ||||
| 		scm->mmgr,  | ||||
| 		QSE_SIZEOF(qse_scm_vbl_t) +  | ||||
| 		QSE_SIZEOF(qse_scm_val_t) * len | ||||
| 		QSE_SIZEOF(qse_scm_enb_t) +  | ||||
| 		QSE_SIZEOF(qse_scm_ent_t) * len | ||||
| 	); | ||||
| 	if (blk == QSE_NULL) | ||||
| 	{ | ||||
| 		scm->err.num = QSE_SCM_ENOMEM; | ||||
| 		qse_scm_seterror (scm, QSE_SCM_ENOMEM, QSE_NULL, QSE_NULL); | ||||
| 		return QSE_NULL; | ||||
| 	} | ||||
|  | ||||
| 	/* initialize the block fields */ | ||||
| 	blk->ptr = (qse_scm_val_t*)(blk + 1); | ||||
| 	blk->ptr = (qse_scm_ent_t*)(blk + 1); | ||||
| 	blk->len = len; | ||||
|  | ||||
| 	/* chain the value block to the block list */ | ||||
| 	blk->next = scm->mem.vbl; | ||||
| 	scm->mem.vbl = blk; | ||||
| 	blk->next = scm->mem.ebl; | ||||
| 	scm->mem.ebl = blk; | ||||
|  | ||||
| 	/* chain each slot to the free slot list */ | ||||
| 	/* 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_val_t* tmp = v++; | ||||
| 		tmp->u.cons.cdr = v; | ||||
| 		qse_scm_ent_t* tmp = v++; | ||||
| 		PAIR_CDR(tmp) = v; | ||||
| 	} | ||||
| 	v->u.cons.cdr = scm->mem.free; | ||||
| 	PAIR_CDR(v) = scm->mem.free; | ||||
| 	scm->mem.free = &blk->ptr[0]; | ||||
|  | ||||
| 	return blk; | ||||
| }; | ||||
|  | ||||
| /* TODO: redefine this ... */ | ||||
| #define IS_ATOM(v)  ((v)->flags & (QSE_SCM_VAL_STRING | QSE_SCM_VAL_NUMBER | QSE_SCM_VAL_PROC) | ||||
|  | ||||
| #define IS_MARKED(v)  ((v)->mark) | ||||
| #define SET_MARK(v)   ((v)->mark = 1) | ||||
| #define CLEAR_MARK(v) ((v)->mark = 0) | ||||
|  | ||||
| #define ZERO_DSW_COUNT(v) ((v)->dsw_count = 0) | ||||
| #define GET_DSW_COUNT(v)  ((v)->dsw_count) | ||||
| #define INC_DSW_COUNT(v)  ((v)->dsw_count++) | ||||
|  | ||||
| static void mark (qse_scm_t* scm, qse_scm_val_t* v) | ||||
| static void mark (qse_scm_t* scm, qse_scm_ent_t* v) | ||||
| { | ||||
| 	/*  | ||||
| 	 * mark values non-recursively with Deutsch-Schorr-Waite(DSW) algorithm  | ||||
| @ -260,24 +258,23 @@ static void mark (qse_scm_t* scm, qse_scm_val_t* v) | ||||
| 	 * with the help of additional variables. | ||||
| 	 */ | ||||
|  | ||||
| 	qse_scm_val_t* parent, * me; | ||||
| 	qse_scm_ent_t* parent, * me; | ||||
|  | ||||
| #if 0 | ||||
| 	/* initialization */ | ||||
| 	parent = QSE_NULL; | ||||
| 	me = v; | ||||
|  | ||||
| 	SET_MARK (me); | ||||
| 	/*if (!IS_ATOM(me))*/ ZERO_DSW_COUNT (me); | ||||
| 	MARK(me) = 1; | ||||
| 	/*if (!ATOM(me))*/ DSWCOUNT(me) = 0; | ||||
|  | ||||
| 	while (1) | ||||
| 	{ | ||||
| 		if (IS_ATOM(me) || GET_DSW_COUNT(me) >= 2) | ||||
| 		if (ATOM(me) || DSWCOUNT(me) >= QSE_COUNTOF(me->u.ref.ent)) | ||||
| 		{ | ||||
| 			/*  | ||||
| 			 * backtrack to the parent node  | ||||
| 			 */ | ||||
| 			qse_scm_val_t* child; | ||||
| 			qse_scm_ent_t* child; | ||||
|  | ||||
| 			/* nothing more to backtrack? end of marking */ | ||||
| 			if (parent == QSE_NULL) return; | ||||
| @ -289,30 +286,30 @@ static void mark (qse_scm_t* scm, qse_scm_val_t* v) | ||||
| 			me = parent; | ||||
|  | ||||
| 			/* change the parent to the parent of parent */ | ||||
| 			parent = me->u.cona.val[GET_DSW_COUNT(me)]; | ||||
| 			parent = me->u.ref.ent[DSWCOUNT(me)]; | ||||
| 			 | ||||
| 			/* restore the cell contents */ | ||||
| 			me->u.cona.val[GET_DSW_COUNT(me)] = child; | ||||
| 			me->u.ref.ent[DSWCOUNT(me)] = child; | ||||
|  | ||||
| 			/* increment the counter to indicate that the  | ||||
| 			 * 'count'th field has been processed. | ||||
| 			INC_DSW_COUNT (me); | ||||
| 			 * 'count'th field has been processed. */ | ||||
| 			DSWCOUNT(me)++; | ||||
| 		} | ||||
| 		else  | ||||
| 		{ | ||||
| 			/*  | ||||
| 			 * move on to an unprocessed child  | ||||
| 			 */ | ||||
| 			qse_scm_val_t* child; | ||||
| 			qse_scm_ent_t* child; | ||||
|  | ||||
| 			child = me->u.cona.val[GET_DSW_COUNT(me)]; | ||||
| 			child = me->u.ref.ent[DSWCOUNT(me)]; | ||||
|  | ||||
| 			/* process the field */ | ||||
| 			if (child && !ismark(child)) | ||||
| 			if (child && !MARK(child)) | ||||
| 			{ | ||||
| 				/* change the contents of the child chonse  | ||||
| 				 * to point to the current parent */ | ||||
| 				me->u.cona.val[GET_DSW_COUNT(me)] = parent; | ||||
| 				me->u.ref.ent[DSWCOUNT(me)] = parent; | ||||
|  | ||||
| 				/* link me to the head of parent list */ | ||||
| 				parent = me; | ||||
| @ -320,23 +317,23 @@ static void mark (qse_scm_t* scm, qse_scm_val_t* v) | ||||
| 				/* let me point to the child chosen */ | ||||
| 				me = child; | ||||
|  | ||||
| 				SET_MARK (me); | ||||
| 				/*if (!IS_ATOM(me))*/ ZERO_DSW_COUNT (me); | ||||
| 				MARK(me) = 1; | ||||
| 				/*if (!ATOM(me))*/ DSWCOUNT(me) = 0; | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				INC_DSW_COUNT (me) | ||||
| 				/* increment the count */ | ||||
| 				DSWCOUNT(me)++; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| #endif | ||||
| } | ||||
|  | ||||
|  | ||||
| #if 0 | ||||
| static void mark (qse_scm_t* scm, qse_scm_val_t* v) | ||||
| static void mark (qse_scm_t* scm, qse_scm_ent_t* v) | ||||
| { | ||||
| 	qse_scm_val_t* t, * p, * q; | ||||
| 	qse_scm_ent_t* t, * p, * q; | ||||
|  | ||||
| 	t = QSE_NULL; | ||||
| 	p = v; | ||||
| @ -389,9 +386,9 @@ E6: | ||||
| } | ||||
| #endif | ||||
|  | ||||
| static void gc (qse_scm_t* scm, qse_scm_val_t* x, qse_scm_val_t* y) | ||||
| static void gc (qse_scm_t* scm, qse_scm_ent_t* x, qse_scm_ent_t* y) | ||||
| { | ||||
| 	//mark (scm, scm->oblist); | ||||
| 	//mark (scm, scm->symtab); | ||||
| 	mark (scm, scm->genv); | ||||
|  | ||||
| 	mark (scm, scm->reg.arg); | ||||
| @ -399,45 +396,276 @@ static void gc (qse_scm_t* scm, qse_scm_val_t* x, qse_scm_val_t* y) | ||||
| 	mark (scm, scm->reg.cod); | ||||
| 	mark (scm, scm->reg.dmp); | ||||
|  | ||||
| 	/* mark the temporaries */ | ||||
| 	mark (scm, x); | ||||
| 	mark (scm, y); | ||||
|  | ||||
|  | ||||
| 	/* scan the allocated values */ | ||||
| } | ||||
|  | ||||
| static qse_scm_val_t* mkval (qse_scm_t* scm, qse_scm_val_t* x, qse_scm_val_t* y) | ||||
| /* | ||||
|  | ||||
| rsr4  | ||||
|  | ||||
| the following identifiers are syntatic 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) | ||||
| { | ||||
| 	qse_scm_val_t* v; | ||||
| 	/* find a free value slot and return it. | ||||
| 	 * two parameters x and y are saved from garbage collection */ | ||||
|  | ||||
| 	qse_scm_ent_t* v; | ||||
|  | ||||
| 	if (scm->mem.free == scm->nil) | ||||
| 	{ | ||||
| 		gc (scm, x, y); | ||||
| 		/* if no free slot is available */ | ||||
| 		gc (scm, x, y); /* perform garbage collection */ | ||||
| 		if (scm->mem.free == scm->nil) | ||||
| 		{ | ||||
| 			if (newvbl (scm,  1000) == QSE_NULL) return QSE_NULL; | ||||
| 			/* 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 = v->u.cons.cdr; | ||||
| 	scm->mem.free = PAIR_CDR(v); | ||||
| 	 | ||||
| 	return v; | ||||
| } | ||||
|  | ||||
|  | ||||
| static qse_scm_val_t* mkcons ( | ||||
| 	qse_scm_t* scm, qse_scm_val_t* car, qse_scm_val_t* cdr) | ||||
| static qse_scm_ent_t* make_pair_entity ( | ||||
| 	qse_scm_t* scm, qse_scm_ent_t* car, qse_scm_ent_t* cdr) | ||||
| { | ||||
| 	qse_scm_val_t* v; | ||||
| 	qse_scm_ent_t* v; | ||||
|  | ||||
| 	v = mkval (scm, car, cdr); | ||||
| 	v = alloc_entity (scm, car, cdr); | ||||
| 	if (v == QSE_NULL) return QSE_NULL; | ||||
|  | ||||
| #if 0 | ||||
| 	v->flag = QSE_SCM_VAL_PAIR; | ||||
| 	v->u.cons.car = car; | ||||
| 	v->u.cons.cdr = car; | ||||
| #endif | ||||
| 	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_string_entity ( | ||||
| 	qse_scm_t* scm, const qse_char_t* str, qse_size_t len) | ||||
| { | ||||
| 	qse_scm_ent_t* v; | ||||
|  | ||||
| 	v = alloc_entity (scm, scm->nil, scm->nil); | ||||
| 	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, scm->nil, scm->nil); | ||||
| 	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, scm->nil); | ||||
| 	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.  | ||||
| 	 */ | ||||
| 	TYPE(v) |= QSE_SCM_ENT_SYNT;  | ||||
| 	SYNT_CODE(v) = code;  | ||||
|  | ||||
| 	return v; | ||||
| } | ||||
|  | ||||
| static qse_scm_ent_t* make_proc_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 | ||||
| 	 * that can be overridden by a user while a syntax entity | ||||
| 	 * represents a lower-level syntatic function that can't  | ||||
| 	 * be overriden.  | ||||
| 	 * (define lambda 10) is legal but does not change the | ||||
| 	 *    meaning of lambda when used as a function name. 	 | ||||
| 	 * (define eval 10) changes the meaning of eval totally. | ||||
| 	 */  | ||||
|  | ||||
| 	/* create a symbol containing the name */ | ||||
| 	sym = make_symbol_entity (scm, name); | ||||
| 	if (sym == QSE_NULL) return QSE_NULL; | ||||
|  | ||||
| 	/* create an actual procecure value which is a number containing | ||||
| 	 * the opcode for the procedure */ | ||||
| 	proc = alloc_entity (scm, scm->nil, scm->nil); | ||||
| 	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->genv)); | ||||
| 	if (pair == QSE_NULL) return QSE_NULL; | ||||
| 	PAIR_CAR(scm->genv) = pair; | ||||
|  | ||||
| 	return proc; | ||||
| } | ||||
|  | ||||
| @ -40,65 +40,100 @@ | ||||
| #define QSE_SCM_TOUPPER(scm,c)  QSE_TOUPPER(c) | ||||
| #define QSE_SCM_TOLOWER(scm,c)  QSE_TOLOWER(c) | ||||
|  | ||||
| #define QSE_SCM_VAL_STRING         1    /* 0000000000000001 */ | ||||
| #define QSE_SCM_VAL_NUMBER         2    /* 0000000000000010 */ | ||||
| #define QSE_SCM_VAL_SYMBOL         4    /* 0000000000000100 */ | ||||
| #define QSE_SCM_VAL_SYNTAX         8    /* 0000000000001000 */ | ||||
| #define QSE_SCM_VAL_PROC          16    /* 0000000000010000 */ | ||||
|  | ||||
| #define QSE_SCM_VAL_PAIR          32    /* 0000000000100000 */ | ||||
| #define QSE_SCM_VAL_CLOSURE       64    /* 0000000001000000 */ | ||||
| #define QSE_SCM_VAL_CONTINUATION 128    /* 0000000010000000 */ | ||||
| #define QSE_SCM_VAL_MACRO        256    /* 0000000100000000 */ | ||||
| #define QSE_SCM_VAL_PROMISE      512    /* 0000001000000000 */ | ||||
| #define QSE_SCM_VAL_ATOM        4096    /* 0001000000000000 */ /* only for gc */ | ||||
|  | ||||
| typedef struct qse_scm_val_t qse_scm_val_t; | ||||
| struct qse_scm_val_t | ||||
| enum qse_scm_ent_type_t | ||||
| { | ||||
| 	qse_uint16_t dsw_count: 2; | ||||
| 	qse_uint16_t mark:      1; | ||||
| 	qse_uint16_t types:     13; | ||||
| 	QSE_SCM_ENT_NIL     = (1 << 0), | ||||
| 	QSE_SCM_ENT_T       = (1 << 1), | ||||
| 	QSE_SCM_ENT_F       = (1 << 2), | ||||
| 	QSE_SCM_ENT_NUM     = (1 << 3), | ||||
| 	QSE_SCM_ENT_STR     = (1 << 4),  | ||||
| 	QSE_SCM_ENT_NAM     = (1 << 5), | ||||
| 	QSE_SCM_ENT_SYM     = (1 << 6), | ||||
| 	QSE_SCM_ENT_PAIR    = (1 << 7), | ||||
| 	QSE_SCM_ENT_PROC    = (1 << 8), | ||||
| 	QSE_SCM_ENT_SYNT    = (1 << 9) | ||||
|  | ||||
| }; | ||||
|  | ||||
| #if 0 | ||||
| #define QSE_SCM_ENT_CLOSURE       64    /* 0000000001000000 */ | ||||
| #define QSE_SCM_ENT_CONTINUATION 128    /* 0000000010000000 */ | ||||
| #define QSE_SCM_ENT_MACRO        256    /* 0000000100000000 */ | ||||
| #define QSE_SCM_ENT_PROMISE      512    /* 0000001000000000 */ | ||||
| #endif | ||||
|  | ||||
| typedef struct qse_scm_ent_t qse_scm_ent_t; | ||||
|  | ||||
| /** | ||||
|  * The qse_scm_ent_t type defines an entity that represents an individual | ||||
|  * value in scheme. | ||||
|  */ | ||||
| struct qse_scm_ent_t | ||||
| { | ||||
| 	qse_uint16_t dswcount: 2; | ||||
| 	qse_uint16_t mark:     1; | ||||
| 	qse_uint16_t atom:     1; | ||||
| 	qse_uint16_t type:     12; | ||||
|  | ||||
| 	union | ||||
| 	{ | ||||
| 		struct | ||||
| 		{ | ||||
| 			qse_char_t* ptr; | ||||
| 			qse_size_t  len; | ||||
| 		} str; | ||||
| 			qse_long_t val; | ||||
| 		} num; /* number */ | ||||
|  | ||||
| 		struct | ||||
| 		{ | ||||
| 			qse_long_t val; | ||||
| 		} num; | ||||
| 			/* a string doesn't need to be null-terminated  | ||||
| 			 * as the length is remembered */ | ||||
| 			qse_char_t* ptr;  | ||||
| 			qse_size_t  len; | ||||
| 		} str; /* string */ | ||||
|  | ||||
| 		struct | ||||
| 		{ | ||||
| 			qse_char_t* ptr;  /* null-terminated string */ | ||||
| 			int         code; /* used for syntax entities only */ | ||||
| 		} lab; /* label */ | ||||
|  | ||||
| 		struct | ||||
| 		{ | ||||
| 			int code; | ||||
| 		} proc; | ||||
| 		 | ||||
| 		struct | ||||
| 		{ | ||||
| 			qse_scm_val_t* car; | ||||
| 			qse_scm_val_t* cdr; | ||||
| 		} cons; | ||||
|  | ||||
| 		/* arrayed cons. cona must maintain the | ||||
| 		 * same size as cons */ | ||||
| 		struct | ||||
| 		{ | ||||
| 			qse_scm_val_t* val[2]; | ||||
| 		} cona;  | ||||
| 			qse_scm_ent_t* ent[2]; | ||||
| 		} ref;  | ||||
| 	} u; | ||||
| }; | ||||
|  | ||||
| #define DSWCOUNT(v)       ((v)->dswcount) | ||||
| #define MARK(v)           ((v)->mark) | ||||
| #define TYPE(v)           ((v)->type) | ||||
| #define ATOM(v)           ((v)->atom) | ||||
| #define NUM_VALUE(v)      ((v)->u.num.val) | ||||
| #define STR_PTR(v)        ((v)->u.str.ptr) | ||||
| #define STR_LEN(v)        ((v)->u.str.len) | ||||
| #define LAB_PTR(v)        ((v)->u.lab.ptr) | ||||
| #define LAB_CODE(v)       ((v)->u.lab.code) | ||||
| #define SYM_NAME(v)       ((v)->u.ref.ent[0]) | ||||
| #define SYM_PROP(v)       ((v)->u.ref.ent[1]) | ||||
| #define PAIR_CAR(v)       ((v)->u.ref.ent[0]) | ||||
| #define PAIR_CDR(v)       ((v)->u.ref.ent[1]) | ||||
| #define PROC_CODE(v)      ((v)->u.proc.code) | ||||
| #define SYNT_CODE(v)      LAB_CODE(SYM_NAME(v)) | ||||
|  | ||||
| /** | ||||
|  * The qse_scm_vbl_t type defines a value block. A value block is allocated | ||||
|  * The qse_scm_enb_t type defines a value block. A value block is allocated | ||||
|  * when more memory is requested and is chained to existing value blocks. | ||||
|  */ | ||||
| typedef struct qse_scm_vbl_t qse_scm_vbl_t; | ||||
| struct qse_scm_vbl_t | ||||
| typedef struct qse_scm_enb_t qse_scm_enb_t; | ||||
| struct qse_scm_enb_t | ||||
| { | ||||
| 	qse_scm_val_t* ptr; | ||||
| 	qse_scm_ent_t* ptr; | ||||
| 	qse_size_t     len; | ||||
| 	qse_scm_vbl_t* next;	 | ||||
| 	qse_scm_enb_t* next;	 | ||||
| }; | ||||
|  | ||||
| struct qse_scm_t  | ||||
| @ -144,26 +179,29 @@ struct qse_scm_t | ||||
| 	} r; | ||||
|  | ||||
| 	/* common values */ | ||||
| 	qse_scm_val_t* nil; | ||||
| 	qse_scm_val_t* t; | ||||
| 	qse_scm_val_t* f; | ||||
| 	qse_scm_ent_t* nil; | ||||
| 	qse_scm_ent_t* t; | ||||
| 	qse_scm_ent_t* f; | ||||
|  | ||||
| 	/* global environment */ | ||||
| 	qse_scm_val_t* genv; | ||||
| 	qse_scm_ent_t* genv; | ||||
|  | ||||
| 	/* symbol table */ | ||||
| 	qse_scm_ent_t* symtab; | ||||
|  | ||||
| 	/* registers */ | ||||
| 	struct | ||||
| 	{ | ||||
| 		qse_scm_val_t* arg; /* function arguments */ | ||||
| 		qse_scm_val_t* env; /* current environment */ | ||||
| 		qse_scm_val_t* cod; /* current code */ | ||||
| 		qse_scm_val_t* dmp; /* stack register for next evaluation */ | ||||
| 		qse_scm_ent_t* arg; /* function arguments */ | ||||
| 		qse_scm_ent_t* env; /* current environment */ | ||||
| 		qse_scm_ent_t* cod; /* current code */ | ||||
| 		qse_scm_ent_t* dmp; /* stack register for next evaluation */ | ||||
| 	} reg; | ||||
|  | ||||
| 	struct | ||||
| 	{ | ||||
| 		qse_scm_vbl_t* vbl;  /* value block list */ | ||||
| 		qse_scm_val_t* free; | ||||
| 		qse_scm_enb_t* ebl;  /* entity block list */ | ||||
| 		qse_scm_ent_t* free; | ||||
| 	} mem; | ||||
| }; | ||||
|  | ||||
|  | ||||
| @ -136,6 +136,7 @@ DEFS = @DEFS@ | ||||
| DEPDIR = @DEPDIR@ | ||||
| DSYMUTIL = @DSYMUTIL@ | ||||
| DUMPBIN = @DUMPBIN@ | ||||
| ECHO = @ECHO@ | ||||
| ECHO_C = @ECHO_C@ | ||||
| ECHO_N = @ECHO_N@ | ||||
| ECHO_T = @ECHO_T@ | ||||
|  | ||||
		Reference in New Issue
	
	Block a user