So far, we've used "constant" s-expressions as examples for evaluation, and that's pretty cool, but it is, of course, a great deal more interesting to be able to compute expression values when the expression contains variables bound to values at run-time.
For example, the formula for computing the Body Mass Index of a healthy human is given by the following formula:
BMI = (Weight in Kilograms / (Height in Meters) x (Height in Meters))
or as an s-expression
(div weight (prod height height))
If we were able to pass in the values for weight and height for various people, we could get the expression evaluator to compute the BMI.
To accomplish this, we make a few modifications to the Evaluate
function, and pass in an addition symbol table with values for the variables.
public static Expression Evaluate(this Expression _this, Dictionary<string, object> Symbols)
{
switch (_this.Children.Count)
{
case 0:
/* atomic value */
{
switch (_this.Token)
{
...
case E_TOKEN.ValidName:
{
switch (_this.TokenValue.ToLower())
{
... other "known" tokens
default:
{
try
{
_this.SetValue(Symbols[_this.TokenValue]);
}
catch (KeyNotFoundException)
{
_this.RegisterMissingSymbol(_this.TokenValue);
}
}
break;
}
}
break;
case E_TOKEN.Text:
case E_TOKEN.ValidNumber:
case E_TOKEN.SingleQuotedText:
case E_TOKEN.DoubleQuotedText:
{
_this.SetValue(_this.TokenValue);
}
break;
default:
{
throw new EvaluatorException(_this, "Evaluate Error: Unknown Token!");
}
}
return _this;
}
...
}
}
To call our evaluator from some other code, we could do the following:
string strExpression = ... get the string from a resource or database
Dictionary<string, object> Symbols = new Dictionary<string, object>();
Symbols["height"] = ... input from a form or database;
Symbols["weight"] = ... input from a form or database;
double BMI = strExpression.Evaluate(Symbols).ValueAsNumber;
Now if the customer wanted the formula changed on the fly to the non metric version, all we need to do is change the expression to be evaluated to
BMI = ( Weight in Pounds / ( Height in inches ) x ( Height in inches ) ) x 703
or
(prod (div weight (prod height height) 703)
and the compiled version of the code doesn't change at all!
No comments:
Post a Comment