ctalk.cpp
来自「C-Talk is interpreted scripting language」· C++ 代码 · 共 1,191 行 · 第 1/2 页
CPP
1,191 行
int i = h % PRIMITIVE_HASH_TABLE_SIZE;
for (CtkPrimitive* pp = primHashTable[i]; pp != NULL; pp = pp->next) {
if (strcmp(pp->name, name) == 0) {
return pp;
}
}
return NULL;
}
DLL_ENTRY
void* ctkAllocateObject(size_t size, CtkFinalizer finalizer) {
return CtkMemoryManager::instance.allocate(size, finalizer);
}
DLL_ENTRY
char* ctkAllocateStringLiteral(char* str)
{
CtkAllocHeader* hdr = (CtkAllocHeader*)malloc(strlen(str) + 1 + sizeof(CtkAllocHeader));
hdr->finalizer = NULL;
hdr->next = NULL;
char* dst = (char*)(hdr + 1);
strcpy(dst, str);
return dst;
}
DLL_ENTRY
void ctkDeallocateStringLiteral(char* str)
{
free((CtkAllocHeader*)str-1);
}
DLL_ENTRY
CtkFile* ctkCreateFile(char const* name, char const* fmt)
{
FILE* f = fopen(name, fmt);
if (f == NULL) {
return NULL;
}
CtkFile* file = (CtkFile*)ctkAllocateObject(sizeof(CtkFile),
CtkFinalizer(ctkDeleteFile));
file->name = new char[strlen(name) + 1];
CHECK_ALLOC(file->name);
strcpy(file->name, name);
file->f = f;
return file;
}
DLL_ENTRY
void ctkDeleteFile(CtkFile* file) {
if (file->f != NULL) {
fclose(file->f);
delete[] file->name;
file->f = NULL;
}
}
DLL_ENTRY
void ctkPrint(CtkObject obj) {
if (obj.type == CTK_STRING) {
fputs(obj.u.svalue, stdout);
} else {
char buf[256];
ctkToString(obj, buf);
fputs(buf, stdout);
}
}
DLL_ENTRY
void ctkPrintFile(CtkFile* file, CtkObject obj) {
if (file->f == NULL) {
ctkThrowException("File was deleted");
}
if (obj.type == CTK_STRING) {
fputs(obj.u.svalue, file->f);
} else {
char buf[256];
ctkToString(obj, buf);
fputs(buf, file->f);
}
}
DLL_ENTRY
void ctkFlushFile(CtkFile* file) {
if (file->f == NULL) {
ctkThrowException("File was deleted");
}
fflush(file->f);
}
DLL_ENTRY
char* ctkToString(CtkObject obj, char* buf)
{
switch (obj.type) {
case CTK_NULL:
strcpy(buf, "NULL");
break;
case CTK_INTEGER:
sprintf(buf, "%ld", (long)obj.u.ivalue);
break;
case CTK_REAL:
sprintf(buf, "%f", obj.u.rvalue);
break;
case CTK_PRIMITIVE:
sprintf(buf, "<%p:PRIMITIVE %s>", obj.u.ptr, ((CtkPrimitive*)obj.u.ptr)->name);
break;
case CTK_FILE:
sprintf(buf, "<%p:FILE %s>", obj.u.ptr, ((CtkFile*)obj.u.ptr)->name);
break;
case CTK_RAW_POINTER:
sprintf(buf, "<%p:RAW POINTER>", obj.u.ptr);
break;
case CTK_STRING:
sprintf(buf, "<%p:STRING \"%.64s\">", obj.u.svalue, obj.u.svalue);
break;
case CTK_ARRAY:
sprintf(buf, "<%p:ARRAY %d items>", obj.u.ptr, ((CtkArray*)obj.u.ptr)->nUsed);
break;
case CTK_MUTEX:
sprintf(buf, "<%p:MUTEX>", obj.u.ptr);
break;
case CTK_THREAD:
sprintf(buf, "<%p:THREAD>", obj.u.ptr);
break;
case CTK_FUNCTION:
sprintf(buf, "<%p:FUNCTION %s>", obj.u.ptr, ((CtkFunction*)obj.u.ptr)->name);
break;
case CTK_FRAME:
sprintf(buf, "<%p:FRAME>", obj.u.ptr);
break;
case CTK_USER_TYPE:
sprintf(buf, "<%p:UDT>", obj.u.ptr);
break;
default:
sprintf(buf, "%p:UNKNOWN type %d>", obj.u.ptr, obj.type);
}
return buf;
}
static CtkArray* options;
DLL_ENTRY
CtkArray* ctkGetCommandLineOptions() {
return options;
}
DLL_ENTRY
void ctkPrintStackTrace(CtkFrame* frame) {
if (frame->up != NULL) {
ctkPrintStackTrace(frame->up);
}
ctkTrace("%s from module %s",
frame->func->name, frame->func->module->tkn->name);
if (frame->call != NULL) {
ctkTrace(" line %d\n", frame->call->line);
} else {
ctkTrace("\n");
}
}
#define FUNC_HASH_TABLE_SIZE 1031;
static CtkFunction* funcHashTable[PRIMITIVE_HASH_TABLE_SIZE];
static mutex_t funcMutex;
DLL_ENTRY
void ctkAddFunction(CtkFunction* f)
{
critical_section cs(funcMutex);
unsigned h = stringHashCode(f->name);
int i = h % PRIMITIVE_HASH_TABLE_SIZE;
f->next = funcHashTable[i];
funcHashTable[i] = f;
}
DLL_ENTRY
CtkFunction* ctkGetFunction(char const* name)
{
unsigned h = stringHashCode(name);
int i = h % PRIMITIVE_HASH_TABLE_SIZE;
for (CtkFunction* f = funcHashTable[i]; f != NULL; f = f->next) {
if (strcmp(f->name, name) == 0) {
return f;
}
}
return NULL;
}
DLL_ENTRY
CtkFrame* ctkCreateFrame(CtkFunction* func)
{
CtkFrame* frame = (CtkFrame*)ctkAllocateObject(sizeof(CtkFrame)
+ (func->nLocalVars-1)*sizeof(CtkObject), NULL);
memset(frame->vars, 0, func->nLocalVars*sizeof(CtkObject));
frame->nVars = func->nLocalVars;
frame->func = func;
frame->up = NULL;
frame->call = NULL;
frame->thread = NULL;
return frame;
}
DLL_ENTRY
CtkObject ctkCallFunction(CtkFunction* func, CtkObject* args)
{
CtkFrame* frame = ctkCreateFrame(func);
CtkThread* thread = (CtkThread*)ctkGetCurrentThread();
frame->thread = thread;
CtkFrame* saveTopFrame = thread->currFrame;
if (saveTopFrame != NULL) {
saveTopFrame->up = frame;
}
thread->currFrame = frame;
memcpy(frame->vars, args, func->nParams*sizeof(CtkObject));
int sp = thread->sp;
CtkMemoryManager::instance.endAccess(thread);
JumpType jump = func->stmts->executeBlock(frame);
CtkMemoryManager::instance.beginAccess(thread);
CtkObject result;
switch (jump) {
case JMP_RETURN:
result = thread->stack[thread->sp-1];
// no break
case JMP_NEXT:
thread->currFrame = saveTopFrame;
thread->sp = sp;
if (saveTopFrame != NULL) {
saveTopFrame->up = NULL;
}
break;
case JMP_BREAK:
ctkThrowException("Invalid use of BREAK statement");
case JMP_CONTINUE:
ctkThrowException("Invalid use of CONTINUE statement");
case JMP_EXCEPTION:
ctkPropagateException();
}
return result;
}
DLL_ENTRY
void ctkSleep(unsigned seconds)
{
#ifdef _WIN32
Sleep(seconds*1000);
#else
sleep(seconds);
#endif
}
DLL_ENTRY
void ctkNotEnoughMemory()
{
CtkMemoryManager::instance.notEnoughMemory();
}
#ifndef _WIN32
#include <dlfcn.h>
#endif
struct CtkDllDescriptor {
CtkDllDescriptor* next;
static CtkDllDescriptor* chain;
void* dll;
CtkDllDescriptor(void* h) {
dll = h;
next = chain;
chain = this;
}
};
CtkDllDescriptor* CtkDllDescriptor::chain;
DLL_ENTRY
int ctkLoadLibrary(char const* name)
{
char buf[1024];
char* p = strrchr(name, '.');
bool hasExtension = p != NULL && p[1] != '.' && p[1] != '/' && p[1] != '\\';
void* dll;
#ifdef _WIN32
if (!hasExtension) {
sprintf(buf, "%s.dll", name);
name = buf;
}
#ifdef _UNICODE
wchar_t wcbuf[1024];
mbstowcs(wcbuf, name, sizeof wcbuf);
dll = LoadLibrary(wcbuf);
#else
dll = LoadLibrary(name);
#endif
#else
if (!hasExtension) {
sprintf(buf, "%s.so", name);
name = buf;
}
dll = dlopen(name, RTLD_NOW);
#endif
if (dll != NULL) {
new CtkDllDescriptor(dll);
return true;
}
return false;
}
DLL_ENTRY
void* ctkFindFunction(char const* name)
{
for (CtkDllDescriptor* desc = CtkDllDescriptor::chain; desc != NULL; desc = desc->next) {
void* func;
#ifdef _WIN32
func = GetProcAddress((HMODULE)desc->dll, name);
#else
func = dlsym(desc->dll, name);
#endif
if (func != NULL) {
return func;
}
}
return NULL;
}
DLL_ENTRY
long ctkGetTimeMillis()
{
#ifdef _WIN32
return GetTickCount();
#else
struct timeval cur_tv;
gettimeofday(&cur_tv, NULL);
return (cur_tv.tv_sec & 0x1FFFFF)*1000 + cur_tv.tv_usec/1000;
#endif
}
DLL_ENTRY
char* ctkGetModuleName(CtkFrame* frame)
{
return (char*)frame->func->module->tkn->name;
}
DLL_ENTRY
char* ctkGetModuleFilePath(CtkFrame* frame)
{
return (char*)frame->func->module->path;
}
DLL_ENTRY
int ctkEqual(CtkObject o1, CtkObject o2)
{
if (o1.type == CTK_STRING && o2.type == CTK_STRING) {
return strcmp(o1.u.svalue, o2.u.svalue) == 0;
} else if (o1.type == CTK_REAL) {
if (o2.type == CTK_REAL) {
return o1.u.rvalue == o2.u.rvalue;
} else if (o2.type == CTK_INTEGER) {
return o1.u.rvalue == o2.u.ivalue;
}
} else if (o1.type == CTK_INTEGER) {
if (o2.type == CTK_REAL) {
return o1.u.ivalue == o2.u.rvalue;
} else if (o2.type == CTK_INTEGER) {
return o1.u.ivalue == o2.u.ivalue;
}
} else if (o1.type == o2.type) {
return o1.u.ptr == o2.u.ptr;
}
return false;
}
DLL_ENTRY
void ctkParseArguments(int nArgs, CtkObject* args, char const* format, ...)
{
va_list params;
va_start(params, format);
bool optionalParameters = false;
for (int i = 0; i < nArgs; i++) {
CtkObject& o = args[i];
int type = o.type;
switch (*format++) {
case ',':
optionalParameters = true;
i -= 1;
continue;
case 'i':
if (type != CTK_INTEGER) {
ctkThrowException("Integer value expected");
}
*va_arg(params, ctk_integer*) = o.u.ivalue;
continue;
case 'I':
if (type != CTK_INTEGER) {
ctkThrowException("Integer value expected");
}
*va_arg(params, CtkObject*) = o;
continue;
case 'r':
if (type != CTK_REAL) {
ctkThrowException("Real value expected");
}
*va_arg(params, ctk_real*) = o.u.rvalue;
continue;
case 'R':
if (type != CTK_REAL) {
ctkThrowException("Real value expected");
}
*va_arg(params, CtkObject*) = o;
continue;
case 'p':
if (type != CTK_RAW_POINTER && type != CTK_NULL) {
ctkThrowException("Raw pointer expected");
}
*va_arg(params, void**) = o.u.ptr;
continue;
case 'P':
if (type != CTK_RAW_POINTER) {
ctkThrowException("Raw pointer expected");
}
*va_arg(params, CtkObject*) = o;
continue;
case 'o':
*va_arg(params, CtkObject*) = o;
continue;
case 'S':
if (type != CTK_STRING) {
ctkThrowException("String expected");
}
*va_arg(params, CtkObject*) = o;
continue;
case 's':
if (type != CTK_STRING && type != CTK_NULL) {
ctkThrowException("String expected");
}
*va_arg(params, char**) = o.u.svalue;
continue;
case 'A':
if (type != CTK_ARRAY) {
ctkThrowException("Array expected");
}
*va_arg(params, CtkObject*) = o;
continue;
case 'a':
if (type != CTK_ARRAY && type != CTK_NULL) {
ctkThrowException("Array expected");
}
*va_arg(params, CtkArray**) = (CtkArray*)o.u.ptr;
continue;
case 'F':
if (type != CTK_FILE) {
ctkThrowException("File expected");
}
*va_arg(params, CtkObject*) = o;
continue;
case 'f':
if (type != CTK_FILE && type != CTK_NULL) {
ctkThrowException("File expected");
}
*va_arg(params, CtkFile**) = (CtkFile*)o.u.ptr;
continue;
case 'M':
if (type != CTK_MUTEX) {
ctkThrowException("Mutex expected");
}
*va_arg(params, CtkObject*) = o;
continue;
case 'm':
if (type != CTK_MUTEX && type != CTK_NULL) {
ctkThrowException("Mutex expected");
}
*va_arg(params, CtkMutex**) = (CtkMutex*)o.u.ptr;
continue;
case 'T':
if (type != CTK_THREAD) {
ctkThrowException("Thread expected");
}
*va_arg(params, CtkObject*) = o;
continue;
case 't':
if (type != CTK_THREAD && type != CTK_NULL) {
ctkThrowException("Thread expected");
}
*va_arg(params, CtkThread**) = (CtkThread*)o.u.ptr;
continue;
case 'L':
if (type != CTK_FUNCTION) {
ctkThrowException("Function expected");
}
*va_arg(params, CtkObject*) = o;
continue;
case 'l':
if (type != CTK_FUNCTION && type != CTK_NULL) {
ctkThrowException("Function expected");
}
*va_arg(params, CtkFunction**) = (CtkFunction*)o.u.ptr;
continue;
case 'U':
if (type != CTK_USER_TYPE) {
ctkThrowException("Value of user defined type expected");
}
*va_arg(params, CtkObject*) = o;
continue;
case 'u':
if (type != CTK_USER_TYPE && type != CTK_NULL) {
ctkThrowException("Value of user defined type expected");
}
*va_arg(params, void**) = o.u.ptr;
continue;
case '\0':
ctkThrowException("Too many arguments for function");
default:
ctkThrowException("Invalid format");
}
}
if (*format != '\0' && *format != ',' && !optionalParameters) {
ctkThrowException("Too few arguments for function");
}
va_end(params);
}
#ifndef EMBEDDED_CTALK
int main(int argc, char* argv[])
{
if (argc == 1) {
printf("C-Talk intergreter version 1.0\n");
printf("Usage: ctalk {options} {module-name}\n"
"Options:\n"
"\t-D<var>=<value>\n"
"\t-p <module-path>{;<module-path>}\n\n");
return 1;
}
CtkCompiler* compiler = &CtkCompiler::instance;
compiler->path = new CtkPath(".", NULL);
CHECK_ALLOC(compiler->path);
options = ctkCreateArray();
CtkObject opt;
MAKE_ARRAY(opt, options);
CtkThreadPool::instance.pushVariable(opt);
for (int i = 1; i < argc; i++) {
if (*argv[i] == '-') {
switch (argv[i][1]) {
case 'p':
case 'P':
if (i+1 < argc) {
char *p, *cp = argv[++i];
while ((p = strchr(cp, ';')) != NULL) {
*p = '\0';
compiler->path = new CtkPath(cp, compiler->path);
CHECK_ALLOC(compiler->path);
cp = p + 1;
}
if (*cp != '\0') {
compiler->path = new CtkPath(cp, compiler->path);
CHECK_ALLOC(compiler->path);
}
continue;
}
break;
case 'd':
case 'D':
{
char* p = strchr(argv[i] + 2, '=');
if (p == NULL) {
break;
} else {
*p = '\0';
CtkObject key;
CtkObject value;
ALLOCATE_STRING(key, argv[i] + 2);
ALLOCATE_STRING(value, p + 1);
ctkPutArray(options, key, value);
continue;
}
}
}
fprintf(stderr, "Invalid option %s\n", argv[i]);
return 1;
} else {
if (compiler->compile(CtkSymbolTable::instance.add(argv[i], IDENT)) == NULL) {
fprintf(stderr, "Failed to locate module \"%s.ctk\"\n", argv[i]);
return 1;
}
}
}
return 0;
}
#endif
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?