/* Copyright or (C) or Copr. GET / ENST, Telecom-Paris, Ludovic Apvrille * * ludovic.apvrille AT enst.fr * * This software is a computer program whose purpose is to allow the * edition of TURTLE analysis, design and deployment diagrams, to * allow the generation of RT-LOTOS or Java code from this diagram, * and at last to allow the analysis of formal validation traces * obtained from external tools, e.g. RTL from LAAS-CNRS and CADP * from INRIA Rhone-Alpes. * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, * modify and/ or redistribute the software under the terms of the CeCILL * license as circulated by CEA, CNRS and INRIA at the following URL * "http://www.cecill.info". * * As a counterpart to the access to the source code and rights to copy, * modify and redistribute granted by the license, users are provided only * with a limited warranty and the software's author, the holder of the * economic rights, and the successive licensors have only limited * liability. * * In this respect, the user's attention is drawn to the risks associated * with loading, using, modifying and/or developing or reproducing the * software by the user in light of its specific status of free software, * that may mean that it is complicated to manipulate, and that also * therefore means that it is reserved for developers and experienced * professionals having in-depth computer knowledge. Users are therefore * encouraged to load and test the software's suitability as regards their * requirements in conditions enabling the security of their systems and/or * data to be ensured and, more generally, to use and operate it in the * same conditions as regards security. * * The fact that you are presently reading this means that you have had * knowledge of the CeCILL license and that you accept its terms. */ package myutil; import java.util.StringTokenizer; /** * Class BoolExpressionEvaluator * Creation: 13/12/2010 * Version 2.0 13/12/2010 * @author Ludovic APVRILLE */ public class BoolExpressionEvaluator { private class IntBoolRes { public static final int AVAILABLE = -1; public static final int INT_TERM = 0; public static final int BOOL_TERM = 1; public static final int FAIL = 2; public static final int INT_BINARY_OP = 3; public static final int BOOL_BINARY_OP = 4; public static final int BOOL_UNARY_OP = 5; public static final int OPEN_PARENTHESIS = 6; public static final int UNKNOWN_TERM = 7; public int id = (int)(Math.ceil(Math.random() * 10000000)); public int i = -18; public boolean b; public int res; //-1: available, 0:int, 2:bool, 3:ko, others : OPs public int op = 0; public String symb; public IntBoolRes left; public IntBoolRes right; public IntBoolRes father; public IntBoolRes() { res = AVAILABLE; } public IntBoolRes(int _type, int _op, IntBoolRes _father) { res = _type; op = _op; father = _father; } public IntBoolRes(int _val, IntBoolRes _father) { i = _val; res = INT_TERM; father = _father; } public IntBoolRes(boolean _val, IntBoolRes _father) { b = _val; res = BOOL_TERM; father = _father; } public IntBoolRes(String val, IntBoolRes _father) { symb = val; res = UNKNOWN_TERM; father = _father; } public IntBoolRes getTop() { if (father == null) { return this; } else return father.getTop(); } public IntBoolRes addTerminalInt(int _value) { if (isFull()) { return null; } IntBoolRes news = new IntBoolRes(_value, this); if (left == null) { TraceManager.addDev("Adding on the left:" + _value); left = news; } else { TraceManager.addDev("Adding on the right:" + _value); right = news; } return news; } public IntBoolRes addTerminalBool(boolean _value) { if (isFull()) { return null; } IntBoolRes news = new IntBoolRes(_value, this); if (left == null) { left = news; } else { right = news; } return news; } public IntBoolRes addTerminalUnknown(String val) { if (isFull()) { return null; } IntBoolRes news = new IntBoolRes(val, this); if (left == null) { left = news; } else { right = news; } return news; } public IntBoolRes addOpenParenthesis() { if ((left != null) && (right != null)) { return null; } if ((left != null) && (op == 0)) { return null; } IntBoolRes newE = new IntBoolRes(OPEN_PARENTHESIS, OPEN_PAR_TOKEN, this); if (left == null) { left = newE; } else { right = newE; } IntBoolRes topPar = new IntBoolRes(); topPar.father = newE; newE.left = topPar; return topPar; } public IntBoolRes addIntOperator(int _op) { // Must have at least one right operator TraceManager.addDev("Add int op"); if (left == null) { TraceManager.addDev("No left terminal!"); return null; } if (right != null) { // Must change the tree structure according to the operator priority IntBoolRes newE = new IntBoolRes(INT_BINARY_OP, _op, this); return addBinaryChangeTreeStruct(newE); /*newE.left = right; newE.father = right.father; right.father = newE; this.right = newE; return newE;*/ } // Element added at the root of the current // If the current has not type .. if (!isAvailable()) { return null; } res = INT_BINARY_OP; op = _op; return this; } public IntBoolRes addUnaryOperator(int _op) { if ((left != null) && (right != null)) { return null; } if ((left != null) && (op == 0)) { return null; } IntBoolRes newE = new IntBoolRes(BOOL_UNARY_OP, _op, this); if (left == null) { left = newE; } else { right = newE; } IntBoolRes topPar = new IntBoolRes(); topPar.father = newE; newE.left = topPar; return topPar; } public IntBoolRes addBinaryOperator(int _op) { // Must have at least one right operator TraceManager.addDev("Add binary op"); if (left == null) { TraceManager.addDev("No left terminal!"); return null; } if (right != null) { // Must change the tree structure accoding to the operator priority IntBoolRes newE = new IntBoolRes(BOOL_BINARY_OP, _op, this); return addBinaryChangeTreeStruct(newE); } // Element added at the root of the current // If the current has no type .. if (!isAvailable()) { return null; } res = BOOL_BINARY_OP; op = _op; return this; } public IntBoolRes addBinaryChangeTreeStruct(IntBoolRes newE) { // Look for the father if (isABinaryOperator() && (newE.getPriority()>=getPriority())) { newE.left = right; right.father = newE; this.right = newE; return newE; } else { // We must find the father where to add the operator // We thus look for the first father with no binary operator // or with a binary operator that has a higher priority TraceManager.addDev("----- Must find a target"); IntBoolRes targetF = this.father; boolean go = true; while(go == true) { TraceManager.addDev("in loop targetF=" + targetF); if (targetF == null) { go = false; } else { if (!(targetF.isABinaryOperator())) { go = false; } else if (targetF.hasAHigherPriorityThan(newE)) { IntBoolRes nexT = targetF.father; if (nexT == targetF) { go = false; } targetF = nexT; } else { go = false; } } } TraceManager.addDev("**************** Considering targetF=" + targetF); if (targetF == null) { newE.left = top; top.father = newE; newE.father = null; top = newE; return top; } else { if (targetF.isABinaryOperator()) { newE.right = targetF.left; targetF.left = newE; newE.father = targetF.father; targetF.father = newE; return newE; } else { TraceManager.addDev("Unaryoperator"); newE.left = targetF.left; targetF.left = newE; newE.father = targetF; return newE; } } } } public boolean isAvailable() { return res == AVAILABLE; } public boolean isFull() { return ((left != null) && (right != null)); } public boolean isTop() { return father == null; } public boolean isTerminal() { return (res == INT_TERM) || (res == BOOL_TERM); } public boolean isRight() { if (father != null) { return father.right == this; } return false; } public boolean isLeft() { if (father != null) { return father.left == this; } return false; } public boolean isABinaryOperator(){ return (res == INT_BINARY_OP) || (res == BOOL_BINARY_OP); } public boolean hasAHigherPriorityThan(IntBoolRes _other) { return (getPriority() > _other.getPriority()); } public int getPriority() { if (res == BOOL_BINARY_OP) { return 1; } if (res == INT_BINARY_OP) { if ((op == PLUS_TOKEN) || (op == MINUS_TOKEN)) return 2; else { TraceManager.addDev("HAVE PRIORITY 3"); return 3; } } return 0; } public String getValueString() { if (res == 0) { return "" + i; } return ""+b; } public Object getObjectValue() { if (res == INT_TERM) { return new Integer(i); } if (res == BOOL_TERM) { return new Boolean(b); } return null; } private int analysisArg(Object ob1) { if (ob1 instanceof Integer) { return ((Integer)ob1).intValue(); } else { if (((Boolean)ob1).booleanValue()) { return 1; } else { return 0; } } } private Boolean makeUnaryOp(int op, int elt1) { if (op == NOT_TOKEN) { if (elt1 == 0) { return new Boolean(true); } else return new Boolean(false); } return null; } private Boolean makeBinaryOp(int op, int elt1, int elt2) { if (op == EQUAL_TOKEN) { return new Boolean(elt1 == elt2); } if (op == NOT_EQUAL_TOKEN) { return new Boolean(elt1 != elt2); } if (op == OR_TOKEN) { return new Boolean((elt1 != 0) || (elt2 != 0)); } if (op == AND_TOKEN) { return new Boolean((elt1 != 0) && (elt2 != 0)); } return null; } private Integer makeIntegerOp(int op, int elt1, int elt2) { if (op == PLUS_TOKEN) { return new Integer(elt1 + elt2); } if (op == MINUS_TOKEN) { return new Integer(elt1 - elt2); } if (op == MULT_TOKEN) { return new Integer(elt1 * elt2); } if (op == DIV_TOKEN) { //TraceManager.addDev("Div token .. elt1 = " + elt1 + " elt2 = " + elt2 + " res=" + new Integer(elt1 / elt2).intValue()); return new Integer(elt1 / elt2); } return null; } private Boolean makeIntegerToBooleanOp(int op, int elt1, int elt2) { if (op == LT_TOKEN) { return new Boolean(elt1 < elt2); } if (op == GT_TOKEN) { return new Boolean(elt1 > elt2); } if (op == LTEQ_TOKEN) { return new Boolean(elt1 <= elt2); } if (op == GTEQ_TOKEN) { return new Boolean(elt1 >= elt2); } return null; } public Object computeValue() { if (isTerminal()) { return getObjectValue(); } if (res == BOOL_UNARY_OP) { if (left == null) { errorMessage = "Badly formatted unary boolean operator"; return null; } Object ob1 = left.computeValue(); if (!(ob1 instanceof Boolean)) { errorMessage = "Bad operand for unary boolean operator"; return null; } int elt1 = analysisArg(ob1); Boolean result = makeUnaryOp(op, elt1); TraceManager.addDev("Result unary=" + result); return result; } if (res == BOOL_BINARY_OP) { if ((right == null) || (left == null)) { errorMessage = "Badly formatted binary boolean operator"; return null; } Object ob1 = right.computeValue(); Object ob2 = left.computeValue(); if ((ob1 == null) || (ob2 == null)) return null; if (((ob1 instanceof Integer) && (ob2 instanceof Integer)) || ((ob1 instanceof Boolean) && (ob2 instanceof Boolean))) { int elt1 = analysisArg(ob1); int elt2 = analysisArg(ob2); Boolean result = makeBinaryOp(op, elt1, elt2); TraceManager.addDev("Result binary=" + result); return result; } } if (res == INT_BINARY_OP) { TraceManager.addDev("Found binary int expr"); if ((right == null) || (left == null)) { errorMessage = "Badly formatted binary int operator"; TraceManager.addDev("Found binary int expr in null"); return null; } Object ob1 = left.computeValue(); Object ob2 = right.computeValue(); if ((ob1 == null) || (ob2 == null)) { TraceManager.addDev("Found binary int expr in null elt"); return null; } if ((ob1 instanceof Integer) && (ob2 instanceof Integer)) { int elt1 = analysisArg(ob1); int elt2 = analysisArg(ob2); if (isIntToBooleanOperator(op)) { Boolean resB = makeIntegerToBooleanOp(op, elt1, elt2); return resB; } Integer result = makeIntegerOp(op, elt1, elt2); TraceManager.addDev("Result int=" + result); return result; } else { errorMessage = "Invalid operands in integer operations"; return null; } } if (res == OPEN_PARENTHESIS) { if (left == null) { return null; } return left.computeValue(); } if (res == AVAILABLE) { if (left == null) { return null; } return left.computeValue(); } errorMessage = "Badly formatted expression from:" + this; return null; } public String toString() { return toString(0); } public String toString(int dec) { String s = "\n" + newLine(dec); if (isRight()) { s = s + "R->"; } if (isLeft()) { s = s + "L->"; } s += id; if (father == null) { s += " father= no"; } else { s += " father=" + id; } s += " type:" + res + " op:" + toStringAction(op) + " int:" + i + " bool:" + b; if (left != null) { s += left.toString(dec+1); } if (right != null) { s += right.toString(dec+1); } return s; } private String newLine(int dec) { String s = ""; for (int i=0; i<dec; i++) { s += "\t"; } return s; } } // ---------------------------------------- public static final String TRUE = "t"; public static final String FALSE = "f"; public static final int TRUE_VALUE = 1; public static final int FALSE_VALUE = 0; public static final int NUMBER_TOKEN = -1; public static final int BOOL_TOKEN = -2; public static final int EQUAL_TOKEN = -3; public static final int NOT_EQUAL_TOKEN = -15; public static final int NOT_TOKEN = -6; public static final int OR_TOKEN = -7; public static final int AND_TOKEN = -8; public static final int LT_TOKEN = -4; public static final int GT_TOKEN = -5; public static final int LTEQ_TOKEN = -9; public static final int GTEQ_TOKEN = -10; public static final int EOLN_TOKEN = -11; public static final int OPEN_PAR_TOKEN = -12; public static final int CLOSE_PAR_TOKEN = -13; public static final int WHITE_SPACE_TOKEN = -14; public static final int PLUS_TOKEN = -19; public static final int MINUS_TOKEN = -16; public static final int DIV_TOKEN = -17; public static final int MULT_TOKEN = -18; public static final String [] VAL_S = {"true", "false", "nb", "bool", "==", "<", ">", "not", "or", "and", "=<", ">=", "eol", "(", ")", " ", "!=", "-", "/", "*", "+"}; public static final boolean isIntToBooleanOperator(int op) { return ((op == LT_TOKEN) || (op == GT_TOKEN) || (op == LTEQ_TOKEN) || (op == GTEQ_TOKEN)); } public static String toStringAction(int val) { if (val >= 0) { return VAL_S[val]; } return VAL_S[Math.abs(val) + 1]; } public static int ID = 0; // PARSING_STAGE public static final int BEGIN_EXPR = 1; private StringTokenizer tokens; private String errorMessage = null; private int currentType; private int currentValue; private int nbOpen; private IntBoolRes top; // top of tree private boolean supportUnknownTerminal = false; public BoolExpressionEvaluator() { } public void setSupportUnknownTerminal(boolean support) { supportUnknownTerminal = support; } public String getError() { if (errorMessage == null) { return null; } int index = errorMessage.indexOf("/"); if (index == -1) { return errorMessage; } return errorMessage.substring(index+1, errorMessage.length()); } public String getFullError() { return errorMessage; } public boolean hasError() { return errorMessage != null; } public boolean hasFinished() { return currentType == EOLN_TOKEN; } public boolean getResultOf(String _expr) { //TraceManager.addDev("Evaluating bool expr: " + _expr); _expr = Conversion.replaceAllString(_expr, "not", "!").trim(); nbOpen = 0; String tmp = Conversion.replaceAllString(_expr, "==", "$").trim(); tmp = Conversion.replaceAllString(tmp, "!=", "$").trim(); tmp = Conversion.replaceAllString(tmp, ">=", ":").trim(); tmp = Conversion.replaceAllString(tmp, "<=", ";").trim(); if (tmp.indexOf("=") > -1) { TraceManager.addDev("Not a bool"); errorMessage = "Not a boolean expression because it contains \"=\" operators"; return false; } _expr = Conversion.replaceAllString(_expr, "true", "t").trim(); _expr = Conversion.replaceAllString(_expr, "false", "f").trim(); _expr = Conversion.replaceAllString(_expr, "||", "|").trim(); _expr = Conversion.replaceAllString(_expr, "&&", "&").trim(); _expr = Conversion.replaceAllString(_expr, "or", "|").trim(); _expr = Conversion.replaceAllString(_expr, "and", "&").trim(); _expr = Conversion.replaceAllString(_expr, "==", "=").trim(); _expr = Conversion.replaceAllString(_expr, "!=", "$").trim(); _expr = Conversion.replaceAllString(_expr, ">=", ":").trim(); _expr = Conversion.replaceAllString(_expr, "<=", ";").trim(); // For not() -> must find the closing bracket int index; int indexPar; while((index = _expr.indexOf("not(")) != -1) { indexPar = Conversion.findMatchingParenthesis(_expr, index+3, '(', ')'); if( indexPar == -1) { errorMessage = "Parenthesis not maching at index " + (index + 3) + " in expression: " + _expr; return false; } _expr = _expr.substring(0, index) + "(!" + _expr.substring(index+3, indexPar) + ")" + _expr.substring(indexPar, _expr.length()); } //TraceManager.addDev("Computing:" + _expr); tokens = new java.util.StringTokenizer(_expr," \t\n\r!$=&|<>():;tf",true); //TraceManager.addDev("Evaluating bool bool bool expr: " + _expr); int result = parseRootExpr1(); if (getError() != null) { TraceManager.addDev("Error: " + getError()); } if (result == TRUE_VALUE) { //TraceManager.addDev("equal true"); return true; } if (result == FALSE_VALUE) { // TraceManager.addDev("equal false"); return false; } /*computeNextToken(); int result = (int)(parseExpression()); if (errorMessage != null) { TraceManager.addDev("Error:" + errorMessage); } if ((errorMessage == null) && (nbOpen!=0)) { errorMessage = "Badly placed parenthesis"; result = -1; } if (result == TRUE_VALUE) { TraceManager.addDev("equal true"); return true; } if (result == FALSE_VALUE) { TraceManager.addDev("equal false"); return false; } errorMessage = "Not a boolean expression: " + _expr; TraceManager.addDev("Error:" + errorMessage);*/ return false; } public int parseRootExpr1() { int[] result = parseNonEmptyExpr(); if ((result[1] == NUMBER_TOKEN) && (errorMessage == null)) { errorMessage = "0/Unexpected integer value"; return result[0]; } return result[0]; } // Returns the value and type of the return // <boolexpr> public int[] parseNonEmptyExpr() { //TraceManager.addDev("1/Parsing non empty expr"); int[] result = new int[2]; computeNextToken1(); //TraceManager.addDev("currentType=" + currentType); if (endOfParsing()) { errorMessage = "2/Unexpected end of expression"; return result; } if (currentType == CLOSE_PAR_TOKEN) { errorMessage = "3/Unexpected closing parenthesis"; return result; } if ((currentType == BOOL_TOKEN) || (currentType == NUMBER_TOKEN)) { result[0] = currentValue; result[1] = currentType; //computeNextToken(); return parseEmptyOrOpExpr(result); } //TraceManager.addDev("Testing parenthesis type=" + currentType); if (currentType == NOT_TOKEN) { result = parseNonEmptyExpr(); if (result[0] == 0) { result[0] = 1; } else { result[0] = 0; } return result; } if (currentType == OPEN_PAR_TOKEN) { //TraceManager.addDev("opening par token"); result = parseNonEmptyExpr(); if (currentType != CLOSE_PAR_TOKEN) { errorMessage = "4/Expecting closing parenthesis"; return result; } return parseEmptyOrOpExpr(result); } return result; } // <empty> or <op bool/int expr> public int[] parseEmptyOrOpExpr(int[] result) { //TraceManager.addDev("parseEmptyOrOpExpr result0= " + result[0] + " result1=" + result[1] + " currentType=" + currentType); computeNextToken1(); if (endOfParsing()) { return result; } if ((currentType == BOOL_TOKEN) || (currentType == NUMBER_TOKEN)) { errorMessage = "5/Unexpected value"; return result; } if (currentType == OPEN_PAR_TOKEN) { errorMessage = "6/Unexpected opening parenthesis"; return result; } if (currentType == CLOSE_PAR_TOKEN) { //errorMessage = "7/Unexpected closing parenthesis"; return result; } return parseBeginExprOp(result); } //<op bool/int expr> // Wrning: token already computed public int[] parseBeginExprOp(int[] result) { //TraceManager.addDev("parseBeginExprOp result0= " + result[0] + " result1=" + result[1] + " currentType=" + currentType); if (endOfParsing()) { errorMessage = "8/Unexpected end of expression"; return result; } if (currentType == CLOSE_PAR_TOKEN) { errorMessage = "9/Unexpected closing parenthesis"; return result; } if (currentType == OPEN_PAR_TOKEN) { errorMessage = "10/Unexpected opening parenthesis"; return result; } if ((currentType == BOOL_TOKEN) || (currentType == NUMBER_TOKEN)) { errorMessage = "11/Unexpected value"; return result; } // So, this is an op! int typeOfOp = currentType; //TraceManager.addDev("Parsing right expression"); int resultRight[] = parseNonEmptyExpr(); if (hasError()) { return result; } // Same type on operand if (resultRight[1] != result[1]) { errorMessage = "12/Type on left and right operand not compatible"; return result; } // Boolean ops if (resultRight[1] == BOOL_TOKEN) { //TraceManager.addDev("** Bool operator = " + typeOfOp); if (typeOfOp == EQUAL_TOKEN) { if (result[0] == resultRight[0]) { result[0] = 1; } else { result[0] = 0; } } else if (typeOfOp == NOT_EQUAL_TOKEN) { if (result[0] == resultRight[0]) { result[0] = 0; } else { result[0] = 1; } } else if (typeOfOp == OR_TOKEN) { result[0] = result[0] + resultRight[0]; if (result[0] > 1) { result[0] = 1; } //TraceManager.addDev("Or result=" + result[0]); } else if (typeOfOp == AND_TOKEN) { result[0] = (result[0] * resultRight[0]); } else { errorMessage = "13/Invalid boolean operator"; } // Int ops } else { //TraceManager.addDev("** Int operator = " + typeOfOp); if (typeOfOp == EQUAL_TOKEN) { if (result[0] == resultRight[0]) { result[0] = 1; } else { result[0] = 0; } result[1] = BOOL_TOKEN; } else if (typeOfOp == NOT_EQUAL_TOKEN) { if (result[0] == resultRight[0]) { result[0] = 0; } else { result[0] = 1; } result[1] = BOOL_TOKEN; }else if (typeOfOp == LT_TOKEN) { if (result[0] < resultRight[0]) { result[0] = 1; } else { result[0] = 0; } result[1] = BOOL_TOKEN; } else if (typeOfOp == GT_TOKEN) { if (result[0] > resultRight[0]) { result[0] = 1; } else { result[0] = 0; } result[1] = BOOL_TOKEN; } else if (typeOfOp == GTEQ_TOKEN) { if (result[0] >= resultRight[0]) { result[0] = 1; } else { result[0] = 0; } result[1] = BOOL_TOKEN; } else if (typeOfOp == LTEQ_TOKEN) { if (result[0] <= resultRight[0]) { result[0] = 1; } else { result[0] = 0; } result[1] = BOOL_TOKEN; } } return result; } public boolean endOfParsing() { return (currentType == EOLN_TOKEN); } public void computeNextToken1() { // If we're at the end, make it an EOLN_TOKEN. if (!tokens.hasMoreTokens()) { currentType = EOLN_TOKEN; return; } // Get a token--if it looks like a number, // make it a NUMBER_TOKEN. String s = tokens.nextToken(); //TraceManager.addDev("Token? = >" + s + "<"); char c1 = s.charAt(0); if (Character.isDigit(c1)) { //TraceManager.addDev("digit found"); try { currentValue = Integer.valueOf(s).intValue(); currentType = NUMBER_TOKEN; //System.out.println("value:" + s); } catch (NumberFormatException x) { errorMessage = "Illegal format for a number."; } return; } //TraceManager.addDev("next 1"); if (s.compareTo(TRUE) == 0) { currentValue = TRUE_VALUE; currentType = BOOL_TOKEN; //TraceManager.addDev("true token!"); return; } if (s.compareTo(FALSE) == 0) { currentValue = FALSE_VALUE; currentType = BOOL_TOKEN; //TraceManager.addDev("false token!"); return; } if (s.compareTo("<") == 0) { currentValue = 0; currentType = LT_TOKEN; return; } if (s.compareTo(">") == 0) { currentValue = 0; currentType = GT_TOKEN; return; } if (s.compareTo(":") == 0) { currentValue = 0; currentType = GTEQ_TOKEN; return; } if (s.compareTo(";") == 0) { currentValue = 0; currentType = LTEQ_TOKEN; return; } if (s.compareTo("=") == 0) { currentValue = 0; currentType = EQUAL_TOKEN; return; } if (s.compareTo("$") == 0) { currentValue = 0; currentType = NOT_EQUAL_TOKEN; return; } if (s.compareTo("!") == 0) { currentValue = 0; currentType = NOT_TOKEN; return; } if (s.compareTo("|") == 0) { currentValue = 0; currentType = OR_TOKEN; return; } if (s.compareTo("&") == 0) { currentValue = 0; currentType = AND_TOKEN; return; } if (s.compareTo(")") == 0) { currentType = CLOSE_PAR_TOKEN; nbOpen --; if (nbOpen < 0) { TraceManager.addDev("Boolean expr: Found pb with a parenthesis"); errorMessage = "Parenthesis mismatch"; } return; } //TraceManager.addDev("next 10"); if (s.compareTo("(") == 0) { //TraceManager.addDev("opening par token"); currentType = OPEN_PAR_TOKEN; nbOpen ++; return; } // Any other single character that is not // white space is a token. if (Character.isWhitespace(c1)) { currentType = WHITE_SPACE_TOKEN; //TraceManager.addDev("White space found: looping"); computeNextToken1(); return; } // Invalid token errorMessage = "Unknown element: " + s; } /** * Match a given token and advance to the next. * This utility is used by our parsing routines. * If the given token does not match * lexer.nextToken(), we generate an appropriate * error message. Advancing to the next token may * also cause an error. * * @param token the token that must match */ private void match(int token) { // First check that the current token matches the // one we were passed; if not, make an error. if (currentType != token) { if (token == EOLN_TOKEN) errorMessage = "Unexpected text after the expression."; else if (token == NUMBER_TOKEN) errorMessage = "Expected an integer number."; else if (token == BOOL_TOKEN) errorMessage = "Expected a boolean."; else if (token == EQUAL_TOKEN) errorMessage = "Expected an equal."; else if (token == NOT_EQUAL_TOKEN) errorMessage = "Expected an not equal."; else errorMessage = "Expected a " + ((char) token) + "."; return; } // Now advance to the next token. computeNextToken(); } /** * Parse an expression. If any error occurs we * return immediately. * * @return the double value of the expression * or garbage in case of errors. */ private double parseExpression() { // <expression> ::= // <mulexp> { ('+' <mulexp>) | ('-' <mulexp>) } Double result = parseMulexp(); if (hasError()) return result; while (true) { if (currentType == '+') { match('+'); if (hasError()) return result; result += parseMulexp(); if (hasError()) return result; } else if (currentType == '-') { match('-'); if (hasError()) return result; result -= parseMulexp(); if (hasError()) return result; } else return result; } } /** * Parse a mulexp, a subexpression at the precedence * level of * and /. If any error occurs we return * immediately. * * @return the double value of the mulexp or * garbage in case of errors. */ private double parseMulexp() { // <mulexp> ::= // <rootexp> { ('==' <rootexp>) | ('*' <rootexp>) | ('/' <rootexp>) } double result = parseRootexp(); double resulttmp; int intresult; int intresult2; if (errorMessage != null) return result; while (true) { //TraceManager.addDev("Token:" + currentType + " value=" + currentValue); if (currentType == EQUAL_TOKEN) { match(EQUAL_TOKEN); if (errorMessage != null) return result; resulttmp = parseRootexp(); //intresult = (int)(resulttmp); //intresult2 = (int)(result); if (errorMessage != null) return result; /*if ((intresult2 != TRUE_VALUE) && (intresult2 != FALSE_VALUE)) { errorMessage = "Expression on the left is not a boolean (result=" + intresult2 + ")"; } if ((intresult != TRUE_VALUE) && (intresult != FALSE_VALUE)) { errorMessage = "Expression on the right is not a boolean (result=" + intresult + ")"; }*/ if (result == resulttmp) { return TRUE_VALUE; } else { return FALSE_VALUE; } } else if (currentType == NOT_EQUAL_TOKEN) { match(NOT_EQUAL_TOKEN); if (errorMessage != null) return result; resulttmp = parseRootexp(); //intresult = (int)(resulttmp); //intresult2 = (int)(result); if (errorMessage != null) return result; /*if ((intresult2 != TRUE_VALUE) && (intresult2 != FALSE_VALUE)) { errorMessage = "Expression on the left is not a boolean (result=" + intresult2 + ")"; } if ((intresult != TRUE_VALUE) && (intresult != FALSE_VALUE)) { errorMessage = "Expression on the right is not a boolean (result=" + intresult + ")"; }*/ if (result != resulttmp) { return TRUE_VALUE; } else { return FALSE_VALUE; } }else if (currentType == LT_TOKEN) { match(LT_TOKEN); if (errorMessage != null) return result; resulttmp = parseRootexp(); if (errorMessage != null) return result; if (result < resulttmp) { return TRUE_VALUE; } else { return FALSE_VALUE; } } else if (currentType == GT_TOKEN) { match(GT_TOKEN); if (errorMessage != null) return result; resulttmp = parseRootexp(); if (errorMessage != null) return result; if (result > resulttmp) { return TRUE_VALUE; } else { return FALSE_VALUE; } } else if (currentType == GTEQ_TOKEN) { match(GTEQ_TOKEN); if (errorMessage != null) return result; resulttmp = parseRootexp(); if (errorMessage != null) return result; if (result >= resulttmp) { return TRUE_VALUE; } else { return FALSE_VALUE; } } else if (currentType == LTEQ_TOKEN) { match(LTEQ_TOKEN); if (errorMessage != null) return result; resulttmp = parseRootexp(); if (errorMessage != null) return result; if (result <= resulttmp) { return TRUE_VALUE; } else { return FALSE_VALUE; } } else if (currentType == OR_TOKEN) { match(OR_TOKEN); if (errorMessage != null) return result; resulttmp = parseRootexp(); //intresult = (int)(resulttmp); //intresult2 = (int)(result); if (errorMessage != null) return result; if ((result != 0) || (resulttmp != 0)) { return TRUE_VALUE; } else { return FALSE_VALUE; } } else if (currentType == AND_TOKEN) { match(AND_TOKEN); if (errorMessage != null) return result; resulttmp = parseRootexp(); //intresult = (int)(resulttmp); //intresult2 = (int)(result); if (errorMessage != null) return result; if ((result != 0) && (resulttmp != 0)) { return TRUE_VALUE; } else { return FALSE_VALUE; } } else if (currentType == NOT_TOKEN) { match(NOT_TOKEN); if (errorMessage != null) return result; //TraceManager.addDev("NOT TOKEN!"); resulttmp = parseRootexp(); //intresult = (int)(resulttmp); //intresult2 = (int)(result); if (errorMessage != null) return result; /*if ((intresult2 != TRUE_VALUE) && (intresult2 != FALSE_VALUE)) { errorMessage = "Expression on the left is not a boolean (result=" + intresult2 + ")"; } if ((intresult != TRUE_VALUE) && (intresult != FALSE_VALUE)) { errorMessage = "Expression on the right is not a boolean (result=" + intresult + ")"; }*/ if (((int)(resulttmp)) == 0) { return TRUE_VALUE; } else { return FALSE_VALUE; } } else if (currentType == '*') { match('*'); if (errorMessage != null) return result; result *= parseRootexp(); if (errorMessage != null) return result; } else if (currentType == '/') { match('/'); if (errorMessage != null) return result; result /= parseRootexp(); if (errorMessage != null) return result; } else return result; } } /** * Parse a rootexp, which is a constant or * parenthesized subexpression. If any error occurs * we return immediately. * * @return the double value of the rootexp or garbage * in case of errors */ private double parseRootexp() { double result = 0.0; // <rootexp> ::= '(' <expression> ')' if (currentType == '(') { match('('); if (errorMessage != null) return result; result = parseExpression(); if (errorMessage != null) return result; match(')'); if (errorMessage != null) return result; } // <rootexp> ::= number else if (currentType==NUMBER_TOKEN){ result = currentValue; if (errorMessage != null) return result; match(NUMBER_TOKEN); if (errorMessage != null) return result; } // <rootexp> ::= bool else if (currentType==BOOL_TOKEN){ result = currentValue; if (errorMessage != null) return result; match(BOOL_TOKEN); if (errorMessage != null) return result; } else if (currentType==NOT_TOKEN){ match(NOT_TOKEN); result = parseExpression(); if (result == TRUE_VALUE) { result = FALSE_VALUE; } else { result = TRUE_VALUE; } if (errorMessage != null) return result; //match(NEG_TOKEN); if (errorMessage != null) return result; } else { errorMessage = "Expected a value or a parenthesis."; } return result; } public void computeNextToken() { while (true) { // If we're at the end, make it an EOLN_TOKEN. if (!tokens.hasMoreTokens()) { currentType = EOLN_TOKEN; return; } // Get a token--if it looks like a number, // make it a NUMBER_TOKEN. String s = tokens.nextToken(); //TraceManager.addDev("Token? = >" + s + "<"); char c1 = s.charAt(0); if (Character.isDigit(c1)) { try { currentValue = Integer.valueOf(s).intValue(); currentType = NUMBER_TOKEN; //System.out.println("value:" + s); } catch (NumberFormatException x) { errorMessage = "Illegal format for a number."; } return; } if (s.compareTo(TRUE) == 0) { currentValue = TRUE_VALUE; currentType = BOOL_TOKEN; //TraceManager.addDev("true token!"); return; } if (s.compareTo(FALSE) == 0) { currentValue = FALSE_VALUE; currentType = BOOL_TOKEN; //TraceManager.addDev("false token!"); return; } if (s.compareTo("<") == 0) { currentValue = 0; currentType = LT_TOKEN; return; } if (s.compareTo(">") == 0) { currentValue = 0; currentType = GT_TOKEN; return; } if (s.compareTo(":") == 0) { currentValue = 0; currentType = GTEQ_TOKEN; return; } if (s.compareTo(";") == 0) { currentValue = 0; currentType = LTEQ_TOKEN; return; } if (s.compareTo("=") == 0) { currentValue = 0; currentType = EQUAL_TOKEN; return; } if (s.compareTo("$") == 0) { currentValue = 0; currentType = NOT_EQUAL_TOKEN; return; } if (s.compareTo("!") == 0) { currentValue = 0; currentType = NOT_TOKEN; return; } if (s.compareTo("|") == 0) { currentValue = 0; currentType = OR_TOKEN; return; } if (s.compareTo("&") == 0) { currentValue = 0; currentType = AND_TOKEN; return; } if (s.compareTo(")") == 0) { currentType = c1; nbOpen --; if (nbOpen < 0) { TraceManager.addDev("Boolean expr: Found pb with a parenthesis"); } return; } if (s.compareTo("(") == 0) { currentType = c1; nbOpen ++; return; } // Any other single character that is not // white space is a token. if (!Character.isWhitespace(c1)) { currentType = c1; return; } } } public boolean getResultOfWithIntExpr(String _expr) { int index, indexPar; String tmp = Conversion.replaceAllString(_expr, "==", "$").trim(); tmp = Conversion.replaceAllString(tmp, "!=", "$").trim(); tmp = Conversion.replaceAllString(tmp, ">=", ":").trim(); tmp = Conversion.replaceAllString(tmp, "<=", ";").trim(); if (tmp.indexOf("=") > -1) { TraceManager.addDev("Not a bool"); errorMessage = "Not a boolean expression because it contains \"=\" operators"; return false; } _expr = Conversion.replaceAllString(_expr, "not", "!").trim(); _expr = Conversion.replaceAllString(_expr, "true", "t").trim(); _expr = Conversion.replaceAllString(_expr, "false", "f").trim(); _expr = Conversion.replaceAllString(_expr, "||", "|").trim(); _expr = Conversion.replaceAllString(_expr, "&&", "&").trim(); _expr = Conversion.replaceAllString(_expr, "or", "|").trim(); _expr = Conversion.replaceAllString(_expr, "and", "&").trim(); _expr = Conversion.replaceAllString(_expr, "==", "=").trim(); _expr = Conversion.replaceAllString(_expr, "!=", "$").trim(); _expr = Conversion.replaceAllString(_expr, ">=", ":").trim(); _expr = Conversion.replaceAllString(_expr, "<=", ";").trim(); while((index = _expr.indexOf("not(")) != -1) { indexPar = Conversion.findMatchingParenthesis(_expr, index+3, '(', ')'); if( indexPar == -1) { errorMessage = "Parenthesis not maching at index " + (index + 3) + " in expression: " + _expr; return false; } _expr = _expr.substring(0, index) + "(!" + _expr.substring(index+3, indexPar) + ")" + _expr.substring(indexPar, _expr.length()); } tokens = new java.util.StringTokenizer(_expr," \t\n\r!$=&|<>():;+-/*tf",true); IntBoolRes resIBR = parseRootExprInt(); if (resIBR == null) { return false; } TraceManager.addDev("Tree of " + _expr + ": " + resIBR.toString() + "\nEnd of tree"); Object res = resIBR.computeValue(); if (res == null) { return false; } TraceManager.addDev("Tree of " + _expr + ": " + resIBR.toString() + "\nEnd of tree"); if(res instanceof Integer) { errorMessage = "Integer expression. Was expecting a boolean expression"; } if (getError() != null) { TraceManager.addDev("Error: " + getError()); } if (res instanceof Boolean) { boolean result = ((Boolean)(res)).booleanValue(); return result; } errorMessage = "Invalid boolean expression"; return false; } public String getNextToken() { if (!tokens.hasMoreTokens()) { return null; } String s = tokens.nextToken(); return s; } public IntBoolRes parseRootExprInt() { top = new IntBoolRes(); IntBoolRes res = top; boolean go = true; while(go) { String s = getNextToken(); if (s == null) { go = false; } else { TraceManager.addDev("Working on token:" + s); res = parseAndMakeTree(res, s); if (res == null) { go = false; } } } return top; } public IntBoolRes parseAndMakeTree(IntBoolRes current, String token) { ID = 0; IntBoolRes newElt; //TraceManager.addDev(current.getTop().toString()); //TraceManager.addDev("<><><><><><> Dealing with token:" + token + " current=" + current); char c1 = token.charAt(0); // Space symbol if (c1 == ' ') { return current; } // Terminal symbol if (Character.isDigit(c1)) { TraceManager.addDev("Adding number:" + token); try { newElt = current.addTerminalInt(Integer.valueOf(token).intValue()); } catch (NumberFormatException x) { errorMessage = "Illegal format for a number."; return null; } if (newElt == null) { errorMessage = "Badly placed int value:" + token; return null; } return current; } if ((c1 == 't') || (c1 == 'f')) { newElt = current.addTerminalBool(c1 == 't'); if (newElt == null) { errorMessage = "Badly placed bool value:" + token; return null; } return current; } // INT BINARY OP if (c1 == '+') { newElt = current.addIntOperator(PLUS_TOKEN); if (newElt == null) { errorMessage = "Badly placed int operator:" + token; return null; } return newElt; } if (c1 == '-') { newElt = current.addIntOperator(MINUS_TOKEN); if (newElt == null) { errorMessage = "Badly placed int operator:" + token; return null; } return newElt; } if (c1 == '*') { newElt = current.addIntOperator(MULT_TOKEN); if (newElt == null) { errorMessage = "Badly placed int operator:" + token; return null; } return newElt; } if (c1 == '/') { newElt = current.addIntOperator(DIV_TOKEN); if (newElt == null) { errorMessage = "Badly placed int operator:" + token; return null; } return newElt; } if (c1 == '<') { newElt = current.addIntOperator(LT_TOKEN); if (newElt == null) { errorMessage = "Badly placed int operator:" + token; return null; } return newElt; } if (c1 == '>') { newElt = current.addIntOperator(GT_TOKEN); if (newElt == null) { errorMessage = "Badly placed int operator:" + token; return null; } return newElt; } if (c1 == '>') { newElt = current.addIntOperator(GT_TOKEN); if (newElt == null) { errorMessage = "Badly placed int operator:" + token; return null; } return newElt; } if (c1 == ';') { newElt = current.addIntOperator(LTEQ_TOKEN); if (newElt == null) { errorMessage = "Badly placed int operator:" + token; return null; } return newElt; } if (c1 == ':') { newElt = current.addIntOperator(GTEQ_TOKEN); if (newElt == null) { errorMessage = "Badly placed int operator:" + token; return null; } return newElt; } // BOOL BINARY OP if (c1 == '=') { newElt = current.addBinaryOperator(EQUAL_TOKEN); if (newElt == null) { errorMessage = "Badly placed bool operator:" + token; return null; } return newElt; } if (c1 == '&') { newElt = current.addBinaryOperator(AND_TOKEN); if (newElt == null) { errorMessage = "Badly placed bool operator:" + token; return null; } return newElt; } if (c1 == '|') { newElt = current.addBinaryOperator(OR_TOKEN); if (newElt == null) { errorMessage = "Badly placed bool operator:" + token; return null; } return newElt; } // Bool unary op if (c1 == '!') { newElt = current.addUnaryOperator(NOT_TOKEN); if (newElt == null) { errorMessage = "Badly placed bool unary operator:" + token; return null; } return newElt; } // PARENTHESIS if (c1 == '(') { newElt = current.addOpenParenthesis(); if (newElt == null) { errorMessage = "Badly placed parenthesis:"; return null; } return newElt; } if (c1 == ')') { // Must find corresponding parenthesis // Looking for father of the correspoing parenthesis; IntBoolRes father = current.father; while(father != null) { if (father.op == OPEN_PAR_TOKEN) { break; } father = father.father; } if (father == null) { return null; } return father.father; } if (supportUnknownTerminal) { TraceManager.addDev("Adding unknown term:" + token); newElt = current.addTerminalUnknown(token); if (newElt == null) { errorMessage = "Badly placed unknown term:" + token; return null; } return current; } return null; } }