tomturton
tomturton

Reputation: 1368

Dynamic conditional logic function

I need to write a function that can take an if statement at runtime (eg. user input, or from a data file). Ideally it should be able to solve an expression no less complex than:

a && ( b || !c || ( d && e ) )

I imagine what I need is a recursive function (one that calls itself). Of course, the function needs to return true or false.

Because of the complexity of the example above, the function would need to not only loop through the individual conditions, but understand the operators, know the order in which to evaluate them and preferably prioritise them for speed (eg. in the example, if a is false there is no need to evaluate the rest of the statement).

Does anyone have any ideas?

Upvotes: 3

Views: 335

Answers (1)

Ilmo Euro
Ilmo Euro

Reputation: 5135

One solution would be using shunting yard algorithm to convert the expression to RPN, and then evaluate it as RPN (because RPN is much easier to evaluate than infix). The first part, conversion to RPN (in pseudocode):

while (tokens left) {
  t = read_token();
  if (t is number) {
    output(t);
  } else if (t is unary operator) {
    push(t);
  } else if (t is binary operator) {
    r = pop();
    if (r is operator and precedence(t)<=precedence(r)) {
       output(r);
    } else {
       push(r);
    }
    push(t);
  } else if (t is left parenthesis) {
    push(t);
  } else if (r is right parenthesis) {
    while ((r = pop()) is not left parenthesis) {
        output(r);
        if (stack is empty) {
          mismatched parenthesis!
        }
    }
    if (top() is unary operator) {
        output(pop());
    }
  }
}
while (stack is not empty) {
  if (top() is parenthesis) {
     mismatched parenthesis!
  }
  output(pop());
}
  • read_token reads a token from input queue
  • output inserts a value into output queue
  • push pushes a value into the stack (you only need one)
  • pop pops a value out of a stack
  • top peeks the value at the top of the stack without popping

The RPN evaluation is simpler:

while (tokens left) {
  t = read_token();
  if (t is number) {
    push(t);
  } else if (t is unary operator) {
    push(eval(t, pop()));
  } else if (t is binary operator) {
    val1 = pop();
    val2 = pop();
    push(eval(t, val1, val2));
  }
}
result = pop();
  • read_token() reads values from the RPN queue generated in previous step
  • eval(t, val) evaluates unary operator t with operand val
  • eval(t, val1, val2) evaluates binary operator t with operands val1 and val2
  • result is the final value of the expression

This simplified algorithm should work if all your operators are left-associative and no functions are used. Note that no recursion is necessary, because we use our own stack implementation. For examples and more information, see Rosetta Code on Shunting-yard and Rosetta Code on RPN

Upvotes: 3

Related Questions