Обратная польская запись: примеры реализации

Материал из Викиверситет
Перейти к: навигация, поиск

Примеры реализации[править]

Forth[править]

3 2 1 + *

Haskell[править]

calc :: String -> [Float]
calc = foldl f [] . words
  where 
    f (x:y:zs) "+" = (y + x):zs
    f (x:y:zs) "-" = (y - x):zs
    f (x:y:zs) "*" = (y * x):zs
    f (x:y:zs) "/" = (y / x):zs
    f xs y         = read y : xs

Erlang[править]

-module(calc).
-export([expr/1]).
expr(L) ->
    [Result] = lists:foldl(fun expr/2, [], string:tokens(L, " ")),
    Result.

expr("+", [A, B | T]) -> [A + B | T];
expr("-", [A, B | T]) -> [A - B | T];
expr("*", [A, B | T]) -> [A * B | T];
expr("/", [A, B | T]) -> [A / B | T];
expr(N, T) -> [read(N) | T].

read(N) ->
    case string:to_float(N) of
	{error, no_float} -> list_to_integer(N);
	{F, _} -> F
    end.

C[править]

/* Компиля:
 *   gcc -o rpn rpn.c
 *
 * Использование:
 *   ./rpn <выражение>
 * 
 * Пример:
 *   ./rpn 3 5 +
 *
 * Замечание: знак умножения `*' заменен на `x', т.к. символ `*' используется
 * командной оболочкой.
 **/

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>

#define STKDPTH 32 /* Глубина стека */

/* Значения, возвращаемые функцией parse */
#define VAL  0  /* В стек занесено новое значение */
#define ADD  1  /* Сложение */
#define SUB  2  /* Вычитание */
#define MUL  3  /* Умножение */
#define DIV  4  /* Деление */
#define SOF -1  /* Переполнение стека */
#define SUF -2  /* В стеке недостаточно операндов */
#define UNK -3  /* Неопознанное значение */

/* Глобальные переменные */
int scount;
double stack[STKDPTH];

/* Функция распознавания аргументов */
int parse(char *);

/* Точка входа */
int main(int argc, char **argv)
{
    /* Организуем цикл для перебора аргументов командной строки */
    while (*++argv) {

        /* Пытаемся распознать текущий аргумент как число или
         * символ арифметической операции */
        switch (parse(*argv)) {
            case VAL: continue;

            /* Вычисляем */
            case ADD:
                stack[scount - 1] += stack[scount];
                break;

            case SUB:
                stack[scount - 1] -= stack[scount];
                break;

            case MUL:
                stack[scount - 1] *= stack[scount];
                break;

            case DIV:
                if (stack[scount] != 0) {
                    stack[scount - 1] /= stack[scount];
                    break;
                } else {
                    fprintf(stderr, "Деление на ноль!\n");
                    return(1);
                }

            /* Обработка ошибок */
            case SUF:
                fprintf(stderr, "Недостаточно операндов!\n");
                return(1);

            case SOF:
                fprintf(stderr, "Переполнение стека!\n");
                return(1);

            case UNK:
                fprintf(stderr, "Неопознанный аргумент!\n");
                return(1);
        }
    }

    /* Вывести результат */
    auto int i;
    for (i = 0; i < scount; i++) printf("%0.3f\n", stack[i]);

    return(0);
}

int parse(char *s)
{
    double tval = 0;
    char * endptr;

    /* Распознаем знаки арифметических операций */
    switch (*s) {
        case '-':
            /* Если минус является первым и не последним символом аргумента,
             * значит пользователь ввел отрицательное число и опознавать его
             * как операцию вычитания не нужно */
            if (*(s+1) != '\0') break;
            if (scount >= 2) {
                scount -= 1;
                return(SUB);
            }
            else return(SUF);

        case '+':
            if (scount >= 2) {
                scount -= 1;
                return(ADD);
            }
            else return(SUF);

        case 'x':
            if (scount >= 2) {
                scount -= 1;
                return(MUL);
            }
            else return(SUF);

        case '/':
            if (scount >= 2) {
                scount -= 1;
                return(DIV);
            }
            else return(SUF);
    }

    errno = 0;

    /* Пытаемся сконвертировать строковый аргумент в число */
    tval = strtod(s, &endptr);

    /* Вернуть ошибку `неопознанный аргумент' в случае неудачи */
    if (errno != 0 || *endptr != '\0') return(UNK);

    /* Проверяем, есть ли свободное место в стеке
     * и сохраняем в нем операнд, иначе возвращаем ошибку переполнения */
    if (scount < STKDPTH) stack[scount++] = tval;
    else return(SOF);

    return(VAL);
}

