Задание 8 Урок 22

Задание 8 Урок 22

Напишите функцию, которая получает на вход произвольную строку вида:

5*(3+4)-7*9+3*(2+(2-7))

(арифметическое выражение со скобками любого уровня вложенности и операциями умножения, вычитания и сложения)

и в качестве ответа возвращает результат этого выражения.

uses SysUtils;

type DataRecord = record
  I, Sum : Integer;
end;

var
  temp1, temp2, temp3, znak: string;
  flag1, flag2: boolean;
  intChislo, intChislo1, intChislo2, intChislo3, Code, sumTemp: integer;

  S :string;
  N :integer;
  Data: DataRecord;

function calc(Data: DataRecord; s: string; i, sum: integer): DataRecord;
var
  temp1, temp2, temp3, znak: string;
  flagNextMultTwoMember, flagNextMultMultipleMember, flagBracketPlus, flagBracketMult: boolean;
  intChislo, intChislo1, intChislo2, intChislo3, Code, multTemp: integer;
begin
  multTemp := 0;       // временная сумма (для слагаемых типа ...a*b*c*...)

  // если только слагаемые то используем temp1 (каждое слагаемое помещаем в temp1 и увеличиваем общую сумму  sum += temp1)
  // если слагаемые состоят максимум из 2х множителей то temp1 и temp2
  // если слагаемое состоит из более чем 2х множителей (...a*b*c*d...) то используем 3 temp переменных:
  // предыдущие множители (a*b*c*...) на каждой итерации становятся multTemp, и умножаются на temp3
  // 1) multTemp = temp1 * temp2
  // 2) multTemp *= temp3
  // 3) goto 2)

  temp1 := '';
  temp2 := '';
  temp3 := '';
  flagNextMultTwoMember := true;           // флаг для перехода в случае 2х множителей в слагаемом
  flagNextMultMultipleMember := true;      // флаг для перехода в случае более 2х множителей в слагаемом
  flagBracketPlus := false;      // флаг для перехода перед скобкой при сложении
  flagBracketMult := false;      // флаг для перехода перед скобкой при умножении
  znak := '';         // знак перед числом

  while (i < (length(s)+1)) do   // итерируем по выражению до конца
  begin
    if((s[i-1] = ')')) then   // выходим из закрывающей скобки (из функции)
    begin
      break;
    end
    else
    begin

   if (i > 1) then  // проверяем знак перед слагаемым
    begin
      if (s[i-1]='-')or(s[i-1]='+') then // и есть ли он вообще
      begin
        znak := s[i-1];
      end;
    end;

    if(s[i]='(') then      // если встречаем скобку то рекурсивно вызываем функцию
    begin
      if(s[i-1]='*') then
      begin
        flagBracketMult := true;
      end
      else
      begin
        flagBracketPlus := true;
      end;
      i := i + 1;
      if(flagBracketMult) then            // умножение перед скобкой !!! не работает !!!
      begin
        Data := calc(Data, S, i, 0);
        i := Data.I+1;
        Val(temp2, intChislo1, Code);
        temp2 := IntToStr(Data.Sum);
        Val(znak + temp1, intChislo1, Code);
        Val(temp2, intChislo2, Code);
        sum := sum + intChislo1 * intChislo2;  // увеличиваем общую сумму на произведение 2х предыдущих множителей
        //сброс параметров
        temp1 := '';
        temp2 := '';
        temp3 := '';
        flagNextMultTwoMember := true;
        flag2 := true;
        flagBracketPlus := false;
        flagBracketMult := false;
        znak := '';
        continue;
      end
      else
      begin
        Data := calc(Data, S, i, 0);  // получили после рекурентного вызова функции позицию и сумму в скобках
        if(s[i-2] = '+') then
         sum := sum + Data.Sum
        else
          sum := sum - Data.Sum;
        i := Data.I+1;
        continue;
      end;
    end;

    if (flagNextMultTwoMember) then
    begin
      temp1 := temp1 + s[i];         //заполняем 1 временное число
      Val(s[i+1], intChislo, Code);  // смотрим на следующий символ
      if (Code = 0) then             // если это цифра то добавляем в temp1 и переходим к следующему символу
      begin
        i := i + 1;
        continue;
      end
      else
      begin
        if (s[i+1] <> '*') then  // если это + или - (множитель ..a*b*c*... закончился )
        begin
          Val(znak + temp1, intChislo1, Code);
          sum := sum + intChislo1; // увеличиваем общую сумму на накопленное число temp1 учитывая знак перед ним
        end
        else                    // если это умножение то идем дальше
        begin
          flagNextMultTwoMember := false;       // переходим ко второму временному множителю  \/
          i := i + 2;                                                //       \/
          continue;                                                  //       \/
        end                                                          //       \/
      end                                                            //       \/
    end                                                              //       \/
    else                                                             //       \/
    begin                       // переходим ко второму временному множителю
      if (flagNextMultMultipleMember) then
      begin
        temp2 := temp2 + s[i];      //заполняем 2 временное число
        Val(s[i+1], intChislo, Code);
        if (Code = 0) then  // если число то добавляем в temp2 и переходим к следующему символу
        begin
          i := i + 1;
          continue;
        end
        else
        begin
          if (s[i+1] <> '*') then             // если это + или - (множитель ..a*b*c*... закончился)
          begin
            Val(znak + temp1, intChislo1, Code);
            Val(temp2, intChislo2, Code);
            sum := sum + intChislo1 * intChislo2;  // увеличиваем общую сумму на произведение 2х предыдущих множителей
          end
          else              // если это * (множитель ..a*b*c*... НЕ закончился)
          begin
            Val(znak + temp1, intChislo1, Code);
            Val(temp2, intChislo2, Code);
            multTemp := intChislo1 * intChislo2;        // делаем временную сумму предыдущих множителей
            flagNextMultMultipleMember := false;               // переходим ко третьему временному множителю     \/
            i := i + 2;                                                            //       \/
            continue;                                                              //       \/
          end                                                                      //       \/
        end                                                                        //       \/
      end                                                                          //       \/
      else                               // переходим ко третьему временному множителю
      begin
        temp3 := temp3 + s[i];           //заполняем 3 временное число
        Val(s[i+1], intChislo, Code);
        if (Code = 0) then  // если число то добавляем в temp3 и переходим к следующему символу
        begin
          i := i + 1;
          continue;
        end
        else
        begin
          if (s[i+1] = '*') then   // если это * (множитель ..a*b*c*... НЕ закончился)
          begin
            Val(temp3, intChislo3, Code);
            multTemp := multTemp * intChislo3;    // увеличиваем временную накопительную переменную (произведение)
            temp3 := '';
            i := i + 2;
            continue;
          end
          else                             // если это + или - (множитель ..a*b*c*... закончился)
          begin
            Val(temp3, intChislo3, Code);
            Val(znak+temp1, intChislo1, Code);
            multTemp := multTemp * intChislo3;    // увеличиваем временную накопительную переменную (произведение)
            sum := sum + multTemp ;  // увеличиваем общую сумму 
          end
        end
      end
    end;

    temp1 := '';       // сброс  (например, множитель ..a*b*c*... закончился)
    temp2 := '';
    temp3 := '';
    flagNextMultTwoMember := true;
    flagNextMultMultipleMember := true;
    flagBracketPlus := false;      // флаг для перехода перед скобкой
    flagBracketMult := false;
    znak := '';
    i := i + 2;   // мы переходим через знак и число (....1+2*3...)+2
    end;
  end;
  Data.I := i;
  Val(temp1, intChislo, Code);
  Data.Sum := sum + intChislo;
  result := Data;
