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 + -
显示快捷键?