ctalk.cpp

来自「C-Talk is interpreted scripting language」· C++ 代码 · 共 1,191 行 · 第 1/2 页

CPP
1,191
字号
#define INSIDE_CTALK 1

#include "compiler.h"
#include "ctkparser.h"

DLL_ENTRY CtkObject ctkNull  = {CTK_NULL, {0}};
DLL_ENTRY CtkObject ctkFalse = {CTK_INTEGER, {0}};
DLL_ENTRY CtkObject ctkTrue  = {CTK_INTEGER, {1}};

int ctkMaxStackSize = 1024;

#ifdef _WIN32
DLL_ENTRY 
void ctkLockMutex(CtkMutex* mutex) { 
    if (mutex->initialized) { 
	EnterCriticalSection(&mutex->cs);
    } else { 
	ctkThrowException("Mutex was deleted");
    }
}

DLL_ENTRY 
void ctkUnlockMutex(CtkMutex* mutex) { 
    if (mutex->initialized) { 
	LeaveCriticalSection(&mutex->cs); 
    } else { 
	ctkThrowException("Mutex was deleted");
    }
}

DLL_ENTRY 
CtkMutex* ctkCreateMutex() { 
    CtkMutex* mutex = 
	(CtkMutex*)ctkAllocateObject(sizeof(CtkMutex), CtkFinalizer(ctkDeleteMutex));
    InitializeCriticalSection(&mutex->cs);
    mutex->initialized = true;
    return mutex;
}
    
DLL_ENTRY 
void ctkDeleteMutex(CtkMutex* mutex) { 
    if (mutex->initialized) { 
	mutex->initialized = false;
	DeleteCriticalSection(&mutex->cs);
    }
} 


#else

#include <sys/time.h>

void ctkLockMutex(CtkMutex* mutex) { 
    if (mutex->initialized) { 
	pthread_t self = pthread_self();
	if (mutex->owner != self) { 
	    pthread_mutex_lock(&mutex->mutex); 
	    mutex->owner = self;
	}
	mutex->count += 1;
    } else { 
	ctkThrowException("Mutex was deleted");
    }
}

void ctkUnlockMutex(CtkMutex* mutex) { 
    if (mutex->initialized) { 
	if (pthread_self() != mutex->owner) { 
	    ctkThrowException("Not owner");
	}
	if (--mutex->count == 0) {
	    mutex->owner = 0;
	    pthread_mutex_unlock(&mutex->mutex);
	}
    } else {
	ctkThrowException("Mutex was deleted");
    }
}

CtkMutex* ctkCreateMutex() { 
    CtkMutex* mutex = (CtkMutex*)ctkAllocateObject(sizeof(CtkMutex), CtkFinalizer(ctkDeleteMutex));
    mutex->count = 0;
    mutex->owner = 0;
    mutex->initialized = true;
    pthread_mutex_init(&mutex->mutex, NULL);
    return mutex;
}
    
void ctkDeleteMutex(CtkMutex* mutex) { 
    pthread_mutex_destroy(&mutex->mutex);
} 

#endif


#define INIT_HASH_SIZE 13

DLL_ENTRY 
CtkArray* ctkCreateArray() { 
    CtkArray* arr = (CtkArray*)ctkAllocateObject(sizeof(CtkArray), CtkFinalizer(ctkDeleteArray));
    arr->entries = new CtkHashEntry*[INIT_HASH_SIZE];
    CHECK_ALLOC(arr->entries); 
    memset(arr->entries, 0, INIT_HASH_SIZE*sizeof(CtkHashEntry*));
    arr->nUsed = 0;
    arr->nAllocated = INIT_HASH_SIZE;
    return arr;
}

inline int hashCode(CtkObject obj) { 
    if (obj.type == CTK_STRING) { 
	int h = 0;
	byte* p = (byte*)obj.u.svalue;
	int ch;
	while ((ch = *p++) != 0) { 
	    h = h*31 + ch;
	}
	return h;
    } else { 
	return (int)obj.u.ivalue;
    }
}

DLL_ENTRY 
void ctkPutArray(CtkArray* arr, CtkObject key, CtkObject value) { 
    if (arr->entries == NULL) {
	ctkThrowException("Array was deleted");
    }
    CtkHashEntry* entry;
    unsigned hash = hashCode(key);
    int i = hash % arr->nAllocated;
    for (entry = arr->entries[i]; entry != NULL; entry = entry->next) { 
	if (entry->hashCode == hash && IS_EQUAL(key, entry->key)) { 
	    entry->value = value;
	    return;
	}
    } 
    if (++arr->nUsed == arr->nAllocated) { 
	// rehash
	int newCapacity = arr->nAllocated * 2;
	CtkHashEntry** newEntries = new CtkHashEntry*[newCapacity];
	CHECK_ALLOC(newEntries);
	memset(newEntries, 0, newCapacity*sizeof(CtkHashEntry*));
	for (int j = arr->nAllocated; --j >= 0;) { 
	    CtkHashEntry* next;
	    for (entry = arr->entries[j]; entry != NULL; entry = next) { 
		next = entry->next;
		int k = entry->hashCode % newCapacity;
		entry->next = newEntries[k];
		newEntries[k]= entry;
	    }
	}
	arr->nAllocated = newCapacity;
	delete[] arr->entries;
	arr->entries = newEntries;
	i = hash % arr->nAllocated;
    }
    entry = new CtkHashEntry();
    CHECK_ALLOC(entry); 
    entry->next = arr->entries[i];
    arr->entries[i] = entry;
    entry->value = value;
    entry->key = key;
    entry->hashCode = hash;
}

DLL_ENTRY 
int ctkDelArray(CtkArray* arr, CtkObject key)
{
    if (arr->entries == NULL) {
	ctkThrowException("Array was deleted");
    }
    CtkHashEntry **epp, *ep;
    unsigned hash = hashCode(key);
    int i = hash % arr->nAllocated;
    for (epp = &arr->entries[i]; (ep = *epp) != NULL; epp = &ep->next) { 	
	if (ep->hashCode == hash && IS_EQUAL(key, ep->key)) { 
	    *epp = ep->next;
	    delete ep;
	    arr->nUsed -= 1;
	    return 1;
	}
    }
    return 0;
}

DLL_ENTRY 
CtkObject ctkGetArray(CtkArray* arr, CtkObject key)
{
    if (arr->entries == NULL) {
	ctkThrowException("Array was deleted");
    }
    CtkHashEntry* entry;
    unsigned hash = hashCode(key);
    int i = hash % arr->nAllocated;
    for (entry = arr->entries[i]; entry != NULL; entry = entry->next) { 
	if (entry->hashCode == hash && IS_EQUAL(key, entry->key)) { 
	    return entry->value;
	}
    } 
    return ctkNull;
}

DLL_ENTRY 
void ctkClearArray(CtkArray* arr)
{
    CtkHashEntry *entry, *next;

    if (arr->entries != NULL) { 
	for (int i = arr->nAllocated; --i >= 0;) { 
	    for (entry = arr->entries[i]; entry != NULL; entry = next) { 
		next = entry->next;
		delete entry;
	    }
	    arr->entries[i] = NULL;
	}
	arr->nUsed = 0;
    }
}

DLL_ENTRY 
void ctkDeleteArray(CtkArray* arr)
{
    ctkClearArray(arr);
    delete[] arr->entries;
    arr->entries = NULL;
}

