SoftCraft
разноликое программирование

Отправная точка
Программирование
Windows API
Автоматы
Нейроинформатика
Парадигмы
Параллелизм
Проектирование
Теория
Техника кодирования
Трансляторы
Учебный процесс
Прочие вопросы

Разное

Беллетристика
Брюзжалки
Цели и задачи
Об авторе


О программировании за 1 минуту


19.10.2002

Появление на сайте статьи Константина Вавилова "Программирование за... 1 (одну) минуту" высветило еще одного сторонника автоматов. При этом я хотел бы отметить два основных момента:

  1. В работе рассматривается решение задачи, типичной для автоматного программирования, что полностью лишило меня повода поспекулировать на несоответствиях между предметной областью и методом решения.
  2. Сама задача не столь существенна и используется в более важных целях: для иллюстрации инструмента, позволяющего формировать код из визуального образа, построенного с использованием графического редактора MS Word.

Таким образом, появился еще один инструмент, позволяющий использовать стандартные средства для визуального представления автомата и его преобразования в код, построенный в соответствии с принципами, декларируемыми switch-технологией. Напомню, что чуть ранее на сайте был представлен конвертер Александра Головешина, осуществляющий преобразование в код аналогичных автоматных диаграмм, нарисованных в Visio.

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

Конечно, стоит отметить, что оба конвертора еще далеки от совершенства, однако их появление уже позволяет говорить о практической полезности инструментов, опирающихся на использование стандартных средств. Представляемая работа, к тому же обеспечивает хорошую методическую поддержку данному направлению.

Начинает сбываться мое нагловатое пожелание, опубликованное аж 19.02.2001 в 8-м письме рассылки:

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

Не удержусь и от цитирования реплики А.А. Шалыто и Н.И. Туккеля по этому поводу.

Кроме этого, хотим не согласиться с Вами, и надеемся, что наше мнение будет донесено до читателей сайта, или хотя бы рассылки Многие, в том числе и Вы, считают, что каждая технология должна быть подкреплена соответствующим инструментальным средством - "специализированной надстройкой, ориентированной на конечных пользователей, рассматриваемой ими, как средство проектирования"...

Подробности воспроизведены в соответствующих брюзжалках.

Таким образом, не надо работать в MS и т.д. чтобы, в конце концов прийти к идее более полного и быстрого удовлетворения своих потребностей посредством удобных инструментов.

В связи с этим хотелось бы выразить сожаление тупиковым состоянием работ по использованию автоматного программирования в среде "Флоры". Хотя, все, вроде бы, хорошо начиналось. В рамках "Флоры" даже появились объекты, непосредственно поддерживающие автоматное программирование. Возможно, проблема заключается в непосредственной интерпретации автоматной модели вместо перекодировки имеющихся объектов в код на языке C. Может быть, сказалось отсутствие методического обеспечение в виде набора "успешных историй", типа той, которая представлена сейчас. Будем надеяться, что автоматный кризис во "Флоре" - явление временное.

Отделение представления модели от кода навело меня еще на одну крамольную мысль (надо хоть в чем-то поперечить:). В общем-то, мысль старая и касается любимого мною оператора goto (автор его обидел:). Высказывалась много раз: разве использование оператора присваивания вместо goto и case вместо метки делает каркас программы нагляднее? Тем более, что программа-то генерируется автоматически. По своей структуре автоматная модель, задаваемая произвольным графом, не позволяет воспринимать код так как завещал Дейкстра. Все равно, мысленно придется прыгать по состояниям. Поэтому, почему бы непосредственно не порождать вот такой код (опираюсь на пример, используемый в статье)?


// Автомат имитации работы затвора.
// Проверка условий переходов.