Delphi[править]

program calc;
{$APPTYPE console}

type
  Real = double;

const
  prs = '+-*/(';
  pri: array [1 .. 5] of byte = (1, 1, 2, 2, 0);

var
  s1, s2: String;
  q: array [0 .. 500] of Real;
  w: array [0 .. 500] of Char;
  n, len, len2: Cardinal;
  t: Real;
  ch: Char;

procedure Push(x: Real);
begin
  Inc(len);
  q[len] := x;
end;

function Pop: Real;
begin
  Pop := q[len];
  q[len] := 0;
  Dec(len);
end;

procedure PushC(x: Char);
begin
  Inc(len2);
  w[len2] := x;
end;

function Popc: Char;
begin
  Popc := w[len2];
  w[len2] := #0;
  Dec(len2);
end;

function Oper(s1, s2: Real; s3: Char): Real;
var
  x, y, z: Real;
begin
  x := s1;
  y := s2;
  case s3 of
    '+': z := x + y;
    '-': z := x - y;
    '*': z := x * y;
    '/': z := x / y;
  end;
  Oper := z;
end;

procedure PreChange(var s: String);
var
  i: Cardinal;
begin
  if s[1] = '-' then
    s := '0' + s;
  i := 1;
  while i <= n do
    if (s[i] = '(') and (s[i + 1] = '-') then
      insert('0', s, i + 1)
    else
      Inc(i);
end;

function Change(s: String): String;
var
  i: Cardinal;
  rezs: String;
  c: Boolean;
begin
  c := false;
  for i := 1 to n do
    begin
      if not(s[i] in ['+', '-', '*', '/', '(', ')']) then
        begin
          if c then
            rezs := rezs + ' ';
          rezs := rezs + s[i];
          c := false;
        end
      else
        begin
          c := true;
          if s[i] = '(' then
            PushC(s[i])
          else
            if s[i] = ')' then
              begin
                while w[len2] <> '(' do
                  begin
                    rezs := rezs + ' ' + Popc;
                  end;
                Popc;
              end
            else
              if s[i] in ['+', '-', '*', '/'] then
                begin
                  while pri[Pos(w[len2], prs)] >= pri[Pos(s[i], prs)] do
                    rezs := rezs + ' ' + Popc;
                  PushC(s[i]);
                end;
        end;
    end;
  while len2 <> 0 do
    rezs := rezs + ' ' + Popc;
  Change := rezs;
end;

function Count(s: String): Real;
var
  ss: String;
  x, s1, s2: Real;
  chh, s3: Char;
  p, i, j: Cardinal;
  tmp: Integer;
begin
  i := 0;
  repeat
    j := i + 1;
    repeat
      Inc(i)
    until s[i] = ' ';
    ss := copy(s, j, i - j);
    chh := ss[1];
    if not(chh in ['+', '-', '*', '/']) then
      begin
        Val(ss, p, tmp);
        Push(p);
      end
    else
      begin
        s2 := Pop;
        s1 := Pop;
        s3 := chh;
        Push(Oper(s1, s2, s3));
      end;
  until i >= n;
  x := Pop;
  Count := x;
end;

procedure WriteL(x: Real);
var
  y, a, b: Cardinal;
  q: Real;
begin
  y := Trunc(x);
  b := 0;
  if Abs(x - y) < (1E-12) then
    Writeln(y)
  else
    begin
      if y > 0 then
        a := round(ln(y) / ln(10)) + 1
      else
        a := 1;
      q := x;
      repeat
        q := q * 10;
        Inc(b);
      until Abs(q - Trunc(q)) < (1E-12);
      Writeln(x:a + b:b);
    end;
end;

begin
  repeat
    Writeln('Enter expression');
    Readln(s1);
    n := Length(s1);
    PreChange(s1);
    n := Length(s1);
    s2 := Change(s1);
    if s2[1] = ' ' then
      delete(s2, 1, 1);
    s2 := s2 + ' ';
    n := Length(s2);
    t := Count(s2);
    WriteL(t);
    Writeln('One more expression?(Y/N)');
    Readln(ch);
  until UpCase(ch) = 'N';

end.

Глагол[править]

ОТДЕЛ ОПН;
    ПЕР
        Стек: РЯД 20H ИЗ ЗНАК;

    ЗАДАЧА Преимущество(зн: ЗНАК): ЦЕЛ;
    УКАЗ
        ВЫБРАТЬ зн ИЗ
                '*', '/': ВОЗВРАТ 3
                | '-', '+': ВОЗВРАТ 2
                | '(', ')': ВОЗВРАТ 1
        ИНАЧЕ
                ВОЗВРАТ 0
        КОН
    КОН Преимущество;
    
    ЗАДАЧА Добавить(зн: ЗНАК);
    УКАЗ
        ЕСЛИ ДЛИНА(Стек) = РАЗМЕР(Стек) ТО
        	Вывод.Цепь("Ошибка: стек переполнен.");
        	СТОП(0)
        КОН;
        Стек[ДЛИНА(Стек)] := зн
    КОН Добавить;
    
    ЗАДАЧА Удалить(): ЗНАК;
    ПЕР
        зн: ЗНАК;
    УКАЗ
        ЕСЛИ ДЛИНА(Стек) = 0 ТО
                Вывод.Цепь("Ошибка: стек пуст.");
                СТОП(0)
        КОН;
        зн := Стек[ДЛИНА(Стек)-1];
        Стек[ДЛИНА(Стек)-1] := 0X;
        ВОЗВРАТ зн
    КОН Удалить;
    
    ЗАДАЧА Перевести(вход-, выход+: РЯД ИЗ ЗНАК);
    ПЕР
        сч1, сч2: УЗКЦЕЛ;
        зн: ЗНАК;
    УКАЗ
        зн := 0X; сч2 := 0;
        ОТ сч1 := 0 ДО ДЛИНА(вход)-1 ВЫП
            ЕСЛИ вход[сч1] = ")" ТО
                ПОКА Стек[ДЛИНА(Стек)-1] # "(" ВЫП
                    выход[сч2] := Удалить();
                    УВЕЛИЧИТЬ(сч2)
                КОН;
                зн := Удалить()
            АЕСЛИ вход[сч1] = "(" ТО
                Добавить(вход[сч1])
            АЕСЛИ (вход[сч1] = "+") ИЛИ (вход[сч1] = "-") ИЛИ (вход[сч1] = "/") ИЛИ (вход[сч1] = "*") ТО
                ЕСЛИ ДЛИНА(Стек) = 0 ТО Добавить(вход[сч1]) ИНАЧЕ
                    ЕСЛИ Преимущество(вход[сч1]) > Преимущество(Стек[ДЛИНА(Стек)-1]) ТО
                        Добавить(вход[сч1])
                    ИНАЧЕ
                        ПОКА (ДЛИНА(Стек) # 0) И (Преимущество(вход[сч1]) <= Преимущество(Стек[ДЛИНА(Стек)-1])) ВЫП
                            выход[сч2] := Удалить(); УВЕЛИЧИТЬ(сч2)
                        КОН;
                        Добавить(вход[сч1])
                    КОН
                КОН
            АЕСЛИ Знак.Буква(вход[сч1]) ТО
                выход[сч2] := вход[сч1];
                УВЕЛИЧИТЬ(сч2)
            КОН
        КОН;
        ПОКА ДЛИНА(Стек) # 0 ВЫП
            выход[сч2] := Удалить();
            УВЕЛИЧИТЬ(сч2)
        КОН
    КОН Перевести;
КОН ОПН.

PHP[править]

Приведение инфиксной записи к постфиксной (ОПЗ)[править]

$str = "(5+3)*2"; //выражение в инфиксе
echo rpn($str); //выведет 5 3 + 2 * Этот результат можно использовать в функции calc (см. ниже подзаголовок "Вычисление результата выражения в ОПЗ")

function rpn($str)
{
	$stack=array(); //объявляем массив стека
	$out=array(); //объявляем массив выходной строки
	
	$prior = array ( //задаем приоритет операторов, а также их ассоциативность
			"^"=> array("prior" => "4", "assoc" => "right"),
			"*"=> array("prior" => "3", "assoc" => "left"),
			"/"=> array("prior" => "3", "assoc" => "left"),
			"+"=> array("prior" => "2", "assoc" => "left"),
			"-"=> array("prior" => "2", "assoc" => "left"),
	);
	
	$token=preg_replace("/\s/", "", $str); //удалим все пробелы
	$token=str_replace(",", ".", $token);//поменяем запятые на точки
	$token = str_split($token);
	/*проверим, не является ли первый символ знаком операции - тогда допишем 0 перед ним */
	
	if (preg_match("/[\+\-\*\/\^]/",$token['0'])){array_unshift($token, "0");}
	
	$lastnum = TRUE; //в выражении теперь точно первым будет идти число - поставим маркер
	foreach ($token as $key=>$value)
	{
	
		if (preg_match("/[\+\-\*\/\^]/",$value))//если встретили оператор
			{
				$endop = FALSE; //маркер конца цикла разбора операторов
				
				while ($endop != TRUE)
				{
					$lastop = array_pop($stack);
					if ($lastop=="")
					{
						$stack[]=$value; //если в стеке нет операторов - просто записываем текущий оператор в стек
						$endop = TRUE; //укажем, что цикл разбора while закончился
					}
					
					else //если в стеке есть операторы - то последний сейчас в переменной $lastop
					{
						/* получим приоритет и ассоциативность текущего оператора и сравним его с $lastop */
						$curr_prior = $prior[$value]['prior']; //приоритет текущиего оператора
						$curr_assoc = $prior[$value]['assoc']; //ассоциативность текущиего оператора
						
						$prev_prior = $prior[$lastop]['prior']; //приоритет предыдущего оператора
						
						switch ($curr_assoc) //проверяем текущую ассоциативность
						{
							case "left": //оператор - лево-ассоциативный
								
								switch ($curr_prior) //проверяем текущий приоритет лево-ассоциаивного оператора
								{
									case ($curr_prior > $prev_prior): //если приоритет текущего опертора больше предыдущего, то записываем в стек предыдущий, потом текйщий
										$stack[]=$lastop;
										$stack[]=$value;
										$endop = TRUE; //укажем, что цикл разбора операторов while закончился
										break;
									
									case ($curr_prior <= $prev_prior): //если тек. приоритет меньше или равен пред. - выталкиваем пред. в строку out[]
										$out[] = $lastop;
										break;
								}
								
							break;
							
							case "right": //оператор - право-ассоциативный
								
								switch ($curr_prior) //проверяем текущий приоритет право-ассоциативного оператора
								{
									case ($curr_prior >= $prev_prior): //если приоритет текущего опертора больше или равен предыдущего, то записываем в стек предыдущий, потом текйщий
										$stack[]=$lastop;
										$stack[]=$value;
										$endop = TRUE; //укажем, что цикл разбора операторов while закончился
										break;
									
									case ($curr_prior < $prev_prior): //если тек. приоритет меньше пред. - выталкиваем пред. в строку out[]
										$out[] = $lastop;
										break;
								}		
								
							break;
						
						}
					
					}
				} //while ($endop != TRUE)
				$lastnum = false; //укажем, что последний разобранный символ - не цифра
			}
		
		elseif (preg_match("/[0-9\.]/",$value)) //встретили цифру или точку
			{
		/*Мы встретили цифру или точку (дробное число). Надо понять, какой символ был разобран перед ней. 
		За это отвечает переменная $lastnum - если она TRUE, то последней была цифра.
		В этом случае надо дописать текущую цифру к последнему элменту массива выходной строки*/
				if ($lastnum == TRUE) //последний разобранный символ - цифра
					{
						$num = array_pop($out); //извлечем содержимое последнего элемента массива строки
						$out[]=$num.$value;
					}
				
				else 
					{
						$out[] = $value; //если последним был знак операции - то открываем новый элемент массива строки
						$lastnum = TRUE; //и указываем, что последним была цифра
					}
			}
		 
		elseif ($value=="(") //встреили скобку ОТкрывающую
			{
		/*Мы встретили ОТкрывающую скобку - надо просто поместить ее в стек*/
						$stack[] = $value; 
						$lastnum = FALSE; // указываем, что последним была НЕ цифра
			}
			
		elseif ($value==")") //встреили скобку ЗАкрывающую
			{
		/*Мы встретили ЗАкрывающую скобку - теперь выталкиваем с вершины стека в строку все операторы, пока не встретим ОТкрывающую скобку*/
						$skobka = FALSE; //маркер нахождения открывающей скобки
						while ($skobka != TRUE) //пока не найдем в стеке ОТкрывающую скобку
						{
							$op = array_pop($stack); //берем оператора с вершины стека
							
								if ($op == "(") 
								{
									$skobka = TRUE; //если встретили открывающую - меняем маркер
								} 
								
								else
								{
									$out[] = $op; //если это не скобка - отправляем символ в строку
								}
							
								
						}
						
						$lastnum = FALSE; //указываем, что последним была НЕ цифра
			}	
	
	}
	/*foreach закончился - мы разобрали все выражение
	теперь вытолкнем все оставшиеся элементы стека в выходную строку, начиная с вершины стека*/

	$stack1 = $stack; //временный массив, копия стека, на случай, если будет нужен сам стек для дебага
	$rpn = $out; //начинаем формировать итоговую строку
	
	while ($stack_el = array_pop($stack1))
	{
		$rpn[]=$stack_el;
	}
	
	$rpn_str = implode(" ", $rpn); //запишем итоговый массив в строку
	return $rpn_str; //функция возвращает строку, в которой исходное выражение представлено в ОПЗ
	
	/* это для дебага
	echo "<pre>";
	print_r($rpn);
	print_r($out);
	print_r($stack);
	echo "</pre>";
	*/

Вычисление результата выражения в ОПЗ[править]

$expr = '3 4 5 * + 7 + 4 6 - /';

echo calc($expr);

function calc($str)
{
	$stack = array();
	
	$token = strtok($str, ' ');
	
	while ($token !== false)
	{
		if (in_array($token, array('*', '/', '+', '-', '^')))
		{
			if (count($stack) < 2)
				throw new Exception("Недостаточно данных в стеке для операции '$token'");
			$b = array_pop($stack);
			$a = array_pop($stack);
			switch ($token)
			{
				case '*': $res = $a*$b; break;
				case '/': $res = $a/$b; break;
				case '+': $res = $a+$b; break;
				case '-': $res = $a-$b; break;
				case '^': $res = pow($a,$b); break;

			}
			array_push($stack, $res);
		} elseif (is_numeric($token))
		{
			array_push($stack, $token);
		} else
		{
			throw new Exception("Недопустимый символ в выражении: $token");
		}

		$token = strtok(' ');
	}
	if (count($stack) > 1)
		throw new Exception("Количество операторов не соответствует количеству операндов");
	return array_pop($stack);
}

C#[править]

Функция toRPN работает некорректно. Можно проверить на формуле 3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3 Должно быть: 3 4 2 * 1 5 − 2 3 ^ ^ / + Функция отдает: 3 4 2 * 1 5 - 2 ^ 3 ^ / +. Да нет, как раз результат 3 4 2 * 1 5 - 2 ^ 3 ^ / + является верным
Некорректно работает для Input = "5"

//  Преобразование инфиксной записи к постфиксной
//      i.dudinov@gmail.com
//  Добавлена функция result для вывода результата
// kiss_a@bk.ru
using System;
using System.Collections.Generic;
using System.Windows.Forms;
namespace PostfixNotation
{
    public class PostfixNotationExpression
    {
        public PostfixNotationExpression()
        {
            operators = new List<string>(standart_operators);
            
        }
        private List<string> operators;
        private List<string> standart_operators =
            new List<string>(new string[] { "(", ")", "+", "-", "*", "/", "^" });

        private IEnumerable<string> Separate(string input)
        {            
            int pos = 0;
            while (pos < input.Length)
            {
                string s = string.Empty + input[pos];
                if (!standart_operators.Contains(input[pos].ToString()))
                {
                    if (Char.IsDigit(input[pos]))
                        for (int i = pos + 1; i < input.Length &&
                            (Char.IsDigit(input[i]) || input[i] == ',' || input[i] == '.'); i++)
                            s += input[i];
                    else if (Char.IsLetter(input[pos]))
                        for (int i = pos + 1; i < input.Length &&
                            (Char.IsLetter(input[i]) || Char.IsDigit(input[i])); i++)
                            s += input[i];
                }
                yield return s;
                pos += s.Length;
            }
        }
        private byte GetPriority(string s)
        {
            switch (s)
            {
                case "(":
                case ")":
                    return 0;
                case "+":
                case "-":
                    return 1;
                case "*":
                case "/":
                    return 2;
                case "^":
                    return 3;
                default:
                    return 4;
            }
        }

        public string[] ConvertToPostfixNotation(string input)
        {
            List<string> outputSeparated = new List<string>();
            Stack<string> stack = new Stack<string>();
            foreach (string c in Separate(input))
            {
                if (operators.Contains(c))
                {
                    if (stack.Count > 0 && !c.Equals("("))
                    {
                        if (c.Equals(")"))
                        {
                            string s = stack.Pop();
                            while (s != "(")
                            {
                                outputSeparated.Add(s);
                                s = stack.Pop();
                            }
                        }
                        else if (GetPriority(c) > GetPriority(stack.Peek()))
                            stack.Push(c);
                        else
                        {
                            while (stack.Count > 0 && GetPriority(c) <= GetPriority(stack.Peek()))
                                outputSeparated.Add(stack.Pop());
                            stack.Push(c);
                        }
                    }
                    else
                        stack.Push(c);
                }
                else
                    outputSeparated.Add(c);
            }
            if (stack.Count > 0)
                foreach (string c in stack)
                    outputSeparated.Add(c);

            return outputSeparated.ToArray();
        }
        public decimal result(string input)
        {
            Stack<string> stack = new Stack<string>();
            Queue<string> queue = new Queue<string>(ConvertToPostfixNotation(input));
            string str = queue.Dequeue();
            while (queue.Count >= 0)
            {
                if (!operators.Contains(str))
                {
                    stack.Push(str);
                    str = queue.Dequeue();
                }
                else
                {
                    decimal summ = 0;
                    try
                    {
                        
                        switch (str)
                        {

                            case "+":
                                {
                                    decimal a = Convert.ToDecimal(stack.Pop());
                                    decimal b = Convert.ToDecimal(stack.Pop());
                                    summ = a + b;
                                    break;
                                }
                            case "-":
                                {
                                    decimal a = Convert.ToDecimal(stack.Pop());
                                    decimal b = Convert.ToDecimal(stack.Pop());
                                    summ=b-a;
                                    break;
                                }
                            case "*":
                                {
                                    decimal a = Convert.ToDecimal(stack.Pop());
                                    decimal b = Convert.ToDecimal(stack.Pop());
                                    summ = b * a;
                                    break;
                                }
                            case "/":
                                {
                                    decimal a = Convert.ToDecimal(stack.Pop());
                                    decimal b = Convert.ToDecimal(stack.Pop());
                                    summ = b / a;
                                    break;
                                }
                            case "^":
                                {
                                    decimal a = Convert.ToDecimal(stack.Pop());
                                    decimal b = Convert.ToDecimal(stack.Pop());
                                    summ = Convert.ToDecimal(Math.Pow(Convert.ToDouble(b), Convert.ToDouble(a)));
                                    break;
                                }
                        }
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message);
                    }
                    stack.Push(summ.ToString());
                    if (queue.Count > 0)
                        str = queue.Dequeue();
                    else
                        break;
                }
                
            }
            return Convert.ToDecimal(stack.Pop());
        }
    }

}

Ruby[править]

# Преобразование к польской записи
# <oskin@rambler.ru>

def opz(iStr, stack)
  priority = Hash["(" => 0, "+" => 1, "-" => 1, "*" => 2, "/" => 2, "^" => 3]
  case iStr
    when /^\s*([^\+\-\*\/\(\)\^\s]+)\s*(.*)/ then $1 + " " + opz($2, stack)
    when /^\s*([\+\-\*\/\^])\s*(.*)/
      if (stack.empty? or priority[stack.last] < priority[$1]) then opz($2, stack.push($1))
      else stack.pop + " " + opz(iStr, stack) end
    when /^\s*\(\s*(.*)/ then opz($1, stack.push("("))
    when /^\s*\)\s*(.*)/
      if stack.empty? then raise "Error: Excess of closing brackets." 
      elsif priority[head = stack.pop] > 0 then head + " " + opz(iStr, stack)
      else opz($1, stack) end
    else if stack.empty? then "" 
         elsif priority[stack.last] > 0 then stack.pop + " " + opz(iStr, stack) 
         else raise "Error: Excess of opening brackets." end
  end
end

while a = gets
  begin
    puts opz(a, [])
  rescue Exception => e
    puts e.message
  end
end

Javascript[править]

const operators = {
    '+': (x, y) => x + y,
    '-': (x, y) => x - y,
    '*': (x, y) => x * y,
    '/': (x, y) => x / y
};

let evaluate = (expr) => {
    let stack = [];
    
    expr.split(' ').forEach((token) => {
        if (token in operators) {
            let [y, x] = [stack.pop(), stack.pop()];
            stack.push(operators[token](x, y));
        } else {
            stack.push(parseFloat(token));
        }
    });

    return stack.pop();
};

Python[править]

import operator

def calc(expr):
    OPERATORS = {'+': operator.add, '-': operator.sub, '*': operator.mul, '/': operator.truediv}
    stack = [0]
    for token in expr.split(" "):
        if token in OPERATORS:
            op2, op1 = stack.pop(), stack.pop()
            stack.append(OPERATORS[token](op1,op2))
        elif token:
            stack.append(float(token))
    return stack.pop()