📄 interpret.c
字号:
context->stackP->val.subr = NULL; context->stackP->tag = NO_TAG; context->stackP++; *(context->stackP++) = noValue; context->stackP->tag = NO_TAG; context->stackP->val.n = nArgs; context->stackP++; context->frameP = context->stackP; /* Initialize and make room on the stack for local variables */ for (s = prog->localSymList; s != NULL; s = s->next) { *(context->frameP + s->value.val.n) = noValue; context->stackP++; } /* Begin execution, return on error or preemption */ return ContinueMacro(context, result, msg);}/*** Continue the execution of a suspended macro whose state is described in** "continuation"*/int ContinueMacro(RestartData *continuation, DataValue *result, char **msg){ register int status, instCount = 0; register Inst *inst; RestartData oldContext; /* To allow macros to be invoked arbitrarily (such as those automatically triggered within smart-indent) within executing macros, this call is reentrant. */ saveContext(&oldContext); /* ** Execution Loop: Call the succesive routine addresses in the program ** until one returns something other than STAT_OK, then take action */ restoreContext(continuation); ErrMsg = NULL; for (;;) { /* Execute an instruction */ inst = PC++; status = (*inst)(); /* If error return was not STAT_OK, return to caller */ if (status != STAT_OK) { if (status == STAT_PREEMPT) { saveContext(continuation); restoreContext(&oldContext); return MACRO_PREEMPT; } else if (status == STAT_ERROR) { *msg = ErrMsg; FreeRestartData(continuation); restoreContext(&oldContext); return MACRO_ERROR; } else if (status == STAT_DONE) { *msg = ""; *result = *--StackP; FreeRestartData(continuation); restoreContext(&oldContext); return MACRO_DONE; } } /* Count instructions executed. If the instruction limit is hit, preempt, store re-start information in continuation and give X, other macros, and other shell scripts a chance to execute */ instCount++; if (instCount >= INSTRUCTION_LIMIT) { saveContext(continuation); restoreContext(&oldContext); return MACRO_TIME_LIMIT; } }}/*** If a macro is already executing, and requests that another macro be run,** this can be called instead of ExecuteMacro to run it in the same context** as if it were a subroutine. This saves the caller from maintaining** separate contexts, and serializes processing of the two macros without** additional work.*/void RunMacroAsSubrCall(Program *prog){ Symbol *s; static DataValue noValue = {NO_TAG, {0}}; /* See subroutine "callSubroutine" for a description of the stack frame for a subroutine call */ StackP->tag = NO_TAG; StackP->val.inst = PC; StackP++; StackP->tag = NO_TAG; StackP->val.dataval = FrameP; StackP++; StackP->tag = NO_TAG; StackP->val.n = 0; StackP++; FrameP = StackP; PC = prog->code; for (s = prog->localSymList; s != NULL; s = s->next) { *(FrameP + s->value.val.n) = noValue; StackP++; }}void FreeRestartData(RestartData *context){ XtFree((char *)context->stack); XtFree((char *)context);}/*** Cause a macro in progress to be preempted (called by commands which take** a long time, or want to return to the event loop. Call ResumeMacroExecution** to resume.*/void PreemptMacro(void){ PreemptRequest = True;}/*** Reset the return value for a subroutine which caused preemption (this is** how to return a value from a routine which preempts instead of returning** a value directly).*/void ModifyReturnedValue(RestartData *context, DataValue dv){ if (*(context->pc-1) == fetchRetVal) *(context->stackP-1) = dv;}/*** Called within a routine invoked from a macro, returns the window in** which the macro is executing (where the banner is, not where it is focused)*/WindowInfo *MacroRunWindow(void){ return InitiatingWindow;}/*** Called within a routine invoked from a macro, returns the window to which** the currently executing macro is focused (the window which macro commands** modify, not the window from which the macro is being run)*/WindowInfo *MacroFocusWindow(void){ return FocusWindow;}/*** Set the window to which macro subroutines and actions which operate on an** implied window are directed.*/void SetMacroFocusWindow(WindowInfo *window){ FocusWindow = window;}/*** install an array iteration symbol** it is tagged as an integer but holds an array node pointer*/Symbol *InstallIteratorSymbol(){ char symbolName[10 + TYPE_INT_STR_SIZE(int)]; DataValue value; static int interatorNameIndex = 0; sprintf(symbolName, "aryiter #%d", interatorNameIndex); ++interatorNameIndex; value.tag = INT_TAG; value.val.arrayPtr = NULL; return(InstallSymbol(symbolName, LOCAL_SYM, value));}/*** Lookup a constant string by its value. This allows reuse of string** constants and fixing a leak in the interpreter.*/Symbol *LookupStringConstSymbol(const char *value){ Symbol *s; for (s = GlobalSymList; s != NULL; s = s->next) { if (s->type == CONST_SYM && s->value.tag == STRING_TAG && !strcmp(s->value.val.str, value)) { return(s); } } return(NULL);}/*** install string str in the global symbol table with a string name*/Symbol *InstallStringConstSymbol(const char *str){ static int stringConstIndex = 0; char stringName[35]; DataValue value; Symbol *sym = LookupStringConstSymbol(str); if (sym) { return sym; } sprintf(stringName, "string #%d", stringConstIndex++); value.tag = STRING_TAG; value.val.str = AllocStringCpy(str); return(InstallSymbol(stringName, CONST_SYM, value));}/*** find a symbol in the symbol table*/Symbol *LookupSymbol(const char *name){ Symbol *s; for (s = LocalSymList; s != NULL; s = s->next) if (strcmp(s->name, name) == 0) return s; for (s = GlobalSymList; s != NULL; s = s->next) if (strcmp(s->name, name) == 0) return s; return NULL;}/*** install symbol name in symbol table*/Symbol *InstallSymbol(const char *name, enum symTypes type, DataValue value){ Symbol *s; s = (Symbol *)malloc(sizeof(Symbol)); s->name = (char *)malloc(strlen(name)+1); /* +1 for '\0' */ strcpy(s->name, name); s->type = type; s->value = value; if (type == LOCAL_SYM) { s->next = LocalSymList; LocalSymList = s; } else { s->next = GlobalSymList; GlobalSymList = s; } return s;}/*** Promote a symbol from local to global, removing it from the local symbol** list.*/Symbol *PromoteToGlobal(Symbol *sym){ Symbol *s; static DataValue noValue = {NO_TAG, {0}}; if (sym->type != LOCAL_SYM) return sym; /* Remove sym from the local symbol list */ if (sym == LocalSymList) LocalSymList = sym->next; else { for (s = LocalSymList; s != NULL; s = s->next) { if (s->next == sym) { s->next = sym->next; break; } } } s = LookupSymbol(sym->name); if (s != NULL) return s; return InstallSymbol(sym->name, GLOBAL_SYM, noValue);}/*** Allocate memory for a string, and keep track of it, such that it** can be recovered later using GarbageCollectStrings. (A linked list** of pointers is maintained by threading through the memory behind** the returned pointers). Length does not include the terminating null** character, so to allocate space for a string of strlen == n, you must** use AllocString(n+1).*//*#define TRACK_GARBAGE_LEAKS*/#ifdef TRACK_GARBAGE_LEAKSstatic int numAllocatedStrings = 0;static int numAllocatedSparseArrayElements = 0;#endif/* Allocate a new string buffer of length chars */char *AllocString(int length){ char *mem; mem = XtMalloc(length + sizeof(char *) + 1); *((char **)mem) = AllocatedStrings; AllocatedStrings = mem;#ifdef TRACK_GARBAGE_LEAKS ++numAllocatedStrings;#endif return mem + sizeof(char *) + 1;}/* Allocate a new string buffer of length chars, and copy in the string s */char *AllocStringNCpy(const char *s, int length){ char *p = AllocString(length + 1); /* add extra char for forced \0 */ if (!p) return p; if (!s) s = ""; p[length] = '\0'; /* forced \0 */ return strncpy(p, s, length);}/* Allocate a new copy of string s */char *AllocStringCpy(const char *s){ return AllocStringNCpy(s, s ? strlen(s) : 0);}static SparseArrayEntry *allocateSparseArrayEntry(void){ SparseArrayEntryWrapper *mem; mem = (SparseArrayEntryWrapper *)XtMalloc(sizeof(SparseArrayEntryWrapper)); mem->next = (struct SparseArrayEntryWrapper *)AllocatedSparseArrayEntries; AllocatedSparseArrayEntries = mem;#ifdef TRACK_GARBAGE_LEAKS ++numAllocatedSparseArrayElements;#endif return(&(mem->data));}static void MarkArrayContentsAsUsed(SparseArrayEntry *arrayPtr){ SparseArrayEntry *globalSEUse; if (arrayPtr) { ((SparseArrayEntryWrapper *)arrayPtr)->inUse = 1; for (globalSEUse = (SparseArrayEntry *)rbTreeBegin((rbTreeNode *)arrayPtr); globalSEUse != NULL; globalSEUse = (SparseArrayEntry *)rbTreeNext((rbTreeNode *)globalSEUse)) { ((SparseArrayEntryWrapper *)globalSEUse)->inUse = 1; /* test first because it may be read-only static string */ if (!(*(globalSEUse->key - 1))) { *(globalSEUse->key - 1) = 1; } if (globalSEUse->value.tag == STRING_TAG) { /* test first because it may be read-only static string */ if (!(*(globalSEUse->value.val.str - 1))) { *(globalSEUse->value.val.str - 1) = 1; } } else if (globalSEUse->value.tag == ARRAY_TAG) { MarkArrayContentsAsUsed((SparseArrayEntry *)globalSEUse->value.val.arrayPtr); } } }}/*** Collect strings that are no longer referenced from the global symbol** list. THIS CAN NOT BE RUN WHILE ANY MACROS ARE EXECUTING. It must** only be run after all macro activity has ceased.*/void GarbageCollectStrings(void){ SparseArrayEntryWrapper *nextAP, *thisAP; char *p, *next; Symbol *s; /* mark all strings as unreferenced */ for (p = AllocatedStrings; p != NULL; p = *((char **)p)) { *(p + sizeof(char *)) = 0; } for (thisAP = AllocatedSparseArrayEntries; thisAP != NULL; thisAP = (SparseArrayEntryWrapper *)thisAP->next) { thisAP->inUse = 0; } /* Sweep the global symbol list, marking which strings are still referenced */ for (s = GlobalSymList; s != NULL; s = s->next) { if (s->value.tag == STRING_TAG) { /* test first because it may be read-only static string */ if (!(*(s->value.val.str - 1))) { *(s->value.val.str - 1) = 1; } } else if (s->value.tag == ARRAY_TAG) { MarkArrayContentsAsUsed((SparseArrayEntry *)s->value.val.arrayPtr); } } /* Collect all of the strings which remain unreferenced */ next = AllocatedStrings; AllocatedStrings = NULL; while (next != NULL) { p = next; next = *((char **)p); if (*(p + sizeof(char *)) != 0) { *((char **)p) = AllocatedStrings; AllocatedStrings = p; } else {#ifdef TRACK_GARBAGE_LEAKS --numAllocatedStrings;#endif XtFree(p); } } nextAP = AllocatedSparseArrayEntries; AllocatedSparseArrayEntries = NULL; while (nextAP != NULL) { thisAP = nextAP; nextAP = (SparseArrayEntryWrapper *)nextAP->next; if (thisAP->inUse != 0) { thisAP->next = (struct SparseArrayEntryWrapper *)AllocatedSparseArrayEntries; AllocatedSparseArrayEntries = thisAP; } else {#ifdef TRACK_GARBAGE_LEAKS --numAllocatedSparseArrayElements;#endif XtFree((void *)thisAP); } }#ifdef TRACK_GARBAGE_LEAKS printf("str count = %d\nary count = %d\n", numAllocatedStrings, numAllocatedSparseArrayElements);#endif}/*** Save and restore execution context to data structure "context"*/static void saveContext(RestartData *context){ context->stack = Stack; context->stackP = StackP; context->frameP = FrameP; context->pc = PC; context->runWindow = InitiatingWindow; context->focusWindow = FocusWindow;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -