                     Решения задач
                     -------------

6.2.2. Задача 2 (8 баллов)
Средний бал решений: 6.3 (78%)

 Введем следующее определение:
Определение
-----------
<выражение> ::= <число>+<число> | <выражение>+<число>
<число> ::= <целое> | <дробь>
<целое> ::= <цифра> | <целое><цифра>
<дробь> ::= .<целое> | <целое>. | <целое>.<целое>
<цифра> ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9

   Задание. Напишите программу, которая проверяет запись на лен-
те и помещает результат проверки справа от нее в виде  двух букв:
   ош - запись не является ни числом, ни выражением;
   чс - запись есть "число";
   вр - запись есть "выражение";

   В начальный момент окошко расположено перед записью, а в кон-
це работы - сразу за ней, если в записи нет ошибок.
   Если запись содержит ошибки, окошко должно  указывать на пер-
вый ошибочный символ.

   Примеры работы программы:

Начальное состояние                 После работы программы
┬─┬─╦═╦─┬─┬─┬─┬─┬─┬─┐               ┬─┬─┬─┬─┬─┬─╦═╦─┬─┬─┐
│░│░║░║1│2│7│░│░│░│░│    ─────>     │░│░│░│1│2│7║░║ч│с│░│
┴─┴─╩═╩─┴─┴─┴─┴─┴─┴─┘               ┴─┴─┴─┴─┴─┴─╩═╩─┴─┴─┘
Начальное состояние                 После работы программы
┬─┬─╦═╦─┬─┬─┬─┬─┬─┬─┐               ┬─┬─┬─┬─┬─┬─╦═╦─┬─┬─┐
│░│░║░║1│.│7│░│░│░│░│    ─────>     │░│░│░│1│.│7║░║ч│с│░│
┴─┴─╩═╩─┴─┴─┴─┴─┴─┴─┘               ┴─┴─┴─┴─┴─┴─╩═╩─┴─┴─┘

Начальное состояние                 После работы программы
┬─┬─╦═╦─┬─┬─┬─┬─┬─┬─┐               ┬─┬─┬─┬─┬─┬─┬─┬─╦═╦─┬─┬─┐
│░│░║░║1│.│7│+│1│░│░│    ─────>     │░│░│░│1│.│7│+│1║░║в│р│░│
┴─┴─╩═╩─┴─┴─┴─┴─┴─┴─┘               ┴─┴─┴─┴─┴─┴─┴─┴─╩═╩─┴─┴─┘

Начальное состояние                 После работы программы
┬─┬─╦═╦─┬─┬─┬─┬─┬─┬─┐               ┬─┬─┬─┬─╦═╦─┬─┬─┬─┬─┐
│░│░║░║1│!│9│░│░│░│░│    ─────>     │░│░│░│1║!║9│░│о│ш│░│
┴─┴─╩═╩─┴─┴─┴─┴─┴─┴─┘               ┴─┴─┴─┴─╩═╩─┴─┴─┴─┴─┘

Решение куратора
   Если при анализе  записи ошибок не обнаружено, то запись яв-
ляется выражением тогда, когда в ней был хотя бы один  знак "+"
или числом, если знаков "+" не было.
   Иными словами необходимо фиксировать  появление  знаков "+",
чтобы после  полного  анализа записи написать правильный ответ.
   Эта часть алгоритма  не отражена в схеме (чтобы не загромож-
дать  ее  деталями), но очень легко программируется при  помощи
ящика Корректора.

      (ответ)          (ошибка)
          ^             ^ ^
          │пусто        │ │
          │             │ │остальное
   цифра  │   остальное │ │
  ┌─────┐ │  ┌──────────┘ │
  │     │ │  │            │
  │     V │  │    цифра   │      .                 остальное
  └──── (целое) <───────(вход)───────────>(дробь?) ─────────>(ошибка)
         ^ │  │                              │
     ┌───┘ │  │ .                   цифра    │
цифра│     │  └──────┐            ┌──────┐   │цифра
     │     │         │            │      │   │
     │     │ +       │            │      V   V  остальное
     │     │         │            └──── (дробь) ─────────────>(ошибка)
     │     │         │                  ^  │  │ пусто
     │     │         └──────────────────┘  │  └──────────────>(ответ)
     │     │                               │+
     │     │   ┌───────────────────────────┘
     │     │   │
     │     V   V      остальное
     └─(начало_числа) ────────>(ошибка)
           │ .
           └──────────────────>(дробь?)

ЭТО вход
 ПИШИ 0     //| Установим ящик
 ЯЩИК+      //| в состояние:
 ПИШИ ПУСТО //| знаков "+" нет
 ВПРАВО                                
 ЕСЛИ       ЦИФРА ТО целое             
 ИНАЧЕ ЕСЛИ .     ТО дробь?
 ИНАЧЕ ошибка
КОНЕЦ                                  
                                       
ЭТО целое
 ВПРАВО
 ЕСЛИ       ЦИФРА ТО целое             
 ИНАЧЕ ЕСЛИ .     ТО дробь             
 ИНАЧЕ ЕСЛИ +     ТО начало_числа      
 ИНАЧЕ ЕСЛИ ПУСТО ТО ответ             
 ИНАЧЕ ошибка
КОНЕЦ
                                       
ЭТО начало_числа                       
 ОБМЕН  //| Установим ящик
 ПИШИ 1 //| в состояние:
 ОБМЕН  //| знак "+" был
 ВПРАВО
 ЕСЛИ       ЦИФРА ТО целое             
 ИНАЧЕ ЕСЛИ .     ТО дробь?            
 ИНАЧЕ ошибка                          
КОНЕЦ                                  

ЭТО дробь?
 ВПРАВО                                
 ЕСЛИ ЦИФРА ТО дробь                   
 ИНАЧЕ ошибка
КОНЕЦ
                                       
ЭТО дробь                              
 ВПРАВО                                
 ЕСЛИ       ПУСТО ТО ответ             
 ИНАЧЕ ЕСЛИ ЦИФРА ТО дробь
 ИНАЧЕ ЕСЛИ +     ТО начало_числа
 ИНАЧЕ ошибка                          
КОНЕЦ                                  
                                       
ЭТО ответ                              
 ОБМЕН
 ЕСЛИ 0 ТО ответ_число
 ИНАЧЕ ответ_выражение                 
КОНЕЦ                                  
                                       
ЭТО ответ_число
 ОБМЕН
 ВПРАВО ПИШИ ч
 ВПРАВО ПИШИ л
 ПОВТОРИ 2 ВЛЕВО
КОНЕЦ

ЭТО ответ_выражение
 ОБМЕН                                 
 ВПРАВО ПИШИ в
 ВПРАВО ПИШИ р
 ПОВТОРИ 2 ВЛЕВО
КОНЕЦ                                  

ЭТО ошибка
 ВПРАВО                                
 ЕСЛИ ПУСТО                            
  ТО ответ_ошибка
  ИНАЧЕ ошибка
 ВЛЕВО                                 
КОНЕЦ                                  
                                       
ЭТО ответ_ошибка
 ВПРАВО ПИШИ о
 ВПРАВО ПИШИ ш
 ПОВТОРИ 2 ВЛЕВО
КОНЕЦ                                  

Типичные ошибки в конкурсных решениях
-------------------------------------

   1) Программа считает  пустую  ленту  числом,  а  записи типа
"+1", "+1.+1" - выражениями.

   2) На записях "1+", "1+." ошибка показана  на последнем сим-
воле, что  неверно  (ошибкой  является  символ  ПУСТО за знаком
"+").
   В записи "1+.+1" в  качестве  ошибки указана точка. На самом
деле первый ошибочный знак - это второй знак "+".

   3) замечания по стилю записи программ

   Текст ВПРАВО ПОКА НЕ ПУСТО читается очень двусмысленно.
   Вроде как двигаемся вправо, пока не пусто. То есть, налицо си-
туация, когда форма  записи не помогает понять программу, а, на-
оборот, максимально усложняет.

Авторская запись                  │А вот так понятнее
──────────────────────────────────┼────────────────────────────
//--------------------------------│//--------------------------------
ЭТО Запись_вр_или_чс              │ЭТО Запись_вр_или_чс
 ВПРАВО ПОКА НЕ ПУСТО             │ ВПРАВО
  { ЕСЛИ + ТО ЯЩИК+ ВПРАВО }      │ ПОКА НЕ ПУСТО
 ВПРАВО                           │ {
 ОБМЕН                            │   ЕСЛИ + ТО ЯЩИК+
 ЕСЛИ + ТО { ПИШИ в ВПРАВО ПИШИ р │   ВПРАВО
             ПОВТОРИ 2 ВЛЕВО }    │ }
  ИНАЧЕ { ПИШИ ч ВПРАВО ПИШИ с    │ ВПРАВО ОБМЕН
          ПОВТОРИ 2 ВЛЕВО }       │ ЕСЛИ + ТО
 ВЛЕВО                            │ {
 ПОКА НЕ ПУСТО ВЛЕВО              │   ПИШИ в ВПРАВО
КОНЕЦ                             │   ПИШИ р ПОВТОРИ 2 ВЛЕВО
//--------------------------------│ }
                                  │ ИНАЧЕ
                                  │ {
                                  │   ПИШИ ч ВПРАВО
                                  │   ПИШИ с ПОВТОРИ 2 ВЛЕВО
                                  │ }
                                  │ ВЛЕВО
                                  │ ПОКА НЕ ПУСТО ВЛЕВО
                                  │КОНЕЦ
                                  │//-------------------------------



   Ошибки типа:
   - (1) строчки неоправданно забиваются плотным программным кодом;
   - (2) нет отступов в записи сложных команд языка;
   - (3) процедуры отделяются друг от друга не очень удачно;
   - (4) переключатели оформляются плохо читаемым образом;
   - (5) имена процедур записываются заглавными буквами;
   - (6) имена процедур не всегда осмысленные.

   иллюстрируются следующими примерами:

(1)                                │
...                                │
ВПРАВО ЕСЛИ Я=Л ТО Ош_1            │Можно прочитать как "идти вправо если символ
...                                │в ящике равен символу на ленте.
                                   │
{ ЕСЛИ Я=Л ТО ПИШИ ПРОБЕЛ Замена } │Можно подумать, что если ящик равен ленте,
...                                │выполняются две команды ПИШИ ПРОБЕЛ и Замена.
                                   │
и так далее                        │

(2)
                                   │
 ЕСЛИ НЕ ПУСТО ТО                  │ ЕСЛИ НЕ ПУСТО ТО
 {                                 │    ЕСЛИ Я=Л ТО ДО_КОНЦА
 ЕСЛИ Я=Л ТО ДО_КОНЦА ИНАЧЕ НАЧАЛО │    ИНАЧЕ       НАЧАЛО
 }                                 │ ИНАЧЕ Число
ИНАЧЕ Число                        │
                                   │
....                               │
                                   │
ЕСЛИ Я=Л ТО  Ош_1                  │ ЕСЛИ Я=Л ТО  Ош_1
ИНАЧЕ                              │ ИНАЧЕ
{                                  │ {
ВПРАВО ВПРАВО ПИШИ в ВПРАВО ПИШИ р │   ВПРАВО
ВЛЕВО ВЛЕВО                        │   ВПРАВО ПИШИ в
}                                  │   ВПРАВО ПИШИ р
                                   │   ВЛЕВО ВЛЕВО
и так далее                        │ }
                                   │
(3)                                │Идея использовать в качестве разделителя
                                   │процедур строку
                                   │//                            !!
                                   │не очень удачная. Лучше использовать пустые
                                   │строки или такие, как в этом примере:
                                   │
//                            !!   │ //------------------------------
ЭТО Число                          │ // Проверяет корректность записи
// Проверяет корректность записи   │ ЭТО Число
ВОЗВРАТ                            │   ВОЗВРАТ
ПИШИ . ЯЩИК+ ПИШИ ПУСТО            │   ПИШИ .
Чи_пр                              │   ЯЩИК+
КОНЕЦ                              │   ПИШИ ПУСТО
//                              !! │   Чи_пр
ЭТО Выражение                      │ КОНЕЦ
// Проверяет правильность записи   │ //------------------------------
// выражения.                      │ // Проверяет правильность записи
ВОЗВРАТ                            │ ЭТО Выражение
Замена                             │   ВОЗВРАТ
КОНЕЦ                              │   Замена
//                               !!│ КОНЕЦ
                                   │ //------------------------------
                                   │
(4)                                │
                                   │
ЕСЛИ НЕ ПУСТО ТО                   │ ЕСЛИ НЕ ПУСТО ТО
{ ЕСЛИ Я=Л ТО Только               │   ЕСЛИ       Я=Л    ТО Только
  ИНАЧЕ ЕСЛИ ЦИФРА ТО То_Ци        │   ИНАЧЕ ЕСЛИ ЦИФРА  ТО То_Ци
        ИНАЧЕ ЕСЛИ ПРОБЕЛ ТО Парный│   ИНАЧЕ ЕСЛИ ПРОБЕЛ ТО Парный
              ИНАЧЕ Ош_1           │   ИНАЧЕ                Ош_1
}                                  │
                                   │
                                   │
                                   │
(5)                                │
                                   │
ЭТО ГЛАВНАЯ                        │ Процедуры для облегчения чтения
ЭТО НАЧАЛО                         │ лучше называть маленькими буквами
ЭТО ДО_КОНЦА                       │ (первую букву можно делать заглавной).
ЭТО ВОЗВРАТ                        │ Такой стиль улучшает чтение программного
                                   │ текста из-за того, что нарушается
                                   │ однородность записи и глазу будет за что
                                   │ "уцепиться".
                                   │
                                   │ ЭТО Главная
                                   │ ЭТО Начало
                                   │ ЭТО ДоКонца
                                   │ ЭТО Возврат
                                   │
(6)                                │
                                   │
                                   │
                                   │
ЭТО То_Ци // Точка или Цифра       │ЭТО ТочкаИлиЦифра
                                   │
ЭТО Чи_пр                          │ЭТО Запись-Число
// Запись есть "число".            │
                                   │


   Стиль записи  программы  одной  из  команд вызвал удивление,
близкое к шоку:

             ЭТО ПРОВЕРКА
ВПРАВО
КОРРЕКТОР
СТОЯТЬ
                 КОНЕЦ
             ЭТО КОРРЕКТОР
ВПРАВО
ЕСЛИ . ТО ТРОПА1
ИНАЧЕ ЕСЛИ ЦИФРА ТО ТРОПА1
ИНАЧЕ ЕСЛИ + ТО РОЛИК
ИНАЧЕ ЕСЛИ - ТО РОЛИК
ИНАЧЕ ЕСЛИ ПУСТО ТО КОНТРОЛЬ
ИНАЧЕ ОШИБКА
                 КОНЕЦ
               ЭТО РОЛИК

и так далее.
