Ответ в теме: Вычисление арифметического выражения (ПОЛИЗ)

      Комментарии к записи Ответ в теме: Вычисление арифметического выражения (ПОЛИЗ) отключены
#2536

Мы смогли преобразовать строку в ПОЛИЗ, теперь нужно вычислить выражение. Для начала надо описать поведение операторов — функция обработки унарного оператора принимает один операнд, а бинарного — два. Сама обработка операндов тривиальна — например, унарный минус возвращает -Operand:

calculate_binary_operator(plus, LeftOperand, RightOperand, Result):-
  !, Result is LeftOperand + RightOperand.
calculate_binary_operator(minus, LeftOperand, RightOperand, Result):-
  !, Result is LeftOperand - RightOperand.
calculate_binary_operator(multiplication, LeftOperand, RightOperand, Result):-
  !, Result is LeftOperand * RightOperand.
calculate_binary_operator(division, LeftOperand, RightOperand, Result):-
  !, Result is LeftOperand / RightOperand.
  
calculate_unary_operator(unary_minus, Operand, OperatorResult):-
  OperatorResult is -Operand.

Функция вычисления выражения, записанного в ПОЛИЗ использует вспомогательный буфер для хранения операндов и промежуточных вычислений:

  1. если выражение кончилось (эквивалентно пустому списку), то в буфере должно быть единственное значение, которое и является результатом вычислений;
  2. если в начале выражения стоит число — оно перемещается в буфер;
  3. если в начале стоит унарный оператор — из буфера выбирается первое число, к которому этот оператор применяется, результат помещается в буфер;
  4. если в начале строки стоит бинарный оператор — первые два числа буфера — операнды, к которым применяется оператор, результат помещается в буфер.

calculate_reverse_polish_notation([], [Result], Result):-!.
calculate_reverse_polish_notation([(number, Value)|Tail], Operands, Result):-
  calculate_reverse_polish_notation(Tail, [Value|Operands], Result), !.
calculate_reverse_polish_notation([UnaryOperator|Tail], [Operand|TailOperands], Result):-
  calculate_unary_operator(UnaryOperator, Operand, OperatorResult),
  calculate_reverse_polish_notation(Tail, [OperatorResult|TailOperands], Result).
calculate_reverse_polish_notation([Operator|Tail], [RightOperand, LeftOperand|TailOperands], Result):-
  calculate_binary_operator(Operator, LeftOperand, RightOperand, OperatorResult),
  calculate_reverse_polish_notation(Tail, [OperatorResult|TailOperands], Result).

Для удобства можно написать вспомогательную функцию, которая принимает строку, преобразует ее в ПОЛИЗ, вычисляет выражение и возвращает число:

calculate_string(String, Result):-
  string_to_expression(unary, String, [], [], Expression),
  calculate_reverse_polish_notation(Expression, [], Result).