22

Are there any jJava libraries or techniques to parsing boolean expressions piecemeal?

What I mean is given an expression like this:

T && ( F || ( F && T ) )

It could be broken down into a expression tree to show which token caused the 'F' value, like so (maybe something like this):

T &&               <- rhs false
    ( F ||         <- rhs false
        ( F && T ) <- eval, false
    )

I am trying to communicate boolean expression evaluations to non-programmers. I have poked around with Anlr, but I couldn't get it to do much (it seems to have a bit of a learning curve).

I'm not opposed to writing it myself, but I'd rather not reinvent the wheel.

6 Answers 6

15

You could do this with MVEL or JUEL. Both are expression language libraries, examples below are using MVEL.

Example:

System.out.println(MVEL.eval("true && ( false || ( false && true ) )"));

Prints: false

If you literally want to use 'T' and 'F' you can do this:

Map<String, Object> context = new java.util.HashMap<String, Object>();
context.put("T", true);
context.put("F", false);
System.out.println(MVEL.eval("T && ( F || ( F && T ) )", context));

Prints: false

Sign up to request clarification or add additional context in comments.

Comments

12

I've coded this using Javaluator.
It's not exactly the output you are looking for, but I think it could be a start point.

package test;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import net.astesana.javaluator.*;

public class TreeBooleanEvaluator extends AbstractEvaluator<String> {
  /** The logical AND operator.*/
  final static Operator AND = new Operator("&&", 2, Operator.Associativity.LEFT, 2);
  /** The logical OR operator.*/
  final static Operator OR = new Operator("||", 2, Operator.Associativity.LEFT, 1);
    
  private static final Parameters PARAMETERS;

  static {
    // Create the evaluator's parameters
    PARAMETERS = new Parameters();
    // Add the supported operators
    PARAMETERS.add(AND);
    PARAMETERS.add(OR);
    // Add the parentheses
    PARAMETERS.addExpressionBracket(BracketPair.PARENTHESES);
  }

  public TreeBooleanEvaluator() {
    super(PARAMETERS);
  }

  @Override
  protected String toValue(String literal, Object evaluationContext) {
    return literal;
  }
        
  private boolean getValue(String literal) {
    if ("T".equals(literal) || literal.endsWith("=true")) return true;
    else if ("F".equals(literal) || literal.endsWith("=false")) return false;
    throw new IllegalArgumentException("Unknown literal : "+literal);
  }
    
  @Override
  protected String evaluate(Operator operator, Iterator<String> operands,
      Object evaluationContext) {
    List<String> tree = (List<String>) evaluationContext;
    String o1 = operands.next();
    String o2 = operands.next();
    Boolean result;
    if (operator == OR) {
      result = getValue(o1) || getValue(o2);
    } else if (operator == AND) {
      result = getValue(o1) && getValue(o2);
    } else {
      throw new IllegalArgumentException();
    }
    String eval = "("+o1+" "+operator.getSymbol()+" "+o2+")="+result;
    tree.add(eval);
    return eval;
  }
        
  public static void main(String[] args) {
    TreeBooleanEvaluator evaluator = new TreeBooleanEvaluator();
    doIt(evaluator, "T && ( F || ( F && T ) )");
    doIt(evaluator, "(T && T) || ( F && T )");
  }
    
  private static void doIt(TreeBooleanEvaluator evaluator, String expression) {
    List<String> sequence = new ArrayList<String>();
    evaluator.evaluate(expression, sequence);
    System.out.println ("Evaluation sequence for :"+expression);
    for (String string : sequence) {
      System.out.println (string);
    }
    System.out.println ();
  }
}

Here is the ouput:

Evaluation sequence for :T && ( F || ( F && T ) )
(F && T)=false
(F || (F && T)=false)=false
(T && (F || (F && T)=false)=false)=false

Evaluation sequence for :(T && T) || ( F && T )
(T && T)=true
(F && T)=false
((T && T)=true || (F && T)=false)=true

2 Comments

Cool, I'll try it out soon and accept if it is what I am trying to do. +1
I fixed a couple of bugs, but overall the idea is there. Thanks!
10

I recently put together a library in Java specifically to manipulate boolean expressions: jbool_expressions.

It includes a tool too parse expressions out of string input:

Expression<String> expr = ExprParser.parse("( ( (! C) | C) & A & B)")

You can also do some fairly simple simplification:

Expression<String> simplified = RuleSet.simplify(expr);
System.out.println(expr);

gives

(A & B)

If you wanted to step through the assignment then, you could assign values one by one. For the example here,

Expression<String> halfAssigned = RuleSet.assign(simplified, Collections.singletonMap("A", true));
System.out.println(halfAssigned);

shows

B

and you could resolve it by assigning B.

Expression<String> resolved = RuleSet.assign(halfAssigned, Collections.singletonMap("B", true));
System.out.println(resolved);

shows

true

Not 100% what you were asking for, but hope it helps.

Comments

1

Check out BeanShell. It has expression parsing that accepts Java-like syntax.

EDIT: Unless you're trying to actually parse T && F literally, though you could do this in BeanShell using the literals true and false.

Comments

1

Try this.

static boolean parseBooleanExpression(String s) {
    return new Object() {

        int length = s.length(), index = 0;

        boolean match(String expect) {
            while (index < length && Character.isWhitespace(s.charAt(index)))
                ++index;
            if (index >= length)
                return false;
            if (s.startsWith(expect, index)) {
                index += expect.length();
                return true;
            }
            return false;
        }

        boolean element() {
            if (match("T"))
                return true;
            else if (match("F"))
                return false;
            else if (match("(")) {
                boolean result = expression();
                if (!match(")"))
                    throw new RuntimeException("')' expected");
                return result;
            } else
                throw new RuntimeException("unknown token");
        }

        boolean term() {
            if (match("!"))
                return !element();
            else
                return element();
        }

        boolean factor() {
            boolean result = term();
            while (match("&&"))
                result &= term();
            return result;
        }

        boolean expression() {
            boolean result = factor();
            while (match("||"))
                result |= factor();
            return result;
        }

        boolean parse() {
            boolean result = expression();
            if (index < length)
                throw new RuntimeException(
                    "extra string '" + s.substring(index) + "'");
            return result;
        }
    }.parse();
}

And

public static void main(String[] args) {
    String s = "T && ( F || ( F && T ) )";
    boolean result = parseBooleanExpression(s);
    System.out.println(result);
}

output:

false

The syntax is

 expression = factor { "||" factor }
 factor     = term { "&&" term }
 term       = [ "!" ] element
 element    = "T" | "F" | "(" expression ")"

Comments

0

mXparser handles Boolean operators - please find few examples

Example 1:

import org.mariuszgromada.math.mxparser.*;
...
...
Expression e = new Expression("1 && (0 || (0 && 1))");
System.out.println(e.getExpressionString() + " = " + e.calculate());

Result 1:

1 && (0 || (0 && 1)) = 0.0

Example 2:

import org.mariuszgromada.math.mxparser.*;
...
...
Constant T = new Constant("T = 1");
Constant F = new Constant("F = 0");
Expression e = new Expression("T && (F || (F && T))", T, F);
System.out.println(e.getExpressionString() + " = " + e.calculate());

Result 2:

T && (F || (F && T)) = 0.0

For more details please follow mXparser tutorial.

Best regards

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.