Написать программу формирования ОПЗ и расчета полученного выражения - Pascal ABC

Узнай цену своей работы

Формулировка задачи:

Написать программу формирования ОПЗ и расчета полученного выражения. Разработать удобный интерфейс ввода исходных данных и вывода результатов. Работу программы проверить на конкретном примере Сам пример со значениями которые должны получиться: (a– b)/(c+d)*e , где а=0.3 b=6.7 c=8.4 d=9.6 e=1.2 Результат должен получиться -0.429. Помогите пожалуйста используя динамический массив заранее спасибо

Решение задачи: «Написать программу формирования ОПЗ и расчета полученного выражения»

textual
Листинг программы
uses math;
type arr = array of string[20];
 
//процедура помещения токена в стек
procedure push(var x: arr; var y: string);
begin
  setlength(x, length(x) + 1); //увеличиваем глубину стека
  x[high(x)] := y //помещаем токен
end;
 
//процедура извлечения токена из стека
procedure pop(var x: arr; var y: string);
begin
  y := x[high(x)]; //извлекаем токен
  setlength(x, length(x) - 1) //уменьшаем глубину стека
end;
 
const op = '()+-*/^'; //операторы в порядке возрастания приоритетов
var s, t, q, error: string; //входная строка, буферы токена, сообщение об ошибке
    i, err: integer; //счётчик, ошибка преобразования строки в число
    num: real; //проверочный результат
    st, st_op: arr; //выходной стек, стек операций
    st_n: array of real; //стек операндов
