Задание 8 Урок 22
Primary tabs
Напишите функцию, которая получает на вход произвольную строку вида:
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
- Log in to post comments
- 494 reads