Читаем О чём не пишут в книгах по Delphi полностью

// Так как грамматика рекурсивна, функция Expr

// должна быть объявлена заранее

function Expr(const S: string; var Р: Integer): Extended; forward;

// Выделение подстроки, соответствующей ,

// и ее вычисление

function Factor(const S: string; var P: Integer): Extended;

begin

 if P > Length(S) then

  raise ESyntaxError.Create('Неожиданный конец строки');

 // По первому символу подстроки определяем,

 // какой это множитель

 case S[Р] of

 '+': // унарный "+"

 begin

  Inc(Р);

  Result := Factor(S, P);

 end;

 '-': // унарный "-"

 begin

  Inc(P);

  Result := -Factor(S, P);

 end;

 '(': // выражение в скобках

 begin

  Inc(P);

  Result := Expr(S, P);

  // Проверяем, что скобка закрыта

  if (Р > Length(S)) or (S[P] <> ')') then

   raise ESyntaxError.Create(

    'Ожидается ")" в позиции ' + IntToStr(P));

  Inc(P);

 end;

 '0'..'9': // Числовая константа

  Result := Number(S, P);

 else

  raise ESyntaxError.Create(

   'Некорректный символ в позиции ' + IntToStr(Р));

 end;

end;

// Выделение подстроки, соответствующей ,

// и ее вычисление

function Term(const S: string; var P: Integer): Extended;

var

 OpSymb: Char;

begin

 Result := Factor(S, P);

 while (P <= Length(S)) and IsOperator2(S[P]) do

 begin

  OpSymb := S[P];

  Inc(P);

  case OpSymb of

  '*': Result := Result * Factor(S, P);

  '/': Result := Result / Factor(S, P);

  end;

 end;

end;

// Выделение подстроки, соответствующей ,

// и ее вычисление

function Expr(const S: string; var Р: Integer): Extended;

var

 OpSymb: Char;

begin

 Result := Term(S, P);

 while (P <= Length(S)) and IsOperator1(S[P]) do

 begin

OpSymb := S[P];

  Inc(P);

  case OpSymb of

  '+': Result := Result + Term(S, P);

  '-': Result := Result - Term(S, P);

  end;

 end;

end;

// Вычисление выражения

function Calculate(const S: string): Extended;

var

 P: Integer;

begin

 P := 1;

 Result := Expr(S, P);

 if P <= Length(S) then

  raise ESyntaxError.Create(

   'Некорректный символ в позиции ' + IntToStr(Р));

end;

По сравнению с предыдущим примером функция Term осталась такой же с точностью до замены вызовов Number на новую функцию Factor. Функция Factor выделяет подстроку, отвечающую отдельному множителю. Множители, напомним, могут быть трех типов: число, выражение в скобках, множитель с унарным оператором. Различить их можно по первому символу подстроки. Функция Factor распознает тип множителя и вызывает соответствующую функцию для его вычисления.

Функция Expr теперь может применяться не только к выражению в целом, но и к отдельной подстроке. Поэтому она, как и все остальные функции, теперь имеет параметр-переменную P, через который передается начало и конец этой подстроки. Из функции убрана проверка того, что в результате ее использования строка проанализирована полностью, т.к. теперь допустим анализ части строки.

Функция Expr в своем новом виде стала не очень удобной для конечного пользователя, поэтому была описана еще одна функция — Calculate. Это вспомогательная функция, которая избавляет пользователя от вникания в детали "внутренней кухни" калькулятора, т.е. использования переменной P и проверки того, что строка проанализирована до конца.

Пример калькулятора со скобками записан на компакт-диске под названием BracketsCalcSample. Анализируя его код, можно заметить, что по сравнению с предыдущим примером незначительно изменена функция Number — из нее в соответствии с новой грамматикой убрана проверка знака в начале выражения.

Перейти на страницу:
Нет соединения с сервером, попробуйте зайти чуть позже