begin
  writeln('Введите выражение:'); //ввод выражения в инфиксной нотации
  readln(s);
  s := s + ' '; //добавляем пробел для удобства алгоритма
  for i := length(s) downto 1 do //разбиваем пробелами выражение на токены
    if pos(s[i], op) > 0 //если очередной символ - оператор
      then begin //то вставляем пробелы до и после него
        insert(' ', s, i + 1);
        insert(' ', s, i)
      end;
  while pos('  ', s) > 0 do delete(s, pos('  ', s), 1); //убираем лишние пробелы
  if (length(s) > 0) and (s[1] = ' ') then delete(s, 1, 1);
  if length(s) = 0 //если строка пустая
    then error := 'Ошибка: пустое выражение' //формируем сообщение об ошибке и более ничего не делаем
    else begin //если строка не пустая, то
      writeln('Выражение:'); //печатаем выражение, разбитое на токены
      writeln(s);
      t := ''; //инициализируем буфер токена: пока пустой
      for i := 1 to length(s) do //сканируем выражение
        begin
          if s[i] <> ' ' //если не пробел,
            then t := t + s[i] //то помещаем символ в буфер токена
            else begin //иначе разбираемся с токеном
              case t[1] of //смотрим первый символ токена
                  '0'..'9', '.': //если относится к числу,
                    begin //то
                      val(t, num, err); //проверяем, является ли токен допустимой записью числа
                      if err = 0
                        then push(st, t) //если да, то помещаем токен в выходной стек
                        else begin //если нет,
                          error := 'Ошибка: не число: ' + t; //то формируем текст ошибки
                          break //и прекращаем сканирование
                        end
                    end;
                  '(': //если открывающая скобка,
                    push(st_op, t); //то помещаем токен в стек
                  ')':
                    begin //если закрывающая скобка,
                      while (length(st_op) > 0) and (t[1] <> '(') do //то пока не встретился токен '(' и стек операторов не опустел
                        begin
                          pop(st_op, t); //извлекаем токен из стека операторов
                          if t[1] <> '(' then push(st, t) //и помещаем его в выходной стек
                        end;
                      if t[1] <> '(' //если последний извлечённый токен не '(',
                        then begin
                          error := 'Ошибка: нарушен баланс скобок'; //то формируем текст ошибки
                          break //и прекращаем сканирование
                        end
                    end;
                  '+', '-', '*', '/', '^': //если токен - операция,
                    begin
                      //то пока стек операторов не пустой и операция на вершине стека операторов с большим или равным приоритетом,
                      while (length(st_op) > 0) and ((pos(t[1], op) - 1) div 2 <= (pos(st_op[high(st_op)][1], op) - 1) div 2) do
                        begin
                          pop(st_op, q); //извлекаем токен из стека операторов
                          push(st, q); //помещаем токен в выходной стек
                        end;
                      push(st_op, t); //добавляем токен к стеку операторов
                    end
                  else //если токен какой-то другой,
                    begin
                      error := 'Ошибка: недействительный оператор: ' + t; //то формируем текст ошибки
                      break //и прекращаем сканирование
                    end
                end;
              t := '' //реинициализируем буфер токена
            end;
        end;
        //сканирование окончено
      while length(st_op) > 0 do //если в стеке операторов остались операторы, перемещаем их в выходной стек
        if pos(st_op[high(st_op)][1], op) < 3 //если оператор - скобка,
          then begin
            error := 'Ошибка: нарушен баланс скобок'; //то формируем текст ошибки
            break //и прекращаем перемещение
          end
          else begin //если оператор - не скобка,
            pop(st_op, t); //то извлекаем его из стека операторов
            push(st, t) //и помещаем в выходной стек
          end;
    end;
  if (length(st) > 0) and (length(error) = 0) //если выходной стек не пуст и нет ошибки,
    then begin //то
      writeln('ОПЗ:'); //печатаем выражение в постфиксной нотации
      for i := 0 to high(st) do write(st[i], ' ');
      writeln;
      for i := 0 to high(st) do //пробегаемся по выходному стеку и пытаемся вычислить выражение
        case st[i][1] of
            '+', '-', '*', '/', '^': //если токен - оператор,
              begin //то пытаемся выполнить операцию
                case st[i][1] of //смотрим, что за оператор
                    '+': st_n[high(st_n) - 1] := st_n[high(st_n) - 1] + st_n[high(st_n)]; //находим сумму
                    '-': st_n[high(st_n) - 1] := st_n[high(st_n) - 1] - st_n[high(st_n)]; //находим разность
                    '*': st_n[high(st_n) - 1] := st_n[high(st_n) - 1] * st_n[high(st_n)]; //находим произведение
                    '/': //деление
                      if st_n[high(st_n)] <> 0 //если делитель не равен 0
                        then st_n[high(st_n) - 1] := st_n[high(st_n) - 1] / st_n[high(st_n)] //то находим частное
                        else begin //иначе ошибка деления на 0
                          error := 'Ошибка: деление на ноль';
                          break
                        end;
                    '^': //возведение в степень
                      if (st_n[high(st_n) - 1] = 0) and (st_n[high(st_n)] = 0) //если 0^0
                        then begin //то ошибка 0^0
                          error := 'Ошибка: 0^0';
                          break
                        end
                        else if (frac(1 / st_n[high(st_n)]) = 0) and not odd(trunc(1 / st_n[high(st_n)])) and (st_n[high(st_n) - 1] < 0)
                          then begin //если корень чётной степени из отрицательного числа, то ошибка
                            error := 'Ошибка: корень чётной степени из отрицательного числа';
                            break
                          end
                          else if st_n[high(st_n) - 1] > 0 //если всё в норме, вычисляем степень
                            then st_n[high(st_n) - 1] := exp(ln(st_n[high(st_n) - 1]) * st_n[high(st_n)])
                            else if st_n[high(st_n) - 1] < 0
                              then st_n[high(st_n) - 1] := -exp(ln(-st_n[high(st_n) - 1]) * st_n[high(st_n)])
                              else st_n[high(st_n) - 1] := 0
                  end;
                setlength(st_n, length(st_n) - 1) //операция выполнена, убираем второй операнд из стека (результат помещён на место первого операнда)
              end
            else begin //если не оператор,
              setlength(st_n, length(st_n) + 1); //то увеличиваем глубину стека операндов
              val(st[i], st_n[high(st_n)], err) //и помещаем в стек операндов токен, преобразованный в число
            end
          end
    end;
  if length(error) > 0 //если есть ошибка,
    then write(error) //то печатаем её
    else write('Результат: ', st_n[high(st_n)]:0:15); //иначе печатаем результат
  readln
end.

Объяснение кода листинга программы

Этот код написан на языке Pascal ABC и предназначен для формирования ОПЗ (обратного порядка слов) и расчета выражений, введенных пользователем. Он работает следующим образом:

  1. Пользователь вводит выражение, которое затем разбивается на отдельные токены.
  2. Каждый токен проверяется на соответствие определенным правилам языка.
  3. Если токен является оператором, то он помещается в стек операторов.
  4. Если токен является числом, то он преобразуется в число и помещается в стек чисел.
  5. Выполняются операции в стеке операторов до тех пор, пока не закончатся операторы или все числа будут использованы.
  6. Результат вычислений помещается в стек чисел.
  7. Стеки чисел и операторов очищаются.
  8. Выводится результат вычислений. Код содержит несколько проверок на ошибки, таких как деление на ноль, ошибка баланса скобок и другие. Если происходит ошибка, то выводится соответствующее сообщение об ошибке. Этот код может быть использован для решения различных задач, связанных с вычислением выражений на языке Pascal.

Оцени полезность:

11   голосов , оценка 3.545 из 5
Похожие ответы