// Вместо switch( AIPS ) {
  _0: // Метка - состояние
    // Вызов вложенных автоматов и выполнение
    // выходных функций в состояниях....

    // Переходы данного состояния
    if((H==9))              { z3=1; zt2=1;                 goto _103; }
    if((H==10))             { z4=1; zt2=1;                 goto _104; }
    if(x1)                  { zt1=1;                       goto _101; }
    if(x2)                  { zt1=1;                       goto _102; }
    goto _break;

  _1:
    // Вызов вложенных автоматов и выполнение
    // выходных функций в состояниях....

    // Переходы данного состояния
    if((H==9))              { zN2=1; z3=1; zt2 = 1;        goto _103; }
    if(x1 && x0)            { zt1=1;                       goto _101; }
    goto _break;

  _2:
    // Вызов вложенных автоматов и выполнение
    // выходных функций в состояниях....

    // Переходы данного состояния
    if((H==10))             { zN1=1; z4=1; zt2=1;          goto _104; }
    if(x2 && x0)            { zt1=1;                       goto _102; }
    goto _break;

  _101:
    // Вызов вложенных автоматов и выполнение
    // выходных функций в состояниях....

    // Переходы данного состояния
    if(T1)                  { zN2=1; z3=1; zNt1=1; zt2=1;  goto _103; }
    if((!x1 || !x0) && x2)  { zNt1=1;                      goto _1; }
    if((!x1 || !x0) && !x2) { zNt1=1;                      goto _0; }
    goto _break;

  _102:
    // Вызов вложенных автоматов и выполнение
    // выходных функций в состояниях....

    // Переходы данного состояния
    if(T1)                  { zN1=1; z4=1; zNt1=1; zt2=1;  goto _104; }
    if((!x2 || !x0) && x1)  { zNt1=1;                      goto _2; }
    if((!x2 || !x0) && !x1) { zNt1=1;                      goto _0; }
    goto _break;

  _103:
    // Вызов вложенных автоматов и выполнение
    // выходных функций в состояниях....

    // Переходы данного состояния
    if(T2 && (H!=7))        { z1=1; zt1=1; zNt2=1;         goto _105; }
    if(T2 && (H==7))        { zN3=1; zNt2=1;               goto _0; }
    if(x3)                  { zt1=1;                       goto _107; }
    goto _break;

  _104:
    // Вызов вложенных автоматов и выполнение
    // выходных функций в состояниях....

    // Переходы данного состояния
    if(T2 && (H!=8))        { z2=1; zt1=1; zNt2=1;         goto _106; }
    if(T2 && (H==8))        { zN4=1; zNt2=1;               goto _0; }
    if(x3)                  { zt1=1;                       goto _108; }
    goto _break;

  _105:
    // Вызов вложенных автоматов и выполнение
    // выходных функций в состояниях....

    // Переходы данного состояния
    if(T1)                  { zN3=1; zNt1=1;               goto _2; }
    if((H==5))              { zNt1=1;                      goto _202; }
    goto _break;

  _106:
    // Вызов вложенных автоматов и выполнение
    // выходных функций в состояниях....

    // Переходы данного состояния
    if(T1)                  { zN4=1; zNt1=1;               goto _1; }
    if((H==6))              { zNt1=1;                      goto _201; }
    goto _break;

  _107:
    // Вызов вложенных автоматов и выполнение
    // выходных функций в состояниях....

    // Переходы данного состояния
    if(!x3)                 { zNt1=1;                      goto _103; }
    if(T1)                  { zN3=1; zNt1=1; zNt2=1;       goto _0; }
    goto _break;

  _108:
    // Вызов вложенных автоматов и выполнение
    // выходных функций в состояниях....

    // Переходы данного состояния
    if(!x3)                 { zNt1=1;                      goto _104; }
    if(T1)                  { zN4=1; zNt1=1; zNt2=1;       goto _0; }
    goto _break;

  _201:
    // Вызов вложенных автоматов и выполнение
    // выходных функций в состояниях....

    // Переходы данного состояния
    if((H!=6))              { zN4=1;                       goto _1; }
    goto _break;

  _202:
    // Вызов вложенных автоматов и выполнение
    // выходных функций в состояниях....

    // Переходы данного состояния
    if((H!=5))              { zN3=1;                       goto _2; }
    goto _break;

  _break: ;
// };

В структурном программировании, в свое время, сложилась довольно типичная для России ситуация. Одному Уважаемому Человеку взбрело в голову, что программа должна исполняться так как она читается, а goto - это зло. Этот частный случай, удобный при решении определенного класса задач, был затем доведен подпевалами до абсурда, что привело к физическому уничтожению несчастного оператора в ряде языков. Инквизиция жгла старые книги, пела дифирамбы кастратам, а в школах запретили даже упоминание обрезанного рудимента (ставшего атавизмом). В результате начали появляться изящные и тормозные конструкции даже там, где можно было описать задачу использованием непосредственного управления.

Однако, в данном случае, я не собираюсь поднимать дискуссию о том, какой вариант кода лучше. Выигрывая в скорости, мы проигрываем, например, в тестировании или других технологических параметрах. Кроме того, найдутся фанаты ООП (или еще чего...), которые станут убеждать, что лучше всего использовать паттерн State. Хотелось бы, в зависимости от целей и задач генерировать ту разновидность кода, которая лучше всего подходит к конкретным условиям. Или, что может быть положительно воспринято другими, в иной язык программирования.

Мое желание можно истолковать как призыв к авторам конвертеров вставить всевозможные разновидности генераторов выходного представления. Конечно же, это не так. Прямая реализация естественно будет опираться на полюбившийся метод, т.е., switch. Но можно попытаться предусмотреть возможность альтернативного расширения созданного продукта другими. Для этого существуют различные пути:

  • открыть код для всеобщей модернизации и получить хаос конвертеров, но для разных вариантов;
  • при закрытом коде сформировать интерфейс к библиотеке, а желающие будут дописывать свои генераторы (по примеру паттерна Observer);
  • осуществить преобразование в общее промежуточное представление, для которого достаточно легко можно будет написать любой конвертер (например в автоматное подмножество XML, реализация которого могла бы плодотворно сказаться на стандартизации автоматного программирования).

Кстати, я бы с удовольствием почитал статьи об объектных моделях Visio и графического редактора MS Word, используемых для преобразования и методах их преобразования в другие формы. Мне кажется, что подобный материал был бы интересен и для печатных журналов, а не только для размещения на сайтах. Возможно, что начитавшись, я вдохновился бы идеей создания собственного инструмента для написания распознователей по диаграммам Вирта или иному, близкому к ним представлению. Жаль, что авторам интересен другой аспект. И список используемых источников отсутствует:(.