/* 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 IntExpressionEvaluator * Creation: 13/12/2010 * Version 2.0 13/12/2010 * @author Ludovic APVRILLE */ public class IntExpressionEvaluator { public static final int NUMBER_TOKEN = -1; public static final int EOLN_TOKEN = -2; private StringTokenizer tokens; private String errorMessage = null; private int currentType; private int currentValue; private int nbOpen; public IntExpressionEvaluator() { } public String getError() { return errorMessage; } public boolean hasError() { return errorMessage != null; } public boolean hasFinished() { return currentType == EOLN_TOKEN; } public double getResultOf(String _expr) { // TraceManager.addDev("Computing:" + _expr); tokens = new java.util.StringTokenizer(_expr," \t\n\r+-*/()",true); computeNextToken(); double d = parseExpression(); if ((errorMessage == null) && (nbOpen!=0)) { errorMessage = "Badly placed parenthesis"; } if (errorMessage != null) { TraceManager.addDev("Expr contains an error:" + errorMessage + " expr=" + _expr); } else { //TraceManager.addDev("Expr is correct"); } return d; } /** * 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 a number."; 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 (errorMessage != null) return result; while (true) { if (currentType == '+') { match('+'); if (errorMessage != null) return result; result += parseMulexp(); if (errorMessage != null) return result; } else if (currentType == '-') { match('-'); if (errorMessage != null) return result; result -= parseMulexp(); if (errorMessage != null) 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>) } double result = parseRootexp(); if (errorMessage != null) return result; while (true) { 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; } else { errorMessage = "Expected a number 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(); char c1 = s.charAt(0); if (s.length()>1 || Character.isDigit(c1)) { try { currentValue = Integer.valueOf(s).intValue(); currentType = NUMBER_TOKEN; } catch (NumberFormatException x) { errorMessage = "Illegal format for a number."; } return; } else if (c1 == ')') { currentType = c1; nbOpen --; //TraceManager.addDev(") met: Nb of open=" + nbOpen); if (nbOpen < 0) { TraceManager.addDev("int Expr: found pb with a parenthesis"); } return; } else if (c1 == '(') { nbOpen ++; //TraceManager.addDev("( met: Nb of open=" + nbOpen); currentType = c1; return; } // Any other single character that is not // white space is a token. else if (!Character.isWhitespace(c1)) { currentType = c1; return; } } } }