// Так как грамматика рекурсивна, функция 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
— из нее в соответствии с новой грамматикой убрана проверка знака в начале выражения.