/*
* File name: EqSolver.java
* Evaulate an Arithmetic expression - supports Add., Sub. Mult., Div. and
* negative numbers.
*/
package OtherTests;
import java.util.Stack;
/**
*
* @author shayzukerman
*/
public class EqSolver
{
/**
* Types of expected tokens in input expression:
*/
public enum TOKEN
{
ERROR,
NONE,
NUMBER,
MINUS,
OPERATOR,
SPACE
};
private static final String NUM_OPERATORS
= "+-*/"; // used to verify operations.
/**
* Evaluate the Arithmetic expression:
* @param mathEpr input expression
* @return its value.
*/
@SuppressWarnings("empty-statement")
static int solveMathExp
(String mathEpr
)
{
int solution = 0;
// Convert the input string to char array to solve some time:
int inpLen = mathEpr.length();
int nextPos = 0; // Next position in the input string:
int pos; // current index in string.
char ch;
TOKEN currToken; // Type of the next xpected token in input
int currNum; // Last identified number;
char currOper = '\0'; // last identfied operator
boolean firstDigitFound; // Used for hadling minus signs:
// Stack holding the numbers to be summed:
Stack<Integer> numStk = new Stack<>();
// Precedence - Should the number put in stack or immedialty used
// for evaluation of sub expression:
boolean evalSubExp = false;
int numSign;
boolean cont = true; // Loop flag
// First expected token:
firstDigitFound = false;
numSign = 1;
currNum = 0;
currToken = TOKEN.NUMBER;
// Scan the input line:
pos = 0;
while (cont)
{
if (pos == inpLen)
{
ch = ' ';
cont = false;
}
else
{
// Skip over spaces:
for (; pos
< inpLen
&& Character.
isWhitespace(mathEpr.
charAt(pos
)); pos
++);
ch = mathEpr.charAt(pos++);
}
TOKEN chToken = char2Token(ch);
if (chToken == TOKEN.ERROR)
{
errorStr
= String.
format("Unexpected character \"%c\" in offset: %d\n",
ch, (1 + nextPos + pos));
currToken = TOKEN.ERROR;
break;
}
if (currToken == TOKEN.NUMBER)
{
switch (chToken)
{
case NUMBER:
if (!firstDigitFound)
firstDigitFound = true;
currNum = currNum * 10 + (ch - '0');
break;
case MINUS:
// IF the Minus sight preceeds any digit
// then treat it as part of the number.
// Otherwise - treat it as an operator:
if (!firstDigitFound)
{
numSign *= -1;
break;
}
// Operator, "-" or anything else:
// Take care of the number:
default:
// First of all, make sure to return to the same
// character in the next iteration:
pos--;
currNum *= numSign;
// Determine what to do:
// Does Operation's precedence requires evaluation now or later:
if (evalSubExp)
{
// Prev. operator is "=" - change number sign:
if (currOper == '-')
currNum *= -1;
else // Mult,div - evaluate the expression
{
if (numStk.size() == 0)
{
System.
out.
format("Invalid expression - missing number Pos: %d\n", nextPos
);
cont = false;
break;
}
int popNum = numStk.pop();
currNum = evalOperation(currOper, popNum, currNum);
}
}
// Store the number for the next operations:
numStk.push(currNum);
// Prepare for the next number:
firstDigitFound = false;
numSign = 1;
currNum = 0;
// The next token to find:
currToken = TOKEN.OPERATOR;
break;
}
}
else if (currToken == TOKEN.OPERATOR)
{
if (chToken == TOKEN.MINUS || chToken == TOKEN.OPERATOR)
{
currOper = ch;
// Determine if the operation should be immediately evaluated:
evalSubExp = (currOper != '+');
currToken = TOKEN.NUMBER;
}
}
}
// Is the expression wrong:
if (currToken != TOKEN.ERROR)
{
// Sum the contents of the stack:
if (numStk.size() > 0)
{
solution = numStk.pop();
while (numStk.size() > 0)
solution += numStk.pop();
}
}
return(solution);
}
/**
* Return the token the input character is belonging to:
* @param ch
* @return
*/
static private TOKEN char2Token(char ch)
{
TOKEN retVal = TOKEN.ERROR;
retVal = TOKEN.NUMBER;
else if (ch == '-')
retVal = TOKEN.MINUS;
retVal = TOKEN.SPACE;
else if (NUM_OPERATORS.indexOf(ch) != -1)
retVal = TOKEN.OPERATOR;
return(retVal);
}
/**
* Evaluate the basic Arithmetic operation,
* @param operChar - Operator
* @param a
* @param b
* @return
* Note: There is no exceptions on Divide by zero ...
*/
static private int evalOperation(char operChar, int a, int b)
{
switch (operChar)
{
case '+':
return(a + b);
case '-':
return(a - b);
case '*':
return(a * b);
case '/': // No exceptions ....
return((b != 0) ? a / b : 0);
}
return(-1);
}
public static void main
(String[] args
)
{
//String inpExp = "-12 + 35 * 4 - -12";
String inpExp
= "1 + 2 * 3 - -5 * 6 - 18 / 6 + 2";
int val = solveMathExp(inpExp);
System.
out.
println(inpExp
+ " = " + val
);
}
}