Пусть десятичная запись числа подается на вход программы символ за символом. Мы хотим << прочесть>> это число (поместить в переменную типа real его значение). Кроме того, надо сообщить об ошибке, если число записано неверно.
Более конкретно, представим себе такую ситуацию. Последовательность символов на входе делится на прочитанную и оставшуюся части. Мы можем пользоваться функцией Next:char, которая дает первый символ оставшейся части, а также функцией Move, которая забирает первый символ из оставшейся части, переводя его в категорию прочитанных.
Будем называть десятичной записью такую последовательность
символов:
а также такую:
Заметим, что согласно этому определению
01. 1
не являются десятичными записями. Сформулируем теперь
задачу точно:
5.2.1. Прочесть из входной строки максимальную часть, которая
может быть началом десятичной записи. Определить, является ли
эта часть десятичной записью или нет.
var state: (Accept, Error, Initial, IntPart, DecPoint, FracPart); state := Initial; while (state <> Accept) or (state <> Error) do begin | if state = Initial then begin | | if Next = ' ' then begin | | | state := Initial; Move; | | end else if Digit(Next) then begin | | | state := IntPart; {после начала целой части} | | | Move; | | end else begin | | | state := Error; | | end; | end else if state = IntPart then begin | | if Digit (Next) then begin | | | state := IntPart; Move; | | end else if Next = '.' then begin | | | state := DecPoint; {после десятичной точки} | | | Move; | | end else begin | | | state := Accept; | | end; | end else if state = DecPoint then begin | | if Digit (Next) then begin | | | state := FracPart; Move; | | end else begin | | | state := Error; {должна быть хоть одна цифра} | | end; | end else if state = FracPart then begin | | if Digit (Next) then begin | | | state := FracPart; Move; | | end else begin | | | state := Accept; | | end; | end else if | | {такого быть не может} | end; end;Заметьте, что присваивания state:=Accept и state:=Error не сопровождаются сдвигом (символ, который не может быть частью числа, не забирается).
Приведенная программа не запоминает значение прочитанного числа.
5.2.2. Решить предыдущую задачу с дополнительным требованием: если
прочитанный кусок является десятичной записью, то в переменную
val:real следует поместить ее значение.
state := Initial; val:= 0; while (state <> Accept) or (state <> Error) do begin | if state = Initial then begin | | if Next = ' ' then begin | | | state := Initial; Move; | | end else if Digit(Next) then begin | | | state := IntPart; {после начала целой части} | | | val := DigitValue (Next); | | | Move; | | end else begin | | | state := Error; | | end; | end else if state = IntPart then begin | | if Digit (Next) then begin | | | state := IntPart; val := 10*val + DigitVal(Next); | | | Move; | | end else if Next = '.' then begin | | | state := DecPoint; {после десятичной точки} | | | step := 0.1; | | | Move; | | end else begin | | | state := Accept; | | end; | end else if state = DecPoint then begin | | if Digit (Next) then begin | | | state := FracPart; | | | val := val + DigitVal(Next)*step; step := step/10; | | | Move; | | end else begin | | | state := Error; {должна быть хоть одна цифра} | | end; | end else if state = FracPart then begin | | if Digit (Next) then begin | | | state := FracPart; | | | val := val + DigitVal(Next)*step; step := step/10; | | | Move; | | end else begin | | | state := Accept; | | end; | end else if | | {такого быть не может} | end; end;`
5.2.3. Та же задача, если перед числом может стоять знак -
или знак + (а может ничего не стоять).
Формат чисел в этой задаче обычно иллюстрируют такой картинкой:
5.2.4. Та же задача, если к тому же после числа может стоять
показатель степени десяти, как в 254E-4 (=0.0254 )
или в 0.123E+9
(). Нарисуйте соответствующую картинку.
5.2.5. Что надо изменить в приведенной выше программе, чтобы
разрешить пустые целую и дробную части (как в 1., .1 или
даже . -- последнее число считаем равным нулю)?
Мы вернемся к конечным автоматам в главе 10 (Сравнение с образцом).