Antlr4 RPN Расчет; окончательный результат в стеке отсутствует

Отказ от ответственности: это для курсовой работы, и это также мой первый пост SO, так как обычно мои вопросы всегда задавались раньше.

После краткого ускоренного курса по antlr я сделал все возможное, чтобы выяснить, как лучше всего решить проблему создания калькулятора RPN, поддерживающего числовые, логические и реляционные операции. Принимаются только int и boolean.

Теперь, хотя мой код, вероятно, далеко не соответствует стандартному качеству antlr, все работает, кроме моего, когда мое правило «старт» совпадает. Я хочу, чтобы он распечатал результат из стека, но по какой-то причине стек всегда пуст после сопоставления.

например 2 3 + ; С моими операторами отладки печати я вижу, что все выталкивается, выталкивается, и результат 5 выталкивается, как и ожидалось. Но тогда стек становится пустым после завершающего ';' соответствует правилу «начало».

Я уверен, что здесь не хватает чего-то фундаментального, так как мы провели с antlr всего день в классе, но я не могу понять это. Мне не удалось найти отладчики для antlr4, которые позволили бы мне выполнять код по мере его выполнения, но я распечатывал входные данные, выталкивал элементы и нажимал элементы по мере того, как я продвигался вперед, и все кажется до «начала».

Ниже приведен пример моего кода только с операцией сложения и без логических входных данных:

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();};

person iantrich    schedule 12.11.2014    source источник
comment
Предпочтительно, чтобы вы разместили свой код здесь, на SO, чтобы, если у кого-то возникнет аналогичный вопрос позже, они могли увидеть, применим ли он. Кроме того, если вы можете, попробуйте опубликовать только наименьший объем кода, который по-прежнему вызывает ошибку, с которой вы столкнулись (сложно, но облегчает ответчикам).   -  person Jias    schedule 13.11.2014
comment
Спасибо за подсказки, я последовал вашим советам.   -  person iantrich    schedule 13.11.2014
comment
Я бы сделал действия парсера действиями лексера, добавив целочисленные правила парсера: INT ‹your action›; и использовать целочисленное правило в других правилах парсера.   -  person Onur    schedule 13.11.2014
comment
Я провел дальнейшую отладку и обнаружил, что по какой-то причине правило парсера обрабатывается раньше правил лексера. Я нашел это, инициализировав переменную до 0 и увеличив ее в операции, а затем напечатав ее в начале. При допустимой операции печатается 0, хотя вывод консоли выглядит так, как будто операция выполняется до запуска, это не так.   -  person iantrich    schedule 15.11.2014


Ответы (1)


Я решил свою проблему. Я до сих пор не совсем понимаю, почему, но кажется, что правила парсера запускаются до правил лексера. Поэтому я изменил свою программу так, чтобы мои правила синтаксического анализатора имели действия для ввода новых данных и выполнения операций.

Если кто-нибудь может помочь мне понять, почему это так, я был бы признателен. На мой взгляд, правила парсера состоят из других правил парсера и правил лексера. Правила лексера состоят из правил регулярных выражений. Поскольку лексер является наименьшим общим знаменателем, я предположил, что правило лексера будет вызываться первым, но, играя с antlr, я обнаружил, что это неверно.

person iantrich    schedule 14.11.2014