0

I am implementing the shunting yard algorithm and I am having trouble handling parenthesis. It works fine with non grouped expressions though. Here's what I have without Parenthesis detection:

public void makePost(String e)
{
    String[] arr = e.split("");
    for(int i = 0; i < arr.length; i++)
    {
        if(arr[i].equals(" "))
        {
            continue;
        }
        Operator o = OperatorList.getOpMap().get(arr[i]);
        if(o == null){
            postfix += " " + arr[i];
            continue;
        }
        if(ops.isEmpty()){
            ops.push(o);
            continue;
        }
        else
        {

            while((!ops.isEmpty()  && (ops.peek().getPresedence() <= o.getPresedence()))){
                postfix += " " + ops.pop();
            }
            ops.push(o);
            continue;
        }

    }
    while(!ops.isEmpty())
    {
        postfix += " " + ops.pop();
    }
    postfix = postfix.trim();

}

ops is the stack that holds Operator objects. There are two types of operators, functions(+,-,* etc) and Parans ("(","["). How would you add parenthesis handling to this? Each time I try, I can't seem to get it to work properly

Here is what I tried:

    public void makePost(String e)
{
    String[] arr = e.split("");
    for(int i = 0; i < arr.length; i++){
        if(arr[i].equals(" ")){
            continue;
        }
        Operator o = OperatorList.getOpMap().get(arr[i]);
        if(o == null){
            postfix += " " + arr[i];
            continue;
        }
        if(ops.isEmpty()){
            ops.push(o);
            continue;
        }
        else
        {
            if(o.isParan())
            {
                Paran p = new Paran(o.toString());
                if(p.isOpen())
                {
                ops.push(o);
                System.out.println(ops);
                continue;
                }else{      
                    while(!ops.isEmpty()){ 
                        if(ops.peek().isParan()){
                            Paran n = new Paran(o.toString());
                            if(n.isOpen()){
                                ops.pop();
                                break;
                            }
                        }
                        postfix += " " + ops.pop();
                    }
                    continue;
                }
            }
            while((!ops.isEmpty()  && (ops.peek().getPresedence() <= o.getPresedence()))){
                postfix += " " + ops.pop();
            }
            ops.push(o);
            continue;
        }

    }
    while(!ops.isEmpty())
    {
        postfix += " " + ops.pop();
    }
    postfix = postfix.trim();

}

I suspect the while loop condition is bad, but I don't know of any proper replacement. It goes on to infinity. This was the cleanest implementation I had. Basically what it is supposed to do is when it encounters an open parenthesis, push it onto the stack. When it hits a closed one, pop everything off the stack onto the output until it hits the open parenthesis. Then it should break, and continue to the next token.

if(o.isParan())
            {
                Paran p = new Paran(o.toString());
                if(p.isOpen())
                {
                ops.push(o);
                System.out.println(ops);
                continue;
                }else{      
                    while(!ops.isEmpty()){ 
                        if(ops.peek().isParan()){
                            Paran n = new Paran(o.toString());
                            if(n.isOpen()){
                                ops.pop();
                                break;
                            }
                        }
                        postfix += " " + ops.pop();
                    }
                    continue;
                }

EDIT: added my attempt

RN_
  • 878
  • 2
  • 11
  • 30
  • This isn't homework, But I can add my attempts – RN_ Jan 04 '14 at 23:49
  • 1
    I think it would add credibility to the question to show something of what you tried that didn't work - yes, please. You also might want to puruse the many many other StackOverflow questions about Shunting Yard :). Right now, on the top of the list to my right, is a question about preserving parens in Shunting Yard ;) – GreenAsJade Jan 04 '14 at 23:50
  • 1
    I'll be sure to check those out :) – RN_ Jan 04 '14 at 23:58
  • 1
    not sure if you've already seen this, but it might help: http://en.wikipedia.org/wiki/Shunting-yard_algorithm – user2570465 Jan 05 '14 at 00:07
  • I used that article to write this, but thanks anyway:) – RN_ Jan 05 '14 at 00:09
  • The next thing I'd be doing is instrumenting the while loop. Heck, while you're at it, instrument the whole thing. I suspect that a trace of what is going on will give you the answer you need. Each time around the while look, print out what is ops.peek and ops.peek.getPrecedence. Print postfix each time around. Should quickly tell you what's going wrong... – GreenAsJade Jan 05 '14 at 00:14
  • is there a specific reason why you have 2 types of parentheses? i think you can accomplish the same order of operations using just the standard "(" for all your parentheses, and it'll simply the handling of parentheses. (e.g. is there something "1-[(3+4)*5]" can do that "1-((3+4)*5)" can't accomplish? – user2570465 Jan 05 '14 at 00:17
  • which loop "goes on to infinity?" it doesn't look like any of your loops could be infinite. can you use print statements and confirm which loops never terminates? (also, are you using your own stack, or are you using Java's built-in stack?) – user2570465 Jan 05 '14 at 00:29
  • @user2570465 the first while(!ops.isEmpty()) loop, The type of parenthesis doesn't really matter, no. I added it incase the user preferred them. I am using this code for an app I am making. – RN_ Jan 05 '14 at 00:35
  • which statements keep executing? the if-statement or the `postfix += " " + ops.pop()` statement? or both? – user2570465 Jan 05 '14 at 00:37
  • @user2570465 No statement, it keeps running because the stack is full and it returns false for the if statement. It never gets to the postfix statement – RN_ Jan 05 '14 at 00:59
  • You didn't yet answer the question"why don't you just print out what is happening at each point?"... – GreenAsJade Jan 05 '14 at 01:08
  • 1
    @GreenAsJade I spent some time debugging with the print statements, and I found my bug. My code is popping off the parenthesis because it has the highest precedence and it's on the top of the stack. I think I will either add a new conditional to my while loop or use some sort of recursion. I will try it out and see what happens, and hopefully might be able to solve my problem – RN_ Jan 05 '14 at 01:36
  • The word is 'precedence', not 'presedence'. – user207421 Feb 27 '17 at 00:19

1 Answers1

0

Got it to work! I added a few checks for parenthesis in logical areas, Here is the final:

    public void makePost(String e)
{
    String[] arr = e.split("");
    for(int i = 0; i < arr.length; i++)
    {

        System.out.println(postfix + " " + i + " " + ops);
        if(arr[i].equals(" "))
        {
            continue;
        }
        if(arr[i].equals("(")){
            ops.push(new Paran("("));
            continue;
        }
        if(!ops.isEmpty() && arr[i].equals(")")){
            while(!ops.isEmpty() && !ops.peek().isOpen()){

                postfix += " " + ops.pop();
            }
            ops.pop();
        }
        Operator o = OperatorList.getOpMap().get(arr[i]);
        if(o == null){
            postfix += " " + arr[i];
            continue;
        }
        if(ops.isEmpty()){

            ops.push(o);

            continue;
        }
        else
        {

            while((!ops.isEmpty()  && (ops.peek().getPresedence() <= o.getPresedence()) && !(ops.peek() instanceof Paran))){

                postfix += " " + ops.pop();
            }
            ops.push(o);
            continue;

        }

    }

    while(!ops.isEmpty())
    {

        postfix += " " + ops.pop();
    }

   postfix = postfix.replaceAll("\\s[)]","");


}

I have the replaceall() call because the output kept return closing parenthesis along with the corrent postfix, ex:

2 4 * 7 8 4 * 4 4 5 * ) / ) * ) +

I have no idea why it does that, but I am glad it works

RN_
  • 878
  • 2
  • 11
  • 30