DLL_ENTRY 
CtkArray* ctkCloneArray(CtkArray* arr)
{
    CtkArray* clone = (CtkArray*)ctkAllocateObject(sizeof(CtkArray), CtkFinalizer(ctkDeleteArray));
    clone->entries = new CtkHashEntry*[arr->nAllocated];
    CHECK_ALLOC(clone->entries); 
    memset(clone->entries, 0, arr->nAllocated*sizeof(CtkHashEntry*));
    clone->nUsed = arr->nUsed;
    clone->nAllocated = arr->nAllocated;
    for (int i = arr->nAllocated; --i >= 0;) { 
	CtkHashEntry **hpp = &clone->entries[i];
	for (CtkHashEntry* entry = arr->entries[i]; entry != NULL; entry = entry->next) { 
	    CtkHashEntry *hp = new CtkHashEntry();
	    CHECK_ALLOC(hp); 
	    hp->key = entry->key;
	    hp->value = entry->value;
	    hp->hashCode = entry->hashCode;
	    *hpp = hp;
	    hpp = &hp->next;
	}
	*hpp = NULL;
    }
    return clone;
}


DLL_ENTRY 
void ctkAddArray(CtkArray* aDst, CtkArray* aSrc)
{
    for (int i = aSrc->nAllocated; --i >= 0;) { 
	for (CtkHashEntry* entry = aSrc->entries[i]; entry != NULL; entry = entry->next) { 
	    ctkPutArray(aDst, entry->key, entry->value);
	}
    }
}

DLL_ENTRY 
void ctkSubArray(CtkArray* aDst, CtkArray* aSrc)
{
    for (int i = aSrc->nAllocated; --i >= 0;) { 
	for (CtkHashEntry* entry = aSrc->entries[i]; entry != NULL; entry = entry->next) { 
	    ctkDelArray(aDst, entry->key);
	}
    }
}

DLL_ENTRY 
void ctkInitializeThread(CtkThread* thr) 
{
    thr->queue.firstItem = thr->queue.lastItem = NULL;
    thr->queue.nItems = 0;
    thr->queue.nBlocked = 0;
    thr->markFunc = NULL;
#ifdef _WIN32
    InitializeCriticalSection(&thr->queue.cs);
    thr->queue.event = CreateEvent(NULL, FALSE, FALSE, NULL);
#else
    pthread_mutex_init(&thr->queue.mutex, NULL);
    pthread_cond_init(&thr->queue.cond, NULL);
#endif   
    thr->exceptionTrace = NULL;
    thr->stackSize = ctkMaxStackSize;
    thr->sp = 0;
    thr->stack = new CtkObject[thr->stackSize];
    CHECK_ALLOC(thr->stack);
    thr->memoryAccess = 0;
    thr->mallocList = NULL;
    thr->lastHeader = NULL;
    thr->exceptionObject = ctkNull;
    thr->usedObject = ctkNull;
    thr->callStack = NULL;
    thr->catchCtx = NULL;
    thr->currFrame = NULL; 
    thr->arg = NULL;
    thr->initialized = 1;

    // Added by KDB
    thr->ctkThreadId = 0;
    CtkThreadPool::instance.addThread(thr);
}

#ifdef _WIN32
DWORD WINAPI threadProg(void* arg) 
#else
void* threadProg(void* arg) 
#endif
{
    CtkThread* t = (CtkThread*)arg; 
    CtkThreadPool::instance.setupThread(t);
    (*t->func)(t->callStack);  
    CtkThreadPool::instance.removeThread(t);
    return 0;
}

DLL_ENTRY 
CtkThread* ctkCreateThread(CtkThreadFunc f, CtkFrame* frame, size_t stackSize)
{
    CtkThread* thr = (CtkThread*)ctkAllocateObject(sizeof(CtkThread), 
						   CtkFinalizer(ctkDeleteThread));
    ctkInitializeThread(thr);
    thr->func = f;
    thr->callStack = frame;

	static int threads_count = 0;
	thr->ctkThreadId = ++threads_count;

    frame->thread = thr;
#ifdef _WIN32    
    HANDLE h = CreateThread(NULL, stackSize, threadProg, thr,
			    0, &thr->threadId);
    CloseHandle(h);
#else
    pthread_attr_t attr;
    pthread_attr_init(&attr);
    pthread_attr_setstacksize(&attr, stackSize);
    pthread_create(&thr->thread, &attr, threadProg, thr);
    pthread_detach(thr->thread);
    pthread_attr_destroy(&attr);
#endif    
    return thr;
}

