コード例 #1
0
FormulaToken::Operator FormulaToken::asOperator() const
{
    if( isOperator() )
        return matchOperator( m_text );
    else
        return OperatorInvalid;
}
コード例 #2
0
TokenList KoEnhancedPathFormula::scan( const QString &formula ) const
{
  // parsing state
  enum { Start, Finish, Bad, InNumber, InDecimal, InExpIndicator, InExponent,
    InString, InIdentifier } state;

    TokenList tokens;

    int i = 0;
    state = Start;
    int tokenStart = 0;
    QString tokenText;
    QString expr = formula + QChar();

    // main loop
    while( (state != Bad) && (state != Finish) && (i < expr.length() ) )
    {
        QChar ch = expr[i];

        switch( state )
        {
            case Start:
                tokenStart = i;

                // skip any whitespaces
                if( ch.isSpace() )
                {
                    i++;
                }
                // check for number
                else if( ch.isDigit() )
                {
                    state = InNumber;
                }
                // beginning with alphanumeric ?
                // could be identifier, function, function reference, modifier reference
                else if( isIdentifier( ch ) )
                {
                    state = InIdentifier;
                }
                // decimal dot ?
                else if ( ch == '.' )
                {
                    tokenText.append( expr[i++] );
                    state = InDecimal;
                }
                // terminator character
                else if ( ch == QChar::Null )
                {
                    state = Finish;
                }
                // look for operator match
                else
                {
                    QString opString( ch );
                    int op = matchOperator( opString );

                    // any matched operator ?
                    if( op != FormulaToken::OperatorInvalid )
                    {
                        i++;
                        tokens.append( FormulaToken( FormulaToken::TypeOperator, opString, tokenStart ) );
                    }
                    else state = Bad;
                }
            break;
            case InIdentifier:
                // consume as long as alpha, dollar sign, question mark, or digit
                if( isIdentifier( ch ) || ch.isDigit() )
                {
                    tokenText.append( expr[i++] );
                }
                // a '(' ? then this must be a function identifier
                else if( ch == '(' )
                {
                    tokens.append( FormulaToken( FormulaToken::TypeFunction, tokenText, tokenStart) );
                    tokenStart = i;
                    tokenText = "";
                    state = Start;
                }
                // we're done with identifier
                else
                {
                    tokens.append( FormulaToken( FormulaToken::TypeReference, tokenText, tokenStart) );
                    tokenStart = i;
                    tokenText = "";
                    state = Start;
                }
            break;
            case InNumber:
                // consume as long as it's digit
                if( ch.isDigit() )
                {
                    tokenText.append( expr[i++] );
                }
                // decimal dot ?
                else if( ch == '.' )
                {
                    tokenText.append( '.' );
                    i++;
                    state = InDecimal;
                }
                // exponent ?
                else if( ch.toUpper() == 'E' )
                {
                    tokenText.append( 'E' );
                    i++;
                    state = InExpIndicator;
                }
                // we're done with integer number
                else
                {
                    tokens.append( FormulaToken( FormulaToken::TypeNumber, tokenText, tokenStart ) );
                    tokenText = "";
                    state = Start;
                };
            break;
            case InDecimal:
                // consume as long as it's digit
                if( ch.isDigit() )
                {
                    tokenText.append( expr[i++] );
                }
                // exponent ?
                else if( ch.toUpper() == 'E' )
                {
                    tokenText.append( 'E' );
                    i++;
                    state = InExpIndicator;
                }
                // we're done with floating-point number
                else
                {
                    tokens.append( FormulaToken( FormulaToken::TypeNumber, tokenText, tokenStart ) );
                    tokenText = "";
                    state = Start;
                };
            break;
            case InExpIndicator:
                // possible + or - right after E, e.g 1.23E+12 or 4.67E-8
                if( ( ch == '+' ) || ( ch == '-' ) )
                {
                    tokenText.append( expr[i++] );
                }
                // consume as long as it's digit
                else if( ch.isDigit() )
                {
                    state = InExponent;
                }
                // invalid thing here
                else state = Bad;
            break;
            case InExponent:
                // consume as long as it's digit
                if( ch.isDigit() )
                {
                    tokenText.append( expr[i++] );
                }
                // we're done with floating-point number
                else
                {
                    tokens.append( FormulaToken( FormulaToken::TypeNumber, tokenText, tokenStart ) );
                    tokenText = "";
                    state = Start;
                };
                break;
            case Bad:
            default:
            break;
        }
    }
     return tokens;
}
コード例 #3
0
ファイル: Math.cpp プロジェクト: FuangCao/cavan
bool Calculator::execute(const char *formula, const char *formula_end, double &result)
{
	double value;

#if CAVAN_MATH_DEBUG
	println("formula = %s", text_header(formula, formula_end - formula));
#endif

	mStackOperand.clear();
	mStackOperator.clear();
	mLastFieldType = FIELD_TYPE_NONE;

	while (formula < formula_end) {
		Operator *op = matchOperator(formula);
		if (op) {
			Operator *top;
			if (mStackOperator.top(top)) {
				if (top->getPriority() <= op->getPriority()) {
					if (!top->execute(mStackOperand)) {
						setErrMsg(top->getErrMsg());
						return false;
					}

					mStackOperator.pop(top);
				}
			}

			if (op->getOmitMul() && mLastFieldType == FIELD_TYPE_VALUE && mStackOperand.hasData()) {
				Operator *mul = matchOperator("*");
				if (mul) {
					mStackOperator.push(mul);
				}
			}

			switch (op->getType()) {
			case OPERATOR_TYPE2:
			case OPERATOR_TYPE1_RIGHT:
				if (!mStackOperator.push(op)) {
					setErrMsg("Operator stack overfrow");
					return false;
				}

				formula += op->getLength();
				break;

			case OPERATOR_TYPE1_LEFT:
			case OPERATOR_TYPE_CONSTANT:
				if (!op->execute(mStackOperand)) {
					setErrMsg(op->getErrMsg());
					return false;
				}

				formula += op->getLength();
				break;

			case OPERATOR_TYPE_LIST: {
				Stack<double> stack(200);
				if (!parseDataList(formula + op->getLength(), formula_end, &formula, stack)) {
					return false;
				}

				if (!op->execute(stack, mStackOperand)) {
					setErrMsg(op->getErrMsg());
					return false;
				}
				break;
			}

			default:
				setErrMsg("Invalid operator");
				return false;
			}

			mLastFieldType = FIELD_TYPE_OPERATOR;
		} else {
			switch (*formula) {
			case ' ':
			case '\r':
			case '\n':
			case '\t':
			case '\f':
				formula++;
				break;

			case '0' ... '9':
				value = text2double_unsigned(formula, formula_end, &formula, 10);
				if (mLastFieldType == FIELD_TYPE_OPERATOR && mStackOperator.count() == 1 && mStackOperand.isEmpty()) {
					Operator *op;
					if (mStackOperator.top(op) && strcmp(op->getSymbol(), "-") == 0) {
						value = -value;
						mStackOperator.pop(op);
					}
				}

				if (!mStackOperand.push(value)) {
					setErrMsg("Operand stack overfrow");
					return false;
				}
				mLastFieldType = FIELD_TYPE_VALUE;
				break;

			case '(':
			case '[':
			case '{':
			{
				const char *p = get_bracket_pair(formula, formula_end);
				if (p == NULL) {
					setErrMsg("No matching brackets");
					return false;
				}

				Calculator calculator;
				if (!calculator.execute(formula + 1, p, value)) {
					setErrMsg(calculator.getErrMsg());
					return false;
				}

				if (!mStackOperand.push(value)) {
					setErrMsg("Operand stack overfrow");
					return false;
				}

				formula = p + 1;
				mLastFieldType = FIELD_TYPE_BRACKET;
				break;
			}

			default:
				setErrMsg("Invalid symbol");
				return false;
			}
		}
	}

	while (1) {
		Operator *op;
		if (!mStackOperator.pop(op)) {
			break;
		}

		if (!op->execute(mStackOperand)) {
			setErrMsg(op->getErrMsg());
			return false;
		}
	}

	if (!mStackOperand.pop(result)) {
		setErrMsg("Missing operand");
		return false;
	}

	if (mStackOperand.hasData()) {
		setErrMsg("Too much operand");
		return false;
	}

	return true;
}