📄 interpret.c
字号:
/* pop past local variables */ StackP = FrameP; /* get stored return information */ nArgs = (--StackP)->val.n; FrameP = (--StackP)->val.dataval; PC = (--StackP)->val.inst; /* pop past function arguments */ StackP -= nArgs; /* push returned value, if requsted */ if (PC == NULL) { if (valOnStack) { PUSH(retVal); } else { PUSH(noValue); } } else if (*PC == fetchRetVal) { if (valOnStack) { PUSH(retVal); PC++; } else { return execError( "using return value of %s which does not return a value", ((Symbol *)*(PC - 2))->name); } } /* NULL return PC indicates end of program */ return PC == NULL ? STAT_DONE : STAT_OK;}/*** Unconditional branch offset by immediate operand**** Before: Prog-> [branchDest], next, ..., (branchdest)next** After: Prog-> branchDest, next, ..., (branchdest)[next]*/static int branch(void){ DISASM_RT(PC-1, 2); STACKDUMP(0, 3); PC += (int)*PC; return STAT_OK;}/*** Conditional branches if stack value is True/False (non-zero/0) to address** of immediate operand (pops stack)**** Before: Prog-> [branchDest], next, ..., (branchdest)next** After: either: Prog-> branchDest, [next], ...** After: or: Prog-> branchDest, next, ..., (branchdest)[next]*/static int branchTrue(void){ int value; Inst *addr; DISASM_RT(PC-1, 2); STACKDUMP(1, 3); POP_INT(value) addr = PC + (int)*PC; PC++; if (value) PC = addr; return STAT_OK;}static int branchFalse(void){ int value; Inst *addr; DISASM_RT(PC-1, 2); STACKDUMP(1, 3); POP_INT(value) addr = PC + (int)*PC; PC++; if (!value) PC = addr; return STAT_OK;}/*** Ignore the address following the instruction and continue. Why? So** some code that uses conditional branching doesn't have to figure out** whether to store a branch address.**** Before: Prog-> [branchDest], next, ...** After: Prog-> branchDest, [next], ...*/static int branchNever(void){ DISASM_RT(PC-1, 2); STACKDUMP(0, 3); PC++; return STAT_OK;}/*** recursively copy(duplicate) the sparse array nodes of an array** this does not duplicate the key/node data since they are never** modified, only replaced*/int ArrayCopy(DataValue *dstArray, DataValue *srcArray){ SparseArrayEntry *srcIter; dstArray->tag = ARRAY_TAG; dstArray->val.arrayPtr = ArrayNew(); srcIter = arrayIterateFirst(srcArray); while (srcIter) { if (srcIter->value.tag == ARRAY_TAG) { int errNum; DataValue tmpArray; errNum = ArrayCopy(&tmpArray, &srcIter->value); if (errNum != STAT_OK) { return(errNum); } if (!ArrayInsert(dstArray, srcIter->key, &tmpArray)) { return(execError("array copy failed", NULL)); } } else { if (!ArrayInsert(dstArray, srcIter->key, &srcIter->value)) { return(execError("array copy failed", NULL)); } } srcIter = arrayIterateNext(srcIter); } return(STAT_OK);}/*** creates an allocated string of a single key for all the sub-scripts** using ARRAY_DIM_SEP as a separator** this function uses the PEEK macros in order to remove most limits on** the number of arguments to an array** I really need to optimize the size approximation rather than assuming** a worst case size for every integer argument*/static int makeArrayKeyFromArgs(int nArgs, char **keyString, int leaveParams){ DataValue tmpVal; int maxIntDigits = (sizeof(tmpVal.val.n) * 3) + 1; int sepLen = strlen(ARRAY_DIM_SEP); int keyLength = 0; int i; keyLength = sepLen * (nArgs - 1); for (i = nArgs - 1; i >= 0; --i) { PEEK(tmpVal, i) if (tmpVal.tag == INT_TAG) { keyLength += maxIntDigits; } else if (tmpVal.tag == STRING_TAG) { keyLength += strlen(tmpVal.val.str); } else { return(execError("can only index array with string or int.", NULL)); } } *keyString = AllocString(keyLength + 1); (*keyString)[0] = 0; for (i = nArgs - 1; i >= 0; --i) { if (i != nArgs - 1) { strcat(*keyString, ARRAY_DIM_SEP); } PEEK(tmpVal, i) if (tmpVal.tag == INT_TAG) { sprintf(&((*keyString)[strlen(*keyString)]), "%d", tmpVal.val.n); } else if (tmpVal.tag == STRING_TAG) { strcat(*keyString, tmpVal.val.str); } else { return(execError("can only index array with string or int.", NULL)); } } if (!leaveParams) { for (i = nArgs - 1; i >= 0; --i) { POP(tmpVal) } } return(STAT_OK);}/*** allocate an empty array node, this is used as the root node and never** contains any data, only refernces to other nodes*/static rbTreeNode *arrayEmptyAllocator(void){ SparseArrayEntry *newNode = allocateSparseArrayEntry(); if (newNode) { newNode->key = NULL; newNode->value.tag = NO_TAG; } return((rbTreeNode *)newNode);}/*** create and copy array node and copy contents, we merely copy pointers** since they are never modified, only replaced*/static rbTreeNode *arrayAllocateNode(rbTreeNode *src){ SparseArrayEntry *newNode = allocateSparseArrayEntry(); if (newNode) { newNode->key = ((SparseArrayEntry *)src)->key; newNode->value = ((SparseArrayEntry *)src)->value; } return((rbTreeNode *)newNode);}/*** copy array node data, we merely copy pointers since they are never** modified, only replaced*/static int arrayEntryCopyToNode(rbTreeNode *dst, rbTreeNode *src){ ((SparseArrayEntry *)dst)->key = ((SparseArrayEntry *)src)->key; ((SparseArrayEntry *)dst)->value = ((SparseArrayEntry *)src)->value; return(1);}/*** compare two array nodes returning an integer value similar to strcmp()*/static int arrayEntryCompare(rbTreeNode *left, rbTreeNode *right){ return(strcmp(((SparseArrayEntry *)left)->key, ((SparseArrayEntry *)right)->key));}/*** dispose an array node, garbage collection handles this, so we mark it** to allow iterators in macro language to determine they have been unlinked*/static void arrayDisposeNode(rbTreeNode *src){ /* Let garbage collection handle this but mark it so iterators can tell */ src->left = NULL; src->right = NULL; src->parent = NULL; src->color = -1;}struct SparseArrayEntry *ArrayNew(void){ return((struct SparseArrayEntry *)rbTreeNew(arrayEmptyAllocator));}/*** insert a DataValue into an array, allocate the array if needed** keyStr must be a string that was allocated with AllocString()*/int ArrayInsert(DataValue *theArray, char *keyStr, DataValue *theValue){ SparseArrayEntry tmpEntry; rbTreeNode *insertedNode; tmpEntry.key = keyStr; tmpEntry.value = *theValue; if (theArray->val.arrayPtr == NULL) { theArray->val.arrayPtr = ArrayNew(); } if (theArray->val.arrayPtr != NULL) { insertedNode = rbTreeInsert((rbTreeNode *)(theArray->val.arrayPtr), (rbTreeNode *)&tmpEntry, arrayEntryCompare, arrayAllocateNode, arrayEntryCopyToNode); if (insertedNode) { return(1); } else { return(0); } } return(0);}/*** remove a node from an array whose key matches keyStr*/void ArrayDelete(DataValue *theArray, char *keyStr){ SparseArrayEntry searchEntry; if (theArray->val.arrayPtr) { searchEntry.key = keyStr; rbTreeDelete((rbTreeNode *)theArray->val.arrayPtr, (rbTreeNode *)&searchEntry, arrayEntryCompare, arrayDisposeNode); }}/*** remove all nodes from an array*/void ArrayDeleteAll(DataValue *theArray){ if (theArray->val.arrayPtr) { rbTreeNode *iter = rbTreeBegin((rbTreeNode *)theArray->val.arrayPtr); while (iter) { rbTreeNode *nextIter = rbTreeNext(iter); rbTreeDeleteNode((rbTreeNode *)theArray->val.arrayPtr, iter, arrayDisposeNode); iter = nextIter; } }}/*** returns the number of elements (nodes containing values) of an array*/int ArraySize(DataValue *theArray){ if (theArray->val.arrayPtr) { return(rbTreeSize((rbTreeNode *)theArray->val.arrayPtr)); } else { return(0); }}/*** retrieves an array node whose key matches** returns 1 for success 0 for not found*/int ArrayGet(DataValue *theArray, char *keyStr, DataValue *theValue){ SparseArrayEntry searchEntry; rbTreeNode *foundNode; if (theArray->val.arrayPtr) { searchEntry.key = keyStr; foundNode = rbTreeFind((rbTreeNode *)theArray->val.arrayPtr, (rbTreeNode *)&searchEntry, arrayEntryCompare); if (foundNode) { *theValue = ((SparseArrayEntry *)foundNode)->value; return(1); } } return(0);}/*** get pointer to start iterating an array*/SparseArrayEntry *arrayIterateFirst(DataValue *theArray){ SparseArrayEntry *startPos; if (theArray->val.arrayPtr) { startPos = (SparseArrayEntry *)rbTreeBegin((rbTreeNode *)theArray->val.arrayPtr); } else { startPos = NULL; } return(startPos);}/*** move iterator to next entry in array*/SparseArrayEntry *arrayIterateNext(SparseArrayEntry *iterator){ SparseArrayEntry *nextPos; if (iterator) { nextPos = (SparseArrayEntry *)rbTreeNext((rbTreeNode *)iterator); } else { nextPos = NULL; } return(nextPos);}/*** evaluate an array element and push the result onto the stack**** Before: Prog-> [nDim], next, ...** Stack-> indnDim, ... ind1, ArraySym, next, ...** After: Prog-> nDim, [next], ...** Stack-> indexedArrayVal, next, ...*/static int arrayRef(void){ int errNum; DataValue srcArray, valueItem; char *keyString = NULL; int nDim; nDim = (int)*PC; PC++; DISASM_RT(PC-2, 2); STACKDUMP(nDim, 3); if (nDim > 0) { errNum = makeArrayKeyFromArgs(nDim, &keyString, 0); if (errNum != STAT_OK) { return(errNum); } POP(srcArray) if (srcArray.tag == ARRAY_TAG) { if (!ArrayGet(&srcArray, keyString, &valueItem)) { return(execError("referenced array value not in array: %s", keyString)); } PUSH(valueItem) return(STAT_OK); } else { return(execError("operator [] on non-array", NULL)); } } else { POP(srcArray) if (srcArray.tag == ARRAY_TAG) { PUSH_INT(ArraySize(&srcArray)) return(STAT_OK); } else { return(execError("operator [] on non-array", NULL)); } }}/*** assign to an array element of a referenced array on the stack**** Before: Prog-> [nDim], next, ...** Stack-> rhs, indnDim, ... ind1, ArraySym, next, ...** After: Prog-> nDim, [next], ...** Stack-> next, ...*/static int arrayAssign(void){ char *keyString = NULL; DataValue srcValue, dstArray; int errNum; int nDim; nDim = (int)*PC; PC++; DISASM_RT(PC-2, 1); STACKDUMP(nDim, 3); if (nDim > 0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -