|
Packit |
df99a1 |
/* -*- C++ -*-
|
|
Packit |
df99a1 |
// -------------------------------------------------------------------
|
|
Packit |
df99a1 |
// MiniExp - Library for handling lisp expressions
|
|
Packit |
df99a1 |
// Copyright (c) 2005 Leon Bottou
|
|
Packit |
df99a1 |
//
|
|
Packit |
df99a1 |
// This software is subject to, and may be distributed under, the
|
|
Packit |
df99a1 |
// GNU General Public License, either version 2 of the license
|
|
Packit |
df99a1 |
// or (at your option) any later version. The license should have
|
|
Packit |
df99a1 |
// accompanied the software or you may obtain a copy of the license
|
|
Packit |
df99a1 |
// from the Free Software Foundation at http://www.fsf.org .
|
|
Packit |
df99a1 |
//
|
|
Packit |
df99a1 |
// This program is distributed in the hope that it will be useful,
|
|
Packit |
df99a1 |
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
df99a1 |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
df99a1 |
// GNU General Public License for more details.
|
|
Packit |
df99a1 |
// -------------------------------------------------------------------
|
|
Packit |
df99a1 |
*/
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
#ifdef HAVE_CONFIG_H
|
|
Packit |
df99a1 |
# include "config.h"
|
|
Packit |
df99a1 |
#endif
|
|
Packit |
df99a1 |
#if NEED_GNUG_PRAGMAS
|
|
Packit |
df99a1 |
# pragma implementation "miniexp.h"
|
|
Packit |
df99a1 |
#endif
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
#include <stddef.h>
|
|
Packit |
df99a1 |
#include <stdlib.h>
|
|
Packit |
df99a1 |
#include <stdio.h>
|
|
Packit |
df99a1 |
#include <ctype.h>
|
|
Packit |
df99a1 |
#include <errno.h>
|
|
Packit |
df99a1 |
#include <string.h>
|
|
Packit |
df99a1 |
#include <time.h>
|
|
Packit |
df99a1 |
#include <stdarg.h>
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
#define MINIEXP_IMPLEMENTATION
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
#include "miniexp.h"
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
#ifdef HAVE_NAMESPACES
|
|
Packit |
df99a1 |
# define BEGIN_ANONYMOUS_NAMESPACE namespace {
|
|
Packit |
df99a1 |
# define END_ANONYMOUS_NAMESPACE }
|
|
Packit |
df99a1 |
#else
|
|
Packit |
df99a1 |
# define BEGIN_ANONYMOUS_NAMESPACE
|
|
Packit |
df99a1 |
# define END_ANONYMOUS_NAMESPACE
|
|
Packit |
df99a1 |
#endif
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
/* -------------------------------------------------- */
|
|
Packit |
df99a1 |
/* ASSERT */
|
|
Packit |
df99a1 |
/* -------------------------------------------------- */
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
#if defined(__GNUC__)
|
|
Packit |
df99a1 |
static void
|
|
Packit |
df99a1 |
assertfail(const char *fn, int ln)
|
|
Packit |
df99a1 |
__attribute__((noreturn));
|
|
Packit |
df99a1 |
#endif
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static void
|
|
Packit |
df99a1 |
assertfail(const char *fn, int ln)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
fprintf(stderr,"Assertion failed: %s:%d\n",fn,ln);
|
|
Packit |
df99a1 |
abort();
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
#define ASSERT(x) \
|
|
Packit |
df99a1 |
do { if (!(x)) assertfail(__FILE__,__LINE__); } while(0)
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
/* -------------------------------------------------- */
|
|
Packit |
df99a1 |
/* GLOBAL MUTEX */
|
|
Packit |
df99a1 |
/* -------------------------------------------------- */
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
#ifndef WITHOUT_THREADS
|
|
Packit |
df99a1 |
# ifdef _WIN32
|
|
Packit |
df99a1 |
# include <windows.h>
|
|
Packit |
df99a1 |
# define USE_WINTHREADS 1
|
|
Packit |
df99a1 |
# elif defined(HAVE_PTHREAD)
|
|
Packit |
df99a1 |
# include <pthread.h>
|
|
Packit |
df99a1 |
# define USE_PTHREADS 1
|
|
Packit |
df99a1 |
# endif
|
|
Packit |
df99a1 |
#endif
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
#if defined(USE_WINTHREADS)
|
|
Packit |
df99a1 |
// Windows critical section
|
|
Packit |
df99a1 |
# define CSLOCK(name) CSLocker name
|
|
Packit |
df99a1 |
BEGIN_ANONYMOUS_NAMESPACE
|
|
Packit |
df99a1 |
struct CS {
|
|
Packit |
df99a1 |
CRITICAL_SECTION cs;
|
|
Packit |
df99a1 |
CS() { InitializeCriticalSection(&cs); }
|
|
Packit |
df99a1 |
~CS() { DeleteCriticalSection(&cs); } };
|
|
Packit |
df99a1 |
static CS globalCS;
|
|
Packit |
df99a1 |
struct CSLocker {
|
|
Packit |
df99a1 |
CSLocker() { EnterCriticalSection(&globalCS.cs); }
|
|
Packit |
df99a1 |
~CSLocker() { LeaveCriticalSection(&globalCS.cs); } };
|
|
Packit |
df99a1 |
END_ANONYMOUS_NAMESPACE
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
#elif defined (USE_PTHREADS)
|
|
Packit |
df99a1 |
// Pthread critical section
|
|
Packit |
df99a1 |
# define CSLOCK(name) CSLocker name
|
|
Packit |
df99a1 |
BEGIN_ANONYMOUS_NAMESPACE
|
|
Packit |
df99a1 |
static pthread_mutex_t globalCS = PTHREAD_MUTEX_INITIALIZER;
|
|
Packit |
df99a1 |
struct CSLocker {
|
|
Packit |
df99a1 |
CSLocker() { pthread_mutex_lock(&globalCS); }
|
|
Packit |
df99a1 |
~CSLocker() { pthread_mutex_unlock(&globalCS); } };
|
|
Packit |
df99a1 |
END_ANONYMOUS_NAMESPACE
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
#else
|
|
Packit |
df99a1 |
// No critical sections
|
|
Packit |
df99a1 |
# define CSLOCK(name) /**/
|
|
Packit |
df99a1 |
#endif
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
/* -------------------------------------------------- */
|
|
Packit |
df99a1 |
/* SYMBOLS */
|
|
Packit |
df99a1 |
/* -------------------------------------------------- */
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static unsigned int
|
|
Packit |
df99a1 |
hashcode(const char *s)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
long h = 0x1013;
|
|
Packit |
df99a1 |
while (*s)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
h = (h<<6) | ((h&0xfc000000)>>26);
|
|
Packit |
df99a1 |
h ^= (*s);
|
|
Packit |
df99a1 |
s++;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
return h;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
BEGIN_ANONYMOUS_NAMESPACE
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
class symtable_t
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
public:
|
|
Packit |
df99a1 |
int nelems;
|
|
Packit |
df99a1 |
int nbuckets;
|
|
Packit |
df99a1 |
struct sym { unsigned int h; struct sym *l; char *n; };
|
|
Packit |
df99a1 |
struct sym **buckets;
|
|
Packit |
df99a1 |
symtable_t();
|
|
Packit |
df99a1 |
~symtable_t();
|
|
Packit |
df99a1 |
struct sym *lookup(const char *n, bool create=false);
|
|
Packit |
df99a1 |
void resize(int);
|
|
Packit |
df99a1 |
private:
|
|
Packit |
df99a1 |
symtable_t(const symtable_t&);
|
|
Packit |
df99a1 |
symtable_t& operator=(const symtable_t&);
|
|
Packit |
df99a1 |
};
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
symtable_t::symtable_t()
|
|
Packit |
df99a1 |
: nelems(0), nbuckets(0), buckets(0)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
resize(7);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
symtable_t::~symtable_t()
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
int i=0;
|
|
Packit |
df99a1 |
for (; i
|
|
Packit |
df99a1 |
while (buckets[i])
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
struct sym *r = buckets[i];
|
|
Packit |
df99a1 |
buckets[i] = r->l;
|
|
Packit |
df99a1 |
delete [] r->n;
|
|
Packit |
df99a1 |
delete r;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
delete [] buckets;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void
|
|
Packit |
df99a1 |
symtable_t::resize(int nb)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
struct sym **b = new sym*[nb];
|
|
Packit |
df99a1 |
memset(b, 0, nb*sizeof(sym*));
|
|
Packit |
df99a1 |
int i=0;
|
|
Packit |
df99a1 |
for (; i
|
|
Packit |
df99a1 |
while (buckets[i])
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
struct sym *s = buckets[i];
|
|
Packit |
df99a1 |
int j = s->h % nb;
|
|
Packit |
df99a1 |
buckets[i] = s->l;
|
|
Packit |
df99a1 |
s->l = b[j];
|
|
Packit |
df99a1 |
b[j] = s;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
delete [] buckets;
|
|
Packit |
df99a1 |
buckets = b;
|
|
Packit |
df99a1 |
nbuckets = nb;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
struct symtable_t::sym *
|
|
Packit |
df99a1 |
symtable_t::lookup(const char *n, bool create)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
unsigned int h = hashcode(n);
|
|
Packit |
df99a1 |
int i = h % nbuckets;
|
|
Packit |
df99a1 |
struct sym *r = buckets[i];
|
|
Packit |
df99a1 |
while (r && strcmp(n,r->n))
|
|
Packit |
df99a1 |
r = r->l;
|
|
Packit |
df99a1 |
if (!r && create)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
CSLOCK(lock);
|
|
Packit |
df99a1 |
nelems += 1;
|
|
Packit |
df99a1 |
r = new sym;
|
|
Packit |
df99a1 |
r->h = h;
|
|
Packit |
df99a1 |
r->l = buckets[i];
|
|
Packit |
df99a1 |
r->n = new char [1+strlen(n)];
|
|
Packit |
df99a1 |
strcpy(r->n, n);
|
|
Packit |
df99a1 |
buckets[i] = r;
|
|
Packit |
df99a1 |
if ( 2 * nelems > 3 * nbuckets)
|
|
Packit |
df99a1 |
resize(2*nbuckets-1);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
return r;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
END_ANONYMOUS_NAMESPACE
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static symtable_t *symbols;
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
const char *
|
|
Packit |
df99a1 |
miniexp_to_name(miniexp_t p)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (miniexp_symbolp(p))
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
struct symtable_t::sym *r;
|
|
Packit |
df99a1 |
r = ((symtable_t::sym*)(((size_t)p)&~((size_t)3)));
|
|
Packit |
df99a1 |
return (r) ? r->n : "##(dummy)";
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
return 0;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
miniexp_t
|
|
Packit |
df99a1 |
miniexp_symbol(const char *name)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
struct symtable_t::sym *r;
|
|
Packit |
df99a1 |
if (! symbols)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
CSLOCK(lock);
|
|
Packit |
df99a1 |
if (! symbols)
|
|
Packit |
df99a1 |
symbols = new symtable_t;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
r = symbols->lookup(name, true);
|
|
Packit |
df99a1 |
return (miniexp_t)(((size_t)r)|((size_t)2));
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
/* -------------------------------------------------- */
|
|
Packit |
df99a1 |
/* MEMORY AND GARBAGE COLLECTION */
|
|
Packit |
df99a1 |
/* -------------------------------------------------- */
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
// A simple mark-and-sweep garbage collector.
|
|
Packit |
df99a1 |
//
|
|
Packit |
df99a1 |
// Memory is managed in chunks of nptrs_chunk pointers.
|
|
Packit |
df99a1 |
// The first two pointers are used to hold mark bytes for the rest.
|
|
Packit |
df99a1 |
// Chunks are carved from blocks of nptrs_block pointers.
|
|
Packit |
df99a1 |
//
|
|
Packit |
df99a1 |
// Dirty hack: The sixteen most recently created pairs are
|
|
Packit |
df99a1 |
// not destroyed by automatic garbage collection, in order
|
|
Packit |
df99a1 |
// to preserve transient objects created in the course
|
|
Packit |
df99a1 |
// of evaluating complicated expressions.
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
#define nptrs_chunk (4*sizeof(void*))
|
|
Packit |
df99a1 |
#define sizeof_chunk (nptrs_chunk*sizeof(void*))
|
|
Packit |
df99a1 |
#define nptrs_block (16384-8)
|
|
Packit |
df99a1 |
#define recentlog (4)
|
|
Packit |
df99a1 |
#define recentsize (1<
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
BEGIN_ANONYMOUS_NAMESPACE
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
struct gctls_t {
|
|
Packit |
df99a1 |
gctls_t *next;
|
|
Packit |
df99a1 |
gctls_t **pprev;
|
|
Packit |
df99a1 |
void **recent[recentsize];
|
|
Packit |
df99a1 |
int recentindex;
|
|
Packit |
df99a1 |
gctls_t();
|
|
Packit |
df99a1 |
~gctls_t();
|
|
Packit |
df99a1 |
};
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
struct block_t
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
block_t *next;
|
|
Packit |
df99a1 |
void **lo;
|
|
Packit |
df99a1 |
void **hi;
|
|
Packit |
df99a1 |
void *ptrs[nptrs_block];
|
|
Packit |
df99a1 |
};
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static struct {
|
|
Packit |
df99a1 |
int lock;
|
|
Packit |
df99a1 |
int request;
|
|
Packit |
df99a1 |
int debug;
|
|
Packit |
df99a1 |
int pairs_total;
|
|
Packit |
df99a1 |
int pairs_free;
|
|
Packit |
df99a1 |
void **pairs_freelist;
|
|
Packit |
df99a1 |
block_t *pairs_blocks;
|
|
Packit |
df99a1 |
int objs_total;
|
|
Packit |
df99a1 |
int objs_free;
|
|
Packit |
df99a1 |
void **objs_freelist;
|
|
Packit |
df99a1 |
block_t *objs_blocks;
|
|
Packit |
df99a1 |
gctls_t *tls;
|
|
Packit |
df99a1 |
} gc;
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
gctls_t::gctls_t()
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
// CSLOCK(locker); [already locked]
|
|
Packit |
df99a1 |
recentindex = 0;
|
|
Packit |
df99a1 |
for (int i=0; i
|
|
Packit |
df99a1 |
recent[i] = 0;
|
|
Packit |
df99a1 |
if ((next = gc.tls))
|
|
Packit |
df99a1 |
next->pprev = &next;
|
|
Packit |
df99a1 |
pprev = &gc.tls;
|
|
Packit |
df99a1 |
gc.tls = this;
|
|
Packit |
df99a1 |
//fprintf(stderr,"Created gctls %p\n", this);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
gctls_t::~gctls_t()
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
//CSLOCK(locker); [already locked]
|
|
Packit |
df99a1 |
//fprintf(stderr,"Deleting gctls %p\n", this);
|
|
Packit |
df99a1 |
if ((*pprev = next))
|
|
Packit |
df99a1 |
next->pprev = pprev;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
END_ANONYMOUS_NAMESPACE
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
#if USE_PTHREADS
|
|
Packit |
df99a1 |
// Manage thread specific data with pthreads
|
|
Packit |
df99a1 |
static pthread_key_t gctls_key;
|
|
Packit |
df99a1 |
static pthread_once_t gctls_once;
|
|
Packit |
df99a1 |
static void gctls_destroy(void* arg) {
|
|
Packit |
df99a1 |
CSLOCK(locker); delete (gctls_t*)arg;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
static void gctls_key_alloc() {
|
|
Packit |
df99a1 |
pthread_key_create(&gctls_key, gctls_destroy);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
# if HAVE_GCCTLS
|
|
Packit |
df99a1 |
static __thread gctls_t *gctls_tv = 0;
|
|
Packit |
df99a1 |
static void gctls_alloc() {
|
|
Packit |
df99a1 |
pthread_once(&gctls_once, gctls_key_alloc);
|
|
Packit |
df99a1 |
gctls_tv = new gctls_t();
|
|
Packit |
df99a1 |
pthread_setspecific(gctls_key, (void*)gctls_tv);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
static gctls_t *gctls() {
|
|
Packit |
df99a1 |
if (! gctls_tv) gctls_alloc();
|
|
Packit |
df99a1 |
return gctls_tv;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
# else
|
|
Packit |
df99a1 |
static gctls_t *gctls_alloc() {
|
|
Packit |
df99a1 |
gctls_t *res = new gctls_t();
|
|
Packit |
df99a1 |
pthread_setspecific(gctls_key, (void*)res);
|
|
Packit |
df99a1 |
return res;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
static gctls_t *gctls() {
|
|
Packit |
df99a1 |
pthread_once(&gctls_once, gctls_key_alloc);
|
|
Packit |
df99a1 |
void *arg = pthread_getspecific(gctls_key);
|
|
Packit |
df99a1 |
return (arg) ? (gctls_t*)(arg) : gctls_alloc();
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
# endif
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
#elif USE_WINTHREADS
|
|
Packit |
df99a1 |
// Manage thread specific data with win32
|
|
Packit |
df99a1 |
#if defined(_MSC_VER) && defined(USE_MSVC_TLS)
|
|
Packit |
df99a1 |
// -- Pre-vista os sometimes crashes on this.
|
|
Packit |
df99a1 |
static __declspec(thread) gctls_t *gctls_tv = 0;
|
|
Packit |
df99a1 |
static gctls_t *gctls() {
|
|
Packit |
df99a1 |
if (! gctls_tv) gctls_tv = new gctls_t();
|
|
Packit |
df99a1 |
return gctls_tv;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
static void NTAPI gctls_cb(PVOID, DWORD dwReason, PVOID) {
|
|
Packit |
df99a1 |
if (dwReason == DLL_THREAD_DETACH && gctls_tv)
|
|
Packit |
df99a1 |
{ CSLOCK(locker); delete gctls_tv; gctls_tv=0; } }
|
|
Packit |
df99a1 |
# else
|
|
Packit |
df99a1 |
// -- Using Tls{Alloc,SetValue,GetValue,Free} instead.
|
|
Packit |
df99a1 |
static DWORD tlsIndex = TLS_OUT_OF_INDEXES;
|
|
Packit |
df99a1 |
static gctls_t *gctls() {
|
|
Packit |
df99a1 |
if (tlsIndex == TLS_OUT_OF_INDEXES) tlsIndex = TlsAlloc();
|
|
Packit |
df99a1 |
ASSERT(tlsIndex != TLS_OUT_OF_INDEXES);
|
|
Packit |
df99a1 |
gctls_t *addr = (gctls_t*)TlsGetValue(tlsIndex);
|
|
Packit |
df99a1 |
if (! addr) TlsSetValue(tlsIndex, (LPVOID)(addr = new gctls_t()));
|
|
Packit |
df99a1 |
ASSERT(addr != 0);
|
|
Packit |
df99a1 |
return addr;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
static void NTAPI gctls_cb(PVOID, DWORD dwReason, PVOID) {
|
|
Packit |
df99a1 |
if (dwReason == DLL_THREAD_DETACH && tlsIndex != TLS_OUT_OF_INDEXES)
|
|
Packit |
df99a1 |
{CSLOCK(r);delete(gctls_t*)TlsGetValue(tlsIndex);TlsSetValue(tlsIndex,0);}
|
|
Packit |
df99a1 |
if (dwReason == DLL_PROCESS_DETACH && tlsIndex != TLS_OUT_OF_INDEXES)
|
|
Packit |
df99a1 |
{CSLOCK(r);TlsFree(tlsIndex);tlsIndex=TLS_OUT_OF_INDEXES;}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
# endif
|
|
Packit |
df99a1 |
// -- Very black magic to clean tls variables.
|
|
Packit |
df99a1 |
# ifdef _M_IX86
|
|
Packit |
df99a1 |
# pragma comment (linker, "/INCLUDE:_tlscb")
|
|
Packit |
df99a1 |
# else
|
|
Packit |
df99a1 |
# pragma comment (linker, "/INCLUDE:tlscb")
|
|
Packit |
df99a1 |
# endif
|
|
Packit |
df99a1 |
# pragma const_seg(".CRT$XLB")
|
|
Packit |
df99a1 |
extern "C" PIMAGE_TLS_CALLBACK tlscb = gctls_cb;
|
|
Packit |
df99a1 |
# pragma const_seg()
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
#else
|
|
Packit |
df99a1 |
// No threads
|
|
Packit |
df99a1 |
static gctls_t *gctls() {
|
|
Packit |
df99a1 |
static gctls_t g;
|
|
Packit |
df99a1 |
return &g;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
#endif
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static inline char *
|
|
Packit |
df99a1 |
markbase(void **p)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
return (char*)(((size_t)p) & ~(sizeof_chunk-1));
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static inline char *
|
|
Packit |
df99a1 |
markbyte(void **p)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
char *base = markbase(p);
|
|
Packit |
df99a1 |
return base + ((p - (void**)base)>>1);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static block_t *
|
|
Packit |
df99a1 |
new_block(void)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
block_t *b = new block_t;
|
|
Packit |
df99a1 |
memset(b, 0, sizeof(block_t));
|
|
Packit |
df99a1 |
b->lo = (void**)markbase(b->ptrs+nptrs_chunk-1);
|
|
Packit |
df99a1 |
b->hi = (void**)markbase(b->ptrs+nptrs_block);
|
|
Packit |
df99a1 |
return b;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static void
|
|
Packit |
df99a1 |
clear_marks(block_t *b)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
for (void** m=b->lo; m<b->hi; m+=nptrs_chunk)
|
|
Packit |
df99a1 |
m[0] = m[1] = 0;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static void
|
|
Packit |
df99a1 |
collect_free(block_t *b, void **&freelist, int &count, bool destroy)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
for (void **m=b->lo; m<b->hi; m+=nptrs_chunk)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
char *c = (char*)m;
|
|
Packit |
df99a1 |
for (unsigned int i=1; i
|
|
Packit |
df99a1 |
if (! c[i])
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
miniobj_t *obj = (miniobj_t*)m[i+i];
|
|
Packit |
df99a1 |
if (destroy && obj && m[i+i]==m[i+i+1])
|
|
Packit |
df99a1 |
obj->destroy();
|
|
Packit |
df99a1 |
m[i+i] = (void*)freelist;
|
|
Packit |
df99a1 |
m[i+i+1] = 0;
|
|
Packit |
df99a1 |
freelist = &m[i+i];
|
|
Packit |
df99a1 |
count += 1;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static void
|
|
Packit |
df99a1 |
new_pair_block(void)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
int count = 0;
|
|
Packit |
df99a1 |
block_t *b = new_block();
|
|
Packit |
df99a1 |
b->next = gc.pairs_blocks;
|
|
Packit |
df99a1 |
gc.pairs_blocks = b;
|
|
Packit |
df99a1 |
clear_marks(b);
|
|
Packit |
df99a1 |
collect_free(b, gc.pairs_freelist, count, false);
|
|
Packit |
df99a1 |
gc.pairs_total += count;
|
|
Packit |
df99a1 |
gc.pairs_free += count;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static void
|
|
Packit |
df99a1 |
new_obj_block(void)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
int count = 0;
|
|
Packit |
df99a1 |
block_t *b = new_block();
|
|
Packit |
df99a1 |
b->next = gc.objs_blocks;
|
|
Packit |
df99a1 |
gc.objs_blocks = b;
|
|
Packit |
df99a1 |
clear_marks(b);
|
|
Packit |
df99a1 |
collect_free(b, gc.objs_freelist, count, false);
|
|
Packit |
df99a1 |
gc.objs_total += count;
|
|
Packit |
df99a1 |
gc.objs_free += count;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
#if defined(__GNUC__) && (__GNUC__ >= 3)
|
|
Packit |
df99a1 |
static void gc_mark_object(void **v) __attribute__((noinline));
|
|
Packit |
df99a1 |
#else
|
|
Packit |
df99a1 |
static void gc_mark_object(void **v);
|
|
Packit |
df99a1 |
#endif
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static bool
|
|
Packit |
df99a1 |
gc_mark_check(void *p)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (((size_t)p) & 2)
|
|
Packit |
df99a1 |
return false;
|
|
Packit |
df99a1 |
void **v = (void**)(((size_t)p) & ~(size_t)3);
|
|
Packit |
df99a1 |
if (! v)
|
|
Packit |
df99a1 |
return false;
|
|
Packit |
df99a1 |
char *m = markbyte(v);
|
|
Packit |
df99a1 |
if (*m)
|
|
Packit |
df99a1 |
return false;
|
|
Packit |
df99a1 |
*m = 1;
|
|
Packit |
df99a1 |
if (! (((size_t)p) & 1))
|
|
Packit |
df99a1 |
return true;
|
|
Packit |
df99a1 |
gc_mark_object((void**)v);
|
|
Packit |
df99a1 |
return false;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static void
|
|
Packit |
df99a1 |
gc_mark_pair(void **v)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
// This is a simple recursive code.
|
|
Packit |
df99a1 |
// Despite the tail recursion for the cdrs,
|
|
Packit |
df99a1 |
// it consume a stack space that grows like
|
|
Packit |
df99a1 |
// the longest chain of cars.
|
|
Packit |
df99a1 |
for(;;)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (gc_mark_check(v[0]))
|
|
Packit |
df99a1 |
gc_mark_pair((void**)v[0]);
|
|
Packit |
df99a1 |
if (! gc_mark_check(v[1]))
|
|
Packit |
df99a1 |
break;
|
|
Packit |
df99a1 |
v = (void**)v[1];
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static void
|
|
Packit |
df99a1 |
gc_mark(miniexp_t *pp)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
void **v = (void**)*pp;
|
|
Packit |
df99a1 |
if (gc_mark_check((void**)*pp))
|
|
Packit |
df99a1 |
gc_mark_pair(v);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static void
|
|
Packit |
df99a1 |
gc_mark_object(void **v)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
ASSERT(v[0] == v[1]);
|
|
Packit |
df99a1 |
miniobj_t *obj = (miniobj_t*)v[0];
|
|
Packit |
df99a1 |
if (obj)
|
|
Packit |
df99a1 |
obj->mark(gc_mark);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static void
|
|
Packit |
df99a1 |
gc_run(void)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
gc.request++;
|
|
Packit |
df99a1 |
if (gc.lock == 0)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
block_t *b;
|
|
Packit |
df99a1 |
gc.request = 0;
|
|
Packit |
df99a1 |
// clear marks
|
|
Packit |
df99a1 |
for (b=gc.objs_blocks; b; b=b->next)
|
|
Packit |
df99a1 |
clear_marks(b);
|
|
Packit |
df99a1 |
for (b=gc.pairs_blocks; b; b=b->next)
|
|
Packit |
df99a1 |
clear_marks(b);
|
|
Packit |
df99a1 |
// mark recents
|
|
Packit |
df99a1 |
for (gctls_t *tls = gc.tls; tls; tls=tls->next)
|
|
Packit |
df99a1 |
for (int i=0; i
|
|
Packit |
df99a1 |
gc_mark((miniexp_t*)(char*)&(tls->recent[i]));
|
|
Packit |
df99a1 |
// mark roots
|
|
Packit |
df99a1 |
minivar_t::mark(gc_mark);
|
|
Packit |
df99a1 |
// sweep
|
|
Packit |
df99a1 |
gc.objs_free = gc.pairs_free = 0;
|
|
Packit |
df99a1 |
gc.objs_freelist = gc.pairs_freelist = 0;
|
|
Packit |
df99a1 |
for (b=gc.objs_blocks; b; b=b->next)
|
|
Packit |
df99a1 |
collect_free(b, gc.objs_freelist, gc.objs_free, true);
|
|
Packit |
df99a1 |
for (b=gc.pairs_blocks; b; b=b->next)
|
|
Packit |
df99a1 |
collect_free(b, gc.pairs_freelist, gc.pairs_free, false);
|
|
Packit |
df99a1 |
// alloc 33% extra space
|
|
Packit |
df99a1 |
while (gc.objs_free*4 < gc.objs_total)
|
|
Packit |
df99a1 |
new_obj_block();
|
|
Packit |
df99a1 |
while (gc.pairs_free*4 < gc.pairs_total)
|
|
Packit |
df99a1 |
new_pair_block();
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static void **
|
|
Packit |
df99a1 |
gc_alloc_pair(void *a, void *d)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (!gc.pairs_freelist)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
gc_run();
|
|
Packit |
df99a1 |
if (!gc.pairs_freelist)
|
|
Packit |
df99a1 |
new_pair_block();
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else if (gc.debug)
|
|
Packit |
df99a1 |
gc_run();
|
|
Packit |
df99a1 |
void **p = gc.pairs_freelist;
|
|
Packit |
df99a1 |
gc.pairs_freelist = (void**)p[0];
|
|
Packit |
df99a1 |
gc.pairs_free -= 1;
|
|
Packit |
df99a1 |
p[0] = a;
|
|
Packit |
df99a1 |
p[1] = d;
|
|
Packit |
df99a1 |
return p;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static void **
|
|
Packit |
df99a1 |
gc_alloc_object(void *obj)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (!gc.objs_freelist)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
gc_run();
|
|
Packit |
df99a1 |
if (!gc.objs_freelist)
|
|
Packit |
df99a1 |
new_obj_block();
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else if (gc.debug)
|
|
Packit |
df99a1 |
gc_run();
|
|
Packit |
df99a1 |
void **p = gc.objs_freelist;
|
|
Packit |
df99a1 |
gc.objs_freelist = (void**)p[0];
|
|
Packit |
df99a1 |
gc.objs_free -= 1;
|
|
Packit |
df99a1 |
p[0] = p[1] = obj;
|
|
Packit |
df99a1 |
return p;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
/* ---- USER FUNCTIONS --- */
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
miniexp_t
|
|
Packit |
df99a1 |
minilisp_acquire_gc_lock(miniexp_t x)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
CSLOCK(locker);
|
|
Packit |
df99a1 |
gc.lock++;
|
|
Packit |
df99a1 |
return x;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
miniexp_t
|
|
Packit |
df99a1 |
minilisp_release_gc_lock(miniexp_t x)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
minivar_t v = x;
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
CSLOCK(locker);
|
|
Packit |
df99a1 |
if (gc.lock > 0)
|
|
Packit |
df99a1 |
if (--gc.lock == 0)
|
|
Packit |
df99a1 |
if (gc.request > 0)
|
|
Packit |
df99a1 |
gc_run();
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
return x;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void
|
|
Packit |
df99a1 |
minilisp_gc(void)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
CSLOCK(locker);
|
|
Packit |
df99a1 |
for (gctls_t *tls = gc.tls; tls; tls=tls->next)
|
|
Packit |
df99a1 |
for (int i=0; i
|
|
Packit |
df99a1 |
tls->recent[i] = 0;
|
|
Packit |
df99a1 |
gc_run();
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void
|
|
Packit |
df99a1 |
minilisp_debug(int debug)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
gc.debug = debug;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void
|
|
Packit |
df99a1 |
minilisp_info(void)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
CSLOCK(locker);
|
|
Packit |
df99a1 |
time_t tim = time(0);
|
|
Packit |
df99a1 |
const char *dat = ctime(&tim);
|
|
Packit |
df99a1 |
printf("--- begin info -- %s", dat);
|
|
Packit |
df99a1 |
printf("symbols: %d symbols in %d buckets\n",
|
|
Packit |
df99a1 |
symbols->nelems, symbols->nbuckets);
|
|
Packit |
df99a1 |
if (gc.debug)
|
|
Packit |
df99a1 |
printf("gc.debug: true\n");
|
|
Packit |
df99a1 |
if (gc.lock)
|
|
Packit |
df99a1 |
printf("gc.locked: true, %d requests\n", gc.request);
|
|
Packit |
df99a1 |
printf("gc.pairs: %d free, %d total\n", gc.pairs_free, gc.pairs_total);
|
|
Packit |
df99a1 |
printf("gc.objects: %d free, %d total\n", gc.objs_free, gc.objs_total);
|
|
Packit |
df99a1 |
printf("--- end info -- %s", dat);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
miniexp_t
|
|
Packit |
df99a1 |
miniexp_mutate(miniexp_t, miniexp_t *var, miniexp_t val)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
CSLOCK(locker);
|
|
Packit |
df99a1 |
*var = val;
|
|
Packit |
df99a1 |
return val;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
/* -------------------------------------------------- */
|
|
Packit |
df99a1 |
/* MINIVARS */
|
|
Packit |
df99a1 |
/* -------------------------------------------------- */
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
minivar_t::minivar_t()
|
|
Packit |
df99a1 |
: data(0)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
CSLOCK(locker);
|
|
Packit |
df99a1 |
if ((next = vars))
|
|
Packit |
df99a1 |
next->pprev = &next;
|
|
Packit |
df99a1 |
pprev = &vars;
|
|
Packit |
df99a1 |
vars = this;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
minivar_t::minivar_t(miniexp_t p)
|
|
Packit |
df99a1 |
: data(p)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
CSLOCK(locker);
|
|
Packit |
df99a1 |
if ((next = vars))
|
|
Packit |
df99a1 |
next->pprev = &next;
|
|
Packit |
df99a1 |
pprev = &vars;
|
|
Packit |
df99a1 |
vars = this;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
minivar_t::minivar_t(const minivar_t &v)
|
|
Packit |
df99a1 |
: data(v.data)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
CSLOCK(locker);
|
|
Packit |
df99a1 |
if ((next = vars))
|
|
Packit |
df99a1 |
next->pprev = &next;
|
|
Packit |
df99a1 |
pprev = &vars;
|
|
Packit |
df99a1 |
vars = this;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
minivar_t::~minivar_t()
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
CSLOCK(locker);
|
|
Packit |
df99a1 |
if ((*pprev = next))
|
|
Packit |
df99a1 |
next->pprev = pprev;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
minivar_t *minivar_t::vars = 0;
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void
|
|
Packit |
df99a1 |
minivar_t::mark(minilisp_mark_t *f)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
for (minivar_t *v = vars; v; v=v->next)
|
|
Packit |
df99a1 |
(*f)(&v->data);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
minivar_t *
|
|
Packit |
df99a1 |
minivar_alloc(void)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
return new minivar_t;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void
|
|
Packit |
df99a1 |
minivar_free(minivar_t *v)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
delete v;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
miniexp_t *
|
|
Packit |
df99a1 |
minivar_pointer(minivar_t *v)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
return &(*v);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
/* -------------------------------------------------- */
|
|
Packit |
df99a1 |
/* LISTS */
|
|
Packit |
df99a1 |
/* -------------------------------------------------- */
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static inline miniexp_t &
|
|
Packit |
df99a1 |
car(miniexp_t p) {
|
|
Packit |
df99a1 |
return ((miniexp_t*)p)[0];
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static inline miniexp_t &
|
|
Packit |
df99a1 |
cdr(miniexp_t p) {
|
|
Packit |
df99a1 |
return ((miniexp_t*)p)[1];
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
int
|
|
Packit |
df99a1 |
miniexp_length(miniexp_t p)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
int n = 0;
|
|
Packit |
df99a1 |
bool toggle = false;
|
|
Packit |
df99a1 |
miniexp_t q = p;
|
|
Packit |
df99a1 |
while (miniexp_consp(p))
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
p = cdr(p);
|
|
Packit |
df99a1 |
if (p == q)
|
|
Packit |
df99a1 |
return -1;
|
|
Packit |
df99a1 |
if ((toggle = !toggle))
|
|
Packit |
df99a1 |
q = cdr(q);
|
|
Packit |
df99a1 |
n += 1;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
return n;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
miniexp_t
|
|
Packit |
df99a1 |
miniexp_caar(miniexp_t p)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
return miniexp_car(miniexp_car(p));
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
miniexp_t
|
|
Packit |
df99a1 |
miniexp_cadr(miniexp_t p)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
return miniexp_car(miniexp_cdr(p));
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
miniexp_t
|
|
Packit |
df99a1 |
miniexp_cdar(miniexp_t p)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
return miniexp_cdr(miniexp_car(p));
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
miniexp_t
|
|
Packit |
df99a1 |
miniexp_cddr(miniexp_t p)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
return miniexp_cdr(miniexp_cdr(p));
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
miniexp_t
|
|
Packit |
df99a1 |
miniexp_caddr(miniexp_t p)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
return miniexp_car(miniexp_cdr(miniexp_cdr(p)));
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
miniexp_t
|
|
Packit |
df99a1 |
miniexp_cdddr(miniexp_t p)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
return miniexp_cdr(miniexp_cdr(miniexp_cdr(p)));
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
miniexp_t
|
|
Packit |
df99a1 |
miniexp_nth(int n, miniexp_t l)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
while (--n>=0 && miniexp_consp(l))
|
|
Packit |
df99a1 |
l = cdr(l);
|
|
Packit |
df99a1 |
return miniexp_car(l);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
miniexp_t
|
|
Packit |
df99a1 |
miniexp_cons(miniexp_t a, miniexp_t d)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
CSLOCK(locker);
|
|
Packit |
df99a1 |
miniexp_t r = (miniexp_t)gc_alloc_pair((void*)a, (void*)d);
|
|
Packit |
df99a1 |
gctls_t *tls = gctls();
|
|
Packit |
df99a1 |
tls->recent[(++(tls->recentindex)) & (recentsize-1)] = (void**)r;
|
|
Packit |
df99a1 |
return r;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
miniexp_t
|
|
Packit |
df99a1 |
miniexp_rplaca(miniexp_t pair, miniexp_t newcar)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (miniexp_consp(pair))
|
|
Packit |
df99a1 |
return miniexp_mutate(pair, &car(pair), newcar);
|
|
Packit |
df99a1 |
return 0;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
miniexp_t
|
|
Packit |
df99a1 |
miniexp_rplacd(miniexp_t pair, miniexp_t newcdr)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (miniexp_consp(pair))
|
|
Packit |
df99a1 |
return miniexp_mutate(pair, &cdr(pair), newcdr);
|
|
Packit |
df99a1 |
return 0;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
miniexp_t
|
|
Packit |
df99a1 |
miniexp_reverse(miniexp_t p)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
miniexp_t l = 0;
|
|
Packit |
df99a1 |
while (miniexp_consp(p))
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
miniexp_t q = cdr(p);
|
|
Packit |
df99a1 |
miniexp_mutate(p, &cdr(p), l);
|
|
Packit |
df99a1 |
l = p;
|
|
Packit |
df99a1 |
p = q;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
return l;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
/* -------------------------------------------------- */
|
|
Packit |
df99a1 |
/* MINIOBJ */
|
|
Packit |
df99a1 |
/* -------------------------------------------------- */
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
miniobj_t::~miniobj_t()
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
const miniexp_t miniobj_t::classname = 0;
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
bool
|
|
Packit |
df99a1 |
miniobj_t::isa(miniexp_t) const
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
return false;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void
|
|
Packit |
df99a1 |
miniobj_t::mark(minilisp_mark_t*)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void
|
|
Packit |
df99a1 |
miniobj_t::destroy()
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
delete this;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
char *
|
|
Packit |
df99a1 |
miniobj_t::pname() const
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
const char *cname = miniexp_to_name(classof());
|
|
Packit |
df99a1 |
char *res = new char[strlen(cname)+24];
|
|
Packit |
df99a1 |
sprintf(res,"#%s:<%p>",cname,this);
|
|
Packit |
df99a1 |
return res;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
miniexp_t
|
|
Packit |
df99a1 |
miniexp_object(miniobj_t *obj)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
CSLOCK(locker);
|
|
Packit |
df99a1 |
void **v = gc_alloc_object((void*)obj);
|
|
Packit |
df99a1 |
v = (void**)(((size_t)v)|((size_t)1));
|
|
Packit |
df99a1 |
gctls_t *tls = gctls();
|
|
Packit |
df99a1 |
tls->recent[(++(tls->recentindex)) & (recentsize-1)] = (void**)v;
|
|
Packit |
df99a1 |
return (miniexp_t)(v);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
miniexp_t
|
|
Packit |
df99a1 |
miniexp_classof(miniexp_t p)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
miniobj_t *obj = miniexp_to_obj(p);
|
|
Packit |
df99a1 |
if (obj) return obj->classof();
|
|
Packit |
df99a1 |
return miniexp_nil;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
miniexp_t
|
|
Packit |
df99a1 |
miniexp_isa(miniexp_t p, miniexp_t c)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
miniobj_t *obj = miniexp_to_obj(p);
|
|
Packit |
df99a1 |
if (obj && obj->isa(c))
|
|
Packit |
df99a1 |
return obj->classof();
|
|
Packit |
df99a1 |
return miniexp_nil;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
/* -------------------------------------------------- */
|
|
Packit |
df99a1 |
/* STRINGS */
|
|
Packit |
df99a1 |
/* -------------------------------------------------- */
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
BEGIN_ANONYMOUS_NAMESPACE
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
class ministring_t : public miniobj_t
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
MINIOBJ_DECLARE(ministring_t,miniobj_t,"string");
|
|
Packit |
df99a1 |
public:
|
|
Packit |
df99a1 |
~ministring_t();
|
|
Packit |
df99a1 |
ministring_t(const char *s);
|
|
Packit |
df99a1 |
ministring_t(char *s, bool steal);
|
|
Packit |
df99a1 |
operator const char*() const { return s; }
|
|
Packit |
df99a1 |
virtual char *pname() const;
|
|
Packit |
df99a1 |
private:
|
|
Packit |
df99a1 |
char *s;
|
|
Packit |
df99a1 |
private:
|
|
Packit |
df99a1 |
ministring_t(const ministring_t &);
|
|
Packit |
df99a1 |
ministring_t& operator=(const ministring_t &);
|
|
Packit |
df99a1 |
};
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
MINIOBJ_IMPLEMENT(ministring_t,miniobj_t,"string");
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
ministring_t::~ministring_t()
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
delete [] s;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
ministring_t::ministring_t(const char *str)
|
|
Packit |
df99a1 |
: s(new char[strlen(str)+1])
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
strcpy(s,str);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
ministring_t::ministring_t(char *str, bool steal)
|
|
Packit |
df99a1 |
: s(str)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
ASSERT(steal);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
END_ANONYMOUS_NAMESPACE
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static bool
|
|
Packit |
df99a1 |
char_quoted(int c, int flags)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
bool print7bits = (flags & miniexp_io_print7bits);
|
|
Packit |
df99a1 |
if (c>=0x80 && !print7bits)
|
|
Packit |
df99a1 |
return false;
|
|
Packit |
df99a1 |
if (c==0x7f || c=='\"' || c=='\\')
|
|
Packit |
df99a1 |
return true;
|
|
Packit |
df99a1 |
if (c>=0x20 && c<0x7f)
|
|
Packit |
df99a1 |
return false;
|
|
Packit |
df99a1 |
return true;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static bool
|
|
Packit |
df99a1 |
char_utf8(int &c, const char* &s)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (c < 0xc0)
|
|
Packit |
df99a1 |
return (c < 0x80);
|
|
Packit |
df99a1 |
if (c >= 0xf8)
|
|
Packit |
df99a1 |
return false;
|
|
Packit |
df99a1 |
int n = (c < 0xe0) ? 1 : (c < 0xf0) ? 2 : 3;
|
|
Packit |
df99a1 |
int x = c & (0x3f >> n);
|
|
Packit |
df99a1 |
for (int i=0; i
|
|
Packit |
df99a1 |
if ((s[i] & 0xc0) == 0x80)
|
|
Packit |
df99a1 |
x = (x << 6) + (s[i] & 0x3f);
|
|
Packit |
df99a1 |
else
|
|
Packit |
df99a1 |
return false;
|
|
Packit |
df99a1 |
static int lim[] = {0, 0x80, 0x800, 0x10000};
|
|
Packit |
df99a1 |
if (x < lim[n])
|
|
Packit |
df99a1 |
return false;
|
|
Packit |
df99a1 |
if (x > 0x10ffff)
|
|
Packit |
df99a1 |
return false;
|
|
Packit |
df99a1 |
if (x >= 0xd800 && x <= 0xdfff)
|
|
Packit |
df99a1 |
return false;
|
|
Packit |
df99a1 |
s += n;
|
|
Packit |
df99a1 |
c = x;
|
|
Packit |
df99a1 |
return true;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static void
|
|
Packit |
df99a1 |
char_out(int c, char* &d, int &n)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
n++;
|
|
Packit |
df99a1 |
if (d)
|
|
Packit |
df99a1 |
*d++ = c;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static int
|
|
Packit |
df99a1 |
print_c_string(const char *s, char *d, int flags = 0)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
int c;
|
|
Packit |
df99a1 |
int n = 0;
|
|
Packit |
df99a1 |
char_out('\"', d, n);
|
|
Packit |
df99a1 |
while ((c = (unsigned char)(*s++)))
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (char_quoted(c, flags))
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
char buffer[10];
|
|
Packit |
df99a1 |
static const char *tr1 = "\"\\tnrbf";
|
|
Packit |
df99a1 |
static const char *tr2 = "\"\\\t\n\r\b\f";
|
|
Packit |
df99a1 |
buffer[0] = buffer[1] = 0;
|
|
Packit |
df99a1 |
char_out('\\', d, n);
|
|
Packit |
df99a1 |
for (int i=0; tr2[i]; i++)
|
|
Packit |
df99a1 |
if (c == tr2[i])
|
|
Packit |
df99a1 |
buffer[0] = tr1[i];
|
|
Packit |
df99a1 |
if (buffer[0] == 0 && c >= 0x80
|
|
Packit |
df99a1 |
&& (flags & (miniexp_io_u4escape | miniexp_io_u6escape))
|
|
Packit |
df99a1 |
&& char_utf8(c, s) )
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (c <= 0xffff && (flags & miniexp_io_u4escape))
|
|
Packit |
df99a1 |
sprintf(buffer,"u%04X", c);
|
|
Packit |
df99a1 |
else if (flags & miniexp_io_u6escape) // c# style
|
|
Packit |
df99a1 |
sprintf(buffer,"U%06X", c);
|
|
Packit |
df99a1 |
else if (flags & miniexp_io_u4escape) // json style
|
|
Packit |
df99a1 |
sprintf(buffer,"u%04X\\u%04X",
|
|
Packit |
df99a1 |
0xd800+(((c-0x10000)>>10)&0x3ff),
|
|
Packit |
df99a1 |
0xdc00+(c&0x3ff));
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
if (buffer[0] == 0)
|
|
Packit |
df99a1 |
sprintf(buffer, "%03o", c);
|
|
Packit |
df99a1 |
for (int i=0; buffer[i]; i++)
|
|
Packit |
df99a1 |
char_out(buffer[i], d, n);
|
|
Packit |
df99a1 |
continue;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
char_out(c, d, n);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
char_out('\"', d, n);
|
|
Packit |
df99a1 |
char_out(0, d, n);
|
|
Packit |
df99a1 |
return n;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
char *
|
|
Packit |
df99a1 |
ministring_t::pname() const
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
int n = print_c_string(s, 0);
|
|
Packit |
df99a1 |
char *d = new char[n];
|
|
Packit |
df99a1 |
if (d) print_c_string(s, d);
|
|
Packit |
df99a1 |
return d;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
int
|
|
Packit |
df99a1 |
miniexp_stringp(miniexp_t p)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
return miniexp_isa(p, ministring_t::classname) ? 1 : 0;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
const char *
|
|
Packit |
df99a1 |
miniexp_to_str(miniexp_t p)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
miniobj_t *obj = miniexp_to_obj(p);
|
|
Packit |
df99a1 |
if (miniexp_stringp(p))
|
|
Packit |
df99a1 |
return (const char*) * (ministring_t*) obj;
|
|
Packit |
df99a1 |
return 0;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
miniexp_t
|
|
Packit |
df99a1 |
miniexp_string(const char *s)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
ministring_t *obj = new ministring_t(s);
|
|
Packit |
df99a1 |
return miniexp_object(obj);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
miniexp_t
|
|
Packit |
df99a1 |
miniexp_substring(const char *s, int n)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
int l = strlen(s);
|
|
Packit |
df99a1 |
n = (n < l) ? n : l;
|
|
Packit |
df99a1 |
char *b = new char[n+1];
|
|
Packit |
df99a1 |
strncpy(b, s, n);
|
|
Packit |
df99a1 |
b[n] = 0;
|
|
Packit |
df99a1 |
ministring_t *obj = new ministring_t(b, true);
|
|
Packit |
df99a1 |
return miniexp_object(obj);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
miniexp_t
|
|
Packit |
df99a1 |
miniexp_concat(miniexp_t p)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
miniexp_t l = p;
|
|
Packit |
df99a1 |
const char *s;
|
|
Packit |
df99a1 |
int n = 0;
|
|
Packit |
df99a1 |
if (miniexp_length(l) < 0)
|
|
Packit |
df99a1 |
return miniexp_nil;
|
|
Packit |
df99a1 |
for (p=l; miniexp_consp(p); p=cdr(p))
|
|
Packit |
df99a1 |
if ((s = miniexp_to_str(car(p))))
|
|
Packit |
df99a1 |
n += strlen(s);
|
|
Packit |
df99a1 |
char *b = new char[n+1];
|
|
Packit |
df99a1 |
char *d = b;
|
|
Packit |
df99a1 |
for (p=l; miniexp_consp(p); p=cdr(p))
|
|
Packit |
df99a1 |
if ((s = miniexp_to_str(car(p)))) {
|
|
Packit |
df99a1 |
strcpy(d, s);
|
|
Packit |
df99a1 |
d += strlen(d);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
ministring_t *obj = new ministring_t(b, true);
|
|
Packit |
df99a1 |
return miniexp_object(obj);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
/* -------------------------------------------------- */
|
|
Packit |
df99a1 |
/* FLOATNUMS */
|
|
Packit |
df99a1 |
/* -------------------------------------------------- */
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
BEGIN_ANONYMOUS_NAMESPACE
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
class minifloat_t : public miniobj_t
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
MINIOBJ_DECLARE(minifloat_t,miniobj_t,"floatnum");
|
|
Packit |
df99a1 |
public:
|
|
Packit |
df99a1 |
minifloat_t(double x) : val(x) {}
|
|
Packit |
df99a1 |
operator double() const { return val; }
|
|
Packit |
df99a1 |
virtual char *pname() const;
|
|
Packit |
df99a1 |
private:
|
|
Packit |
df99a1 |
double val;
|
|
Packit |
df99a1 |
};
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
MINIOBJ_IMPLEMENT(minifloat_t,miniobj_t,"floatnum");
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
END_ANONYMOUS_NAMESPACE
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
int
|
|
Packit |
df99a1 |
miniexp_floatnump(miniexp_t p)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
return miniexp_isa(p, minifloat_t::classname) ? 1 : 0;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
miniexp_t
|
|
Packit |
df99a1 |
miniexp_floatnum(double x)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
minifloat_t *obj = new minifloat_t(x);
|
|
Packit |
df99a1 |
return miniexp_object(obj);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
double
|
|
Packit |
df99a1 |
miniexp_to_double(miniexp_t p)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (miniexp_numberp(p))
|
|
Packit |
df99a1 |
return (double) miniexp_to_int(p);
|
|
Packit |
df99a1 |
else if (miniexp_floatnump(p))
|
|
Packit |
df99a1 |
return (double) * (minifloat_t*) miniexp_to_obj(p);
|
|
Packit |
df99a1 |
return 0.0;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
miniexp_t
|
|
Packit |
df99a1 |
miniexp_double(double x)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
miniexp_t exp = miniexp_number((int)(x));
|
|
Packit |
df99a1 |
if (x != (double)miniexp_to_int(exp))
|
|
Packit |
df99a1 |
exp = miniexp_floatnum(x);
|
|
Packit |
df99a1 |
return exp;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static bool
|
|
Packit |
df99a1 |
str_looks_like_double(const char *s)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (isdigit(s[0]))
|
|
Packit |
df99a1 |
return true;
|
|
Packit |
df99a1 |
if ((s[0] == '+' || s[0] == '-') && s[1])
|
|
Packit |
df99a1 |
return true;
|
|
Packit |
df99a1 |
return false;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
char *
|
|
Packit |
df99a1 |
minifloat_t::pname() const
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
char *r = new char[64];
|
|
Packit |
df99a1 |
sprintf(r,"%f",val);
|
|
Packit |
df99a1 |
if (! str_looks_like_double(r))
|
|
Packit |
df99a1 |
sprintf(r,"+%f",val);
|
|
Packit |
df99a1 |
return r;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static bool
|
|
Packit |
df99a1 |
str_is_double(const char *s, double &x)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (str_looks_like_double(s))
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
char *end;
|
|
Packit |
df99a1 |
errno = 0;
|
|
Packit |
df99a1 |
x = (double) strtol(s, &end, 0);
|
|
Packit |
df99a1 |
if (*end == 0 && errno == 0)
|
|
Packit |
df99a1 |
return true;
|
|
Packit |
df99a1 |
x = (double) strtod(s, &end;;
|
|
Packit |
df99a1 |
if (*end == 0 && errno == 0)
|
|
Packit |
df99a1 |
return true;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
return false;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
/* -------------------------------------------------- */
|
|
Packit |
df99a1 |
/* INPUT/OUTPUT */
|
|
Packit |
df99a1 |
/* -------------------------------------------------- */
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static int true_stdio_fputs(miniexp_io_t *io, const char *s) {
|
|
Packit |
df99a1 |
FILE *f = (io->data[1]) ? (FILE*)(io->data[1]) : stdout;
|
|
Packit |
df99a1 |
return ::fputs(s, f);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
static int compat_puts(const char *s) {
|
|
Packit |
df99a1 |
return true_stdio_fputs(&miniexp_io, s);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
static int stdio_fputs(miniexp_io_t *io, const char *s) {
|
|
Packit |
df99a1 |
if (io == &miniexp_io)
|
|
Packit |
df99a1 |
return (*minilisp_puts)(s);
|
|
Packit |
df99a1 |
return true_stdio_fputs(io, s);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static int true_stdio_fgetc(miniexp_io_t *io) {
|
|
Packit |
df99a1 |
FILE *f = (io->data[0]) ? (FILE*)(io->data[0]) : stdin;
|
|
Packit |
df99a1 |
return ::getc(f);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
static int compat_getc() {
|
|
Packit |
df99a1 |
return true_stdio_fgetc(&miniexp_io);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
static int stdio_fgetc(miniexp_io_t *io)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (io == &miniexp_io)
|
|
Packit |
df99a1 |
return (*minilisp_getc)();
|
|
Packit |
df99a1 |
return true_stdio_fgetc(io);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static int true_stdio_ungetc(miniexp_io_t *io, int c) {
|
|
Packit |
df99a1 |
FILE *f = (io->data[0]) ? (FILE*)(io->data[0]) : stdin;
|
|
Packit |
df99a1 |
return ::ungetc(c, f);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
static int compat_ungetc(int c) {
|
|
Packit |
df99a1 |
return true_stdio_ungetc(&miniexp_io, c);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
static int stdio_ungetc(miniexp_io_t *io, int c) {
|
|
Packit |
df99a1 |
if (io == &miniexp_io)
|
|
Packit |
df99a1 |
return (*minilisp_ungetc)(c);
|
|
Packit |
df99a1 |
return true_stdio_ungetc(io, c);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
extern "C"
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
// SunCC needs this to be defined inside extern "C" { ... }
|
|
Packit |
df99a1 |
// Beware the difference between extern "C" {...} and extern "C".
|
|
Packit |
df99a1 |
miniexp_t (*minilisp_macrochar_parser[128])(void);
|
|
Packit |
df99a1 |
miniexp_t (*minilisp_diezechar_parser[128])(void);
|
|
Packit |
df99a1 |
minivar_t minilisp_macroqueue;
|
|
Packit |
df99a1 |
int minilisp_print_7bits;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
miniexp_io_t miniexp_io = {
|
|
Packit |
df99a1 |
stdio_fputs, stdio_fgetc, stdio_ungetc, { 0, 0, 0, 0 },
|
|
Packit |
df99a1 |
(int*)&minilisp_print_7bits,
|
|
Packit |
df99a1 |
(miniexp_macrochar_t*)minilisp_macrochar_parser,
|
|
Packit |
df99a1 |
(miniexp_macrochar_t*)minilisp_diezechar_parser,
|
|
Packit |
df99a1 |
(minivar_t*)&minilisp_macroqueue,
|
|
Packit |
df99a1 |
0
|
|
Packit |
df99a1 |
};
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
int (*minilisp_puts)(const char *) = compat_puts;
|
|
Packit |
df99a1 |
int (*minilisp_getc)(void) = compat_getc;
|
|
Packit |
df99a1 |
int (*minilisp_ungetc)(int) = compat_ungetc;
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void
|
|
Packit |
df99a1 |
miniexp_io_init(miniexp_io_t *io)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
io->fputs = stdio_fputs;
|
|
Packit |
df99a1 |
io->fgetc = stdio_fgetc;
|
|
Packit |
df99a1 |
io->ungetc = stdio_ungetc;
|
|
Packit |
df99a1 |
io->data[0] = io->data[1] = io->data[2] = io->data[3] = 0;
|
|
Packit |
df99a1 |
io->p_flags = (int*)&minilisp_print_7bits;;
|
|
Packit |
df99a1 |
io->p_macrochar = (miniexp_macrochar_t*)minilisp_macrochar_parser;
|
|
Packit |
df99a1 |
io->p_diezechar = (miniexp_macrochar_t*)minilisp_diezechar_parser;
|
|
Packit |
df99a1 |
io->p_macroqueue = (minivar_t*)&minilisp_macroqueue;
|
|
Packit |
df99a1 |
io->p_reserved = 0;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void
|
|
Packit |
df99a1 |
miniexp_io_set_output(miniexp_io_t* io, FILE *f)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
io->fputs = stdio_fputs;
|
|
Packit |
df99a1 |
io->data[1] = f;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void
|
|
Packit |
df99a1 |
miniexp_io_set_input(miniexp_io_t* io, FILE *f)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
io->fgetc = stdio_fgetc;
|
|
Packit |
df99a1 |
io->ungetc = stdio_ungetc;
|
|
Packit |
df99a1 |
io->data[0] = f;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
/* ---- OUTPUT */
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
BEGIN_ANONYMOUS_NAMESPACE
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
struct printer_t
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
int tab;
|
|
Packit |
df99a1 |
bool dryrun;
|
|
Packit |
df99a1 |
miniexp_io_t *io;
|
|
Packit |
df99a1 |
printer_t(miniexp_io_t *io) : tab(0), dryrun(false), io(io) {}
|
|
Packit |
df99a1 |
void mlput(const char *s);
|
|
Packit |
df99a1 |
void mltab(int n);
|
|
Packit |
df99a1 |
void print(miniexp_t p);
|
|
Packit |
df99a1 |
bool must_quote_symbol(const char *s, int flags);
|
|
Packit |
df99a1 |
void mlput_quoted_symbol(const char *s);
|
|
Packit |
df99a1 |
virtual miniexp_t begin() { return miniexp_nil; }
|
|
Packit |
df99a1 |
virtual bool newline() { return false; }
|
|
Packit |
df99a1 |
virtual void end(miniexp_t) { }
|
|
Packit |
df99a1 |
virtual ~printer_t() {};
|
|
Packit |
df99a1 |
};
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void
|
|
Packit |
df99a1 |
printer_t::mlput(const char *s)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (! dryrun)
|
|
Packit |
df99a1 |
io->fputs(io, s);
|
|
Packit |
df99a1 |
while (*s)
|
|
Packit |
df99a1 |
if (*s++ == '\n')
|
|
Packit |
df99a1 |
tab = 0;
|
|
Packit |
df99a1 |
else
|
|
Packit |
df99a1 |
tab += 1;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void
|
|
Packit |
df99a1 |
printer_t::mltab(int n)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
while (tab+8 <= n)
|
|
Packit |
df99a1 |
mlput(" ");
|
|
Packit |
df99a1 |
while (tab+1 <= n)
|
|
Packit |
df99a1 |
mlput(" ");
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
bool
|
|
Packit |
df99a1 |
printer_t::must_quote_symbol(const char *s, int flags)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
int c;
|
|
Packit |
df99a1 |
const char *r = s;
|
|
Packit |
df99a1 |
while ((c = *r++))
|
|
Packit |
df99a1 |
if (c=='(' || c==')' || c=='\"' || c=='|' ||
|
|
Packit |
df99a1 |
isspace(c) || !isascii(c) || !isprint(c) ||
|
|
Packit |
df99a1 |
(c >= 0 && c < 128 && io->p_macrochar && io->p_macrochar[c]) )
|
|
Packit |
df99a1 |
return true;
|
|
Packit |
df99a1 |
double x;
|
|
Packit |
df99a1 |
if (flags & miniexp_io_quotemoresymbols)
|
|
Packit |
df99a1 |
return str_looks_like_double(s);
|
|
Packit |
df99a1 |
return str_is_double(s, x);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void
|
|
Packit |
df99a1 |
printer_t::mlput_quoted_symbol(const char *s)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
int l = strlen(s);
|
|
Packit |
df99a1 |
char *r = new char[l+l+3];
|
|
Packit |
df99a1 |
char *z = r;
|
|
Packit |
df99a1 |
*z++ = '|';
|
|
Packit |
df99a1 |
while (*s)
|
|
Packit |
df99a1 |
if ((*z++ = *s++) == '|')
|
|
Packit |
df99a1 |
*z++ = '|';
|
|
Packit |
df99a1 |
*z++ = '|';
|
|
Packit |
df99a1 |
*z++ = 0;
|
|
Packit |
df99a1 |
mlput(r);
|
|
Packit |
df99a1 |
delete [] r;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void
|
|
Packit |
df99a1 |
printer_t::print(miniexp_t p)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
int flags = (io->p_flags) ? *io->p_flags : 0;
|
|
Packit |
df99a1 |
static char buffer[32];
|
|
Packit |
df99a1 |
miniexp_t b = begin();
|
|
Packit |
df99a1 |
if (p == miniexp_nil)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
mlput("()");
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else if (miniexp_numberp(p))
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
sprintf(buffer, "%d", miniexp_to_int(p));
|
|
Packit |
df99a1 |
mlput(buffer);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else if (miniexp_symbolp(p))
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
const char *s = miniexp_to_name(p);
|
|
Packit |
df99a1 |
if (must_quote_symbol(s, flags))
|
|
Packit |
df99a1 |
mlput_quoted_symbol(s);
|
|
Packit |
df99a1 |
else
|
|
Packit |
df99a1 |
mlput(s);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else if (miniexp_stringp(p))
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
const char *s = miniexp_to_str(p);
|
|
Packit |
df99a1 |
int n = print_c_string(s, 0, flags);
|
|
Packit |
df99a1 |
char *d = new char[n];
|
|
Packit |
df99a1 |
if (d)
|
|
Packit |
df99a1 |
print_c_string(s, d, flags);
|
|
Packit |
df99a1 |
mlput(d);
|
|
Packit |
df99a1 |
delete [] d;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else if (miniexp_objectp(p))
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
miniobj_t *obj = miniexp_to_obj(p);
|
|
Packit |
df99a1 |
char *s = obj->pname();
|
|
Packit |
df99a1 |
mlput(s);
|
|
Packit |
df99a1 |
delete [] s;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else if (miniexp_listp(p))
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
// TODO - detect more circular structures
|
|
Packit |
df99a1 |
int skip = 1;
|
|
Packit |
df99a1 |
int indent = tab + 1;
|
|
Packit |
df99a1 |
bool multiline = false;
|
|
Packit |
df99a1 |
bool toggle = true;
|
|
Packit |
df99a1 |
miniexp_t q = p;
|
|
Packit |
df99a1 |
mlput("(");
|
|
Packit |
df99a1 |
if (miniexp_consp(p) && miniexp_symbolp(car(p)))
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
skip++;
|
|
Packit |
df99a1 |
indent++;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
while (miniexp_consp(p))
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
skip -= 1;
|
|
Packit |
df99a1 |
if (multiline || (newline() && skip<0 && tab>indent))
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
mlput("\n");
|
|
Packit |
df99a1 |
mltab(indent);
|
|
Packit |
df99a1 |
multiline=true;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
print(car(p));
|
|
Packit |
df99a1 |
if ((p = cdr(p)))
|
|
Packit |
df99a1 |
mlput(" ");
|
|
Packit |
df99a1 |
if ((toggle = !toggle))
|
|
Packit |
df99a1 |
q = cdr(q);
|
|
Packit |
df99a1 |
if (p == q)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
mlput("...");
|
|
Packit |
df99a1 |
p = 0;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
if (p)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
skip -= 1;
|
|
Packit |
df99a1 |
if (multiline || (newline() && skip<0 && tab>indent))
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
mlput("\n");
|
|
Packit |
df99a1 |
mltab(indent);
|
|
Packit |
df99a1 |
multiline=true;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
mlput(". ");
|
|
Packit |
df99a1 |
print(p);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
if (multiline)
|
|
Packit |
df99a1 |
mlput(" )");
|
|
Packit |
df99a1 |
else
|
|
Packit |
df99a1 |
mlput(")");
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
end(b);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
struct pprinter_t : public printer_t
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
int width;
|
|
Packit |
df99a1 |
minivar_t l;
|
|
Packit |
df99a1 |
pprinter_t(miniexp_io_t *io) : printer_t(io) {}
|
|
Packit |
df99a1 |
virtual miniexp_t begin();
|
|
Packit |
df99a1 |
virtual bool newline();
|
|
Packit |
df99a1 |
virtual void end(miniexp_t);
|
|
Packit |
df99a1 |
};
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
miniexp_t
|
|
Packit |
df99a1 |
pprinter_t::begin()
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (dryrun)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
l = miniexp_cons(miniexp_number(tab), l);
|
|
Packit |
df99a1 |
return l;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
ASSERT(miniexp_consp(l));
|
|
Packit |
df99a1 |
ASSERT(miniexp_numberp(car(l)));
|
|
Packit |
df99a1 |
l = cdr(l);
|
|
Packit |
df99a1 |
return miniexp_nil;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
bool
|
|
Packit |
df99a1 |
pprinter_t::newline()
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (! dryrun)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
ASSERT(miniexp_consp(l));
|
|
Packit |
df99a1 |
ASSERT(miniexp_numberp(car(l)));
|
|
Packit |
df99a1 |
int len = miniexp_to_int(car(l));
|
|
Packit |
df99a1 |
if (tab + len >= width)
|
|
Packit |
df99a1 |
return true;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
return false;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void
|
|
Packit |
df99a1 |
pprinter_t::end(miniexp_t p)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (dryrun)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
ASSERT(miniexp_consp(p));
|
|
Packit |
df99a1 |
ASSERT(miniexp_numberp(car(p)));
|
|
Packit |
df99a1 |
int pos = miniexp_to_int(car(p));
|
|
Packit |
df99a1 |
ASSERT(tab >= pos);
|
|
Packit |
df99a1 |
miniexp_rplaca(p, miniexp_number(tab - pos));
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
END_ANONYMOUS_NAMESPACE
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
miniexp_t
|
|
Packit |
df99a1 |
miniexp_prin_r(miniexp_io_t *io, miniexp_t p)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
minivar_t xp = p;
|
|
Packit |
df99a1 |
printer_t printer(io);
|
|
Packit |
df99a1 |
printer.print(p);
|
|
Packit |
df99a1 |
return p;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
miniexp_t
|
|
Packit |
df99a1 |
miniexp_print_r(miniexp_io_t *io, miniexp_t p)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
minivar_t xp = p;
|
|
Packit |
df99a1 |
miniexp_prin_r(io, p);
|
|
Packit |
df99a1 |
io->fputs(io, "\n");
|
|
Packit |
df99a1 |
return p;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
miniexp_t
|
|
Packit |
df99a1 |
miniexp_pprin_r(miniexp_io_t *io, miniexp_t p, int width)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
minivar_t xp = p;
|
|
Packit |
df99a1 |
pprinter_t printer(io);
|
|
Packit |
df99a1 |
printer.width = width;
|
|
Packit |
df99a1 |
// step1 - measure lengths into list <l>
|
|
Packit |
df99a1 |
printer.tab = 0;
|
|
Packit |
df99a1 |
printer.dryrun = true;
|
|
Packit |
df99a1 |
printer.print(p);
|
|
Packit |
df99a1 |
// step2 - print
|
|
Packit |
df99a1 |
printer.tab = 0;
|
|
Packit |
df99a1 |
printer.dryrun = false;
|
|
Packit |
df99a1 |
printer.l = miniexp_reverse(printer.l);
|
|
Packit |
df99a1 |
printer.print(p);
|
|
Packit |
df99a1 |
// check
|
|
Packit |
df99a1 |
ASSERT(printer.l == 0);
|
|
Packit |
df99a1 |
return p;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
miniexp_t
|
|
Packit |
df99a1 |
miniexp_pprint_r(miniexp_io_t *io, miniexp_t p, int width)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
miniexp_pprin_r(io, p, width);
|
|
Packit |
df99a1 |
io->fputs(io, "\n");
|
|
Packit |
df99a1 |
return p;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
/* ---- PNAME */
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static int
|
|
Packit |
df99a1 |
pname_fputs(miniexp_io_t *io, const char *s)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
char *b = (char*)(io->data[0]);
|
|
Packit |
df99a1 |
size_t l = (size_t)(io->data[2]);
|
|
Packit |
df99a1 |
size_t m = (size_t)(io->data[3]);
|
|
Packit |
df99a1 |
size_t x = strlen(s);
|
|
Packit |
df99a1 |
if (l + x >= m)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
size_t nm = l + x + 256;
|
|
Packit |
df99a1 |
char *nb = new char[nm+1];
|
|
Packit |
df99a1 |
memcpy(nb, b, l);
|
|
Packit |
df99a1 |
delete [] b;
|
|
Packit |
df99a1 |
b = nb;
|
|
Packit |
df99a1 |
m = nm;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
strcpy(b + l, s);
|
|
Packit |
df99a1 |
io->data[0] = (void*)(b);
|
|
Packit |
df99a1 |
io->data[2] = (void*)(l + x);
|
|
Packit |
df99a1 |
io->data[3] = (void*)(m);
|
|
Packit |
df99a1 |
return x;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
miniexp_t
|
|
Packit |
df99a1 |
miniexp_pname(miniexp_t p, int width)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
minivar_t r;
|
|
Packit |
df99a1 |
miniexp_io_t io;
|
|
Packit |
df99a1 |
miniexp_io_init(&io);
|
|
Packit |
df99a1 |
io.fputs = pname_fputs;
|
|
Packit |
df99a1 |
io.data[0] = io.data[2] = io.data[3] = 0;
|
|
Packit |
df99a1 |
try
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (width > 0)
|
|
Packit |
df99a1 |
miniexp_pprin_r(&io, p, width);
|
|
Packit |
df99a1 |
else
|
|
Packit |
df99a1 |
miniexp_prin_r(&io, p);
|
|
Packit |
df99a1 |
if (io.data[0])
|
|
Packit |
df99a1 |
r = miniexp_string((const char*)io.data[0]);
|
|
Packit |
df99a1 |
delete [] (char*)(io.data[0]);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
catch(...)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
delete [] (char*)(io.data[0]);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
return r;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
/* ---- INPUT */
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static void
|
|
Packit |
df99a1 |
grow(char* &s, int &l, int &m)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
int nm = ((m<256)?256:m) + ((m>32000)?32000:m);
|
|
Packit |
df99a1 |
char *ns = new char[nm+1];
|
|
Packit |
df99a1 |
memcpy(ns, s, l);
|
|
Packit |
df99a1 |
delete [] s;
|
|
Packit |
df99a1 |
m = nm;
|
|
Packit |
df99a1 |
s = ns;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static void
|
|
Packit |
df99a1 |
append(int c, char* &s, int &l, int &m)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (l >= m)
|
|
Packit |
df99a1 |
grow(s, l, m);
|
|
Packit |
df99a1 |
s[l++] = c;
|
|
Packit |
df99a1 |
s[l] = 0;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static void
|
|
Packit |
df99a1 |
append_utf8(int x, char *&s, int &l, int &m)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (x >= 0 && x <= 0x10ffff)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (l + 4 >= m)
|
|
Packit |
df99a1 |
grow(s, l, m);
|
|
Packit |
df99a1 |
if (x <= 0x7f) {
|
|
Packit |
df99a1 |
s[l++] = (char)x;
|
|
Packit |
df99a1 |
} else if (x <= 0x7ff) {
|
|
Packit |
df99a1 |
s[l++] = (char)((x>>6)|0xc0);
|
|
Packit |
df99a1 |
s[l++] = (char)((x|0x80)&0xbf);
|
|
Packit |
df99a1 |
} else if (x <= 0xffff) {
|
|
Packit |
df99a1 |
s[l++] = (char)((x>>12)|0xe0);
|
|
Packit |
df99a1 |
s[l++] = (char)(((x>>6)|0x80)&0xbf);
|
|
Packit |
df99a1 |
s[l++] = (char)((x|0x80)&0xbf);
|
|
Packit |
df99a1 |
} else {
|
|
Packit |
df99a1 |
s[l++] = (char)((x>>18)|0xf0);
|
|
Packit |
df99a1 |
s[l++] = (char)(((x>>12)|0x80)&0xbf);
|
|
Packit |
df99a1 |
s[l++] = (char)(((x>>6)|0x80)&0xbf);
|
|
Packit |
df99a1 |
s[l++] = (char)((x|0x80)&0xbf);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
s[l] = 0;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static void
|
|
Packit |
df99a1 |
skip_blank(miniexp_io_t *io, int &c)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
while (isspace(c))
|
|
Packit |
df99a1 |
c = io->fgetc(io);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static void
|
|
Packit |
df99a1 |
skip_newline(miniexp_io_t *io, int &c)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
int d = c;
|
|
Packit |
df99a1 |
if (c == '\n' || c == '\r')
|
|
Packit |
df99a1 |
c = io->fgetc(io);
|
|
Packit |
df99a1 |
if ((c == '\n' || c == '\r') && (c != d))
|
|
Packit |
df99a1 |
c = io->fgetc(io);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static int
|
|
Packit |
df99a1 |
skip_octal(miniexp_io_t *io, int &c, int maxlen=3)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
int n = 0;
|
|
Packit |
df99a1 |
int x = 0;
|
|
Packit |
df99a1 |
while (c >= '0' && c < '8' && n++ < maxlen)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
x = (x<<3) + c - '0';
|
|
Packit |
df99a1 |
c = io->fgetc(io);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
return x;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static int
|
|
Packit |
df99a1 |
skip_hexadecimal(miniexp_io_t *io, int &c, int maxlen=2)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
int n = 0;
|
|
Packit |
df99a1 |
int x = 0;
|
|
Packit |
df99a1 |
while (isxdigit(c) && n++ < maxlen && x <= 0x10fff) // unicode range only
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
x = (x<<4) + (isdigit(c) ? c-'0' : toupper(c)-'A'+10);
|
|
Packit |
df99a1 |
c = io->fgetc(io);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
return x;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static miniexp_t
|
|
Packit |
df99a1 |
read_error(miniexp_io_t *io, int &c)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
while (c!=EOF && c!='\n')
|
|
Packit |
df99a1 |
c = io->fgetc(io);
|
|
Packit |
df99a1 |
return miniexp_dummy;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static miniexp_t
|
|
Packit |
df99a1 |
read_c_string(miniexp_io_t *io, int &c)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
miniexp_t r;
|
|
Packit |
df99a1 |
char *s = 0;
|
|
Packit |
df99a1 |
int l = 0;
|
|
Packit |
df99a1 |
int m = 0;
|
|
Packit |
df99a1 |
ASSERT(c == '\"');
|
|
Packit |
df99a1 |
c = io->fgetc(io);
|
|
Packit |
df99a1 |
for(;;)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (c==EOF || (isascii(c) && !isprint(c)))
|
|
Packit |
df99a1 |
return read_error(io, c);
|
|
Packit |
df99a1 |
else if (c=='\"')
|
|
Packit |
df99a1 |
break;
|
|
Packit |
df99a1 |
else if (c=='\\')
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
c = io->fgetc(io);
|
|
Packit |
df99a1 |
if (c == '\n' || c == '\r')
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
skip_newline(io, c);
|
|
Packit |
df99a1 |
continue;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else if (c>='0' && c<='7')
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
int x = skip_octal(io, c, 3);
|
|
Packit |
df99a1 |
append((char)x, s, l, m);
|
|
Packit |
df99a1 |
continue;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else if (c=='x' || c=='X')
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
int d = c;
|
|
Packit |
df99a1 |
c = io->fgetc(io);
|
|
Packit |
df99a1 |
if (isxdigit(c))
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
int x = skip_hexadecimal(io, c, 2);
|
|
Packit |
df99a1 |
append((char)x, s, l, m);
|
|
Packit |
df99a1 |
continue;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
io->ungetc(io, c);
|
|
Packit |
df99a1 |
c = d;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else if (c == 'u' || c == 'U')
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
int x = -1;
|
|
Packit |
df99a1 |
int d = c;
|
|
Packit |
df99a1 |
c = io->fgetc(io);
|
|
Packit |
df99a1 |
if (isxdigit(c))
|
|
Packit |
df99a1 |
x = skip_hexadecimal(io, c, isupper(d) ? 6 : 4);
|
|
Packit |
df99a1 |
while (x >= 0xd800 && x <= 0xdbff && c == '\\')
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
c = io->fgetc(io);
|
|
Packit |
df99a1 |
if (c != 'u' && c != 'U')
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
io->ungetc(io, c);
|
|
Packit |
df99a1 |
c = '\\';
|
|
Packit |
df99a1 |
break;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
d = c;
|
|
Packit |
df99a1 |
c = io->fgetc(io);
|
|
Packit |
df99a1 |
int z = -1;
|
|
Packit |
df99a1 |
if (isxdigit(c))
|
|
Packit |
df99a1 |
z = skip_hexadecimal(io, c, isupper(d) ? 6 : 4);
|
|
Packit |
df99a1 |
if (z >= 0xdc00 && z <= 0xdfff)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
x = 0x10000 + ((x & 0x3ff) << 10) + (z & 0x3ff);
|
|
Packit |
df99a1 |
break;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
append_utf8(x, s, l, m);
|
|
Packit |
df99a1 |
x = z;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
if (x >= 0)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
append_utf8(x, s, l, m);
|
|
Packit |
df99a1 |
continue;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
io->ungetc(io, c);
|
|
Packit |
df99a1 |
c = d;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
static const char *tr1 = "tnrbfva";
|
|
Packit |
df99a1 |
static const char *tr2 = "\t\n\r\b\f\013\007";
|
|
Packit |
df99a1 |
for (int i=0; tr1[i]; i++)
|
|
Packit |
df99a1 |
if (c == tr1[i])
|
|
Packit |
df99a1 |
c = tr2[i];
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
append(c,s,l,m);
|
|
Packit |
df99a1 |
c = io->fgetc(io);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
c = io->fgetc(io);
|
|
Packit |
df99a1 |
r = miniexp_string(s ? s : "");
|
|
Packit |
df99a1 |
delete [] s;
|
|
Packit |
df99a1 |
return r;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static miniexp_t
|
|
Packit |
df99a1 |
read_quoted_symbol(miniexp_io_t *io, int &c)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
miniexp_t r;
|
|
Packit |
df99a1 |
char *s = 0;
|
|
Packit |
df99a1 |
int l = 0;
|
|
Packit |
df99a1 |
int m = 0;
|
|
Packit |
df99a1 |
ASSERT(c == '|');
|
|
Packit |
df99a1 |
for(;;)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
c = io->fgetc(io);
|
|
Packit |
df99a1 |
if (c==EOF || (isascii(c) && !isprint(c)))
|
|
Packit |
df99a1 |
return read_error(io, c);
|
|
Packit |
df99a1 |
if (c=='|')
|
|
Packit |
df99a1 |
if ((c = io->fgetc(io)) != '|')
|
|
Packit |
df99a1 |
break;
|
|
Packit |
df99a1 |
append(c,s,l,m);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
r = miniexp_symbol(s ? s : "");
|
|
Packit |
df99a1 |
delete [] s;
|
|
Packit |
df99a1 |
return r;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static miniexp_t
|
|
Packit |
df99a1 |
read_symbol_or_number(miniexp_io_t *io, int &c)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
miniexp_t r;
|
|
Packit |
df99a1 |
char *s = 0;
|
|
Packit |
df99a1 |
int l = 0;
|
|
Packit |
df99a1 |
int m = 0;
|
|
Packit |
df99a1 |
for(;;)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (c==EOF || c=='(' || c==')' || c=='|' || c=='\"'
|
|
Packit |
df99a1 |
|| isspace(c) || !isascii(c) || !isprint(c)
|
|
Packit |
df99a1 |
|| (io->p_macrochar && io->p_macroqueue
|
|
Packit |
df99a1 |
&& c < 128 && c >= 0 && io->p_macrochar[c] ) )
|
|
Packit |
df99a1 |
break;
|
|
Packit |
df99a1 |
append(c,s,l,m);
|
|
Packit |
df99a1 |
c = io->fgetc(io);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
if (l <= 0)
|
|
Packit |
df99a1 |
return read_error(io, c);
|
|
Packit |
df99a1 |
double x;
|
|
Packit |
df99a1 |
if (str_is_double(s, x))
|
|
Packit |
df99a1 |
r = miniexp_double(x);
|
|
Packit |
df99a1 |
else
|
|
Packit |
df99a1 |
r = miniexp_symbol(s);
|
|
Packit |
df99a1 |
delete [] s;
|
|
Packit |
df99a1 |
return r;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static miniexp_t
|
|
Packit |
df99a1 |
read_miniexp(miniexp_io_t *io, int &c)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
for(;;)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (io->p_macroqueue && miniexp_consp(*io->p_macroqueue))
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
miniexp_t p = car(*io->p_macroqueue);
|
|
Packit |
df99a1 |
*io->p_macroqueue = cdr(*io->p_macroqueue);
|
|
Packit |
df99a1 |
return p;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
skip_blank(io, c);
|
|
Packit |
df99a1 |
if (c == EOF)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
// clean end-of-file.
|
|
Packit |
df99a1 |
return miniexp_dummy;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else if (c == ')')
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
c = io->fgetc(io);
|
|
Packit |
df99a1 |
continue;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else if (c == '(')
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
minivar_t l = miniexp_cons(miniexp_nil, miniexp_nil);
|
|
Packit |
df99a1 |
miniexp_t tail = l;
|
|
Packit |
df99a1 |
minivar_t p;
|
|
Packit |
df99a1 |
c = io->fgetc(io);
|
|
Packit |
df99a1 |
for(;;)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
skip_blank(io, c);
|
|
Packit |
df99a1 |
if (c == ')')
|
|
Packit |
df99a1 |
break;
|
|
Packit |
df99a1 |
if (c == '.')
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
int d = io->fgetc(io);
|
|
Packit |
df99a1 |
io->ungetc(io, d);
|
|
Packit |
df99a1 |
if (isspace(d))
|
|
Packit |
df99a1 |
break;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
p = read_miniexp(io, c);
|
|
Packit |
df99a1 |
if ((miniexp_t)p == miniexp_dummy)
|
|
Packit |
df99a1 |
return read_error(io, c);
|
|
Packit |
df99a1 |
p = miniexp_cons(p, miniexp_nil);
|
|
Packit |
df99a1 |
miniexp_rplacd(tail, p);
|
|
Packit |
df99a1 |
tail = p;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
if (c == '.')
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
c = io->fgetc(io);
|
|
Packit |
df99a1 |
skip_blank(io, c);
|
|
Packit |
df99a1 |
if (c != ')')
|
|
Packit |
df99a1 |
miniexp_rplacd(tail, read_miniexp(io, c));
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
skip_blank(io, c);
|
|
Packit |
df99a1 |
if (c != ')')
|
|
Packit |
df99a1 |
return read_error(io, c);
|
|
Packit |
df99a1 |
c = io->fgetc(io);
|
|
Packit |
df99a1 |
return cdr(l);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else if (c == '"')
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
return read_c_string(io, c);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else if (c == '|')
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
return read_quoted_symbol(io, c);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else if (io->p_macrochar && io->p_macroqueue
|
|
Packit |
df99a1 |
&& c >= 0 && c < 128 && io->p_macrochar[c])
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
miniexp_t p = io->p_macrochar[c](io);
|
|
Packit |
df99a1 |
if (miniexp_length(p) > 0)
|
|
Packit |
df99a1 |
*io->p_macroqueue = p;
|
|
Packit |
df99a1 |
else if (p)
|
|
Packit |
df99a1 |
return read_error(io, c);
|
|
Packit |
df99a1 |
c = io->fgetc(io);
|
|
Packit |
df99a1 |
continue;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else if (c == '#')
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
int nc = io->fgetc(io);
|
|
Packit |
df99a1 |
if (io->p_diezechar && io->p_macroqueue
|
|
Packit |
df99a1 |
&& nc >= 0 && nc < 128 && io->p_diezechar[nc])
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
miniexp_t p = io->p_macrochar[nc](io);
|
|
Packit |
df99a1 |
if (miniexp_length(p) > 0)
|
|
Packit |
df99a1 |
*io->p_macroqueue = p;
|
|
Packit |
df99a1 |
else if (p)
|
|
Packit |
df99a1 |
return read_error(io, c);
|
|
Packit |
df99a1 |
c = io->fgetc(io);
|
|
Packit |
df99a1 |
continue;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else if (nc == '#')
|
|
Packit |
df99a1 |
return read_error(io, c);
|
|
Packit |
df99a1 |
io->ungetc(io, nc);
|
|
Packit |
df99a1 |
// fall thru
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
// default
|
|
Packit |
df99a1 |
return read_symbol_or_number(io, c);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
miniexp_t
|
|
Packit |
df99a1 |
miniexp_read_r(miniexp_io_t *io)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
int c = io->fgetc(io);
|
|
Packit |
df99a1 |
miniexp_t p = read_miniexp(io, c);
|
|
Packit |
df99a1 |
if (c != EOF)
|
|
Packit |
df99a1 |
io->ungetc(io, c);
|
|
Packit |
df99a1 |
return p;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
/* ---- COMPAT */
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
miniexp_t miniexp_read(void)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
return miniexp_read_r(&miniexp_io);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
miniexp_t miniexp_prin(miniexp_t p)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
return miniexp_prin_r(&miniexp_io, p);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
miniexp_t miniexp_print(miniexp_t p)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
return miniexp_print_r(&miniexp_io, p);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
miniexp_t miniexp_pprin(miniexp_t p, int w)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
return miniexp_pprin_r(&miniexp_io, p, w);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
miniexp_t miniexp_pprint(miniexp_t p, int w)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
return miniexp_pprint_r(&miniexp_io, p, w);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void
|
|
Packit |
df99a1 |
minilisp_set_output(FILE *f)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
minilisp_puts = compat_puts;
|
|
Packit |
df99a1 |
miniexp_io_set_output(&miniexp_io, f);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void
|
|
Packit |
df99a1 |
minilisp_set_input(FILE *f)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
minilisp_getc = compat_getc;
|
|
Packit |
df99a1 |
minilisp_ungetc = compat_ungetc;
|
|
Packit |
df99a1 |
miniexp_io_set_input(&miniexp_io, f);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
/* -------------------------------------------------- */
|
|
Packit |
df99a1 |
/* CLEANUP (SEE GC ABOVE) */
|
|
Packit |
df99a1 |
/* -------------------------------------------------- */
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static void
|
|
Packit |
df99a1 |
gc_clear(miniexp_t *pp)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
*pp = 0;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void
|
|
Packit |
df99a1 |
minilisp_finish(void)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
CSLOCK(locker);
|
|
Packit |
df99a1 |
ASSERT(!gc.lock);
|
|
Packit |
df99a1 |
// clear minivars
|
|
Packit |
df99a1 |
minivar_t::mark(gc_clear);
|
|
Packit |
df99a1 |
for (gctls_t *tls = gc.tls; tls; tls=tls->next)
|
|
Packit |
df99a1 |
for (int i=0; i
|
|
Packit |
df99a1 |
tls->recent[i] = 0;
|
|
Packit |
df99a1 |
// collect everything
|
|
Packit |
df99a1 |
gc_run();
|
|
Packit |
df99a1 |
// deallocate everything
|
|
Packit |
df99a1 |
ASSERT(gc.pairs_free == gc.pairs_total);
|
|
Packit |
df99a1 |
while (gc.pairs_blocks)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
block_t *b = gc.pairs_blocks;
|
|
Packit |
df99a1 |
gc.pairs_blocks = b->next;
|
|
Packit |
df99a1 |
delete b;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
ASSERT(gc.objs_free == gc.objs_total);
|
|
Packit |
df99a1 |
while (gc.objs_blocks)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
block_t *b = gc.objs_blocks;
|
|
Packit |
df99a1 |
gc.objs_blocks = b->next;
|
|
Packit |
df99a1 |
delete b;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
delete symbols;
|
|
Packit |
df99a1 |
symbols = 0;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|