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