Чтение онлайн

ЖАНРЫ

О чём не пишут в книгах по Delphi

Григорьев Антон Борисович

Шрифт:
Примечание

Строго говоря, определения операторов

if
и
for
в Delphi сложнее, чем те, которые мы здесь привели. Это связано с тем, что
<if>
и
<for>
— это альтернативы символа
<Operator>
. Поэтому может возникнуть конструкция типа
if Condition1 then if Condition2 then Operator1 else Operator2
. Из нашего определения невозможно сделать вывод о том, к какому из двух
if
в данном случае относится
else
. В языках программирования принято, что
else
относится к последнему из
if
, который еще не имеет
else
. Чтобы описать это правило, требуется более сложный синтаксис, чем мы здесь привели. Однако этот вопрос выходит за рамки данной книги и более подробно рассмотрен в [5].

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

<Unsigned> ::= {<Digit>}

Это простое определение не совсем верно, т.к. фигурные скобки указывают на повторение ноль или большее число раз, т.е. пустая строка также будет соответствовать нашему определению

<Unsigned>
. Чтобы этого не происходило, исправим наше определение:

<Unsigned> ::= <Digit> {<Digit>}

Теперь синтаксическое правило, определяемое символом

<Unsigned>
, требует, чтобы выражение состояло из одной или более цифр.

В некоторых случаях после закрывающей фигурной скобки ставят символ "+" в верхнем индексе, чтобы показать, что содержимое скобок должно повторяться не менее одного раза. Например, следующее определение

<Unsigned>
эквивалентно предыдущему:

<Unsigned> ::= {<Digit>}+

Однако это обозначение не является общепризнанным, поэтому мы не будем им пользоваться.

Этим исчерпывается набор правил БНФ. Далее мы будем использовать эти правила для описания различных синтаксических конструкций. При этом мы увидим, что, несмотря на простоту, БНФ позволяет описывать очень сложные конструкции, и это описание просто для понимания.

4.3. Синтаксис вещественного числа

Попытаемся описать синтаксис вещественного числа с помощью БНФ. Сначала опишем этот синтаксис словами: "Перед числом может стоять знак — плюс или минус. Затем идет одна или несколько цифр. Потом может следовать точка, после которой будет еще одна или несколько цифр. Затем может быть указан показатель степени "Е" (большое или малое), после которого может стоять знак плюс или минус, а затем должна быть одна или несколько цифр". Указанные правила описывают синтаксис записи вещественных чисел, принятый в Delphi. Согласно им, правильными вещественными числами считаются, например, выражения "10", "0.1", "+4", "-3.2", "8.26е-5" и т.п. Такие выражения, как, например, ".6" и "-.5", этим правилам не удовлетворяют, т.к. перед десятичной точкой должна стоять хотя бы одна цифра. В некоторых языках программирования такая запись допускается, но Delphi требует обязательного наличия целой части.

Теперь переведем эти правила на язык БНФ (листинг 4.1).

Листинг 4.1. Синтаксис вещественного числа

<Number> ::= [<Sign>] <Digit> {<Digit>}

 [<Separator> <Digit> {<Digit>}]

 [<Exponent> [<Sign>] <Digit> {<Digit>}]

<Digit> ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'

<Sign> ::= '+' | '-'

<Separator> ::= '.'

<Exponent> ::= 'E' | 'e'

На основе этих правил можно написать функцию

IsNumber
,
которая в качестве параметра принимает строку и возвращает
True
, если эта строка удовлетворяет правилам записи числа, и
False
, если не удовлетворяет (листинг 4.2).

Листинг 4.2. Функция для определения соответствия строки синтаксису вещественного числа

// Проверка символа на соответствие <Digit>

function IsDigit(Ch: Char): Boolean;

begin

 Result := Ch in ['0'..'9'];

end;

// Проверка символа на соответствие <Sign>

function IsSign(Ch: Char): Boolean;

begin

 Result := (Ch = '+') or (Ch = '-');

end;

// Проверка символа на соответствие <Separator>

function IsSeparator(Ch: Char): Boolean;

begin

 Result := Ch='.';

end;

// Проверка символа на соответствие <Exponent>

function IsExponent(Ch: Char): Boolean;

begin

 Result := (Ch = 'E') or (Ch = 'e');

end;

function IsNumber(const S: string): Boolean;

var

 P: Integer; // Номер символа выражения, который сейчас проверяется

begin

 Result := False;

 // Проверка, что выражение содержит хотя бы один символ — пустая строка

 // не является числом

 if Length(S) = 0 then Exit;

 // Начинаем проверку с первого символа

 Р := 1;

 // Если первый символ — <Sign>, переходим к следующему

 if IsSign(S[Р]) then Inc(Р);

 // Проверяем, что в данной позиции стоит хотя бы одна цифра

 if (Р > Length(S)) or not IsDigit(S[Р]) then Exit;

 // Переходим к следующей позиции, пока не достигнем конца строки

 // или не встретим не цифру

 repeat

Inc(Р);

 until (Р > Length(S)) or not IsDigit(S[Р]);

 // Если достигли конца строки, выражение корректно — число.

 // не имеющее дробной части и экспоненты

 if Р > Length(S) then

 begin

Result := True;

Exit;

 end;

 // Если следующей символ — <Separator>, проверяем, что после него

 // стоит хотя бы одна цифра

 if IsSeparator(S[P]) then

 begin

Inc(P);

if (P > Length(S)) or not IsDigit(S[P]) then Exit;

repeat

Inc(P);

Поделиться с друзьями: