Инфикс к Postfix и унарным/бинарным операторам

У меня есть фрагмент кода, который преобразует инфиксное выражение в дерево выражений в памяти. Это прекрасно работает. Есть только одна маленькая неприятность. Я просто подключаюсь, разрабатываю, как правильно задействовать унарные операторы (правильные ассоциативные).

Со следующим инфиксным выражением:

+1 + +2 - -3 - -4

Я бы ожидал, что RPN:

1+2++3-4--

Тем не менее, ни один из онлайн-преобразователей инфикс-пост, который я могу найти, не обрабатывает этот пример так, как я ожидал. Есть ли у кого-нибудь четкое объяснение обработки правильных ассоциативных операторов, особенно бинарных, которые можно принять за унарные?

Редактировать/уточнить: я хотел бы знать, как обращаться с унарными операторами при переводе с инфикса на постфикс. То есть: распознавание одного и того же символа «-», например, как унарного вместо бинарного оператора и, следовательно, другого приоритета. Я бы подумал об использовании конечного автомата, возможно, с двумя состояниями, но...?


person Jaapjan    schedule 12.03.2010    source источник
comment
@Jaapjan: Непонятно, в чем твоя проблема. Разбирает ли он инфиксное выражение? Это преобразование дерева выражений в RPN?   -  person    schedule 12.03.2010
comment
Вы пропустили знак минус, должно быть 1+2++3--4--   -  person Andrei    schedule 09.08.2010


Ответы (2)


Ну, вам нужно определить, является ли данный оператор бинарным или унарным, на этапе анализа. Как только вы это сделаете, при создании RPN вы можете пометить операторы как принимающие 2 или 1 аргумент.

Вы можете попробовать использовать алгоритм Shunting Yard для анализа (и одновременного создания RPN). ), который также предназначен для работы с унарными операторами.

В любом случае, если все, что вам нужно, это унарный + или -, вы можете просто вставить 0 с квадратными скобками, когда увидите + или -, которые появляются «неожиданно».

Например

+1 + +2 - -3 - -4

Вы должны быть в состоянии пройти через него и преобразовать в

(0+1) + (0+2) - (0-3) - (0-4)

Теперь вам не нужно беспокоиться об унарных + или - и, вероятно, можно забыть о пометке операторов числом аргументов, которые они принимают.

person Community    schedule 13.03.2010
comment
Да, я реализовал алгоритм маневровой станции, но он, как вы говорите, требует, чтобы вы уже определили - и + как унарные +, - или бинарные варианты. В итоге я использовал измененный код синтаксического анализа, чтобы лучше решить, с чем я имею дело. Я не хочу изменять фактическое выражение, потому что мне нужно снова записать проанализированное выражение. Тем не менее, у меня есть некоторые проблемы с принятием решения о том, когда записывать унарные операторы в вывод RPN. Я еще раз посмотрю на алгоритм. - person Jaapjan; 16.03.2010
comment
@Jaapjan. Оценка RPN должна знать, сколько аргументов принимает оператор. Правильный способ сделать это - использовать грамматику, которая может определить, когда + является унарным, а когда двоичным и т. д. Кстати, почему это имеет значение, если вы включаете нули в записанное обратно выражение? Поскольку вы пометили это как самообучение, кажется, что это не имеет значения. - person ; 16.03.2010
comment
Это самообучение, потому что я пытаюсь научиться читать выражения в исходном коде с помощью программы. Если моя программа возвращает "очищенные" выражения, то я предпочитаю, чтобы в них не было лишних нулей. К сожалению, он также должен иметь дело с переменным количеством параметров для функций. Следовательно, пытаясь выяснить, как другие справляются с этой ситуацией. Я предполагаю, например, что -1--1 станет в этом случае 1 neg 1 neg минус. Но я не нахожу ясного способа справиться с вложенными выражениями с функциями переменной длины в них... ммм. - person Jaapjan; 17.03.2010
comment
@Jaapjan: В вики для алгоритма маневровой станции есть ссылка на оригинальную статью Дейкстры, которая, по-видимому, также имеет дело с функциями и параметрами. Конечно, вы можете сделать это, используя стандартные методы синтаксического анализа. Вы слышали о книге «Дракон»? Рекурсивный синтаксический анализ спуска может быть хорошим вариантом для изучения синтаксического анализа. - person ; 17.03.2010
comment
Я принял твой ответ. И да, он имеет дело с параметрами, но только тогда, когда количество параметров известно заранее. Раньше у меня был прототип, в котором вместо маневровой станции использовался рекурсивный приличный синтаксический анализ, но SY оказалось, по крайней мере, тогда, с ним было легче работать. У меня все еще есть некоторые мысли, и я буду изучать книгу драконов, чтобы получить некоторые внешние мысли от других людей. Я принял ваш ответ, спасибо за потраченное время. - person Jaapjan; 18.03.2010