void ctkRunThread(CtkFrame* frame) { 
#ifdef USE_CTALK_EXCEPTION
    try {
#else
    jmp_buf buf;
    frame->thread->catchCtx = &buf;
    if (setjmp(buf) == 0) { 
#endif
	JumpType jump = frame->func->stmts->executeBlock(frame);
	frame->thread->callStack = NULL;
	switch (jump) { 
	  case JMP_EXCEPTION:
	    ctkTrace("Uncatched exception %s\n", 
		     IF_STRING(frame->thread->exceptionObject));
	    break;
	  case JMP_BREAK:
	  case JMP_CONTINUE:
	    ctkTrace("Unexpected BREAK or CONTINUE statement at line\n"); 
	    break;
	  default:
	    return;
	}
#ifdef USE_CTALK_EXCEPTION
    } catch (CtkException const& x) {
#else
    } else { 
#endif
	ctkTrace("Uncatched exception %s\n", 
		 IF_STRING(frame->thread->exceptionObject));
    } 
    ctkPrintStackTrace(frame);
}
    
DLL_ENTRY 
int ctkGetThreadQueueLength(CtkThread* thr)
{
    return thr->queue.nItems;
}

DLL_ENTRY 
CtkObject ctkGetMessage(CtkThread* thr)
{
    if (!thr->initialized) {
	ctkThrowException("Thread was deleted");
    }
    CtkQueueItem* item;

    CtkThread* curthr = ctkGetCurrentThread();
    int i, nAccesses = curthr->memoryAccess;
    for (i = nAccesses; --i >= 0; CtkMemoryManager::instance.endAccess(curthr));
    
#ifdef _WIN32    
    EnterCriticalSection(&thr->queue.cs);
#else
    pthread_mutex_lock(&thr->queue.mutex);
#endif
    while (thr->queue.nItems == 0) { 
	thr->queue.nBlocked += 1;
#ifdef _WIN32    
	LeaveCriticalSection(&thr->queue.cs);
	WaitForSingleObject(thr->queue.event, INFINITE);
	EnterCriticalSection(&thr->queue.cs);
#else
	pthread_cond_wait(&thr->queue.cond, &thr->queue.mutex);
#endif
    }
    item = thr->queue.firstItem;
    CtkObject value = item->value;
    thr->usedObject = value;
    thr->queue.firstItem = item->next;
    if (item == thr->queue.lastItem) { 
	thr->queue.lastItem = NULL;
    }
    thr->queue.nItems -= 1;

#ifdef _WIN32
    LeaveCriticalSection(&thr->queue.cs);
#else
    pthread_mutex_unlock(&thr->queue.mutex);
#endif
    delete item;
    for (i = nAccesses; --i >= 0; CtkMemoryManager::instance.beginAccess(curthr));
    return value;
}

DLL_ENTRY 
void ctkPutMessage(CtkThread* thr, CtkObject msg)
{
    if (!thr->initialized) {
	ctkThrowException("Thread was deleted");
    }
    CtkQueueItem* item = new CtkQueueItem();
    CHECK_ALLOC(item);
    item->value = msg;
#ifdef _WIN32    
    EnterCriticalSection(&thr->queue.cs);
#else
    pthread_mutex_lock(&thr->queue.mutex);
#endif
    item->next = NULL;
    if (thr->queue.lastItem != NULL) { 
	thr->queue.lastItem->next = item;
    } else { 
	thr->queue.firstItem = item;
    }
    thr->queue.lastItem = item;
    if (thr->queue.nBlocked > 0) { 
	thr->queue.nBlocked -= 1;
#ifdef _WIN32
	SetEvent(thr->queue.event);
#else 
	pthread_cond_signal(&thr->queue.cond);
#endif
    }
    thr->queue.nItems += 1;
#ifdef _WIN32
    LeaveCriticalSection(&thr->queue.cs);
#else
    pthread_mutex_unlock(&thr->queue.mutex);
#endif    
}

DLL_ENTRY 
void ctkDeleteThread(CtkThread* thr) 
{
    if (thr->initialized) { 
	thr->initialized = false;
#ifdef _WIN32
	CloseHandle(thr->queue.event);
	DeleteCriticalSection(&thr->queue.cs);
#else
	pthread_mutex_destroy(&thr->queue.mutex);
	pthread_cond_destroy(&thr->queue.cond);
#endif
	CtkQueueItem *item, *next;
	for (item = thr->queue.firstItem; item != NULL; item = next) { 
	    next = item->next;
	    delete item;
	}
	thr->queue.nItems = 0;
    }
}

DLL_ENTRY 
CtkThread* ctkGetCurrentThread()
{
#ifdef _WIN32
    return (CtkThread*)TlsGetValue(CtkThreadPool::instance.threadKey);
#else
    return (CtkThread*)pthread_getspecific(CtkThreadPool::instance.threadKey);
#endif
}

DLL_ENTRY 
void* ctkThrowException(char const* msg)
{
    CtkThread* thr = ctkGetCurrentThread();
    CtkMemoryManager::instance.beginAccess(thr);
    ALLOCATE_STRING(thr->exceptionObject, (char*)msg);
    CtkMemoryManager::instance.endAccess(thr);
#ifdef USE_CTALK_EXCEPTION
    throw CtkException(thr->exceptionObject.u.svalue);
#else
    longjmp(*thr->catchCtx, 1);
#endif
    return NULL;
}

DLL_ENTRY 
void ctkPropagateException()
{
    CtkThread* thr = ctkGetCurrentThread();
#ifdef USE_CTALK_EXCEPTION
    throw CtkException(thr->exceptionObject.u.svalue);
#else
    longjmp(*thr->catchCtx, 1);
#endif
}

static void defaultTraceFunction(char const* msg, va_list args)
{
    vfprintf(stderr, msg, args);
}

static ctkTraceFunction traceHook = &defaultTraceFunction;

void ctkTrace(char const* msg, ...)
{
    va_list args;
    va_start(args, msg);
    (*traceHook)(msg, args);
    va_end(args);
}

DLL_ENTRY 
ctkTraceFunction ctkSetTraceFunction(ctkTraceFunction hook)
{
    ctkTraceFunction saveHook = traceHook;
    traceHook = hook;
    return saveHook;
}


#define PRIMITIVE_HASH_TABLE_SIZE 1031

CtkObject ctkDefaultPrimitiveTrampolile(CtkPrimitive* prim, int nArgs, CtkObject* args)
{
    return prim->func(nArgs, args);
}

static CtkPrimitive* primHashTable[PRIMITIVE_HASH_TABLE_SIZE];

inline int stringHashCode(char const* s)
{ 
    int h = 0;
    unsigned char* p = (unsigned char*)s;
    while (*p != 0) { 
	h = h*31 + *p++;
    }
    return h;
}

DLL_ENTRY 
void ctkAddPrimitive(CtkPrimitive* prim)
{
    static mutex_t primMutex;
    critical_section cs(primMutex);
    unsigned h = stringHashCode(prim->name);
    int i = h % PRIMITIVE_HASH_TABLE_SIZE;
    for (CtkPrimitive* pp = primHashTable[i]; pp != NULL; pp = pp->next) { 
	if (strcmp(pp->name, prim->name) == 0) { 
	    if (pp->overload) { 
		return;
	    } else if (!prim->overload) { 
		ctkTrace("Redefinition of primitive %s\n", prim->name);
	    }
	    break;
	}
    }
    prim->next = primHashTable[i];
    primHashTable[i] = prim;
}

DLL_ENTRY 
CtkPrimitive* ctkGetPrimitive(char const* name)
{
    unsigned h = stringHashCode(name);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?