bool ExprEvaluator::isHigherPriority(oper o1, oper o2){ if(isBinary(o1) && isBinary(o2)) if(o1 == oper::DIVIDE || o1 == oper::MULTIPLY || o2 == oper::BPLUS || o2 == oper::BMINUS) return true; else return false; if(isUnary(o1) && isBinary(o2)) return true; if(isUnary(o2)) return false; if(o1 == oper::SANTINEL && o2 != oper::SANTINEL) return false; if(o2 == oper::SANTINEL) return true; throw new Error(tokenizer.getExpr(), tokenizer.getTokPos(), ":Error comparing operator priorities"); }
unsigned CExpression::operatorCount(sintElem* op) { unsigned k = 1; signed j = 0; while(k)//проверку на достижение начала массива ставить не нужно, если мы предпологаем нотацию разрешаемой {//Ну пошутил. . . Если это оператор, добавить 1 если он бинарный, если не оператор (число) вычесть 1. k += isOperation(op[-++j].lexeme) ? !isUnary(op[-j].lexeme) : -1;//по моему это приведёт нас ко второму операнду } return j; }
int error2(const struct command_t* command){ /*if((isNum(command->token[0]) && isUnary(command->token[1]) && isNum(command->token[2]) && strcmp(command->token[3], "") == 0) || (isNum(command->token[0]) && isBinary(command->token[1]) && strcmp(command->token[2], "") == 0))*/ if(isNum(command->token[0])) if(isUnary(command->token[1])) if(isNum(command->token[2])) if(strcmp(command->token[3], "") == 0) return 1; if(isNum(command->token[0])) if(isBinary(command->token[1])) if(strcmp(command->token[2], "") == 0) return 1; return 0; }
std::ostream& AssignInsn::printTo(std::ostream& stream) const { getLhs()->printTo(stream); stream << " = "; if (isAssign()) { getRhs1()->printTo(stream); } else if (isUnary()) { stream << op; getRhs1()->printTo(stream); } else { getRhs1()->printTo(stream); stream << op; getRhs2()->printTo(stream); } return stream; }
CExpression& CExpression::rebild(const char* CExpression) { delete[] walkthroughArray; delete[] numArray; walkthroughArray = 0; numArray = 0; fine = true; if (!isExp(CExpression)) { fine = false; return *this; } int len = static_cast<int>(strlen(CExpression)); char* sourseString = new char[len * 3 + 1]; for (int i = 0, j = 0; i < len; ++i) sourseString[j++] = CExpression[i]; sourseString[len] = 0; sintAdaptation(sourseString);//Делает строку регистронезависимой, удаляет пробелы/'\t'/'\n', приводит скобочки к однообразию addCode(sourseString);//Заменяет ссылки на функции символами от -128 для удобства дальнейшего анализа std::cout << sourseString << std::endl; for (int i(0); sourseString[i]; ++i) { if (sourseString[i] == 't') sourseString[i] = 'y'; } std::cout << sourseString << std::endl; if (expForm) { toExpForm(sourseString);//Преобразовывает записи типа -3.0e-2 так, }//чтобы они вычислялись как экспоненциальная форма числа. addMult(sourseString);//Добавляет * и 0 для реализации унарного минуса. Функции объеденены по историческим причинам. sortPoland(setArray(sourseString));/*При вызове преобразует строку в массив sintElem и высылает его для сортировки в польскую нотацию*/ short i = 0, numbersCount = 0, opCount = 1; while (walkthroughArray[i].lexeme != 127) { if (walkthroughArray[i].lexeme == 'x' || walkthroughArray[i].lexeme == 'y' || !walkthroughArray[i].lexeme) { ++numbersCount;//Посчитать максимально возможное количество чисел в стеке(тоесть все числа вобще) } else { opCount += !isUnary(walkthroughArray[i].lexeme); } ++i; } //qDebug() << opCount << '<' << numbersCount; if (opCount > numbersCount) { delete[] walkthroughArray; delete[] numArray; walkthroughArray = 0; numArray = 0; fine = false; return *this; } numArray = new double[numbersCount + 1];//1 лишний элемент нужен для оптимизации алгаритма вычисления //std::cout << "объект создан.\n"; return *this; }
CExpression& CExpression::optimization() { /* Проводит беглый предрасчёт выражения. Не учитывает комутативность операци. */ if (!fine) { return *this; } unsigned counter = 0; while(walkthroughArray[counter].lexeme != 127) ++counter; sintElem* temp = new sintElem[counter + 1]; unsigned i = 0, j = 0; while(walkthroughArray[i].lexeme != 127) { if(!walkthroughArray[i].lexeme || walkthroughArray[i].lexeme == 'x' || walkthroughArray[i].lexeme == 'y') temp[j++] = walkthroughArray[i]; else if(isUnary(walkthroughArray[i].lexeme)) if( !temp[j - 1].lexeme ) temp[j - 1] = doIt(walkthroughArray[i].lexeme, temp[j - 1]); else temp[j++] = walkthroughArray[i]; else if( !temp[j - 1].lexeme && !temp[j - 2].lexeme ) { --j; temp[j - 1] = doIt(walkthroughArray[i].lexeme, temp[j - 1], temp[j]); } else temp[j++] = walkthroughArray[i]; ++i; } temp[j].lexeme = 127; /*Безсмысленные операции: * 1, 0 + 0 / 1 - 0 ^ 1 я вижу *, как я ищу операнды? все возможные операции находящиеся перед ним уже выполнены, т. е. может быть 1 x 3 ^ * это же 1*х^3, что должно быть x^3, что значит что я должен собирать какой-то стек из переменных пока не найду в обоих сторонах x или не соберу все, тогда с одной из сторон должен остатся только безсмысленный операнд, проверить обе стороны на его наличие, удалить требуемое. */ i = j = 0; if(temp[1].lexeme != 127) ++(++i);//речь о бинарных операциях, нет смысла изучать что там раньше третьего знака. while(temp[i].lexeme != 127) { switch(temp[i].lexeme) { case '*': if(!temp[i - 1].lexeme && temp[i - 1].number == 1)//правый операнд мы можем проверить сразу { delElements(temp + i - 1, 2);//убираем 1 и * --(--i); } else if(!temp[i - 1].lexeme && temp[i - 1].number == 0) { temp[i].lexeme = 0; temp[i].number = 0;//Чтобы не вызывать два удаления записываем 0 вместо * j = operatorCount(temp + i - 1);//собираем второй операнд, удаляем его и *. delElements(temp + i - j - 1, j + 1); i -= j + 1; } else//иначе просто собираем всё что попадает в правый операнд { j = operatorCount(temp + i); if(!temp[i - j - 1].lexeme && temp[i - j - 1].number == 1) {//удаляем 1 и само умножение. delElements(temp + i, 1); delElements(temp + i - j - 1, 1); --(--i); } else if(!temp[i - j - 1].lexeme && temp[i - j - 1].number == 0) { delElements(temp + i - j, j + 1);//удаляем всё кроме нуля i -= j + 1; } } break; case '+': case '-': if(!temp[i - 1].lexeme && temp[i - 1].number == 0) { delElements(temp + i - 1, 2); --(--i); } else { j = operatorCount(temp + i); if(!temp[i - j - 1].lexeme && temp[i - j - 1].number == 0) { delElements(temp + i, 1); delElements(temp + i - j - 1, 1); --(--i); } } break; case '/': if(!temp[i - 1].lexeme && temp[i - 1].number == 1) { delElements(temp + i - 1, 2); --(--i); } if(!temp[i - 1].lexeme && temp[i - 1].number == 0) { temp[i].lexeme = 0; temp[i].number = 1; j = operatorCount(temp + i - 1); delElements(temp + i - j - 1, j + 1); i -= j + 1; } else { j = operatorCount(temp + i); if(!temp[i - j - 1].lexeme && temp[i - j - 1].number == 0) { delElements(temp + i - j, j + 1); i -= j + 1; } } break; case '^': case -121: if(!temp[i - 1].lexeme && temp[i - 1].number == 1) { delElements(temp + i - 1, 2); --(--i); } else { j = operatorCount(temp + i); if(!temp[i - j - 1].lexeme && ( temp[i - j - 1].number == 0 || temp[i - j - 1].number == 1 ) ) { delElements(temp + i - j, j + 1); i -= j + 1; } } break; } ++i; } delete[] walkthroughArray; walkthroughArray = temp; /* std::cout << "Оптимизированная нотация:\n"; for(i = 0; walkthroughArray[i].lexeme != 127; ++i) if(walkthroughArray[i].lexeme) std::cout << walkthroughArray[i].lexeme << std::endl; else std::cout << walkthroughArray[i].number << std::endl; //*/ return *this; }
Value *OperatorExpression::evaluate(Evaluator &evaluator) const { //qDebug() << "OperatorExpression:" << operatorToText(_op); // Get the operands. Value *rightValue = (_op == MEMBER || _op == AND || _op == OR? nullptr : evaluator.popResult()); Value *leftScopePtr = nullptr; Value *leftValue = (_leftOperand? evaluator.popResult(&leftScopePtr) : nullptr); Value *result = (leftValue? leftValue : rightValue); QScopedPointer<Value> leftScope(leftScopePtr); // will be deleted if not needed DENG2_ASSERT(_op == MEMBER || _op == AND || _op == OR || (!isUnary(_op) && leftValue && rightValue) || ( isUnary(_op) && rightValue)); try { switch (_op) { case PLUS: if (leftValue) { leftValue->sum(*rightValue); } else { // Unary plus is a no-op. } break; case PLUS_ASSIGN: verifyAssignable(leftValue); leftValue->sum(*rightValue); break; case MINUS: if (leftValue) { leftValue->subtract(*rightValue); } else { // Negation. rightValue->negate(); } break; case MINUS_ASSIGN: verifyAssignable(leftValue); leftValue->subtract(*rightValue); break; case DIVIDE: leftValue->divide(*rightValue); break; case DIVIDE_ASSIGN: verifyAssignable(leftValue); leftValue->divide(*rightValue); break; case MULTIPLY: leftValue->multiply(*rightValue); break; case MULTIPLY_ASSIGN: verifyAssignable(leftValue); leftValue->multiply(*rightValue); break; case MODULO: leftValue->modulo(*rightValue); break; case MODULO_ASSIGN: verifyAssignable(leftValue); leftValue->modulo(*rightValue); break; case NOT: result = newBooleanValue(rightValue->isFalse()); break; case RESULT_TRUE: result = newBooleanValue(rightValue->isTrue()); break; case AND: if (!leftValue->isTrue()) { // Early termination. result = newBooleanValue(false); } else { isResultTrue.push(evaluator); _rightOperand->push(evaluator); result = nullptr; } break; case OR: if (leftValue->isTrue()) { // Early termination. result = newBooleanValue(true); } else { isResultTrue.push(evaluator); _rightOperand->push(evaluator); result = nullptr; } break; case EQUAL: result = newBooleanValue(!leftValue->compare(*rightValue)); break; case NOT_EQUAL: result = newBooleanValue(leftValue->compare(*rightValue) != 0); break; case LESS: result = newBooleanValue(leftValue->compare(*rightValue) < 0); break; case GREATER: result = newBooleanValue(leftValue->compare(*rightValue) > 0); break; case LEQUAL: result = newBooleanValue(leftValue->compare(*rightValue) <= 0); break; case GEQUAL: result = newBooleanValue(leftValue->compare(*rightValue) >= 0); break; case IN: result = newBooleanValue(rightValue->contains(*leftValue)); break; case CALL: leftValue->call(evaluator.process(), *rightValue, leftScope.take()); // Result comes from whatever is being called. result = 0; break; case INDEX: { /* LOG_DEV_TRACE_DEBUGONLY("INDEX: types %s [ %s ] byref:%b", DENG2_TYPE_NAME(*leftValue) << DENG2_TYPE_NAME(*rightValue) << flags().testFlag(ByReference)); */ // As a special case, records can be indexed also by reference. RecordValue *recValue = dynamic_cast<RecordValue *>(leftValue); if (flags().testFlag(ByReference) && recValue) { result = new RefValue(&recValue->dereference()[rightValue->asText()]); } else { // Index by value. result = leftValue->duplicateElement(*rightValue); } break; } case SLICE: result = performSlice(*leftValue, *rightValue); break; case MEMBER: { Record *scope = (leftValue? leftValue->memberScope() : 0); if (!scope) { throw ScopeError("OperatorExpression::evaluate", "Left side of " + operatorToText(_op) + " does not have members [" + DENG2_TYPE_NAME(*leftValue) + "]"); } // Now that we know what the scope is, push the rest of the expression // for evaluation (in this specific scope). _rightOperand->push(evaluator, leftValue); // Cleanup. //delete leftValue; DENG2_ASSERT(rightValue == NULL); // The MEMBER operator does not evaluate to any result. // Whatever is on the right side will be the result. return nullptr; } default: throw Error("OperatorExpression::evaluate", "Operator " + operatorToText(_op) + " not implemented"); } } catch (Error const &) { delete rightValue; delete leftValue; throw; } // Delete the unnecessary values. if (result != rightValue) delete rightValue; if (result != leftValue) delete leftValue; return result; }
//Takes an expression in a string and evalutates in, boolean or arithmentic double evaluate_expression(string& input) { SyntaxChecker check; //Here's our checker object double rhs, lhs, result; //Some doubles we will need syntax_status oper; //this is for passing into the function process stack<double> operands; //Operand stack stack<syntax_status> operators; //Operator stack list<exprToken> expression; //Here's the list we need to pass into syntax_check //Here we pass in the expression to see if it passes the test if (check.syntax_check(input, expression) != 0) //this also populates the list of tokens { return numeric_limits<double>::quiet_NaN(); //if the input is invalid, return NaN } if (expression.size() == 0) { return numeric_limits<double>::quiet_NaN(); } //Iterate through the list of tokens for (list<exprToken>::iterator itr = expression.begin(); itr != expression.end(); ++itr) { //If it's a number push it on the operand stack if (itr->isANumber) { operands.push(itr->number); //If there is a negative or not on top of the stack, process it now while (!operators.empty() && isUnary(operators.top())) { if (isNot(operators.top())) result = !operands.top(); else if (isNegative(operators.top())) result = -operands.top(); operands.pop(); operators.pop(); operands.push(result); } } //If it's an operator else if (isOperator(itr->token)) { //if there are none, push it onto the stack if (operators.empty()) { operators.push(itr->token); } //if it's precedence is lower or equal to what's on top, process the last one else if (precedence(itr->token) <= precedence(operators.top())) { rhs = operands.top(); operands.pop(); lhs = operands.top(); operands.pop(); oper = operators.top(); operators.pop(); result = process(lhs, rhs, oper); operands.push(result); operators.push(itr->token); } //if it's of higher precedence, push it on to be processed later else if (precedence(itr->token) > precedence(operators.top())) { operators.push(itr->token); } } //it's an opening parenthesis, put it in operator stack else if (isOpen(itr->token)) { operators.push(itr->token); } //It's a closing parenthesis, process until the last opening parenthesis else if (isClose(itr->token)) { while (!isOpen(operators.top())) { rhs = operands.top(); operands.pop(); lhs = operands.top(); operands.pop(); oper = operators.top(); operators.pop(); operands.push(process(lhs, rhs, oper)); } operators.pop(); //dump the last opening parenthesis, we're done with it //Now if there is a ! or - on top of the operator stack we need to evaluate it //for the expression that was inside the parenthesis while (!operators.empty() && isUnary(operators.top())) { if (isNot(operators.top())) result = !operands.top(); else if (isNegative(operators.top())) result = -operands.top(); operands.pop(); operators.pop(); operands.push(result); } } //If we have a - or ! we need to put it in the operand stack regardless of any precedence else if (isUnary(itr->token)) { operators.push(itr->token); } } //After we finish going through the list, we need to evaluate any remaining operators while (!operators.empty()) { rhs = operands.top(); operands.pop(); lhs = operands.top(); operands.pop(); oper = operators.top(); operators.pop(); operands.push(process(lhs, rhs, oper)); } //The top of the operand stack is the solution return operands.top(); }