Ввод чисел

Пусть десятичная запись числа подается на вход программы символ за символом. Мы хотим << прочесть>> это число  (поместить в переменную типа real его значение). Кроме того, надо сообщить об ошибке, если число записано неверно.

Более конкретно, представим себе такую ситуацию. Последовательность символов на входе делится на прочитанную и оставшуюся части. Мы можем пользоваться функцией Next:char, которая дает первый символ оставшейся части, а также функцией Move, которая забирает первый символ из оставшейся части, переводя его в категорию прочитанных.

\begin{displaymath}
\begin{picture}
(17,4)

\thinlines 
 
\put(1,1){\line(1,0){1...
 ...rm ?}}}}
\put(13,1){\makebox(2,2){{\hbox{\rm ?}}}}\end{picture}\end{displaymath}

Будем называть десятичной записью такую последовательность символов: \begin{displaymath}
\langle 0\ {\hbox{\rm или более пробелов}}\rangle\
 \langle 1\ {\hbox{\rm или более цифр}}\rangle,\end{displaymath}а также такую: \begin{displaymath}
\langle 0\ {\hbox{\rm или более пробелов}}\rangle\
 \langle ...
 ...e{\hbox{\tt .}}
 \langle 1\ {\hbox{\rm или более цифр}}\rangle.\end{displaymath}Заметим, что согласно этому определению 01. 1 \begin{displaymath}
{\hbox{\tt 1.}} \qquad \qquad {\hbox{\tt .1}} \qquad \qquad
 \box0 \qquad \qquad {\hbox{\tt -1.1}}\end{displaymath}не являются десятичными записями. Сформулируем теперь задачу точно:


$\scriptstyle{\blacktriangleright}$ 5.2.1. Прочесть из входной строки максимальную часть, которая может быть началом десятичной записи. Определить, является ли эта часть десятичной записью или нет.

Решение. Запишем программу на паскале (используя << перечислимый тип>> для наглядности записи: переменная state может принимать одно из значений, указанных в скобках).
    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 не сопровождаются сдвигом (символ, который не может быть частью числа, не забирается).$\scriptstyle\blacktriangleleft$

Приведенная программа не запоминает значение прочитанного числа.


$\scriptstyle{\blacktriangleright}$ 5.2.2. Решить предыдущую задачу с дополнительным требованием: если прочитанный кусок является десятичной записью, то в переменную val:real следует поместить ее значение.

Решение. При чтении дробной части используется переменная step -- множитель при следующей десятичной цифре.
    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;`


$\scriptstyle{\blacktriangleright}$ 5.2.3. Та же задача, если перед числом может стоять знак - или знак + (а может ничего не стоять).$\scriptstyle\blacktriangleleft$

Формат чисел в этой задаче обычно иллюстрируют такой картинкой:

\begin{displaymath}
\begin{picture}
(23,6)

\thinlines 
 
\put(1,4.5){\line(1,0)...
 ...\vector(-1,0){2.5}}
\put(20,1){\vector(-1,0){2.5}}\end{picture}\end{displaymath}


$\scriptstyle{\blacktriangleright}$ 5.2.4. Та же задача, если к тому же после числа может стоять показатель степени десяти, как в 254E-4 (=0.0254 ) или в 0.123E+9 ($=123\,000\,000$). Нарисуйте соответствующую картинку.$\scriptstyle\blacktriangleleft$


$\scriptstyle{\blacktriangleright}$ 5.2.5. Что надо изменить в приведенной выше программе, чтобы разрешить пустые целую и дробную части (как в 1., .1 или даже . -- последнее число считаем равным нулю)?$\scriptstyle\blacktriangleleft$

Мы вернемся к конечным автоматам в главе 10 (Сравнение с образцом).



pvv
1/8/1999