end;


begin
    S := '5*(3+4)';
    Data :=  calc(Data, S, 1, 0);
    writeln(S, ' = ', Data.Sum);

    S := '7*9';
    Data :=  calc(Data, S, 1, 0);
    writeln(S, ' = ', Data.Sum);

    S := '3*(2+(2-7))';
    Data :=  calc(Data, S, 1, 0);
    writeln(S, ' = ', Data.Sum);

    S := '5*(3+4)-7*9+3*(2+(2-7))';
    Data :=  calc(Data, S, 1, 0);
    writeln(S, ' = ', Data.Sum);

    S := '5*(3+4)-7*9+3*(2+(2-7))+1';
    Data :=  calc(Data, S, 1, 0);
    writeln(S, ' = ', Data.Sum);

    S := '5*(3+4)-7*9+3*(2+(2-7))-1*1*(1+1)';
    Data :=  calc(Data, S, 1, 0);
    writeln(S, ' = ', Data.Sum);
end.

консоль:

5*(3+4) = 35
7*9 = 63
3*(2+(2-7)) = -9
5*(3+4)-7*9+3*(2+(2-7)) = -37
5*(3+4)-7*9+3*(2+(2-7))+1 = -36
5*(3+4)-7*9+3*(2+(2-7))-1*1*(1+1) = -39