Here is a recursive descent parser for a subset of the grammar on the Wikipedia page on recursive descent parsers that seems relevant for your case.
I haven't included a tokenizer, but it should be fairly straightforward to write one that suits the interface. The code isn't significantly different to what is on the Wikipedia page, with the exception that only implements a subset of the grammar, and it actually performs the calculations.
/**
* From http://en.wikipedia.org/wiki/Recursive_descent_parser
*
* expression =
* [ "+" | "-" ] term { ("+" | "-") term } .
*
* term =
* factor { ( "*" | "/" ) factor } .
*
* factor =
* number
* | "(" expression ")" .
*/
public class Arithmetic
{
private final TokenStream tokenStream;
private TokenStream.Token currentToken;
private double currentValue;
public Arithmetic(TokenStream tokenStream) {
this.tokenStream = tokenStream;
}
public double parse() {
nextToken();
return expression();
}
private double expression() {
double lhs = 0.0;
if (accept(TokenStream.Token.MINUS)) {
lhs = -term();
} else {
// Optional unary plus swallowed
accept(TokenStream.Token.PLUS);
lhs = term();
}
for (boolean moreTerms = true; moreTerms; ) {
if (accept(TokenStream.Token.PLUS)) {
lhs += term();
} else if (accept(TokenStream.Token.MINUS)) {
lhs -= term();
} else {
moreTerms = false;
}
}
return lhs;
}
private double term() {
double lhs = factor();
for (boolean moreFactors = true; moreFactors; ) {
if (accept(TokenStream.Token.TIMES)) {
lhs *= factor();
} else if (accept(TokenStream.Token.DIVIDED_BY)) {
lhs /= factor();
} else {
moreFactors = false;
}
}
return lhs;
}
private double factor() {
if (peek(TokenStream.Token.NUMBER)) {
// Save currentValue before calling nextToken()
double value = currentValue;
nextToken();
return value;
}
require(TokenStream.Token.OPEN);
double value = expression();
require(TokenStream.Token.CLOSE);
return value;
}
private void nextToken() {
currentToken = tokenStream.nextToken();
if (currentToken == TokenStream.Token.NUMBER) {
currentValue = tokenStream.getValue();
}
}
private boolean peek(TokenStream.Token token) {
return (currentToken == token);
}
private boolean accept(TokenStream.Token token) {
if (peek(token)) {
nextToken();
return true;
}
return false;
}
private void require(TokenStream.Token token) {
if (currentToken == token) {
nextToken();
} else {
throw new IllegalStateException("Unexpected token " + currentToken);
}
}
}
The interface for TokenStream is pretty simple:
public interface TokenStream {
public enum Token {
// Terminals
PLUS,
MINUS,
TIMES,
DIVIDED_BY,
OPEN,
CLOSE,
NUMBER,
EOF
}
Token nextToken();
// Retrieve value when nextToken() returns NUMBER
double getValue();
}
Another possibility is to use the scripting facilities to evaluate some JavaScript like so:
try
{
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("JavaScript");
Object result = engine.eval("1 + 2 / 2");
System.out.println(result.getClass().getCanonicalName());
System.out.println(result);
}
catch (ScriptException e)
{
e.printStackTrace();
}