📄 interpret.c
字号:
static int decrement(void){ UNARY_NUMERIC_OPERATION(--)}static int gt(void){ BINARY_NUMERIC_OPERATION(>)}static int lt(void){ BINARY_NUMERIC_OPERATION(<)}static int ge(void){ BINARY_NUMERIC_OPERATION(>=)}static int le(void){ BINARY_NUMERIC_OPERATION(<=)}/*** verify that compares are between integers and/or strings only** Before: Stack-> value1, value2, next, ...** After: Stack-> resValue, next, ...** where resValue is 1 for true, 0 for false*/static int eq(void){ DataValue v1, v2; DISASM_RT(PC-1, 1); STACKDUMP(2, 3); POP(v1) POP(v2) if (v1.tag == INT_TAG && v2.tag == INT_TAG) { v1.val.n = v1.val.n == v2.val.n; } else if (v1.tag == STRING_TAG && v2.tag == STRING_TAG) { v1.val.n = !strcmp(v1.val.str, v2.val.str); } else if (v1.tag == STRING_TAG && v2.tag == INT_TAG) { int number; if (!StringToNum(v1.val.str, &number)) { v1.val.n = 0; } else { v1.val.n = number == v2.val.n; } } else if (v2.tag == STRING_TAG && v1.tag == INT_TAG) { int number; if (!StringToNum(v2.val.str, &number)) { v1.val.n = 0; } else { v1.val.n = number == v1.val.n; } } else { return(execError("incompatible types to compare", NULL)); } v1.tag = INT_TAG; PUSH(v1) return(STAT_OK);}/* negated eq() call */static int ne(void){ eq(); return not();}/*** if left and right arguments are arrays, then the result is a new array** in which only the keys which exist in both the right or left are copied** the values from the right array are used in the result array** Before: Stack-> value2, value1, next, ...** After: Stack-> resValue, next, ...*/static int bitAnd(void){ DataValue leftVal, rightVal, resultArray; int n1, n2; DISASM_RT(PC-1, 1); STACKDUMP(2, 3); PEEK(rightVal, 0) if (rightVal.tag == ARRAY_TAG) { PEEK(leftVal, 1) if (leftVal.tag == ARRAY_TAG) { SparseArrayEntry *leftIter, *rightIter; resultArray.tag = ARRAY_TAG; resultArray.val.arrayPtr = ArrayNew(); POP(rightVal) POP(leftVal) leftIter = arrayIterateFirst(&leftVal); rightIter = arrayIterateFirst(&rightVal); while (leftIter && rightIter) { int insertResult = 1; int compareResult = arrayEntryCompare((rbTreeNode *)leftIter, (rbTreeNode *)rightIter); if (compareResult < 0) { leftIter = arrayIterateNext(leftIter); } else if (compareResult > 0) { rightIter = arrayIterateNext(rightIter); } else { insertResult = ArrayInsert(&resultArray, rightIter->key, &rightIter->value); leftIter = arrayIterateNext(leftIter); rightIter = arrayIterateNext(rightIter); } if (!insertResult) { return(execError("array insertion failure", NULL)); } } PUSH(resultArray) } else { return(execError("can't mix math with arrays and non-arrays", NULL)); } } else { POP_INT(n2) POP_INT(n1) PUSH_INT(n1 & n2) } return(STAT_OK);}/*** if left and right arguments are arrays, then the result is a new array** in which only the keys which exist in either the right or left but not both** are copied** Before: Stack-> value2, value1, next, ...** After: Stack-> resValue, next, ...*/static int bitOr(void){ DataValue leftVal, rightVal, resultArray; int n1, n2; DISASM_RT(PC-1, 1); STACKDUMP(2, 3); PEEK(rightVal, 0) if (rightVal.tag == ARRAY_TAG) { PEEK(leftVal, 1) if (leftVal.tag == ARRAY_TAG) { SparseArrayEntry *leftIter, *rightIter; resultArray.tag = ARRAY_TAG; resultArray.val.arrayPtr = ArrayNew(); POP(rightVal) POP(leftVal) leftIter = arrayIterateFirst(&leftVal); rightIter = arrayIterateFirst(&rightVal); while (leftIter || rightIter) { int insertResult = 1; if (leftIter && rightIter) { int compareResult = arrayEntryCompare((rbTreeNode *)leftIter, (rbTreeNode *)rightIter); if (compareResult < 0) { insertResult = ArrayInsert(&resultArray, leftIter->key, &leftIter->value); leftIter = arrayIterateNext(leftIter); } else if (compareResult > 0) { insertResult = ArrayInsert(&resultArray, rightIter->key, &rightIter->value); rightIter = arrayIterateNext(rightIter); } else { leftIter = arrayIterateNext(leftIter); rightIter = arrayIterateNext(rightIter); } } else if (leftIter) { insertResult = ArrayInsert(&resultArray, leftIter->key, &leftIter->value); leftIter = arrayIterateNext(leftIter); } else { insertResult = ArrayInsert(&resultArray, rightIter->key, &rightIter->value); rightIter = arrayIterateNext(rightIter); } if (!insertResult) { return(execError("array insertion failure", NULL)); } } PUSH(resultArray) } else { return(execError("can't mix math with arrays and non-arrays", NULL)); } } else { POP_INT(n2) POP_INT(n1) PUSH_INT(n1 | n2) } return(STAT_OK);}static int and(void){ BINARY_NUMERIC_OPERATION(&&)}static int or(void){ BINARY_NUMERIC_OPERATION(||)} static int not(void){ UNARY_NUMERIC_OPERATION(!)}/*** raise one number to the power of another** Before: Stack-> raisedBy, number, next, ...** After: Stack-> result, next, ...*/static int power(void){ int n1, n2, n3; DISASM_RT(PC-1, 1); STACKDUMP(2, 3); POP_INT(n2) POP_INT(n1) /* We need to round to deal with pow() giving results slightly above or below the real result since it deals with floating point numbers. Note: We're not really wanting rounded results, we merely want to deal with this simple issue. So, 2^-2 = .5, but we don't want to round this to 1. This is mainly intended to deal with 4^2 = 15.999996 and 16.000001. */ if (n2 < 0 && n1 != 1 && n1 != -1) { if (n1 != 0) { /* since we're integer only, nearly all negative exponents result in 0 */ n3 = 0; } else { /* allow error to occur */ n3 = (int)pow((double)n1, (double)n2); } } else { if ((n1 < 0) && (n2 & 1)) { /* round to nearest integer for negative values*/ n3 = (int)(pow((double)n1, (double)n2) - (double)0.5); } else { /* round to nearest integer for positive values*/ n3 = (int)(pow((double)n1, (double)n2) + (double)0.5); } } PUSH_INT(n3) return errCheck("exponentiation");}/*** concatenate two top items on the stack** Before: Stack-> str2, str1, next, ...** After: Stack-> result, next, ...*/static int concat(void){ char *s1, *s2, *out; int len1, len2; DISASM_RT(PC-1, 1); STACKDUMP(2, 3); POP_STRING(s2) POP_STRING(s1) len1 = strlen(s1); len2 = strlen(s2); out = AllocString(len1 + len2 + 1); strncpy(out, s1, len1); strcpy(&out[len1], s2); PUSH_STRING(out) return STAT_OK;}/*** Call a subroutine or function (user defined or built-in). Args are the** subroutine's symbol, and the number of arguments which have been pushed** on the stack.**** For a macro subroutine, the return address, frame pointer, number of** arguments and space for local variables are added to the stack, and the** PC is set to point to the new function. For a built-in routine, the** arguments are popped off the stack, and the routine is just called.**** Before: Prog-> [subrSym], nArgs, next, ...** Stack-> argN-arg1, next, ...** After: Prog-> next, ... -- (built-in called subr)** Stack-> retVal?, next, ...** or: Prog-> (in called)next, ... -- (macro code called subr)** Stack-> symN-sym1(FP), nArgs, oldFP, retPC, argN-arg1, next, ...*/static int callSubroutine(void){ Symbol *sym, *s; int i, nArgs; static DataValue noValue = {NO_TAG, {0}}; Program *prog; char *errMsg; sym = (Symbol *)*PC++; nArgs = (int)*PC++; DISASM_RT(PC-3, 3); STACKDUMP(nArgs, 3); if (nArgs > MAX_ARGS) return execError("too many arguments to subroutine %s (max 9)", sym->name); /* ** If the subroutine is built-in, call the built-in routine */ if (sym->type == C_FUNCTION_SYM) { DataValue result; /* "pop" stack back to the first argument in the call stack */ StackP -= nArgs; /* Call the function and check for preemption */ PreemptRequest = False; if (!sym->value.val.subr(FocusWindow, StackP, nArgs, &result, &errMsg)) return execError(errMsg, sym->name); if (*PC == fetchRetVal) { if (result.tag == NO_TAG) return execError("%s does not return a value", sym->name); PUSH(result); PC++; } return PreemptRequest ? STAT_PREEMPT : STAT_OK; } /* ** Call a macro subroutine: ** ** Push all of the required information to resume, and make space on the ** stack for local variables (and initialize them), on top of the argument ** values which are already there. */ if (sym->type == MACRO_FUNCTION_SYM) { 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 = nArgs; StackP++; FrameP = StackP; prog = (Program *)sym->value.val.str; PC = prog->code; for (s = prog->localSymList; s != NULL; s = s->next) { *(FrameP + s->value.val.n) = noValue; StackP++; } return STAT_OK; } /* ** Call an action routine */ if (sym->type == ACTION_ROUTINE_SYM) { String argList[MAX_ARGS]; Cardinal numArgs = nArgs; XKeyEvent key_event; Display *disp; Window win; /* Create a fake event with a timestamp suitable for actions which need timestamps, a marker to indicate that the call was from a macro (to stop shell commands from putting up their own separate banner) */ disp=XtDisplay(InitiatingWindow->shell); win=XtWindow(InitiatingWindow->shell); key_event.type = KeyPress; key_event.send_event = MACRO_EVENT_MARKER; key_event.time=XtLastTimestampProcessed(XtDisplay(InitiatingWindow->shell)); /* The following entries are just filled in to avoid problems in strange cases, like calling "self_insert()" directly from the macro menu. In fact the display was sufficient to cure this crash. */ key_event.display=disp; key_event.window=key_event.root=key_event.subwindow=win; /* pop arguments off the stack and put them in the argument list */ for (i=nArgs-1; i>=0; i--) { POP_STRING(argList[i]) } /* Call the action routine and check for preemption */ PreemptRequest = False; sym->value.val.xtproc(FocusWindow->lastFocus, (XEvent *)&key_event, argList, &numArgs); if (*PC == fetchRetVal) return execError("%s does not return a value", sym->name); return PreemptRequest ? STAT_PREEMPT : STAT_OK; } /* Calling a non subroutine symbol */ return execError("%s is not a function or subroutine", sym->name);}/*** This should never be executed, returnVal checks for the presence of this** instruction at the PC to decide whether to push the function's return** value, then skips over it without executing.*/static int fetchRetVal(void){ return execError("internal error: frv", NULL);}/* see comments for returnValOrNone() */static int returnNoVal(void){ return returnValOrNone(False);}static int returnVal(void){ return returnValOrNone(True);}/*** Return from a subroutine call** Before: Prog-> [next], ...** Stack-> retVal?, ...(FP), nArgs, oldFP, retPC, argN-arg1, next, ...** After: Prog-> next, ..., (in caller)[FETCH_RET_VAL?], ...** Stack-> retVal?, next, ...*/static int returnValOrNone(int valOnStack){ DataValue retVal; static DataValue noValue = {NO_TAG, {0}}; int nArgs; DISASM_RT(PC-1, 1); STACKDUMP(StackP - FrameP + FrameP[-1].val.n + 3, 3); /* return value is on the stack */ if (valOnStack) { POP(retVal); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -