ВИЗУАЛИЗАЦИЯ ПРОГРАММНОЙ ЛОГИКИ ВЕРХНЕГО УРОВНЯ

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

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

Для процедур описания логики работы верхнего уровня желательно
выполнение следующих условий:
1) эти процедуры должны быть написаны в стиле самодокументирования;
2) возможность автоматической генерации визуальных схем этих процедур
из их исходного кода без добавления в него каких-либо служебных
комментариев.

Я постарался выполнить оба эти условия для следующего частного случая:
1) В качестве языка программирования используется русскоязычная версия КП;
2) для автоматической генерации визуальных схем из исходного кода
процедур логики верхнего уровня используется программа dal2html v.0.86 от 16.10.2013.

При этом в файле конфигурации программы dal2html были заданы следующие
ключевые слова для построения схемы из исходного кода процедуры:
## Код:
```
;
; ключевые слова для программы: 
;
__строка_док_IF        "ЕСЛИ"            ; начало условия
__строка_док_EI        "ИНЕСЛИ"          ; дополнительное условие   
__строка_док_EB        "ИНАЧЕ"           ; альтернатива условиям
__строка_док_END       "КОНЕЦ"           ; конец условия
__строка_док_CB        "ЦИКЛ"       
__строка_док_CE        "КОНЕЦ_ЦИКЛА" 
__строка_док_A         "(**"             ; основное начало действия   
;                                        ; простейшее задание действия
;                                        ; для программы:  (**)
__строка_док_RET       "ВЫХОД"           ; оператор возврата,
;                                        ; возможно с параметром                                            
__строка_док_STOP      "КОНЕЦ_ПРОЦЕДУРЫ"         
__проверка_ветки       "ветка ="         ; в условии
__переход_к_ветке      "ветка :="        ; путем присваивания 
;                                        ; нового значения
;
__альтернативные_начала_действия "команда(| := "  ; разделены "|"
;
; альтернативное начало действия должно присутствовать в строке,
; но не обязано находиться в ее начале в отличие от основных
; ключевых слов
```

Для КП в файл <каталог BB>/i21edu/Rsrc/ru.odc я добавил следующие
соответствия между английскими и русскими ключевыми словами:
## Код:
```
END   КОНЕЦ_ЦИКЛА
   END   КОНЕЦ_ЦИКЛА_ПОКА
   END   КОНЕЦ_ЦИКЛА_ДЛЯ
   END   КОНЕЦ_ПРОЦЕДУРЫ
   UNTIL   КОНЕЦ_ЦИКЛА_ДО
   LOOP   ЦИКЛ
   EXIT   ВЫЙТИ_ИЗ_ЦИКЛА
   WHILE   ЦИКЛ_ПОКА
   FOR   ЦИКЛ_ДЛЯ
   REPEAT   ЦИКЛ_ДО
   RETURN   ВЫХОД
   INTEGER   ЦЕЛЫЙ
```

Для обмена данными с процедурами нижнего уровня я использовал
следующие 2 типа процедур:

ПРОЦЕДУРА_ПЕРЕМ_ЦЕЛЫЙ* = ПРОЦЕДУРА(ПЕРЕМ П:ЦЕЛЫЙ);   (* команда *)
ФУНКЦИЯ_П_ЦЕЛ_Р_ЦЕЛ*   = ПРОЦЕДУРА(К:ЦЕЛЫЙ): ЦЕЛЫЙ;  (* запрос *)

Каждая процедура логики верхнего уровня имеет свой номер, задаваемый в
ее имени, например:
ПРОЦЕДУРА  П1__СОЗДАНИЕ_HTM_ФАЙЛА;

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

N цроц = N кз div 100, например:

К1__ОТКРЫТЬ_HTM_ДЛЯ_ЗАПИСИ         = 100;
З1__ЗАПИСЬ_ЗАГОЛОВКА_HTM           = 101;
З1__ССЫЛКИ_ДЛЯ_ЗАПИСЕЙ_HTM         = 102;
...

Это позволяет из общего обработчика для команд и запросов вызывать
обработчики для каждой процедуры:

procedure  _komanda(k:integer);
begin
form_ls.state := 0;

if      ((k div 100) = 1) then   komanda__1(k)
else if ((k div 100) = 2) then   komanda__2(k)

end;


Исходный код процедуры  П1__СОЗДАНИЕ_HTM_ФАЙЛА:
## Код:
```
(* i.3. П1__СОЗДАНИЕ_HTM_ФАЙЛА *)

ПРОЦЕДУРА  П1__СОЗДАНИЕ_HTM_ФАЙЛА*;
ПЕРЕМЕННЫЕ 
    ветка, число_записей, длина_записи:ЦЕЛЫЙ;
    тек_запись, тек_стр_записи:ЦЕЛЫЙ;
НАЧАЛО
    ветка := 1;
    ЦИКЛ_ПОКА (ветка # 0)  ДЕЛАТЬ
    ЕСЛИ (ветка = 1) ТО
      команда(К1__ОТКРЫТЬ_HTM_ДЛЯ_ЗАПИСИ);
      ЕСЛИ (запрос(З1__ЗАПИСЬ_ЗАГОЛОВКА_HTM) = ОТВЕТ_НЕТ) ТО
        ветка := 40;
      ИНЕСЛИ (запрос(З1__ССЫЛКИ_ДЛЯ_ЗАПИСЕЙ_HTM) = ОТВЕТ_НЕТ) ТО
        ветка := 40;
      ИНАЧЕ
       число_записей := запрос(З1__ДАТЬ_ЧИСЛО_ЗАПИСЕЙ);
       тек_запись:= 1;
       ветка := 2;
      КОНЕЦ; 
    ИНЕСЛИ (ветка = 2) ТО (* цикл для записей *)
      ЕСЛИ ((запрос(З1__ОШИБОК_НЕТ) = ОТВЕТ_НЕТ) ИЛИ
            (тек_запись > число_записей)) ТО
        ветка := 40;
      ИНАЧЕ 
        длина_записи := запрос(З1__СМЕЩЕНИЕ_ДЛИНА_ЗАПИСИ);
        тек_стр_записи:= 1;
        ветка := 3;
      КОНЕЦ    
    ИНЕСЛИ (ветка = 3) ТО (* цикл для записи *)
      ЕСЛИ (запрос(З1__ОШИБОК_НЕТ) = ОТВЕТ_НЕТ) ТО
        ветка := 40;
      ИНЕСЛИ (тек_стр_записи > длина_записи) ТО
        тек_запись := запрос(З1__СЛЕДУЮЩАЯ_ЗАПИСЬ);
        ветка := 2;
      ИНЕСЛИ (запрос(З1__ЗАПИСАТЬ_СТРОКУ_ЗАПИСИ) = ОТВЕТ_НЕТ) ТО
        ветка := 40;
      ИНАЧЕ
        ЕСЛИ ((тек_стр_записи = 1) & 
            (запрос(З1__ЗАГОЛОВОК_ПРОГР_ЗАПИСИ) = ОТВЕТ_ДА)) ТО
          команда(К1__ПОЛУЧИТЬ_ИМЕНА_СХЕМЫ);
          П2__СЧИТАТЬ_СХЕМУ;
          ЕСЛИ (запрос(З1__НЕТ_ОШИБОК_СХЕМЫ) = ОТВЕТ_ДА) ТО
            команда(К1__НАРИСОВАТЬ_СХЕМУ);
            ЕСЛИ (запрос(З1__НЕТ_ОШИБОК_СХЕМЫ) = ОТВЕТ_ДА) ТО
              команда(К1__ЗАПИСАТЬ_СХЕМУ);
              команда(К1__СОЗДАТЬ_ССЫЛОЧНУЮ_КАРТУ);
            ИНАЧЕ
              команда(К1__СООБЩЕНИЕ_ОБ_ОШИБКЕ);
            КОНЕЦ;
          КОНЕЦ;
        КОНЕЦ;
        тек_стр_записи := запрос(З1__СЛЕДУЮЩАЯ_СТРОКА_ЗАПИСИ);
        ветка := 3;
      КОНЕЦ;
    ИНЕСЛИ (ветка = 40) ТО
      команда(К1__ЗАКОНЧИТЬ_ЗАПИСЬ_HTM);
      команда(К1__СООБЩЕНИЕ_HTM_СОЗДАН);
      ветка := 0;
    КОНЕЦ
    КОНЕЦ_ЦИКЛА_ПОКА;
    ВЫХОД;
КОНЕЦ_ПРОЦЕДУРЫ  П1__СОЗДАНИЕ_HTM_ФАЙЛА;
```

Вложение:
1_3.jpg [ 277.16 КБ | Просмотров: 10463 ]

В качестве примера для демонстрации взаимодействия логики верхнего и
нижнего уровня я взял программу dal2html.
Логику нижнего уровня и работу с формами я оставил на Delphi, а
демонстрационный фрагмент логики верхнего уровня я перенес на КП.
Дельфийские процедуры реализованы как DLL, вызываемая программой,
собранной в среде BlackBox - я использовал школьную сборку от 8.04.2008.

Чтобы не заморачиваться, я взял за основу программы на КП 2 примера:
создание окна средствами Win32 и динамическая загрузка DLL средствами
Win32.
DLL загружается уже после открытия окна, что позволяет "оживить"
создаваемые дельфийские формы, т.к. их окна автоматически встраиваются
в оконную систему задачи. Единственный недостаток в том, что на панели
задач появляются пиктограммы 2 окон - окна BB (я запускаю его в
минимизированном виде) и окна дельфийской формы, но для программы-макета
это вполне допустимо. Выйти из программы можно, закрыв окно дельфийской
формы.