#include #include "evaluator.h" #include "value.h" evaluator::evaluator(const char * display_name) : m_display_name(display_name) { } /* XXX: This is really ugly. I'm sure there is a way to do this with function * overloads, but I can't figure out how. */ value * evaluator::evaluate( value * l, value * r) { enum value_type l_type = get_value_type(l); enum value_type r_type = get_value_type(r); switch(l_type) { case VALUE_TYPE_FLOAT: return evaluate((float_value*)l, r); default: switch(r_type) { case VALUE_TYPE_FLOAT: return evaluate(l, (float_value*)r); default: return default_evaluate(l, r); } } } value * evaluator::evaluate( float_value * l, value * r) { enum value_type r_type = get_value_type(r); switch(r_type) { case VALUE_TYPE_FLOAT: return evaluate(l, (float_value*)r); default: return default_evaluate(l, r); } } value * evaluator::evaluate( value * l, float_value * r) { enum value_type l_type = get_value_type(l); switch(l_type) { case VALUE_TYPE_FLOAT: return evaluate((float_value*)l, r); default: return default_evaluate(l, r); } } value * evaluator::default_evaluate( value * l, value * r) { return new tree_value(this, l, r); } value_type evaluator::get_value_type(value * val) { return val ? val->get_type() : VALUE_TYPE_FLOAT; } std::string evaluator::to_string() { return m_display_name; } add_evaluator::add_evaluator() : evaluator("+") { } value * add_evaluator::evaluate( float_value * l, float_value * r) { float_value * new_val; if (!l || !r || !l->m_has_value || !r->m_has_value) { return default_evaluate(l, r); } new_val = new float_value(); new_val->set_value(l->m_value + r->m_value); return new_val; } mul_evaluator::mul_evaluator() : evaluator("*") { } value * mul_evaluator::evaluate( float_value * l, float_value * r) { float_value * new_val; if (!l || !r || !l->m_has_value || !r->m_has_value) { return default_evaluate(l,r); } new_val = new float_value(l->m_value * r->m_value); return new_val; } abs_evaluator::abs_evaluator() : evaluator("abs()") { } value * abs_evaluator::evaluate( float_value * l, float_value * r) { if (!l || !l->m_has_value) { return default_evaluate(l, r); } return new float_value(fabsf(l->m_value)); } sub_evaluator::sub_evaluator() : evaluator("-") { } value * sub_evaluator::evaluate( float_value * l, float_value * r) { if (!l || !r || !l->m_has_value || !r->m_has_value) { return default_evaluate(l, r); } return new float_value(l->m_value - r->m_value); } sat_evaluator::sat_evaluator() : evaluator("SAT") { } value * sat_evaluator::evaluate( float_value * l, float_value * r) { float val; if (!l || !l->m_has_value) { return default_evaluate(l, r); } val = l->m_value; if (val < 0.0f) { val = 0.0f; } if (val > 1.0f) { val = 1.0f; } return new float_value(val); } rcp_evaluator::rcp_evaluator() : evaluator("RCP") { } value * rcp_evaluator::evaluate( float_value * l, float_value * r) { float val; int float_type; if (!l || !l->m_has_value) { return default_evaluate(l, r); } /* XXX: This should be configurable via virtual functions. */ float_type = fpclassify(l->m_value); switch(float_type) { case FP_NAN: val = NAN; break; case FP_INFINITE: val = 0.0f; break; default: /* XXX: fpclassify should be used to test for zero once I * figure out if FP_ZERO is portable. */ if (l->m_value == 0.0f) { val = INFINITY; } else { val = 1.0f / l->m_value; } break; } return new float_value(val); } min_evaluator::min_evaluator() : evaluator("MIN") { } value * min_evaluator::evaluate( float_value * l, float_value * r) { if (!l || !l->m_has_value || !r || !r->m_has_value) { return default_evaluate(l, r); } return new float_value( l->m_value < r->m_value ? l->m_value : r->m_value); } max_evaluator::max_evaluator() : evaluator("MAX") { } value * max_evaluator::evaluate( float_value * l, float_value * r) { if (!l || !l->m_has_value || !r || !r->m_has_value) { return default_evaluate(l, r); } return new float_value( l->m_value > r->m_value ? l->m_value : r->m_value); }