1

I want to make a tree of functions in C, which would look like this: http://scr.hu/5rq/vdja0

So basically I want the result to be like this: http://scr.hu/5rq/f04uu

where x is an variable which I can provide (float). The F0 to F6 are random functions which take two arguments (functions like multiplying, adding, or giving random number). So my exact question is: how i can do that? I know that it can be done easily, by storing exact value given by each function in arrays. But then it gets complicated when it comes to getting different "x" value. My initial thought was to create function which attaches random function to each node in the tree, but then, i am unsure how should be done structure which makes that tree,

typedef struct drzewo typ;

struct drzewo {
    typ *right;
    typ *left;
    typ *up;
    float *value; //what to do with this ?
};

I would like to somehow change line "float *value;" into something that could store a function like Function1(left->value,right->value); but not runned, and not exact value of function with given arguments, and where Function1() or Function2() means function which divides both arguments or multiplies them or so on.

No it is not for school, and yes this is my miserable try to use genetic programming.

SetFreeByTruth
  • 819
  • 8
  • 23
mmajewsk
  • 99
  • 11
  • It looks like you're trying to achieve dynamic expression evaluation. Does that describe your problem? It would probably be easier for you to do this in an object oriented language. – Wug Jul 16 '12 at 19:26

2 Answers2

5

To create a type that points to a function, use the function prototype and replace the function name with (*<typename>). So if you have a function foo that looks like:

float foo( int arg1, char *arg2 );

You can create a type "foo_fn" which is a pointer to a function like foo using:

typedef float (*foo_fn)( int, char * );

Then store it in your structure like:

typedef struct drzewo typ;
struct drzewo {
    typ *right;
    typ *left;
    typ *up;
    foo_fn fn_ptr;
};

If you want to have a structure that holds various types of functions (that may have different return types or take different parameters), you may just want to store them as void * and cast them to the right function pointer type when you want to call them.

Graeme Perrow
  • 56,086
  • 21
  • 82
  • 121
0

You could start with something like:

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

Then you could put that into some sort of general purpose wrapper function and call that wrapper from your special purpose EvalFunc functions which you will write in a minute:

float EVAL(ExprNode * node)
{
    return eval_array[node->op](node);
}

// for bonus points, use a #define
// #define EVAL(node) eval_array[node->op](node)

From there, you would need a bunch of functions with signatures that matched EvalFunc, such as this one, the simplest, which would be suitable for use with the VALUE specifier:

float Eval_Value(ExprNode * node)
{
    return node->value;
}

Or this slightly more in depth (but still simple) one, that does addition:

float Eval_Add(ExprNode * node)
{
    return EVAL(node->left) + EVAL(node->right);
}

You can now put all of these functions into the eval_array array so you can call them quickly with an indexed lookup, like this:

eval_array[VALUE] = &Eval_Value;
eval_array[ADD]   = &Eval_Add;
// etc

You might wish to include some sort of initializer function for ExprNodes to take the tedium out of initializing them:

ExprNode_init(ExprNode * node, Operation _op, float _value, ExprNode * _left, ExprNode * _right)
{
    node->op    = _op;
    node->left  = _left;
    node->right = _right;
    node->value = _value;
}

Then, you copy all of your prototypes to some header file and #include it wherever you need it. You will be able to build chains of expressions and evaluate them in the following manner:

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
Wug
  • 12,956
  • 4
  • 34
  • 54