может быть, этот хаотичный код C # поможет вам. унарный оператор имеет максимальный приоритет в арифметических операциях, поэтому приоритет для них будет выше. для идентификации унарного оператора я взял логическую переменную unary, которая будет установлена ​​в true после каждого токена оператора и в false после операнда. Вы должны использовать другое обозначение для унарного оператора плюс и минус, чтобы вы могли различать унарный и бинарный оператор в PFE. здесь «#» и «~» используются для обозначения унарного плюса и унарного минуса в постфиксном выражении (PFE).

вы можете обрабатывать все случаи, такие как 1+-1,1+(-1),1---1,1+--1, используя этот подход.

using System;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DSA
{
    class Calculator
    {
        string PFE;
        public Calculator()
        {
            Console.WriteLine("Intializing Calculator");
        }

        public double Calculate(string expression)
        {
            ConvertToPost(expression);
            return CalculatePOST();
        }

        public void ConvertToPost(string expression)
        {
            expression = "(" + expression + ")";

            var temp = new DSA.Stack<char>();
            string ch = string.Empty;
            bool unary = true;
            char a;
            foreach (var b in expression)
            {
                a = b;
                if (!a.IsOperator()) {
                    ch += a.ToString();
                    unary = false;
                }
                else
                {
                    if (ch!=string.Empty) 
                    PFE += ch+",";
                    ch = string.Empty;
                    if(a!='(' && a!=')')
                    {
                        if (unary == true)
                        {
                            if (a == '-') a = '~'; else if (a == '+') a = '#'; else throw new InvalidOperationException("invalid input string");
                        }
                        try
                        {
                            if (a.Precedence() <= temp.Peek().Precedence())
                            {
                                PFE += temp.Pop().ToString() + ",";
                            }
                          }
                        catch(InvalidOperationException e)
                        {

                        }

                            temp.Push(a);
                            unary = true;
                    }
                    if (a == '(') { temp.Push(a);}
                    if(a==')')
                    {
                       for(char t=temp.Pop();t!='(';t=temp.Pop())
                        {
                            PFE += t.ToString() + ","; 
                        }
                    }
                }

            }

        }

        public double CalculatePOST()
        {
            var eval = new Stack<double>();
            string ch = string.Empty;
            bool skip = false;
            foreach(char c in PFE)
            {
                if(!c.IsOperator())
                {
                    if (c == ',')
                    {
                        if (skip == true)

                        {
                            skip = false;
                            continue;
                        }
                        eval.Push(Double.Parse(ch));
                        ch = string.Empty;
                    }
                    else ch += c;
                }
                else
                {
                    if (c == '~')
                    {
                        var op1 = eval.Pop();
                        eval.Push(-op1);
                    }
                    else if (c == '#') ;
                    else
                    {
                        var op2 = eval.Pop();
                        var op1 = eval.Pop();
                        eval.Push(Calc(op1, op2, c));
                    }
                    skip = true;
                }
              }
            return eval.Pop();
        }

        private double Calc(double op1, double op2, char c)
        {   
           switch(c)
            {

                case '+':
                    return op1 + op2;
                case '-':
                    return op1 - op2;
                case '*':
                    return op1 * op2;
                case '%':
                    return op1 % op2;
                case '/':
                    return op1 / op2;
                case '^':
                    return float.Parse(Math.Pow(op1,op2).ToString());
                default:
                    throw new InvalidOperationException();
            }
        }
    }


    public static class extension
    {
        public static bool IsOperator(this char a)
        {
            char[] op = {'+','-','/','*','(',')','^','!','%','~','#'};
             return op.Contains(a);
        }

        public static int Precedence(this char a)
        {
            if (a == '~' || a== '#')
                return 1;
            if (a == '^')
                return 0;
            if (a == '*' || a == '/' || a=='%')
                return -1;
            if (a == '+' || a == '-')
                return -2;
            return -3;       
        }       
    }
}
person Dhairya Bhardwaj    schedule 21.12.2016
comment
Можете ли вы объяснить свой код, чтобы другие могли учиться на нем? Stackoverflow — это не сброс кода, который другие могут просто скопировать и вставить, а изучение и понимание того, как все работает. - person Robert; 21.12.2016
comment
@ Роберт, я плохо объясняю. Некоторые изменения внесены с учетом вашего комментария, но можете ли вы предложить какое-то улучшение в приведенном выше объяснении? Благодарю. - person Dhairya Bhardwaj; 22.12.2016