Antlr4 RPN Calc; final result on stack missing

224 views Asked by At

Disclaimer: This is for course work and this is also my first SO post as usually my questions have always been asked before

After a brief crash course on antlr I've done my best to figure out how best to tackle the problem of creating a RPN calculator that supports numerical, logical and relational operations. Only int and boolean are accepted.

Now, while my code is probably not nowhere near standard antlr quality, it is all working except for my when my 'start' rule matches. I want it to print out the result from the stack, but for some reason the stack is always empty after matching.

e.g. 2 3 + ; With my print debug statements I see that everything is pushed, popped and the result of 5 is pushed as expected. But the stack is then empty once the terminating ';' is matched for the 'start' rule.

I'm sure I'm missing something fundamental here, as we've only spent a day with antlr in class, but I cannot figure it out. I haven't had any luck finding debuggers for antlr4 that would allow me to step through the code as it runs, but did print out inputs, popped items and pushed items as I went along and everything seems until the 'start'

Below is a sample of my code with only the addition operation and no boolean inputs:

grammar RPN;    

@header {
    import java.util.Stack;
}

@members {
    Stack<String> s = new Stack<String>();
    int first;
    int second;

    int parseInteger(String value) {
        if(tryParseInt(value)) {
            System.out.println("Integer parsed from stack: " + value + "\n");
            return Integer.parseInt(value);
        } else {
            System.out.println("ERROR: Invalid integer value; Unable to parse\n");
            return 0;
        }
    }
    boolean tryParseInt(String value) {
        try {
            Integer.parseInt(value);
            return true;
        } catch(NumberFormatException nfe) {
            return false;
        }
}
    boolean stackCheck(Stack st, int size) {
        if(st.size() >= size) {
            return true;
        }
        else {
            System.out.println("ERROR: Operation needs " + Integer.toString(size) + " values\n");
            return false;
        }
    }
}

// PARSER RULES
start
    : ( expr+ ';')+ EOF
                {
                    if(stackCheck(s, 1)) {
                        System.out.println("Result: " + s.pop() + ';');
                    }
                    if(s.size() > 0) {
                        System.out.println("Too many operands supplied\n");
                    }
                };
expr
    : atom+ OPERATION;

atom
    : INT;

// LEXER RULES
INT         
    : [0-9]+    { s.push(getText()); };
OPERATION   
    : '+'       {
                    if(stackCheck(s, 2)) {
                        second = parseInteger(s.pop());
                        first = parseInteger(s.pop());
                        s.push(Integer.toString(first + second));
                    }
                };
WS          
    : ( ' ' | '\t' | '\r' | '\n' )+   {skip();};
1

There are 1 answers

0
iantrich On BEST ANSWER

I have solved my problem. I still don't have full understanding of why, but it seems that parser rules are ran before lexer rules. I therefore altered my program so that my parser rules were the ones to have the actions for pushing new input and performing operations.

If anyone can help me understand why this is, I would appreciate it. In my mind, parser rules are made up of other parser rules and lexer rules. Lexer rules are made up of regex rules. Being that lexer is the lowest common denominator, I assumed that the lexer rule would be invoked first, but in my playing with antlr found that to be false.