package org.jacorb.idl;
/*
* JacORB - a free Java ORB
*
* Copyright (C) 1997-2014 Gerald Brose / The JacORB Team.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
import java.util.HashMap;
/**
* Based on the MathEvaluator class by The-Son LAI,
* <a href="mailto:Lts@writeme.com">Lts@writeme.com</a>
*
* <i>Expression evaluator for IDL constant expression</i>
*
* Supports the following functions:
* <code>+, -, *, /, ^, %, ^, | , t {@literal <<},{@literal >>}</code><br>
*
* When the getValue() is called, a Double object is returned.
* If it returns null, an error occured.<p>
* @author Gerald Brose,
* The-Son LAI <a href="mailto:Lts@writeme.com">Lts@writeme.com</a>
*/
public class ConstExprEvaluator
{
private static Operator[] operators = null;
private Node node = null;
private String expression = null;
/**
* creates a ConstExprEvaluator and assign the expression string.
*/
public ConstExprEvaluator(String s)
{
if ( operators == null )
{
initializeOperators();
}
expression = s;
}
/**
* evaluates and returns the value of the expression
*/
public Double getValue()
{
if (expression == null)
{
return null;
}
try
{
node = new Node(expression);
return evaluate(node);
}
catch (Exception e)
{
lexer.emit_error("unexpected exception: " + e.getMessage());
e.printStackTrace();
// TODO throw exception?
return null;
}
}
private static Double evaluate(Node n)
{
if ( n.hasOperator() && n.hasChild() )
{
if ( n.getOperator().getType() == 1 )
n.setValue ( evaluateExpression( n.getOperator(), evaluate( n.getLeft() ), null ) );
else if ( n.getOperator().getType() == 2 )
{
n.setValue( evaluateExpression( n.getOperator(), evaluate( n.getLeft() ), evaluate( n.getRight() ) ) );
}
}
return n.getValue();
}
private static Double evaluateExpression( Operator o, Double f1, Double f2)
{
String op = o.getOperator();
Double res = null;
if ( "+".equals(op) )
res = new Double( f1.doubleValue() + f2.doubleValue() );
else if ( "-".equals(op) )
res = new Double( f1.doubleValue() - f2.doubleValue() );
else if ( "*".equals(op) )
res = new Double( f1.doubleValue() * f2.doubleValue() );
else if ( "/".equals(op) )
res = new Double( f1.doubleValue() / f2.doubleValue() );
else if ( "%".equals(op) )
res = new Double( f1.doubleValue() % f2.doubleValue() );
else if ( "|".equals(op) )
res = new Double(Double.longBitsToDouble( Double.doubleToLongBits( f1.doubleValue()) | Double.doubleToLongBits( f2.doubleValue() ) ));
else if ( "&".equals(op) )
res = new Double( Double.longBitsToDouble( Double.doubleToLongBits( f1.doubleValue() ) & Double.doubleToLongBits( f2.doubleValue() ) ));
else if ( "^".equals(op) )
res = new Double( Double.longBitsToDouble( Double.doubleToLongBits( f1.doubleValue() ) ^ Double.doubleToLongBits( f2.doubleValue() ) ));
else if ( "<<".equals(op) )
res = new Double( Double.longBitsToDouble( Double.doubleToLongBits( f1.doubleValue() ) << Double.doubleToLongBits( f2.doubleValue() ) ));
else if ( ">>".equals(op) )
res = new Double( Double.longBitsToDouble( Double.doubleToLongBits( f1.doubleValue() ) >> Double.doubleToLongBits( f2.doubleValue() ) ));
return res;
}
private void initializeOperators()
{
operators = new Operator[10];
// bit-wise operators
operators[0] = new Operator("|" , 2, 0);
operators[1] = new Operator("^" , 2, 2);
operators[2] = new Operator("&" , 2, 4);
operators[3] = new Operator(">>" , 2, 6);
operators[4] = new Operator("<<" , 2, 6);
// arithmetic operators
operators[5] = new Operator("+" , 2, 8);
operators[6] = new Operator("-" , 2, 8);
operators[7] = new Operator("*" , 2, 10);
operators[8] = new Operator("/" , 2, 10);
operators[9] = new Operator("%" , 2, 10);
}
private Double getDouble(String s)
{
if ( s == null )
return null;
Double res = null;
try
{
res = new Double(Double.parseDouble(s));
}
catch(Exception e)
{
}
return res;
}
static protected class Operator
{
private String op;
private int type;
private int priority;
public Operator(String o, int t, int p)
{
op = o;
type = t;
priority = p;
}
public String getOperator()
{
return op;
}
public void setOperator(String o)
{
op = o;
}
public int getType()
{
return type;
}
public int getPriority()
{
return priority;
}
}
protected class Node
{
public String nString = null;
public Operator nOperator = null;
public Node nLeft = null;
public Node nRight = null;
public Node nParent = null;
public int nLevel = 0;
public Double nValue = null;
public Node(String s) throws Exception
{
init(null, s, 0);
}
public Node(Node parent, String s, int level) throws Exception
{
init(parent, s, level);
}
private void init(Node parent, String s, int level) throws Exception
{
s = removeIllegalCharacters(s);
s = removeBrackets(s);
s = addZero(s);
if ( checkBrackets(s) != 0 )
throw new Exception("Wrong number of brackets in [" + s + "]");
nParent = parent;
nString = s;
nValue = getDouble(s);
nLevel = level;
int sLength = s.length();
int inBrackets = 0;
int startOperator = 0;
for (int i=0; i<sLength; i++)
{
if ( s.charAt(i) == '(' )
inBrackets++;
else if ( s.charAt(i) == ')' )
inBrackets--;
else
{
// the expression must be at "root" level
if ( inBrackets == 0 )
{
Operator o = getOperator(nString,i);
if ( o != null )
{
// if first operator or lower priority operator
if ( nOperator == null || nOperator.getPriority() >= o.getPriority() )
{
nOperator = o;
startOperator = i;
}
}
}
}
}
if ( nOperator != null )
{
// one operand, should always be at the beginning
if ( startOperator==0 && nOperator.getType() == 1 )
{
// the brackets must be ok
if ( checkBrackets( s.substring( nOperator.getOperator().length() ) ) == 0 )
{
nLeft =
new Node( this, s.substring( nOperator.getOperator().length() ) , nLevel + 1);
nRight = null;
return;
}
throw new Exception("Error during parsing... missing brackets in [" + s + "]");
}
// two operands
else if ( startOperator > 0 && nOperator.getType() == 2 )
{
nLeft =
new Node( this, s.substring(0, startOperator), nLevel + 1 );
nRight =
new Node( this, s.substring(startOperator + nOperator.getOperator().length()), nLevel + 1);
}
}
}
private Operator getOperator(String s, int start)
{
String temp = s.substring(start);
temp = getNextWord(temp);
for (int i=0; i<operators.length; i++)
{
if ( temp.startsWith(operators[i].getOperator()) )
return operators[i];
}
return null;
}
private String getNextWord(String s)
{
int sLength = s.length();
for (int i=1; i<sLength; i++)
{
char c = s.charAt(i);
if ( (c > 'z' || c < 'a') && (c > '9' || c < '0') )
return s.substring(0, i);
}
return s;
}
/**
* checks if there is any missing brackets
* @return true if s is valid
*/
protected int checkBrackets(String s)
{
int sLength = s.length();
int inBracket = 0;
for (int i=0; i<sLength; i++)
{
if ( s.charAt(i) == '(' && inBracket >= 0 )
inBracket++;
else if ( s.charAt(i) == ')' )
inBracket--;
}
return inBracket;
}
/**
* returns a string that doesnt start with a + or a -
*/
protected String addZero(String s)
{
if ( s.startsWith("+") || s.startsWith("-") )
{
int sLength = s.length();
for (int i=0; i<sLength; i++)
{
if ( getOperator(s, i) != null )
return "0" + s;
}
}
return s;
}
protected boolean hasChild()
{
return ( nLeft != null || nRight != null );
}
protected boolean hasOperator()
{
return ( nOperator != null );
}
protected boolean hasLeft()
{
return ( nLeft != null );
}
protected Node getLeft()
{
return nLeft;
}
protected boolean hasRight()
{
return ( nRight != null );
}
protected Node getRight()
{
return nRight;
}
protected Operator getOperator()
{
return nOperator;
}
protected int getLevel()
{
return nLevel;
}
protected Double getValue()
{
return nValue;
}
protected void setValue(Double f)
{
nValue = f;
}
protected String getString()
{
return nString;
}
/**
* Removes spaces, tabs and brackets at the begining
*/
public String removeBrackets(String s)
{
String res = s;
if ( s.length() > 2 && res.startsWith("(") && res.endsWith(")") && checkBrackets(s.substring(1,s.length()-1)) == 0 )
{
res = res.substring(1, res.length()-1 );
}
if ( res != s )
return removeBrackets(res);
else
return res;
}
/**
* Removes illegal characters
*/
public String removeIllegalCharacters(String s)
{
char[] illegalCharacters = { ' ' };
String res = s;
for ( int j=0; j<illegalCharacters.length; j++)
{
int i = res.lastIndexOf(illegalCharacters[j], res.length());
while ( i != -1 )
{
String temp = res;
res = temp.substring(0,i);
res += temp.substring(i + 1);
i = res.lastIndexOf(illegalCharacters[j], s.length());
}
}
return res;
}
}
}