您可以从以下内容开始:
typedef enum Operation
{
VALUE, // 0 argument (uses value)
NOT, SIN, COS, TAN // 1 argument
ADD, SUB, DIV, MUL, POW, LOG, AND, OR, XOR, // 2 argument
SENTINEL; // the last element
}
Operation;
typedef struct ExprNode
{
Operation op;
struct ExprNode * left;
struct ExprNode * right;
float value;
}
ExprNode;
typedef float (* EvalFunc)(ExprNode *);
EvalFunc eval_array[SENTINEL]; // array size is number of operations in enum
然后您可以将其放入某种通用包装函数中,并从您将在一分钟内编写的专用 EvalFunc 函数中调用该包装器:
float EVAL(ExprNode * node)
{
return eval_array[node->op](node);
}
// for bonus points, use a #define
// #define EVAL(node) eval_array[node->op](node)
从那里,您将需要一堆具有与 EvalFunc 匹配的签名的函数,例如这个最简单的函数,它适合与 VALUE 说明符一起使用:
float Eval_Value(ExprNode * node)
{
return node->value;
}
或者这个稍微更深入(但仍然很简单)的一个,它确实增加了:
float Eval_Add(ExprNode * node)
{
return EVAL(node->left) + EVAL(node->right);
}
您现在可以将所有这些函数放入eval_array
数组中,以便通过索引查找快速调用它们,如下所示:
eval_array[VALUE] = &Eval_Value;
eval_array[ADD] = &Eval_Add;
// etc
您可能希望为 ExprNodes 包含某种初始化函数,以消除初始化它们的乏味:
ExprNode_init(ExprNode * node, Operation _op, float _value, ExprNode * _left, ExprNode * _right)
{
node->op = _op;
node->left = _left;
node->right = _right;
node->value = _value;
}
然后,您将所有原型复制到某个头文件中,并在需要的任何地方#include 它。您将能够构建表达式链并以下列方式评估它们:
ExprNode n1, n2, n3, X, Y, Z;
ExprNode_init(&n1, SUM, 0, &n2, &n3 ); // expression nodes: value is ignored
ExprNode_init(&n2, MUL, 0, &X, &Y ); // some functions only require 1 arg
ExprNode_init(&n3, DIV, 0, &Z, &Y ); // right can be omitted for these
ExprNode_init(&X, VALUE, 3, NULL, NULL); // value nodes: value is not ignored
ExprNode_init(&Y, VALUE, 4, NULL, NULL); // left and right are both ignored
ExprNode_init(&Z, VALUE, 6, NULL, NULL); // both can be null
float result = EVAL(n1); // X*Y + Z/Y : X=3, Y=4, Z=6; should be 13.5