Главная · Поиск книг · Поступления книг · Top 40 · Форумы · Ссылки · Читатели

Настройка текста
Перенос строк


    Прохождения игр    
Demon's Souls |#13| Storm King
Demon's Souls |#11| Мaneater part 2
Demon's Souls |#10| Мaneater (part 1)
Demon's Souls |#9| Heart of surprises

Другие игры...


liveinternet.ru: показано число просмотров за 24 часа, посетителей за 24 часа и за сегодня
Rambler's Top100
Образование - Различные авторы Весь текст 991.22 Kb

Программирование в теоремах и задачах

Предыдущая страница Следующая страница
1 ... 74 75 76 77 78 79 80  81 82 83 84 85
за B. Множество всех таких терминалов обозначим  Посл(N).  (Если
никакое N-слово не является собственным началом другого N-слова,
то множество Посл(N) пусто.)

     13.2.2. Указать (а) Посл(E) для примера 1;  (б)  Посл(E)  и
Посл(T)  для примера 2; (в) Посл(<слаг>) и Посл(<множ>) для при-
мера 3.
     Ответ.  (а)  Посл(e)  =  {  [, ( }. (б) Посл(e) = { [, ( };
Посл(t) пусто (никакое t-слово не является началом другого). (в)
Посл(<слаг>) = {*}; Посл(<множ>) пусто.

Кроме  того,  для  каждого  нетерминала N обозначим через Нач(N)
множество всех терминалов, являющихся первыми  буквами  непустых
N-слов.  Это  обозначение  - вместе с предыдущим - позволит дать
достаточное условие корректности процедуры ReadK в описанной вы-
ше ситуации.

     13.2.3.  Доказать,  что  если  Посл  (L)  не пересекается с
Нач(M) и множество всех M-слов непусто, то ReadK корректна.

     Решение. Рассмотрим два случая. (1) Пусть после ReadL  зна-
чение  переменной  b  ложно. В этом случае ReadM читает со входа
максимальное M-начало A, не являющееся  M-словом.  Оно  является
K-началом (здесь важно, что множество L-слов непусто.). Будет ли
оно максимальным K-началом среди начал входа? Если нет, то A яв-
ляется  началом  слова BC, где B есть L-слово, C есть M-начало и
BC - более длинное начало входа, чем A. Если B длиннее A, то A -
не максимальное начало входа, являющееся L-началом, что противо-
речит корректности ReadL. Если B = A, то A было бы  L-словом,  а
это  не так. Значит, B короче A, C непусто и первый символ слова
C следует в A за последним символом слова B, т.е. Посл(L)  пере-
секается с Нач(M). Противоречие. Итак, A максимально. Из сказан-
ного  следует  также,  что  A не является K-словом. Корректность
процедуры ReadK в этом случае проверена.
     (2) Пусть после ReadL значение переменной b истинно.  Тогда
прочитанное  процедурой  ReadK  начало входа имеет вид AB, где A
есть L-слово, а B есть M-начало. Тем  самым  AB  есть  K-начало.
Проверим его максимальность. Пусть C есть большее K-начало. Тог-
да  либо  C есть L-начало (что невозможно, так как A было макси-
мальным L-началом), либо C = A'B', где A' - L-слово, B' -  M-на-
чало.  Если  A'  короче A, то B' непусто и начинается с символа,
принадлежащего и Нач(M), и  Посл(L),  что  невозможно.  Если  A'
длиннее  A,  то  это противоречит тому, что A было максимальным.
Итак, A' = A. Но в этом случае B' есть продолжение B, что проти-
воречит корректности ReadM. Итак, AB  -  максимальное  K-начало.
Остается  проверить  правильность  выдаваемого  процедурой ReadK
значения переменной b. Если оно истинно, то это  очевидно.  Если
оно  ложно,  то B не есть M-слово, и надо проверить, что AB - не
K-слово. В самом деле, если бы выполнялось AB = A'B', где  A'  -
L-слово,  B' - M-слово, то A' не может быть длиннее A (ReadL чи-
тает максимальное слово), A' не может быть  равно  A  (тогда  B'
равно  B  и  не  является  M-словом) и A' не может быть короче A
(тогда первый символ B' принадлежит и Нач(M), и Посл(L)). Задача
решена.

     Перейдем теперь к другому частному случаю. Пусть в КС-грам-
матике есть правила
        K -> L
        K -> M
        K -> N
и других правил с левой частью K нет.

     13.2.4.  Считая, что ReadL, ReadM и ReadN корректны (для L,
M и N) и что множества Нач(L), Нач(M) и Нач(N) не  пересекаются,
написать процедуру, корректную для K.

     Решение. Схема процедуры такова:

     procedure ReadK;
     begin
     | if (Next принадлежит Нач(L)) then begin
     | | ReadL;
     | end else if (Next принадлежит Нач(M)) then begin
     | | ReadM;
     | end else if (Next принадлежит Нач(N)) then begin
     | | ReadN;
     | end else begin
     | | b := true или false  в зависимости от того,
     | |      выводимо ли пустое слово из K или нет
     | end;
     end;

Докажем, что ReadK корректно реализует K. Если Next не принадле-
жит ни одному из множеств Нач(L), Нач(M), Нач(N),то пустое слово
является наибольшим началом входа,  являющимся  K-началом.  Если
Next  принадлежит  одному  (и,  следовательно, только одному) из
этих множеств, то максимальное начало входа, являющееся  K-нача-
лом, непусто и читается соответствующей процедурой.

     13.2.5. Используя сказанное, составьте процедуру  распозна-
вания  выражений для грамматики (уже рассматривавшейся в примере
3):

    <выр>     -> <слаг> <оствыр>
    <оствыр>  -> + <выр>
    <оствыр>  ->
    <слаг>    -> <множ> <остслаг>
    <остслаг> -> * <слаг>
    <остслаг> ->
    <множ>    -> x
    <множ>    -> ( <выр> )

     Решение. Эта грамматика не полностью подпадает под рассмот-
ренные частные случаи: в правых частях есть комбинации  термина-
лов и нетерминалов
        + <выр>
и группы из трех символов
        ( <выр> )
В  грамматике есть также несколько правил с одной левой частью и
с правыми частями разного рода, например
    <оствыр>  -> + <выр>
    <оствыр>  ->
Эти ограничения не являются принципиальными. Так, правило типа
        K -> L M N
можно  было бы заменить на два правила K -> LQ и Q -> MN, терми-
нальные символы в правой части - на нетерминалы  (с  едиственным
правилом  замены на соответствующие терминалы). Несколько правил
с одной левой частью и разнородными правыми также можно свести к
уже разобранному случаю: например,

        K -> L M N
        K -> P Q
        K ->

можно заменить на правила

        K  -> K1
        K  -> K2
        K  -> K3
        K1 -> L M N
        K2 -> P Q
        K3 ->

Но  мы  не будем этого делать - а сразу же запишем то, что полу-
чится, если подставить описания процедур для новых  терминальных
символов в места их использования. Например, для правила
        K -> L M N
это дает процедуру

        procedure ReadK;
        begin
        | ReadL;
        | if b then begin ReadM; end;
        | if b then begin ReadN; end;
        end;

Для  ее  корректности  надо,  чтобы  Посл(L)  не  пересекалось с
Нач(MN) (которое равно Нач(M), если из  M  не  выводится  пустое
слово,  и  равно объединению Нач(M) и Нач(N), если выводится), а
также чтобы Посл(M) не пересекалось с Нач(N).
     Аналогичным образом правила
        K -> L M N
        K -> P Q
        K ->
приводят к процедуре

        procedure ReadK;
        begin
        | if (Next принадлежит Нач(LMN)) then begin
        | | ReadB;
        | | if b then begin ReadM; end;
        | | if b then begin ReadN; end;
        | end else if (Next принадлежит Нач(PQ)) then begin
        | | ReadP;
        | | if b then begin ReadQ; end;
        | end else begin
        | | b := true;
        | end;
        end;
Читая  приведенную  далее  программу, полезно иметь в виду соот-
ветствие между русскими и английскими словами:

        ВЫРажение               EXPRession
        ОСТаток ВЫРажения       REST of EXPRession
        СЛАГаемое               ADDitive term
        ОСТаток СЛАГаемого      REST of ADDitive term
        МНОЖитель               MULTiplier

     procedure ReadSymb (c: Symbol);
     | b := (Next = c);
     | if b then begin Move; end;
     end;

     procedure ReadExpr;
     | ReadAdd;
     | if b then begin ReadRestExpr; end;
     end;

     procedure ReadRestExpr;
     | if Next = '+' then begin
     | | ReadSymb ('+');
     | | if b then begin ReadExpr; end;
     | end else begin
     | | b := true;
     | end;
     end;

     procedure ReadAdd;
     | ReadMult;
     | if b then begin ReadRestAdd; end;
     end;

     procedure ReadRestAdd;
     | if Next = '*' then begin
     | | ReadSymb ('*');
     | | if b then begin ReadAdd; end;
     | end else begin
     | | b := true;
     | end;
     end;

     procedure ReadMult;
     | if Next = 'x' then begin
     | | ReadSymb ('x');
     | end else if Next = '(' then begin
     | | ReadSymb ('(');
     | | if b then begin ReadExpr; end;
     | | if b then begin ReadSymb (')'); end;
     | end else begin
     | | b := false;
     | end;
     end;

Осталось  обсудить проблемы, связанные с взаимной рекурсивностью
этих процедур (одна использует другую и наоборот). В паскале это
допускается, только требуется дать предварительное описание про-
цедур  ("forward").  Как всегда для рекурсивных процедур, помимо
доказательства того, что каждая процедура работает  правильно  в
предположении,  что  используемые в ней вызовы процедур работают
правильно, надо доказать отдельно, что работа завершается.  (Это
не  очевидно: если бы в грамматике было правило K -> KK, то из K
ничего не выводится, Посл(K) и Нач(K) пусты,  но  написанная  по
нашим канонам процедура

     procedure ReadK;
     begin
     | ReadK;
     | if b then begin
     | | ReadK;
     | end;
     end;

не заканчивает работы.)
     В   даннном  случае  процедуры  ReadRestExpr,  ReadRestAdd,
ReadMult либо завершаются, либо  уменьшают  длину  непрочитанной
части  входа. Поскольку любой цикл вызовов включает одну из них,
то зацикливание невозможно. Задача решена.

     13.2.6. Пусть в грамматике имеются два правила  с  нетерми-
иналом K в левой части, имеющих вид
        K -> LK
        K ->
по   которым  K-слово  представляет  собой  конечную  последова-
тельность L-слов, причем множества Посл(L) и  Нач(K)  (в  данном
случае  равное Нач(L)) не пересекаются. Используя корректную для
L процедуру ReadL, написать корректную для K процедуру ReadK, не
используя рекурсии. Предполагается, что пустое слово не выводимо
из L.

     Решение. По нашим правилам следовало бы написать

     procedure ReadK;
     begin
     | if (Next принадлежит Нач (L)) then begin
     | | ReadL;
     | | if b then begin ReadK; end;
     | end else begin
     | | b := true;
     | end;
     end;

завершение работы гарантируется тем, что пустое слово не выводи-
мо из L (и, следовательно, перед рекурсивным вызовом длина  неп-
рочитанной части уменьшается).
     Эта рекурсивная процедура эквивалентна нерекурсивной:

     procedure ReadK;
     begin
     | b := true;
     | while b and (Next принадлежит Нач (L)) do begin
     | | ReadL;
     | end;
     end;

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

     if (Next принадлежит Нач (K)) then begin
     | ReadL;
     | if b then begin
     | | b := true;
     | | while b and (Next принадлежит Нач (L)) do begin
     | | | ReadL;
     | | end;
     | end;
     end else begin
     | b := true;
     end;

Первую команду b := true можно выкинуть (в этом месте  и  так  b
истинно). Вторую команду можно перенести в начало:

     b := true;
     if (Next принадлежит Нач (K)) then begin
     | ReadL;
     | if b then begin
     | | while b and (Next принадлежит Нач (L)) do begin
     | | | ReadL;
     | | end;
     | end;
     end;

Теперь  внутренний  if  можно выкинуть (если b ложно, цикл while
все равно не выполняется) и добавить в условие внешнего if усло-
вие b (которое все равно истинно).

     b := true;
     if b and (Next принадлежит Нач (L)) then begin
     | ReadL;
     | while b and (Next принадлежит Нач (A)) do begin
     | | ReadL;
     | end;
     end;

что эквивалентно приведенной выше  нерекурсивной  процедуре  (из
которой вынесена первая итерация цикла).

     13.2.7.  Доказать корректность приведенной выше нерекурсив-
ной программы непосредственно, без ссылок на рекурсивную.

     Решение. Рассмотрим  наибольшее  начало  входа,  являющееся
K-началом.  Оно  представляется  в виде конкатенации (последова-
тельного приписывания) нескольких непустых L-слов  и,  возможно,
одного  непустого  L-начала,  не являющегося L-словом. Инвариант
цикла: прочитано несколько из них; b <=> (последнее  прочитанное
Предыдущая страница Следующая страница
1 ... 74 75 76 77 78 79 80  81 82 83 84 85
Ваша оценка:
Комментарий:
  Подпись:
(Чтобы комментарии всегда подписывались Вашим именем, можете зарегистрироваться в Клубе читателей)
  Сайт:
 
Комментарии (1)

Реклама