mirror of
https://github.com/mcneel/opennurbs.git
synced 2026-03-01 11:36:09 +08:00
938 lines
23 KiB
C++
938 lines
23 KiB
C++
//
|
|
// Copyright (c) 1993-2022 Robert McNeel & Associates. All rights reserved.
|
|
// OpenNURBS, Rhinoceros, and Rhino3D are registered trademarks of Robert
|
|
// McNeel & Associates.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
|
|
// ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF
|
|
// MERCHANTABILITY ARE HEREBY DISCLAIMED.
|
|
//
|
|
// For complete openNURBS copyright information see <http://www.opennurbs.org>.
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
#include "opennurbs.h"
|
|
|
|
#if !defined(ON_COMPILING_OPENNURBS)
|
|
// This check is included in all opennurbs source .c and .cpp files to insure
|
|
// ON_COMPILING_OPENNURBS is defined when opennurbs source is compiled.
|
|
// When opennurbs source is being compiled, ON_COMPILING_OPENNURBS is defined
|
|
// and the opennurbs .h files alter what is declared and how it is declared.
|
|
#error ON_COMPILING_OPENNURBS must be defined when compiling opennurbs
|
|
#endif
|
|
|
|
class ON_ArithmeticCalculatorImplementation
|
|
{
|
|
public:
|
|
ON_ArithmeticCalculatorImplementation();
|
|
|
|
enum ARITHMETIC_OP
|
|
{
|
|
op_unset = 0, // stack element is not set
|
|
op_number = 1, // most recently entered number or expression value
|
|
op_mult = 2, // first operand in a multiplication
|
|
op_div = 3, // first operand in a division
|
|
op_add = 4, // first operand in a addition
|
|
op_sub = 5 // first operand in a subtraction
|
|
};
|
|
|
|
enum
|
|
{
|
|
// op_stack_capacity is large to accomodate expressions
|
|
// with nested parenthises. A stack of four elements
|
|
// suffices to parse expressions that do not not contain
|
|
// nested parentheses.
|
|
op_stack_capacity = 62
|
|
};
|
|
|
|
// configuration settings true or false
|
|
unsigned char m_bImpliedMultiplicationEnabled; // default = true
|
|
|
|
// states 1 or 0
|
|
unsigned char m_bPendingImpliedMultiplication;
|
|
unsigned char m_bPendingUnaryPlus;
|
|
unsigned char m_bPendingUnaryMinus;
|
|
unsigned char m_bUnsetValue;
|
|
unsigned char m_error_condition;
|
|
|
|
unsigned char m_reserved[2];
|
|
|
|
unsigned int m_op_stack_pointer;
|
|
unsigned int m_expression_depth;
|
|
|
|
struct tagOP_STACK_ELEMENT
|
|
{
|
|
double m_x;
|
|
ARITHMETIC_OP m_op;
|
|
unsigned int m_level;
|
|
};
|
|
|
|
// operation stack
|
|
struct tagOP_STACK_ELEMENT m_op_stack[op_stack_capacity];
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
//
|
|
// State queries
|
|
//
|
|
bool IsEmpty() const;
|
|
|
|
bool IsUnsetValue() const;
|
|
|
|
ARITHMETIC_OP ArithmeticOperationIsPending() const;
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
//
|
|
// Calculation actions
|
|
//
|
|
bool AppendUnaryOperation(
|
|
double sign
|
|
);
|
|
|
|
bool AppendNumber( double number, bool bSupportImpliedMultiplication );
|
|
|
|
bool AppendArithmeticOperator( ARITHMETIC_OP op );
|
|
|
|
bool IncreaseExpressionDepth();
|
|
|
|
bool DecreaseExpressionDepth();
|
|
|
|
bool EvaluatePendingArithmeticOperation();
|
|
|
|
bool Evaluate(
|
|
double* value
|
|
);
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
//
|
|
// Other
|
|
//
|
|
void ClearStack();
|
|
|
|
void ClearStates();
|
|
|
|
void SetErrorCondition(
|
|
ON_ArithmeticCalculator::ERROR_CONDITION error_condition
|
|
);
|
|
};
|
|
|
|
ON_ArithmeticCalculatorImplementation::ON_ArithmeticCalculatorImplementation()
|
|
: m_bImpliedMultiplicationEnabled(1)
|
|
{
|
|
ClearStates();
|
|
ClearStack();
|
|
}
|
|
|
|
ON_ArithmeticCalculator::ON_ArithmeticCalculator()
|
|
: m_pCalc(0)
|
|
{
|
|
// suppress MSC "conditional expression is constant" warning
|
|
#pragma ON_PRAGMA_WARNING_PUSH
|
|
#pragma ON_PRAGMA_WARNING_DISABLE_MSC( 4127 )
|
|
if ( sizeof(*m_pCalc) <= sizeof(m_inplace_buffer) )
|
|
{
|
|
m_pCalc = new ((void*)(&m_inplace_buffer[0])) ON_ArithmeticCalculatorImplementation();
|
|
}
|
|
#pragma ON_PRAGMA_WARNING_POP
|
|
}
|
|
|
|
ON_ArithmeticCalculator::ON_ArithmeticCalculator(const ON_ArithmeticCalculator& src)
|
|
: m_pCalc(0)
|
|
{
|
|
if ( 0 != src.m_pCalc )
|
|
{
|
|
// suppress MSC "conditional expression is constant" warning
|
|
#pragma ON_PRAGMA_WARNING_PUSH
|
|
#pragma ON_PRAGMA_WARNING_DISABLE_MSC( 4127 )
|
|
if ( sizeof(*m_pCalc) <= sizeof(m_inplace_buffer) )
|
|
{
|
|
m_pCalc = new ((void*)(&m_inplace_buffer[0])) ON_ArithmeticCalculatorImplementation();
|
|
*m_pCalc = *src.m_pCalc;
|
|
}
|
|
#pragma ON_PRAGMA_WARNING_POP
|
|
}
|
|
}
|
|
|
|
ON_ArithmeticCalculator::ON_ArithmeticCalculator(ON_ArithmeticCalculator&& src)
|
|
: m_pCalc(0)
|
|
{
|
|
// The && version is here because the implementation may change
|
|
// in a way that will permit the && version to be more efficient.
|
|
if ( 0 != src.m_pCalc )
|
|
{
|
|
// suppress MSC "conditional expression is constant" warning
|
|
#pragma ON_PRAGMA_WARNING_PUSH
|
|
#pragma ON_PRAGMA_WARNING_DISABLE_MSC( 4127 )
|
|
if ( sizeof(*m_pCalc) <= sizeof(m_inplace_buffer) )
|
|
{
|
|
m_pCalc = new ((void*)(&m_inplace_buffer[0])) ON_ArithmeticCalculatorImplementation();
|
|
*m_pCalc = *src.m_pCalc;
|
|
}
|
|
src.m_pCalc = 0;
|
|
#pragma ON_PRAGMA_WARNING_POP
|
|
}
|
|
}
|
|
|
|
ON_ArithmeticCalculator& ON_ArithmeticCalculator::operator=(const ON_ArithmeticCalculator& src)
|
|
{
|
|
if ( this != &src )
|
|
{
|
|
if ( m_pCalc )
|
|
{
|
|
if ( src.m_pCalc )
|
|
*m_pCalc = *src.m_pCalc;
|
|
else
|
|
ClearAll();
|
|
}
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
ON_ArithmeticCalculator& ON_ArithmeticCalculator::operator=(ON_ArithmeticCalculator&& src)
|
|
{
|
|
// The && version is here because the implementation may change
|
|
// in a way that will permit the && version to be more efficient.
|
|
if ( this != &src )
|
|
{
|
|
if ( m_pCalc )
|
|
{
|
|
if ( src.m_pCalc )
|
|
{
|
|
*m_pCalc = *src.m_pCalc;
|
|
}
|
|
else
|
|
ClearAll();
|
|
}
|
|
src.m_pCalc = 0;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
|
|
|
|
bool ON_ArithmeticCalculator::ImpliedMultiplication() const
|
|
{
|
|
return (m_pCalc && m_pCalc->m_bImpliedMultiplicationEnabled)?true:false;
|
|
}
|
|
|
|
void ON_ArithmeticCalculator::SetImpliedMultiplication(
|
|
bool bEnable
|
|
)
|
|
{
|
|
if ( m_pCalc )
|
|
{
|
|
m_pCalc->m_bImpliedMultiplicationEnabled = bEnable ? 1 : 0;
|
|
}
|
|
}
|
|
|
|
ON_ArithmeticCalculator::ERROR_CONDITION ON_ArithmeticCalculator::ErrorCondition() const
|
|
{
|
|
ERROR_CONDITION error_condition;
|
|
if ( 0 == m_pCalc )
|
|
{
|
|
error_condition = ON_ArithmeticCalculator::program_error;
|
|
}
|
|
else
|
|
{
|
|
switch( m_pCalc->m_error_condition )
|
|
{
|
|
case ON_ArithmeticCalculator::no_error:
|
|
error_condition = ON_ArithmeticCalculator::no_error;
|
|
break;
|
|
case ON_ArithmeticCalculator::program_error:
|
|
error_condition = ON_ArithmeticCalculator::program_error;
|
|
break;
|
|
case ON_ArithmeticCalculator::invalid_expression_error:
|
|
error_condition = ON_ArithmeticCalculator::invalid_expression_error;
|
|
break;
|
|
case ON_ArithmeticCalculator::divide_by_zero_error:
|
|
error_condition = ON_ArithmeticCalculator::divide_by_zero_error;
|
|
break;
|
|
case ON_ArithmeticCalculator::overflow_error:
|
|
error_condition = ON_ArithmeticCalculator::overflow_error;
|
|
break;
|
|
default:
|
|
error_condition = ON_ArithmeticCalculator::program_error;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return error_condition;
|
|
}
|
|
|
|
unsigned int ON_ArithmeticCalculator::ParenthesesDepth() const
|
|
{
|
|
return (m_pCalc && m_pCalc->m_expression_depth > 1) ? ( m_pCalc->m_expression_depth - 1) : 0;
|
|
}
|
|
|
|
bool ON_ArithmeticCalculator::PendingUnaryOperation() const
|
|
{
|
|
return (PendingUnaryMinus() || PendingUnaryPlus());
|
|
}
|
|
|
|
bool ON_ArithmeticCalculator::PendingUnaryPlus() const
|
|
{
|
|
return (m_pCalc && m_pCalc->m_bPendingUnaryPlus)?true:false;
|
|
}
|
|
|
|
bool ON_ArithmeticCalculator::PendingUnaryMinus() const
|
|
{
|
|
return (m_pCalc && m_pCalc->m_bPendingUnaryMinus)?true:false;
|
|
}
|
|
|
|
bool ON_ArithmeticCalculator::PendingImpliedMultiplication() const
|
|
{
|
|
return ( (m_pCalc && m_pCalc->m_bImpliedMultiplicationEnabled) ? m_pCalc->m_bPendingImpliedMultiplication : false)?true:false;
|
|
}
|
|
|
|
bool ON_ArithmeticCalculatorImplementation::AppendUnaryOperation(
|
|
double sign
|
|
)
|
|
{
|
|
bool rc = false;
|
|
|
|
for(;;)
|
|
{
|
|
if ( m_error_condition)
|
|
break;
|
|
|
|
if ( m_bPendingUnaryMinus || m_bPendingUnaryPlus )
|
|
{
|
|
SetErrorCondition(ON_ArithmeticCalculator::invalid_expression_error);
|
|
break;
|
|
}
|
|
|
|
if ( 1.0 == sign )
|
|
{
|
|
m_bPendingUnaryPlus = true;
|
|
rc = true;
|
|
break;
|
|
}
|
|
|
|
if ( -1.0 == sign )
|
|
{
|
|
m_bPendingUnaryMinus = true;
|
|
rc = true;
|
|
break;
|
|
}
|
|
|
|
SetErrorCondition(ON_ArithmeticCalculator::invalid_expression_error);
|
|
|
|
break;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
bool ON_ArithmeticCalculator::UnaryPlus()
|
|
{
|
|
return m_pCalc ? m_pCalc->AppendUnaryOperation(1.0) : false;
|
|
}
|
|
|
|
bool ON_ArithmeticCalculator::UnaryMinus()
|
|
{
|
|
return m_pCalc ? m_pCalc->AppendUnaryOperation(-1.0) : false;
|
|
}
|
|
|
|
bool ON_ArithmeticCalculator::LeftParenthesis()
|
|
{
|
|
return m_pCalc ? m_pCalc->IncreaseExpressionDepth() : false;
|
|
}
|
|
|
|
bool ON_ArithmeticCalculator::RightParenthesis()
|
|
{
|
|
return m_pCalc ? m_pCalc->DecreaseExpressionDepth() : false;
|
|
}
|
|
|
|
bool ON_ArithmeticCalculatorImplementation::IncreaseExpressionDepth()
|
|
{
|
|
if ( m_error_condition)
|
|
return false;
|
|
|
|
if ( IsEmpty() )
|
|
{
|
|
// SimpleNumber takes care of any pending unary minus or unary plus operations.
|
|
if ( !AppendNumber(1.0,false) )
|
|
return false;
|
|
if ( !AppendArithmeticOperator(ON_ArithmeticCalculatorImplementation::op_mult) )
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
if ( m_bImpliedMultiplicationEnabled
|
|
&& ON_ArithmeticCalculatorImplementation::op_number == m_op_stack[m_op_stack_pointer].m_op
|
|
)
|
|
{
|
|
// previous element is a value and multiplication
|
|
// is implied
|
|
m_op_stack[m_op_stack_pointer].m_op = ON_ArithmeticCalculatorImplementation::op_mult;
|
|
}
|
|
|
|
const double unary_sign = m_bPendingUnaryMinus ? -1.0 : 1.0;
|
|
m_bPendingUnaryMinus = false;
|
|
m_bPendingUnaryPlus = false;
|
|
switch(m_op_stack[m_op_stack_pointer].m_op)
|
|
{
|
|
case ON_ArithmeticCalculatorImplementation::op_mult:
|
|
case ON_ArithmeticCalculatorImplementation::op_div:
|
|
if ( false == m_bUnsetValue && 0.0 != m_op_stack[m_op_stack_pointer].m_x )
|
|
m_op_stack[m_op_stack_pointer].m_x *= unary_sign;
|
|
break;
|
|
|
|
case ON_ArithmeticCalculatorImplementation::op_add:
|
|
case ON_ArithmeticCalculatorImplementation::op_sub:
|
|
if ( !AppendNumber(unary_sign,false) )
|
|
return false;
|
|
if ( !AppendArithmeticOperator(ON_ArithmeticCalculatorImplementation::op_mult) )
|
|
return false;
|
|
break;
|
|
|
|
default:
|
|
SetErrorCondition(ON_ArithmeticCalculator::invalid_expression_error);
|
|
return false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
m_expression_depth++;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool ON_ArithmeticCalculatorImplementation::DecreaseExpressionDepth()
|
|
{
|
|
if (m_error_condition)
|
|
return false;
|
|
|
|
if ( m_expression_depth <= 1 )
|
|
{
|
|
SetErrorCondition(ON_ArithmeticCalculator::invalid_expression_error);
|
|
return false;
|
|
}
|
|
|
|
if ( m_expression_depth != m_op_stack[m_op_stack_pointer].m_level )
|
|
{
|
|
SetErrorCondition(ON_ArithmeticCalculator::invalid_expression_error);
|
|
return false;
|
|
}
|
|
|
|
m_bPendingImpliedMultiplication = false;
|
|
|
|
const unsigned int pending_op = ArithmeticOperationIsPending();
|
|
switch(pending_op)
|
|
{
|
|
case ON_ArithmeticCalculatorImplementation::op_add:
|
|
case ON_ArithmeticCalculatorImplementation::op_sub:
|
|
if ( !EvaluatePendingArithmeticOperation() )
|
|
return false;
|
|
break;
|
|
|
|
case ON_ArithmeticCalculatorImplementation::op_unset:
|
|
// empty case
|
|
break;
|
|
|
|
default:
|
|
SetErrorCondition(ON_ArithmeticCalculator::invalid_expression_error);
|
|
return false;
|
|
break;
|
|
}
|
|
|
|
if ( m_expression_depth != m_op_stack[m_op_stack_pointer].m_level )
|
|
{
|
|
SetErrorCondition(ON_ArithmeticCalculator::invalid_expression_error);
|
|
return false;
|
|
}
|
|
|
|
if ( ON_ArithmeticCalculatorImplementation::op_number != m_op_stack[m_op_stack_pointer].m_op )
|
|
{
|
|
SetErrorCondition(ON_ArithmeticCalculator::invalid_expression_error);
|
|
return false;
|
|
}
|
|
|
|
m_expression_depth--;
|
|
m_op_stack[m_op_stack_pointer].m_level = m_expression_depth;
|
|
|
|
const unsigned int previous_pending_op = ArithmeticOperationIsPending();
|
|
switch(previous_pending_op)
|
|
{
|
|
case ON_ArithmeticCalculatorImplementation::op_mult:
|
|
case ON_ArithmeticCalculatorImplementation::op_div:
|
|
if ( !EvaluatePendingArithmeticOperation() )
|
|
return false;
|
|
break;
|
|
}
|
|
|
|
m_bPendingImpliedMultiplication = m_bImpliedMultiplicationEnabled;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool ON_ArithmeticCalculatorImplementation::AppendNumber(
|
|
double number,
|
|
bool bSupportImpliedMultiplication
|
|
)
|
|
{
|
|
if (m_error_condition)
|
|
return false;
|
|
|
|
if ( bSupportImpliedMultiplication
|
|
&& m_bImpliedMultiplicationEnabled
|
|
&& false == IsEmpty()
|
|
&& m_expression_depth > 0
|
|
&& m_expression_depth == m_op_stack[m_op_stack_pointer].m_level
|
|
&& ON_ArithmeticCalculatorImplementation::op_number == m_op_stack[m_op_stack_pointer].m_op
|
|
)
|
|
{
|
|
m_op_stack[m_op_stack_pointer].m_op = ON_ArithmeticCalculatorImplementation::op_mult;
|
|
}
|
|
|
|
m_bPendingImpliedMultiplication = false;
|
|
|
|
double x = ON_UNSET_VALUE;
|
|
if ( ON_UNSET_VALUE == number )
|
|
{
|
|
if ( !m_bUnsetValue )
|
|
m_bUnsetValue = true;
|
|
m_bPendingUnaryPlus = false;
|
|
m_bPendingUnaryMinus = false;
|
|
}
|
|
else if ( !ON_IsValid(number) )
|
|
{
|
|
SetErrorCondition(ON_ArithmeticCalculator::invalid_expression_error);
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
x = ( 0.0 != number ) ? number : 0.0;
|
|
if ( m_bPendingUnaryMinus )
|
|
{
|
|
if ( 0.0 != x )
|
|
x = -x;
|
|
m_bPendingUnaryMinus = false;
|
|
}
|
|
else if ( m_bPendingUnaryPlus )
|
|
{
|
|
m_bPendingUnaryPlus = false;
|
|
}
|
|
}
|
|
|
|
if ( IsEmpty() )
|
|
{
|
|
m_expression_depth = 1;
|
|
m_op_stack_pointer = 0;
|
|
}
|
|
else
|
|
{
|
|
if ( m_expression_depth <= 0 )
|
|
{
|
|
SetErrorCondition(ON_ArithmeticCalculator::invalid_expression_error);
|
|
return false;
|
|
}
|
|
|
|
switch( m_op_stack[m_op_stack_pointer].m_op )
|
|
{
|
|
case ON_ArithmeticCalculatorImplementation::op_mult:
|
|
case ON_ArithmeticCalculatorImplementation::op_div:
|
|
case ON_ArithmeticCalculatorImplementation::op_add:
|
|
case ON_ArithmeticCalculatorImplementation::op_sub:
|
|
break;
|
|
default:
|
|
SetErrorCondition(ON_ArithmeticCalculator::invalid_expression_error);
|
|
return false;
|
|
break;
|
|
}
|
|
|
|
m_op_stack_pointer++;
|
|
if ( m_op_stack_pointer >= ON_ArithmeticCalculatorImplementation::op_stack_capacity )
|
|
{
|
|
SetErrorCondition(ON_ArithmeticCalculator::invalid_expression_error);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
m_op_stack[m_op_stack_pointer].m_x = x;
|
|
m_op_stack[m_op_stack_pointer].m_op = ON_ArithmeticCalculatorImplementation::op_number;
|
|
m_op_stack[m_op_stack_pointer].m_level = m_expression_depth;
|
|
|
|
switch( ArithmeticOperationIsPending() )
|
|
{
|
|
case ON_ArithmeticCalculatorImplementation::op_mult:
|
|
case ON_ArithmeticCalculatorImplementation::op_div:
|
|
if ( !EvaluatePendingArithmeticOperation() )
|
|
return false;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if ( bSupportImpliedMultiplication )
|
|
m_bPendingImpliedMultiplication = m_bImpliedMultiplicationEnabled;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool ON_ArithmeticCalculator::Number(double number)
|
|
{
|
|
return m_pCalc ? m_pCalc->AppendNumber(number,true) : false;
|
|
}
|
|
|
|
bool ON_ArithmeticCalculator::SimpleNumber(double number)
|
|
{
|
|
return m_pCalc ? m_pCalc->AppendNumber(number,false) : false;
|
|
}
|
|
|
|
bool ON_ArithmeticCalculator::Multiply()
|
|
{
|
|
return m_pCalc ? m_pCalc->AppendArithmeticOperator(ON_ArithmeticCalculatorImplementation::op_mult) : false;
|
|
}
|
|
|
|
bool ON_ArithmeticCalculator::Divide()
|
|
{
|
|
return m_pCalc ? m_pCalc->AppendArithmeticOperator(ON_ArithmeticCalculatorImplementation::op_div) : false;
|
|
}
|
|
|
|
bool ON_ArithmeticCalculator::Add()
|
|
{
|
|
return m_pCalc ? m_pCalc->AppendArithmeticOperator(ON_ArithmeticCalculatorImplementation::op_add) : false;
|
|
}
|
|
|
|
bool ON_ArithmeticCalculator::Subtract()
|
|
{
|
|
return m_pCalc ? m_pCalc->AppendArithmeticOperator(ON_ArithmeticCalculatorImplementation::op_sub) : false;
|
|
}
|
|
|
|
void ON_ArithmeticCalculator::ClearAll()
|
|
{
|
|
if ( m_pCalc )
|
|
{
|
|
// Do not clear configuration settings.
|
|
|
|
// clear operation stack
|
|
m_pCalc->ClearStack();
|
|
|
|
// clear states
|
|
m_pCalc->ClearStates();
|
|
}
|
|
}
|
|
|
|
void ON_ArithmeticCalculatorImplementation::ClearStack()
|
|
{
|
|
m_op_stack_pointer = 0;
|
|
m_expression_depth = 0;
|
|
m_op_stack[0].m_x = 0.0;
|
|
m_op_stack[0].m_op = ON_ArithmeticCalculatorImplementation::op_unset;
|
|
m_op_stack[0].m_level = 0;
|
|
}
|
|
|
|
void ON_ArithmeticCalculatorImplementation::ClearStates()
|
|
{
|
|
m_bPendingImpliedMultiplication = false;
|
|
m_bPendingUnaryPlus = false;
|
|
m_bPendingUnaryMinus = false;
|
|
m_bUnsetValue = false;
|
|
m_error_condition = ON_ArithmeticCalculator::no_error;
|
|
}
|
|
|
|
bool ON_ArithmeticCalculator::Evaluate(double* value)
|
|
{
|
|
double z = ON_UNSET_VALUE;
|
|
bool rc = m_pCalc ? m_pCalc->Evaluate(&z) : false;
|
|
if ( value )
|
|
*value = z;
|
|
return rc;
|
|
}
|
|
|
|
bool ON_ArithmeticCalculatorImplementation::Evaluate(double* value)
|
|
{
|
|
bool rc = false;
|
|
double x = ON_UNSET_VALUE;
|
|
|
|
for(;;)
|
|
{
|
|
if ( 1 != m_expression_depth )
|
|
{
|
|
SetErrorCondition(ON_ArithmeticCalculator::invalid_expression_error);
|
|
break;
|
|
}
|
|
|
|
if ( 1 == m_op_stack_pointer )
|
|
{
|
|
if ( !EvaluatePendingArithmeticOperation() )
|
|
break;
|
|
}
|
|
|
|
if ( 0 != m_op_stack_pointer
|
|
|| ON_ArithmeticCalculatorImplementation::op_number != m_op_stack[0].m_op
|
|
|| 1 != m_op_stack[0].m_level
|
|
)
|
|
{
|
|
SetErrorCondition(ON_ArithmeticCalculator::invalid_expression_error);
|
|
break;
|
|
}
|
|
|
|
if ( m_bUnsetValue )
|
|
{
|
|
rc = true;
|
|
break;
|
|
}
|
|
|
|
if ( !ON_IsValid(m_op_stack[0].m_x) )
|
|
{
|
|
SetErrorCondition(ON_ArithmeticCalculator::invalid_expression_error);
|
|
break;
|
|
}
|
|
|
|
x = m_op_stack[0].m_x;
|
|
rc = true;
|
|
break;
|
|
}
|
|
|
|
if ( 0 != value )
|
|
*value = x;
|
|
|
|
return rc;
|
|
}
|
|
|
|
bool ON_ArithmeticCalculatorImplementation::IsEmpty() const
|
|
{
|
|
if (m_error_condition)
|
|
return false;
|
|
|
|
return ( 0 == m_op_stack_pointer && 0 == m_expression_depth );
|
|
}
|
|
|
|
bool ON_ArithmeticCalculatorImplementation::IsUnsetValue() const
|
|
{
|
|
if (m_error_condition)
|
|
return false;
|
|
|
|
return m_bUnsetValue?true:false;
|
|
}
|
|
|
|
void ON_ArithmeticCalculatorImplementation::SetErrorCondition(
|
|
ON_ArithmeticCalculator::ERROR_CONDITION error_condition
|
|
)
|
|
{
|
|
if ( ON_ArithmeticCalculator::no_error == m_error_condition )
|
|
{
|
|
ClearStack();
|
|
ClearStates();
|
|
|
|
if (ON_ArithmeticCalculator::no_error == error_condition)
|
|
error_condition = ON_ArithmeticCalculator::program_error;
|
|
|
|
m_error_condition = (unsigned char)error_condition;
|
|
}
|
|
}
|
|
|
|
bool ON_ArithmeticCalculatorImplementation::AppendArithmeticOperator(
|
|
ON_ArithmeticCalculatorImplementation::ARITHMETIC_OP op
|
|
)
|
|
{
|
|
bool rc = false;
|
|
|
|
for(;;)
|
|
{
|
|
if (m_error_condition)
|
|
break;
|
|
|
|
if ( IsEmpty() )
|
|
{
|
|
SetErrorCondition(ON_ArithmeticCalculator::invalid_expression_error);
|
|
break;
|
|
}
|
|
|
|
if ( m_bPendingUnaryPlus || m_bPendingUnaryMinus )
|
|
{
|
|
SetErrorCondition(ON_ArithmeticCalculator::invalid_expression_error);
|
|
break;
|
|
}
|
|
|
|
if ( m_expression_depth < 1 )
|
|
{
|
|
SetErrorCondition(ON_ArithmeticCalculator::invalid_expression_error);
|
|
break;
|
|
}
|
|
|
|
if ( ON_ArithmeticCalculatorImplementation::op_number != m_op_stack[m_op_stack_pointer].m_op )
|
|
{
|
|
SetErrorCondition(ON_ArithmeticCalculator::invalid_expression_error);
|
|
break;
|
|
}
|
|
|
|
if ( m_expression_depth != m_op_stack[m_op_stack_pointer].m_level )
|
|
{
|
|
SetErrorCondition(ON_ArithmeticCalculator::invalid_expression_error);
|
|
break;
|
|
}
|
|
|
|
// specifying an explicit aritimetic operator clears the
|
|
// potential for implied multiplication that occures after
|
|
// a "symbol" value or right parenthesis.
|
|
m_bPendingImpliedMultiplication = false;
|
|
|
|
switch( op )
|
|
{
|
|
case ON_ArithmeticCalculatorImplementation::op_add:
|
|
case ON_ArithmeticCalculatorImplementation::op_sub:
|
|
switch(ArithmeticOperationIsPending())
|
|
{
|
|
case ON_ArithmeticCalculatorImplementation::op_add:
|
|
case ON_ArithmeticCalculatorImplementation::op_sub:
|
|
if ( !EvaluatePendingArithmeticOperation() )
|
|
return false;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
m_op_stack[m_op_stack_pointer].m_op = op;
|
|
rc = true;
|
|
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
ON_ArithmeticCalculatorImplementation::ARITHMETIC_OP ON_ArithmeticCalculatorImplementation::ArithmeticOperationIsPending() const
|
|
{
|
|
ON_ArithmeticCalculatorImplementation::ARITHMETIC_OP rc = ON_ArithmeticCalculatorImplementation::op_unset;
|
|
|
|
if ( m_error_condition )
|
|
return rc;
|
|
|
|
if ( m_op_stack_pointer < 1 )
|
|
return rc;
|
|
|
|
if ( m_op_stack[m_op_stack_pointer-1].m_level != m_op_stack[m_op_stack_pointer].m_level )
|
|
return rc;
|
|
|
|
if ( ON_ArithmeticCalculatorImplementation::op_number != m_op_stack[m_op_stack_pointer].m_op )
|
|
return rc;
|
|
|
|
if ( m_expression_depth != m_op_stack[m_op_stack_pointer].m_level )
|
|
return rc;
|
|
|
|
switch(m_op_stack[m_op_stack_pointer-1].m_op)
|
|
{
|
|
case ON_ArithmeticCalculatorImplementation::op_mult:
|
|
case ON_ArithmeticCalculatorImplementation::op_div:
|
|
case ON_ArithmeticCalculatorImplementation::op_add:
|
|
case ON_ArithmeticCalculatorImplementation::op_sub:
|
|
rc = m_op_stack[m_op_stack_pointer-1].m_op;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
bool ON_ArithmeticCalculatorImplementation::EvaluatePendingArithmeticOperation()
|
|
{
|
|
double z = ON_UNSET_VALUE;
|
|
bool rc = false;
|
|
|
|
for(;;)
|
|
{
|
|
if ( m_error_condition )
|
|
break;
|
|
|
|
const unsigned int op = ArithmeticOperationIsPending();
|
|
if ( ON_ArithmeticCalculatorImplementation::op_unset == op )
|
|
{
|
|
SetErrorCondition(ON_ArithmeticCalculator::invalid_expression_error);
|
|
break;
|
|
}
|
|
|
|
const double x = m_op_stack[m_op_stack_pointer-1].m_x;
|
|
const double y = m_op_stack[m_op_stack_pointer].m_x;
|
|
|
|
if ( !m_bUnsetValue && (ON_UNSET_VALUE == x || ON_UNSET_VALUE == y) )
|
|
{
|
|
SetErrorCondition(ON_ArithmeticCalculator::invalid_expression_error);
|
|
break;
|
|
}
|
|
|
|
if ( !ON_IsValid(x) || !ON_IsValid(y) )
|
|
{
|
|
SetErrorCondition(ON_ArithmeticCalculator::invalid_expression_error);
|
|
break;
|
|
}
|
|
|
|
switch(op)
|
|
{
|
|
case ON_ArithmeticCalculatorImplementation::op_mult:
|
|
z = m_bUnsetValue ? ON_UNSET_VALUE : (x*y);
|
|
rc = true;
|
|
break;
|
|
|
|
case ON_ArithmeticCalculatorImplementation::op_div:
|
|
if ( (0.0 != y) )
|
|
{
|
|
z = m_bUnsetValue ? ON_UNSET_VALUE : (x/y);
|
|
rc = true;
|
|
}
|
|
else
|
|
{
|
|
SetErrorCondition(ON_ArithmeticCalculator::divide_by_zero_error);
|
|
}
|
|
break;
|
|
|
|
case ON_ArithmeticCalculatorImplementation::op_add:
|
|
z = m_bUnsetValue ? ON_UNSET_VALUE : (x + y);
|
|
rc = true;
|
|
break;
|
|
|
|
case ON_ArithmeticCalculatorImplementation::op_sub:
|
|
z = m_bUnsetValue ? ON_UNSET_VALUE : (x - y);
|
|
rc = true;
|
|
break;
|
|
|
|
default:
|
|
SetErrorCondition(ON_ArithmeticCalculator::invalid_expression_error);
|
|
break;
|
|
}
|
|
|
|
if (!rc)
|
|
break;
|
|
|
|
if ( ON_UNSET_VALUE == z )
|
|
{
|
|
if ( !m_bUnsetValue )
|
|
{
|
|
SetErrorCondition(ON_ArithmeticCalculator::invalid_expression_error);
|
|
rc = false;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if ( !ON_IsValid(z) )
|
|
{
|
|
SetErrorCondition(ON_ArithmeticCalculator::overflow_error);
|
|
rc = false;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
if (rc)
|
|
{
|
|
m_op_stack_pointer--;
|
|
m_op_stack[m_op_stack_pointer].m_x = z;
|
|
m_op_stack[m_op_stack_pointer].m_op = ON_ArithmeticCalculatorImplementation::op_number;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|