I am working on a program that solves arithmetic equations. I have encountered a problem that occurs when there are multiple exponential statements in a row the program does not correctly solve them. An example would be: 2^3^2, the correct answer is 512 but the program outputs 64. This is because the program does 2^3 and then 8^2, instead of doing 3^2 and then 2^9. Let me know if you have any ideas on how to modify my current code or have something to add.
import java.text.DecimalFormat;
import java.util.EmptyStackException;
import myUtil.*;
public class PostFixEvaluator extends Asg6
{
public static class SyntaxErrorException extends Exception
{
SyntaxErrorException(String message)
{
super(message);
}
}
private static final String operators = "+-*/^()";
private AStack<Double> operandStack;
private double evaluateOP(char op) throws Exception
{
double rightside = operandStack.pop();
double leftside = operandStack.pop();
double result = 0;
if(op == '+')
{
result = leftside + rightside;
}
else if(op == '-')
{
result = leftside - rightside;
}
else if(op == '*')
{
result = leftside * rightside;
}
else if(op == '/')
{
if(rightside == 0)
{
throw new Exception("Can not divide by 0, the equation is undefined");
}
else
{
result = leftside / rightside;
}
}
else if(op == '^')
{
result = Math.pow(leftside, rightside);
}
return result;
}
private boolean isOperator(char ch)
{
return operators.indexOf(ch) != -1;
}
public double evaluate(String exp) throws Exception
{
operandStack = new AStack<Double>();
String[] tokens = exp.split("\\s+");
try
{
for(String nextToken : tokens)
{
char firstChar = nextToken.charAt(0);
if(Character.isDigit(firstChar))
{
double value = Double.parseDouble(nextToken);
operandStack.push(value);
}
else if (isOperator(firstChar))
{
double result = evaluateOP(firstChar);
operandStack.push(result);
}
else
{
throw new Exception("Invalid character: " + firstChar);
}
}
double answer = operandStack.pop();
if(operandStack.empty())
{
return answer;
}
else
{
throw new Exception("Syntax Error: Stack should be empty");
}
}
catch(EmptyStackException ex)
{
throw new Exception("Syntax Error: The stack is empty");
}
}
}
You're trying to use an LL(1) grammar (which is what a recursive descent parser can parse) to model a right-associative operator (^). A right-associative operator requires left recursion, which doesn't work so easily with LL(1) grammars. You'll want to look at left factoring: http://en.wikipedia.org/wiki/LL_parser#Left_Factoring
I would solve this with operator Priorities as you might want to have them anyway.
For testing i changed the class a bit, so i could test it and its sure not most efficient or readable but you should get
the idea how it works.
import java.text.DecimalFormat;
import java.util.EmptyStackException;
import java.util.*;
public class PostFixEvaluator
{
public static class SyntaxErrorException extends Exception
{
SyntaxErrorException(String message)
{
super(message);
}
}
private static final String operators = "+-*/^()";
private static int[] operatorPriority = {1,1,2,2,3,10,10};
private Stack<Double> operandStack;
private Stack<Character> operatorStack;
private double evaluateOP(char op) throws Exception
{
double rightside = operandStack.pop();
double leftside = operandStack.pop();
double result = 0;
if(op == '+')
{
result = leftside + rightside;
}
else if(op == '-')
{
result = leftside - rightside;
}
else if(op == '*')
{
result = leftside * rightside;
}
else if(op == '/')
{
if(rightside == 0)
{
throw new Exception("Can not divide by 0, the equation is undefined");
}
else
{
result = leftside / rightside;
}
}
else if(op == '^')
{
result = Math.pow(leftside, rightside);
}
return result;
}
private boolean isOperator(char ch)
{
return operators.indexOf(ch) != -1;
}
public double evaluate(String exp) throws Exception
{
operandStack = new Stack<Double>();
operatorStack = new Stack<Character>();
String[] tokens = exp.split("\\s+");
try
{
for(String nextToken : tokens)
{
char firstChar = nextToken.charAt(0);
if(Character.isDigit(firstChar))
{
double value = Double.parseDouble(nextToken);
operandStack.push(value);
}
else if (isOperator(firstChar))
{
// Try to evaluate the operators on the stack
while (!operatorStack.isEmpty())
{
char tmpOperator = operatorStack.pop();
// If Operator has higher Priority than the one before,
// Calculate it first if equal first calculate the second
// operator to get the ^ problem fixed
if (operatorPriority[operators.indexOf(firstChar)] >= operatorPriority[operators.indexOf(tmpOperator)])
{
operatorStack.push(tmpOperator);
// Operand has to be fetched first
break;
}
else
{
double result = evaluateOP(tmpOperator);
operandStack.push(result);
}
}
operatorStack.push(firstChar);
}
else
{
throw new Exception("Invalid character: " + firstChar);
}
}
// Here we need to calculate the operators left on the stack
while (!operatorStack.isEmpty())
{
char tmpOperator = operatorStack.pop();
// Operator Priority has to be descending,
// or the code before is wrong.
double result = evaluateOP(tmpOperator);
operandStack.push(result);
}
double answer = operandStack.pop();
if(operandStack.empty())
{
return answer;
}
else
{
throw new Exception("Syntax Error: Stack should be empty");
}
}
catch(EmptyStackException ex)
{
throw new Exception("Syntax Error: The stack is empty");
}
}
// For testing Only
public static void main(String[] args) throws Exception
{
PostFixEvaluator e = new PostFixEvaluator();
System.out.println(e.evaluate("2 ^ 3 ^ 2"));
}
}
Related
class Exceptions {
public String checkExceptions(double n1, double n2, char op) throws DivideByZeroException, MultiplyByZeroException{
try {
if(op == '/' && n2==0) {
throw new DivideByZeroException();
}
else if(op=='*' && (n1==0 || n2==0)) {
throw new MultiplyByZeroException();
}
else {
return "No exception found";
}
}
catch (DivideByZeroException ex) {
return "Division by zero results in infinity";
}
catch(MultiplyByZeroException ex) {
return "Multiplying by zero";
}
catch(Exception ex) {
return op+" not a valid operator";
}
}
public double calculate(double v1, double v2, char op) throws Exception{ //Error: This method must return a result of type double
try{
checkExceptions(v1, v2, op); //This might be wrong place to put the method. Don't know how to check if this method throws an exception or not.
if(op=='+') {
return v1+v2;
}
else if(op=='-') {
return v1-v2;
}
else{
return 0.0;
}
catch(Exception ex){
System.out.println(ex.getMessage());
}
}
}
class DivideByZeroException extends Exception{
DivideByZeroException(){
super();
}
}
class MultiplyByZeroException extends Exception{
MultiplyByZeroException(){
super();
}
}
The main method takes the input (2 numbers and an operator('+' or '-' or '/' or '*' only) and passes it to the calculate method. The calculate method should check for an exception and if there is no exception, return the calculated value to the main function i.e. v1+v2 or v1-v2;
Else if an exception exists then it should print the error statement and the value that is returned from the calculate method to the main method should be 0.0(Not printed).
You can try in below way and should work fine. You can even overide Exception constructor to pass error message from exception and print e.getMessage() at place where exception is caught. I have just given you working code with simple message print.
class Exceptions {
public void checkExceptions(double n1, double n2, char op) throws DivideByZeroException, MultiplyByZeroException {
if (op == '/' && n2 == 0) {
throw new DivideByZeroException();
} else if (op == '*' && (n1 == 0 || n2 == 0)) {
throw new MultiplyByZeroException();
}
}
public double calculate(double v1, double v2, char op) throws Exception {
double result = 0.0;
try {
checkExceptions(v1, v2, op);
switch(op){
case '+' : result = v1 + v2;
break;
case '-' : result = v1 - v2;
break;
case '/' : result = v1 / v2;
break;
case '*' : result = v1 * v2;
break;
}
} catch (DivideByZeroException ex) {
System.out.println("Division by zero results in infinity");
} catch (MultiplyByZeroException ex) {
System.out.println("Multiplying by zero");
} catch (Exception ex) {
System.out.println(op + " not a valid operator");
}
return result;
}
}
class DivideByZeroException extends Exception {
DivideByZeroException() {
super();
}
}
class MultiplyByZeroException extends Exception {
MultiplyByZeroException() {
super();
}
}
You can do something like
class Exceptions {
public String checkExceptions(double n1, double n2, char op) throws DivideByZeroException, MultiplyByZeroException {
if (op == '/' && n2 == 0) {
throw new DivideByZeroException("Division by zero results in infinity");
} else if (op == '*' && (n1 == 0 || n2 == 0)) {
throw new MultiplyByZeroException("Multiplying by zero");
} else {
return "No exception found";
}
}
public double calculate(double v1, double v2, char op) {
double result = 0;
try {
System.out.println(checkExceptions(v1, v2, op));// Print the message
if (op == '+') {
result = v1 + v2;
} else if (op == '-') {
result = v1 - v2;
} else if (op == '/') {
result = v1 / v2;
} else if (op == '*') {
result = v1 * v2;
}
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return result;// Return result
}
}
class DivideByZeroException extends Exception {
DivideByZeroException(String message) {// Parametrise it
super(message);// Pass the parameter to the constructor of super class
}
}
class MultiplyByZeroException extends Exception {
MultiplyByZeroException(String message) {// Parametrise it
super(message);// Pass the parameter to the constructor of super class
}
}
public class Main {
public static void main(String[] args) {
Exceptions e = new Exceptions();
System.out.println(e.calculate(10, 0, '/'));
System.out.println(e.calculate(10, 5, '/'));
System.out.println(e.calculate(10, 5, '*'));
System.out.println(e.calculate(10, 0, '*'));
System.out.println(e.calculate(10, 5, '+'));
System.out.println(e.calculate(10, 5, '-'));
}
}
I have written enough comments in the code so that you can understand it easily.
Output:
Division by zero results in infinity
0.0
No exception found
2.0
No exception found
50.0
Multiplying by zero
0.0
No exception found
15.0
No exception found
5.0
UPD: I made mistake you should use
Arrays.asList(Arrays.stream(Operators.values()).map(en -> en.op)).contains(op)
instead
Arrays.asList(Operators.values()).contains(op)
You can use Exception(String message) constructor for your excaptions. Also I think you should use Enum for indicate operators
class Exceptions {
public enum Operators {
PLUS('+'),
SUB('-'),
DIV('/'),
MUL('*');
public final char op;
Operators(char op) {
this.op = op;
}
}
public void checkExceptions(double n1, double n2, char op) throws Exception {
if (op == Operators.DIV.op && n2 == 0) {
throw new DivideByZeroException("Division by zero!");
} else if (op == Operators.MUL.op && (n1 == 0 || n2 == 0)) {
throw new MultiplyByZeroException("Multiplying by zero!");
} else if(Arrays.asList(Arrays.stream(Operators.values()).map(en -> en.op)).contains(op)) {
throw new Exception(op + " not a valid operator!");
}
}
public double calculate(double v1, double v2, char op) {
try {
checkExceptions(v1, v2, op);
if (op == Operators.PLUS.op) {
return v1 + v2;
} else if (op == Operators.SUB.op) {
return v1 - v2;
} else if (op == Operators.MUL.op){
return v1 * v2;
} else if(op == Operators.DIV.op) {
return v1 / v2;
} else {
return 0.0;
}
} catch (Exception ex) {
System.out.println(ex.getMessage());
return 0.0;
}
}
class DivideByZeroException extends Exception {
DivideByZeroException(String message) {
super(message);
}
}
class MultiplyByZeroException extends Exception {
MultiplyByZeroException(String message) {
super(message);
}
}
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
im work this assignment and keep getting Exception in thread
"main" java.lang.RuntimeException: Stack Underflow at Stack.pop(Postfix.java:74)
at Postfix.eval(Postfix.java:221)at Postfix.main(Postfix.java:112)
dont know why i look at the stack and write it correct , i cant see problem why it pop when (3*4)/5
import java.io.IOException;
class CharStack
{
private final int STACKSIZE= 80;
private int top;
private char[] items;
public CharStack(){
items = new char[STACKSIZE];
top =-1;
}
public boolean empty() {
if(top==-1){
return true;
}
return false;
}
public char pop() {
if(empty()){
throw new RuntimeException("Stack Underflow");
}
return items[top--];
}
public void push(char symb)
{
if(top == STACKSIZE -1) {
throw new RuntimeException("Stack Overflow");
}
items[++top] =symb;
}
public char peek() {
if(empty()){
throw new RuntimeException("Stack Underflow");
}
return items[top];
}
}
class Stack {
private final int STACKSIZE= 80;
private int top;
private double[] items;
public Stack(){
items = new double[STACKSIZE];
top =-1;
}
public void push(double x)
{
if(top == STACKSIZE -1) {
throw new RuntimeException("Stack Overflow");
}
items[++top] =x;
}
public double pop(){
if(empty()){
System.out.print(top);
throw new RuntimeException("Stack Underflow");
}
return items[top--];
}
public double peek() {
if(empty()){
throw new RuntimeException("Stack Underflow");
}
return items[top];
}
boolean empty()
{
if(top==-1){
return true;
}
return false;
}
}
public class Postfix {
public final static int MAXCOLS = 80;
public static void main(String[] args) throws IOException {
String infix, pfix;
System.out.println("Enter a infix String: ");
infix = readString().trim();
System.out.println("The original infix expr is: " + infix);
pfix = postfix(infix);
System.out.println("The Postfix expr is: " + pfix);
System.out.println("The value is : " + eval(pfix));
} // end main
public static boolean isOperand(char x)
{
if(x == '+')
{
return false;
}
else if(x == '-')
{
return false;
}
else if (x == '*')
{
return false;
}
else if (x == '/')
{
return false;
}
else if ( x== '$')
{
return false;
}
return true;
}
public static int operPrecedence(char oper)
{
if(oper == '+'||oper == '-' )
{
return 1;
}
else if (oper == '*' || oper == '/')
{
return 2;
}
else if (oper == '$')
{
return 3;
}
return 0;
}
public static boolean precedence(char top, char symb)
{
if ((top != '('||top != ')')&&symb == '(')
{
return false;
}
if (top == '(' && (symb != '('||symb != ')') )
{
return false;
}
else if((top != '('||top != ')')&&symb ==')' )
{
return true;
}
int opcode1, opcode2;
opcode1 =operPrecedence(top) ;
opcode2 =operPrecedence(symb) ;
if(opcode1>=opcode2){
return true;
}
return false;
}
public static String readString() throws IOException {
char[] charArray = new char[80];
int position = 0;
char c;
while ((c = (char) System.in.read()) != '\n') {
charArray[position++] = c;
}
return String.copyValueOf(charArray, 0, position); // turns a character array into a string, starting between zero and position-1
}// end read string
public static double eval(String infix) {
char c;
int position;
double opnd1, opnd2, value;
Stack opndstk = new Stack();
for (position = 0; position < infix.length(); position++) {
c = infix.charAt(position);
if (Character.isDigit(c)) // operand-convert the character represent of
// the digit into double and push it into the
// stack
{
opndstk.push((double) Character.digit(c, 10));
} else {
// operator
opnd2 = opndstk.pop();
opnd1 = opndstk.pop();
value = oper(c, opnd1, opnd2);
opndstk.push(value);
} // else
} // end for
return opndstk.pop();
}// end eval
public static String postfix(String infix) {
int position, outpos = 0;
char symb;
char[] postr = new char[MAXCOLS];
CharStack opstk = new CharStack();
for (position = 0; position < infix.length(); position++) {
symb = infix.charAt(position);
if (isOperand(symb)) {
postr[outpos++] = symb;
} else {
while (!opstk.empty() && precedence(opstk.peek(), symb)) {
postr[outpos++] = opstk.pop();
} // end while
if (symb != ')') {
opstk.push(symb);
} else {
opstk.pop();
}
} // end else
} // end for
while (!opstk.empty()) {
postr[outpos++] = opstk.pop();
}
return String.copyValueOf(postr, 0, outpos);
}// end pos
public static double oper(char symb, double op1, double op2) {
double value = 0;
switch (symb) {
case '+':
value = op1 + op2;
break;
case '-':
value = op1 - op2;
break;
case '*':
value = op1 * op2;
break;
case '/':
value = op1 / op2;
break;
case '$':
value = Math.pow(op1, op2);
break;
default:
throw new RuntimeException("illegal operator: " + symb);
}// end switch
return value;
}// end oper
}
At least part of the problem you're having is your isOperand method. The characters ( and ) are not operands, however, when they are passed to this method, it would return true. For a quick test, I added the following lines to the end of the method:
else if (x == '(')
{
return true;
}
else if (x == ')')
{
return true;
}
And your example input, (3*4)/5) runs successfully. However, this breaks your postfix output, as it leaves the brackets out of the postfix version and instead prints 34*5/, which I am guessing you don't want.
Then, I looked at your eval method, which is where the problem is coming from, according to the error message I'm receiving:
Exception in thread "main" java.lang.RuntimeException: Stack Underflow
at Stack.pop(Postfix.java:74)
at Postfix.eval(Postfix.java:221)
at Postfix.main(Postfix.java:112)
Note the line Postfix.java:221, which indicates the line that called the method which created the error. If you output your character c right before that line is called, you'll notice that c is the ( character, which means your eval method is recognizing ( as an operator, and is attempting to pop two operands after it, causing your underflow.
All of this is fairly simple to determine with some System.out.println() calls, and looking at your error. I'll leave the actual fixing to you, but at least you've hopefully got a direction to head in now.
I keep getting the following error message in my method:
"Error: 'void' type not allowed here" on the line outEquation = outEquation + opSt.pop() + " ";.
The code I'm working on currently is a stacked linked list which takes in user input (in infix notation) and converts it to postfix. Any help would be appreciated.
import java.util.Scanner;
public class StackDemo
{
public static void main(String[] args)
{
final int right = 0;
final int left = 1;
final int ADD = 0;
final int MULT = 1;
final int EXP = 2;
final int PAR = -1;
}
public void UserPrompt()
{
Scanner keyboard = new Scanner(System.in);
String input = keyboard.nextLine();
System.out.println("Please select what type of conversion you would like to do: ");
System.out.println();
System.out.println("1) Infix to postfix \n2) Postfix to infix \n3) Print Equations \n4) Exit");
if(input == "1")
{
infix();
}
else if(input == "2")
{
postfix();
}
else if(input == "3")
{
print();
}
else if(input == "4")
{
System.exit(0);
}
else
{
System.out.println("That is not a correct input, please re-enter.");
UserPrompt();
}
}
public String infix()
{
String outEquation = "";
LinkedStackClass<String> opSt = new LinkedStackClass<String>();
Scanner keyboard = new Scanner(System.in);
System.out.println("Please enter the infix equation: ");
while(keyboard.hasNext())
{
String str = keyboard.next();
if(!isOperator(str))
{
outEquation = outEquation + str + " ";
}
else if(str.equals("("))
{
opSt.push(str);
}
else if(str.equals(")"))
{
while(!opSt.peek().equals("("))
{
outEquation = outEquation + opSt.pop() + " ";
}
opSt.pop();
}
else
{
while(opSt.size() > 0 && precede(opSt.peek(), str))
{
if(!opSt.peek().equals("("))
{
outEquation = outEquation + opSt.pop() + " ";
}
else
{
opSt.pop();
}
}
if(!str.equals(")"))
{
opSt.push(str);
}
}
while(opSt.size() > 0)
{
outEquation = outEquation + opSt.pop() + " ";
}
}
}
private static int getExpOrder(String op)
{
switch(op)
{
case "+":
case "-":
case "*":
case "/":
return left;
case "^":
return right;
//default
}
}
private boolean precede(String l, String r)
{
return (getPrec(l) > getPrec(r) || (getPrec(l) == getPrec(r) && getExpOrder(l) == left));
}
private int getPrec(String op)
{
switch(op)
{
case "+":
case "-":
return ADD;
case "*":
case "/":
return MULT;
case "^":
return EXP;
case "(":
case ")":
return PAR;
}
}
public static boolean isOperator(String op)
{
return (op.length() == 1 && "+-*/()".indexOf(op.charAt(0)) != -1);
}
public String toString()
{
return outEquation;
}
public void postfix()
{
System.out.println("Postfix");
}
public void print()
{
System.out.println("Print");
}
}
public class LinkedStackClass<T> extends UnorderedLinkedList<T>
{
public LinkedStackClass()
{
super();
}
public void initializeStack()
{
initializeList();
}
public boolean isEmptyStack()
{
return isEmptyList();
}
public boolean isFullStack()
{
return false;
}
public void push(T newElement)
{
insertFirst(newElement);
} //end push
public T peek() throws StackUnderflowException
{
if (first == null)
throw new StackUnderflowException();
return front();
} //end peek
public void pop()throws StackUnderflowException
{
if (first == null)
throw new StackUnderflowException();
first = first.link;
count--;
if (first == null)
last = null;
}//end pop
}
Ok, so the reason are you getting that error message is because your pop() function has a void return. Typically, in a stack implementation, the pop operation will remove the top item of the stack and return it. Your function only removes the element.
So change your pop() function to look as follows (I apologize in advanced, as Java is not my forté, and this may not even be correct, so you may need to tweak this):
public T pop() throws StackUnderflowException
{
if (first == null)
throw new StackUnderflowException();
// Get the top-most element
T top = peek();
first = first.link;
count--;
if (first == null)
last = null;
return top;
} //end pop
However as user Ashley Frieze stated, better to use an existing implementation if possible, rather than roll your own.
So the task is to create our own parser for a expression calculator. For Example:
Input: 3+2*1-6/3
Output: 3
Input: 3++2
Output: Invalid Expression
Input: -5+2
Output: -3
Input: 5--2
Output: 7
The code here solves a part of the problem except that it has a fixed input and negative values cannot be solved, And I'm not quite sure yet if it really does solve the expression with operator precedence.
but I already modified it to get an input expression from the user.
and I've been wondering for hours how to implement the solving for negative values. help anyone?
NO JAVASCRIPT ENGINE PLEASE.
here's the current code
import java.util.*;
public class ExpressionParser
{
// Associativity constants for operators
private static final int LEFT_ASSOC = 0;
private static final int RIGHT_ASSOC = 1;
// Operators
private static final Map<String, int[]> OPERATORS = new HashMap<String, int[]>();
static
{
// Map<"token", []{precendence, associativity}>
OPERATORS.put("+", new int[] { 0, LEFT_ASSOC });
OPERATORS.put("-", new int[] { 0, LEFT_ASSOC });
OPERATORS.put("*", new int[] { 5, LEFT_ASSOC });
OPERATORS.put("/", new int[] { 5, LEFT_ASSOC });
}
// Test if token is an operator
private static boolean isOperator(String token)
{
return OPERATORS.containsKey(token);
}
// Test associativity of operator token
private static boolean isAssociative(String token, int type)
{
if (!isOperator(token))
{
throw new IllegalArgumentException("Invalid token: " + token);
}
if (OPERATORS.get(token)[1] == type) {
return true;
}
return false;
}
// Compare precedence of operators.
private static final int cmpPrecedence(String token1, String token2)
{
if (!isOperator(token1) || !isOperator(token2))
{
throw new IllegalArgumentException("Invalid tokens: " + token1
+ " " + token2);
}
return OPERATORS.get(token1)[0] - OPERATORS.get(token2)[0];
}
// Convert infix expression format into reverse Polish notation
public static String[] expToRPN(String[] inputTokens)
{
ArrayList<String> out = new ArrayList<String>();
Stack<String> stack = new Stack<String>();
// For each token
for (String token : inputTokens)
{
// If token is an operator
if (isOperator(token))
{
// While stack not empty AND stack top element
// is an operator
while (!stack.empty() && isOperator(stack.peek()))
{
if ((isAssociative(token, LEFT_ASSOC) &&
cmpPrecedence(token, stack.peek()) <= 0) ||
(isAssociative(token, RIGHT_ASSOC) &&
cmpPrecedence(token, stack.peek()) < 0))
{
out.add(stack.pop());
continue;
}
break;
}
// Push the new operator on the stack
stack.push(token);
}
// If token is a left bracket '('
else if (token.equals("("))
{
stack.push(token); //
}
// If token is a right bracket ')'
else if (token.equals(")"))
{
while (!stack.empty() && !stack.peek().equals("("))
{
out.add(stack.pop());
}
stack.pop();
}
// If token is a number
else
{
// if(!isOperator(stack.peek())){
// out.add(String.valueOf(token*10));
// }
out.add(token);
}
}
while (!stack.empty())
{
out.add(stack.pop());
}
String[] output = new String[out.size()];
return out.toArray(output);
}
public static double RPNtoDouble(String[] tokens)
{
Stack<String> stack = new Stack<String>();
// For each token
for (String token : tokens) //for each
{
// If the token is a value push it onto the stack
if (!isOperator(token))
{
stack.push(token);
}
else
{
// Token is an operator: pop top two entries
Double d2 = Double.valueOf( stack.pop() );
Double d1 = Double.valueOf( stack.pop() );
//Get the result
Double result = token.compareTo("*") == 0 ? d1 * d2 :
token.compareTo("/") == 0 ? d1 / d2 :
token.compareTo("+") == 0 ? d1 + d2 :
d1 - d2;
// Push result onto stack
stack.push( String.valueOf( result ));
}
}
return Double.valueOf(stack.pop());
}
public static void main(String[] args) throws Exception{
Scanner in = new Scanner(System.in);
String reg = "((?<=[<=|>=|==|\\+|\\*|\\-|<|>|/|=])|(?=[<=|>=|==|\\+|\\*|\\-|<|>|/|=]))";
while(true){
try{
System.out.println("Enter Your Expression");
//String[] input = "( 1 + 2 ) * ( 3 / 4 ) - ( 5 + 6 )".split(" ");
String[] input = in.nextLine() .split(reg);
String[] output = expToRPN(input);
// Build output RPN string minus the commas
System.out.print("Stack: ");
for (String token : output) {
System.out.print("[ ");System.out.print(token + " "); System.out.print("]");
}
System.out.println(" ");
// Feed the RPN string to RPNtoDouble to give result
Double result = RPNtoDouble( output );
System.out.println("Answer= " + result);
}catch (NumberFormatException | EmptyStackException nfe){
System.out.println("INVALID EXPRESSION"); }
}
}
}
UPDATED CODE:
Added: unaryToexp() function.
what I wanted to do was that everytime a " - " occurs, the code treats it as a binary by changing it to " _ " as another operator and this operator solves multiplies thing by -1 (what I wanted first was to add [-1] and [*] to the rpn stack). still got problems here.
compiler says:
Enter Your Expression
-5+3
Stack: [ ][ 5 ][ - ][ 3 ][ + ]
Exception in thread "main" java.lang.NumberFormatException: empty String
at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:10 11)
at java.lang.Double.valueOf(Double.java:504)
at ExpressionParser.RPNtoDouble(ExpressionParser.java:160)
at ExpressionParser.main(ExpressionParser.java:194)*
I think it has something to do with the Double d1 = Double.valueOf( stack.pop() ); cause it still pops another two values, where I only need one for a solving a unary operator. any help?
public class ExpressionParser
{
// Associativity constants for operators
private static final int LEFT_ASSOC = 0;
private static final int RIGHT_ASSOC = 1;
// Operators
private static final Map<String, int[]> OPERATORS = new HashMap<String, int[]>();
static
{
// Map<"token", []{precendence, associativity}>
OPERATORS.put("-", new int[] { 0, LEFT_ASSOC });
OPERATORS.put("+", new int[] { 0, LEFT_ASSOC });
OPERATORS.put("*", new int[] { 5, LEFT_ASSOC });
OPERATORS.put("/", new int[] { 5, LEFT_ASSOC });
OPERATORS.put("_", new int[] { 5, RIGHT_ASSOC });
}
// Test if token is an operator
private static boolean isOperator(String token)
{
return OPERATORS.containsKey(token);
}
// Test associativity of operator token
private static boolean isAssociative(String token, int type)
{
if (!isOperator(token))
{
throw new IllegalArgumentException("Invalid token: " + token);
}
if (OPERATORS.get(token)[1] == type) {
return true;
}
return false;
}
// Compare precedence of operators.
private static final int cmpPrecedence(String token1, String token2)
{
if (!isOperator(token1) || !isOperator(token2))
{
throw new IllegalArgumentException("Invalid tokens: " + token1
+ " " + token2);
}
return OPERATORS.get(token1)[0] - OPERATORS.get(token2)[0];
}
// CONVERT UNARY OPERATORS
public static String[] unaryToexp(String[] inputTokens)
{
ArrayList<String> out = new ArrayList<String>();
Stack<String> stack = new Stack<String>();
//if token is an unary minus
for (String token : inputTokens)
{
if( ((token == "-") && (isOperator(stack.peek()) || stack.empty() ))){ //
token = "_";
}
else if (token == "-"){
token = "-";
}
out.add(token);
while (!stack.empty())
{
out.add(stack.pop());
}
}
String[] output = new String[out.size()];
return out.toArray(output);
}
// Convert infix expression format into reverse Polish notation
public static String[] expToRPN(String[] inputTokens)
{
ArrayList<String> out = new ArrayList<String>();
Stack<String> stack = new Stack<String>();
// For each token
for (String token : inputTokens)
{
// If token is an operator
if (isOperator(token))
{
// While stack not empty AND stack top element
// is an operator
while (!stack.empty() && isOperator(stack.peek()))
{
if ((isAssociative(token, LEFT_ASSOC) &&
cmpPrecedence(token, stack.peek()) <= 0) ||
(isAssociative(token, RIGHT_ASSOC) &&
cmpPrecedence(token, stack.peek()) < 0))
{
out.add(stack.pop());
continue;
}
break;
}
// Push the new operator on the stack
stack.push(token);
}
// If token is a left bracket '('
else if (token.equals("("))
{
stack.push(token); //
}
// If token is a right bracket ')'
else if (token.equals(")"))
{
while (!stack.empty() && !stack.peek().equals("("))
{
out.add(stack.pop());
}
stack.pop();
}
// If token is a number
else
{
out.add(token);
}
}
while (!stack.empty())
{
out.add(stack.pop());
}
String[] output = new String[out.size()];
return out.toArray(output);
}
public static double RPNtoDouble(String[] tokens)
{
Stack<String> stack = new Stack<String>();
// For each token
for (String token : tokens)
{
// If the token is a value push it onto the stack
if (!isOperator(token))
{
stack.push(token);
}
else
{
// Token is an operator: pop top two entries
Double d2 = Double.valueOf( stack.pop() );
Double d1 = Double.valueOf( stack.pop() );
//Get the result
Double result = token.compareTo("_") == 0 ? d2 * -1 :
token.compareTo("*") == 0 ? d1 * d2 :
token.compareTo("/") == 0 ? d1 / d2 :
token.compareTo("+") == 0 ? d1 + d2 :
d1 - d2;
// Push result onto stack
stack.push( String.valueOf( result ));
}
}
return Double.valueOf(stack.pop());
}
public static void main(String[] args) throws Exception{
Scanner in = new Scanner(System.in);
String reg = "((?<=[<=|>=|==|\\+|\\*|\\-|\\_|<|>|/|=])|(?=[<=|>=|==|\\+|\\*|\\-|<|>|/|=]))";
while(true){
//try{
System.out.println("Enter Your Expression");
//String[] input = "( 1 + 2 ) * ( 3 / 4 ) - ( 5 + 6 )".split(" ");
String[] input = in.nextLine() .split(reg);
String[] unary = unaryToexp(input); //.split(reg);
String[] output = expToRPN(unary);
// Build output RPN string minus the commas
System.out.print("Stack: ");
for (String token : output) {
System.out.print("[ ");System.out.print(token); System.out.print(" ]");
}
System.out.println(" ");
// Feed the RPN string to RPNtoDouble to give result
Double result = RPNtoDouble( output );
System.out.println("Answer= " + result);
//}catch (){
//System.out.println("INVALID EXPRESSION"); }
}
}
}
Here you are:
private static final ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript");
public static String eval(String matlab_expression){
if(matlab_expression == null){
return "NULL";
}
String js_parsable_expression = matlab_expression
.replaceAll("\\((\\-?\\d+)\\)\\^(\\-?\\d+)", "(Math.pow($1,$2))")
.replaceAll("(\\d+)\\^(\\-?\\d+)", "Math.pow($1,$2)");
try{
return engine.eval(js_parsable_expression).toString();
}catch(javax.script.ScriptException e1){
return null; // Invalid Expression
}
}
Couldn't you use the javascript scripting engine? (you would need a bit of tweaking for the 5--2 expression) The code below outputs:
3+2*1-6/3 = 3.0
3++2 = Invalid Expression
-5+2 = -3.0
5--2 = 7.0
Code:
public class Test1 {
static ScriptEngine engine;
public static void main(String[] args) throws Exception {
engine = new ScriptEngineManager().getEngineByName("JavaScript");
printValue("3+2*1-6/3");
printValue("3++2");
printValue("-5+2");
printValue("5--2");
}
private static void printValue(String expression) {
String adjustedExpression = expression.replaceAll("--", "- -");
try {
System.out.println(expression + " = " + engine.eval(adjustedExpression));
} catch (ScriptException e) {
System.out.println(expression + " = Invalid Expression");
}
}
}
Rather than re-invent the wheel you could use a parser generator such as JavaCC or antlr, which is specifically designed for this kind of task. This is a nice example of a simple expression parser and evaluator in a couple of dozen lines of JavaCC.
Take a look at some examples and try to find a rule how to distinguish negative values from operators.
A rule like:
if (token is + or -) and next token is a number
and
(the previous token was empty
or the prvious token was ')' or another operator)
then it is a sign to the current value.
You could iterate through your original token list and create a new token list based on this rules.
I have just written such an expression evaluator and have an iterator for tokenizing expressions at hand. plan to publish it after some extensions on GitHub.
EDIT: Here is the iterator, the references and calls should be clear, it is a bit more complex because of support for variables/functions and multi-character operators:
private class Tokenizer implements Iterator<String> {
private int pos = 0;
private String input;
private String previousToken;
public Tokenizer(String input) {
this.input = input;
}
#Override
public boolean hasNext() {
return (pos < input.length());
}
private char peekNextChar() {
if (pos < (input.length() - 1)) {
return input.charAt(pos + 1);
} else {
return 0;
}
}
#Override
public String next() {
StringBuilder token = new StringBuilder();
if (pos >= input.length()) {
return previousToken = null;
}
char ch = input.charAt(pos);
while (Character.isWhitespace(ch) && pos < input.length()) {
ch = input.charAt(++pos);
}
if (Character.isDigit(ch)) {
while ((Character.isDigit(ch) || ch == decimalSeparator)
&& (pos < input.length())) {
token.append(input.charAt(pos++));
ch = pos == input.length() ? 0 : input.charAt(pos);
}
} else if (ch == minusSign
&& Character.isDigit(peekNextChar())
&& ("(".equals(previousToken) || ",".equals(previousToken)
|| previousToken == null || operators
.containsKey(previousToken))) {
token.append(minusSign);
pos++;
token.append(next());
} else if (Character.isLetter(ch)) {
while (Character.isLetter(ch) && (pos < input.length())) {
token.append(input.charAt(pos++));
ch = pos == input.length() ? 0 : input.charAt(pos);
}
} else if (ch == '(' || ch == ')' || ch == ',') {
token.append(ch);
pos++;
} else {
while (!Character.isLetter(ch) && !Character.isDigit(ch)
&& !Character.isWhitespace(ch) && ch != '('
&& ch != ')' && ch != ',' && (pos < input.length())) {
token.append(input.charAt(pos));
pos++;
ch = pos == input.length() ? 0 : input.charAt(pos);
if (ch == minusSign) {
break;
}
}
if (!operators.containsKey(token.toString())) {
throw new ExpressionException("Unknown operator '" + token
+ "' at position " + (pos - token.length() + 1));
}
}
return previousToken = token.toString();
}
#Override
public void remove() {
throw new ExpressionException("remove() not supported");
}
}
The following class is used by another program. When it is accessed, it throws a StackOverFlowError. This is part of a Postfix Calculator I have to do as a project at my university.
Any help would be greatly appreciated, thank you in advance. I'm quite new at Java and I have no idea what to do.
CODE:
import java.util.Queue;
import java.util.Stack;
public class MyPostfixMachine implements PostfixMachineInterface {
MyMathOperations mmo = new MyMathOperations();
MyPostfixMachine mpm = new MyPostfixMachine();
public String evaluate(Queue q) {
if (q.isEmpty()) {//if the input is empty, terminate the program
System.exit(0);
}
if (q.size() == 1) {//if there is only one number in the queue, return it as the solution
if (mpm.isParsableToDouble(String.valueOf(q.remove()))) {
return String.valueOf(q.remove());
}
}
Stack<String> finalxp = new Stack<String>();//create an empty stack
if (mpm.isParsableToDouble(String.valueOf(q.remove()))) {//if first element of queue q is a number,push it into the stack
finalxp.push(String.valueOf(q.remove()));
} else {//depending on the operator perform the corresponding operations
if (q.remove() == "+") {
String str = String.valueOf(finalxp.pop());
String str2 = String.valueOf(finalxp.pop());
finalxp.push(mmo.addition(str, str2));
}
if (q.remove() == "-") {
String str = String.valueOf(finalxp.pop());
String str2 = String.valueOf(finalxp.pop());
finalxp.push(mmo.substraction(str, str2));
}
if (q.remove() == "*") {
String str = String.valueOf(finalxp.pop());
String str2 = String.valueOf(finalxp.pop());
finalxp.push(mmo.product(str, str2));
}
if (q.remove() == "/") {
String str = String.valueOf(finalxp.pop());
String str2 = String.valueOf(finalxp.pop());
finalxp.push(mmo.division(str, str2));
}
if (q.remove() == "fibo") {
String str = String.valueOf(finalxp.pop());
finalxp.push(mmo.fibonacci(str));
}
if (q.remove() == "fac") {
String str = String.valueOf(finalxp.pop());
finalxp.push(mmo.factorial(str));
}
if (q.remove() == "han") {
String str = String.valueOf(finalxp.pop());
finalxp.push(mmo.hanoi(str));
}
}
return String.valueOf(finalxp.pop());
}
public boolean isParsableToDouble(String candidate) {
try {
Double.parseDouble(candidate);
return true;
} catch (NumberFormatException nfe) {
return false;
}
}
}
public class MyMathOperations implements MathOperationsInterface {
public String addition(String s1, String s2) {
double A = Double.parseDouble(s1);
double B = Double.parseDouble(s2);
return String.valueOf((A + B));
}
public String substraction(String s1, String s2) {
double A = Double.parseDouble(s1);
double B = Double.parseDouble(s2);
return String.valueOf((A - B));
}
public String product(String s1, String s2) {
double A = Double.parseDouble(s1);
double B = Double.parseDouble(s2);
return String.valueOf((A * B));
}
public String division(String s1, String s2) {
double A = Double.parseDouble(s1);
double B = Double.parseDouble(s2);
return String.valueOf((A / B));
}
public String fibonacci(String s) {
int n = Integer.parseInt(s);
return String.valueOf(fibo(n));
}
public int fibo(int f) {
if (f < 0) {
throw new IllegalArgumentException("Cannot apply Fibonacci method");
} else if (f == 0) {
return 0;
} else if (f == 1) {
return 1;
} else {
return fibo(f - 1) + fibo(f - 2);
}
}
public String hanoi(String s) {
int a = Integer.parseInt(s);
int han = 0;
if (a < 0) {
throw new IllegalArgumentException("Not a valid integer");
} else {
han = (int) Math.pow(2, a) - 1;
}
return String.valueOf(han);
}
public String factorial(String s) {
int a = Integer.parseInt(s);
if (a < 0) {
throw new IllegalArgumentException("Incorrect argument for factorial operatiion");
}
switch (a) {
case 0:
case 1:
return String.valueOf(1);
default:
int res = a;
while (true) {
if (a == 1) {
break;
}
res *= --a;
}
return String.valueOf(res);
}
}
private static double pDouble(String s) {
double res = 0d;
try {
res = Double.parseDouble(s);
} catch (NumberFormatException e) {
System.exit(1);
}
return res;
}
}
The problem is that your class MyPostfixMachine has a private field MyPostfixMachine mpm which is initialized with a new MyPostfixMachine. Since this new MyPostfixMachine also has a private field MyPostfixMachine mpm which is initialized with a new MyPostfixMachine... you get it. :) This goes on and on forever (or until your stack is full).
Here is the problematic piece of code:
public class MyPostfixMachine implements PostfixMachineInterface {
MyMathOperations mmo = new MyMathOperations();
MyPostfixMachine mpm = new MyPostfixMachine(); // problem is here
// ...
}
I think you can simply remove the private field mpm. Just call the methods on the current instance. So instead of:
if (mpm.isParsableToDouble(String.valueOf(q.remove()))) {...}
you can simply write:
if (isParsableToDouble(String.valueOf(q.remove()))) {...}
or (equivallent but more explicit):
if (this.isParsableToDouble(String.valueOf(q.remove()))) {...}
Anyway, just remove the private field mpm and the StackOverflowException should be gone.
I'm not sure how you're getting a StackOverflowError (I don't see any loops or recursion in this code), but one definite problem is your overuse of Queue.remove(). Every time you look at the queue in your if clauses, you're lopping-off the first element -- I'd expect this code to be barfing-out NoSuchElementExceptions.
To say nothing of all the EmptyStackExceptions you should be getting from popping from an empty Stack.
So I'd say....
Quit calling `remove()` when you should be calling `peek()` instead.
Quit popping from an empty stack; you want to be pulling those values from your input queue, yes?
The problem giving you your `StackOverFlowError` is elsewhere. (Unless I'm overlooking something -- always possible!) Look for a loop or a recursive call.