Написать программу формирования ОПЗ и расчета полученного выражения - 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 и предназначен для формирования ОПЗ (обратного порядка слов) и расчета выражений, введенных пользователем. Он работает следующим образом:
- Пользователь вводит выражение, которое затем разбивается на отдельные токены.
- Каждый токен проверяется на соответствие определенным правилам языка.
- Если токен является оператором, то он помещается в стек операторов.
- Если токен является числом, то он преобразуется в число и помещается в стек чисел.
- Выполняются операции в стеке операторов до тех пор, пока не закончатся операторы или все числа будут использованы.
- Результат вычислений помещается в стек чисел.
- Стеки чисел и операторов очищаются.
- Выводится результат вычислений. Код содержит несколько проверок на ошибки, таких как деление на ноль, ошибка баланса скобок и другие. Если происходит ошибка, то выводится соответствующее сообщение об ошибке. Этот код может быть использован для решения различных задач, связанных с вычислением выражений на языке Pascal.