OberonCore

Библиотека  Wiki  Форум  BlackBox  Компоненты  Проекты
Текущее время: Вторник, 19 Март, 2024 05:30

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ Сообщений: 8 ] 
Автор Сообщение
СообщениеДобавлено: Среда, 16 Октябрь, 2013 22:10 

Зарегистрирован: Вторник, 15 Декабрь, 2009 11:43
Сообщения: 164
ВИЗУАЛИЗАЦИЯ ПРОГРАММНОЙ ЛОГИКИ ВЕРХНЕГО УРОВНЯ

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

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

Для процедур описания логики работы верхнего уровня желательно
выполнение следующих условий:
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
1_3.jpg [ 277.16 КБ | Просмотров: 8383 ]

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

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


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Четверг, 17 Октябрь, 2013 18:28 

Зарегистрирован: Вторник, 15 Декабрь, 2009 11:43
Сообщения: 164
Приношу мои извинения уважаемому Эдуарду Ильченко за случайное искажение его имени на французский манер.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Вторник, 22 Октябрь, 2013 19:52 

Зарегистрирован: Вторник, 15 Декабрь, 2009 11:43
Сообщения: 164
Выкладываю 8-мистраничный материал по программной логике верхнего
уровня, более подробный, чем 1-е сообщение темы.
Вложение:
plwu.pdf [182.28 КБ]
Скачиваний: 430

Вот 2 цитаты из начала и конца выложенного материала:

. . . уже ставшая хронической проблема выделения четких алгоритмов
работы из исходного кода программ наталкивает на мысль о том, что фраза
«программная логика верхнего уровня» обозначает сейчас в
программировании скорее общепринятое понятие с расплывчатыми
границами, а не четкую логическую формулировку.
. . .
Для чего все это нужно ?
1) Выделение ЛВУ, независимой от изменений в исходном коде
низкоуровневых процедур, фактически означает проведение алгоритмизации
программы – ее высокоуровневые алгоритмы становятся ясными и
наглядными.
2) ЛВУ для основных императивных языков программирования
высокого уровня становится унифицированной и может быть автоматически
переведена с одного языка программирования на другой.
3) Визуализация алгоритмов ЛВУ становится делом техники и может
выполняться автоматически.
4) исходный код ПО становится более читаемым для программиста,
что способствует снижению издержек на разработку и сопровождение ПО.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Пятница, 25 Октябрь, 2013 16:38 

Зарегистрирован: Воскресенье, 01 Ноябрь, 2009 05:13
Сообщения: 2046
Всё ж таки есть ощущение, что ЛВУ, обладающая вышеперечисленными свойствами - это то же самое, что у Усова в КУБе работает... Т.е. вариант обсуждавшегося здесь. И она, ессно, будет работать как для машинного исполнителя, так и для человека...


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Среда, 10 Декабрь, 2014 20:16 

Зарегистрирован: Вторник, 15 Декабрь, 2009 11:43
Сообщения: 164
ЛОГИКА ВЕРХНЕГО УРОВНЯ - РЕДАКЦИЯ 2

В этом году моя работа с программой dalvjaz2 практически оказалась
замороженной в связи с отсутствием интересных для меня новых мыслей по
дальнейшему развитию программы.
И вот пришла мысль набросать материал на тему "КП и Delphi". Для ясного
понимания нижеследующего текста было бы полезно ознакомиться с материалом
1-го сообщения темы "КП и Delphi" (если вкратце, то программа на Delphi
вызывает обработчики событий из DLL на КП, которая, в свою очередь,
вызывает функции нижнего уровня из DLL на Delphi).

Написание материала "КП и Delphi" подвигло меня перетащить на логику
верхнего уровня (далее по тексту - ЛВУ) процедуру вывода схемы из проекта
dal2851.
Весь материал по ЛВУ 2 выложен в файле lvu2.txt.
Здесь привожу сокращенный вариант.

Исходный текст процедуры вывода схемы приведен в файле lvu2.txt.

В файле kpdll.txt находится текст полученной процедуры ЛВУ для вывода
схемы (я редактировал kpdll.txt в обычном текстововом редакторе,
загружал в BB, компилировал и линковал, а при обнаружении ошибок
компиляции опять редактировал и повторял процедуру сборки DLL).

Код:
MODULE Dal2Kpdll;

IMPORT S := SYSTEM, WinApi;

VAR
    dll: WinApi.HINSTANCE;
    ot:WinApi.BOOL;

(*==========================================*)

КОНСТАНТЫ
      ОТВЕТ_ДА         = 1;
      ОТВЕТ_НЕТ        = 0;
      НЕ_ЗАДАН         = -1;
     
      (* типы элементов схемы, см. u_ls.pas *)
      т_ЕСЛИ           = 1;
      т_ИНЕСЛИ         = 2;
      т_ИНАЧЕ          = 3;
      т_КОНЕЦ          = 4;
      т_ЦИКЛ           = 5;
      т_КОНЕЦ_ЦИКЛА    = 6;
      т_ЗАГОЛОВОК      = 7;  (*// заголовок схемы (1-я запись схемы) *)
      т_АДРЕС          = 8;  (*// t_AD пока исключен
                               // адрес следующей ветки силуэта  N | EXIT
                               // N - номер следующей ветки
                               // EXIT - переход к ветке ВЫХОД *)
      т_ДЕЙСТВИЕ       = 9;
      т_ВЫХОД          = 10; (* конец, возврат из процедуры *)
     

      (* типы вертикалей *)
      ГЛАВНАЯ_ВЕРТИКАЛЬ  = 1;
      ВЕРТИКАЛЬ_ДОЧЬ     = 2;
      ВЕРТИКАЛЬ_ЦИКЛА    = 3;


      (* запросы от dal2 *)

      ОСВОБОДИТЬ_БИБЛИОТЕКУ              = 1000;
      ЗАГРУЗИТЬ_БИБЛИОТЕКУ               = 1001;
      ВЫВОД_СХЕМЫ                        = 1002;

      (* команды (К*_)/ данные (Д*_)/ запросы (З*_)/ значения (В*_) *)
        (* 1. вывод_схемы *)
      К1_ПОЛУЧИТЬ_РАЗМЕРЫ_КАНВЫ             = 10001;
      К1_ВЫВОД_ТЕКСТА                       = 10002;
      К1_ОБНОВИТЬ_КАНВУ                     = 10003;
      К1_СТИЛЬ__СОЕДИНИТЕЛЬНЫЕ_ЛИНИИ        = 10004;
      К1_СТИЛЬ__ЦВЕТ_ФОНА                   = 10005;
      К1_ФОН_СХЕМЫ                          = 10006;
      К1_ВЫВОД_ЭЛЕМЕНТА                     = 10007;
      К1_ЛИНИЯ                              = 10008;
      К1_СТРЕЛКА_ЦИКЛА                      = 10009;
      Д1_ВЕРТИКАЛЬ                          = 10010;
      Д1_ИНДЕКС_ЭЛЕМЕНТА                    = 10011;
      Д1_ТЕК_ЭЛ_ВЕРТИКАЛИ                   = 10012;
      Д1_КООРД_Х1                           = 10013;
      Д1_КООРД_У1                           = 10014;
      Д1_КООРД_Х2                           = 10015;
      Д1_КООРД_У2                           = 10016;
      З1_НАЧАЛО_ПРОГРАММЫ                   = 10017;
      З1_ТЕКСТОВАЯ_ЗАПИСЬ                   = 10018;
      З1_ПОДСЧЕТ_МАКС_КООРДИНАТ             = 10019;
      З1_КОЛ_ДОП_ВЕРТИКАЛЕЙ                 = 10020;
      З1_СМЕЩЕНИЕ_СХЕМЫ_ПО_Х                = 10021;
      З1_СМЕЩЕНИЕ_СХЕМЫ_ПО_У                = 10022;
      З1_ШАГ_ТЕКСТА_ПО_У                    = 10023;
      В1_ИНД_1_ЭЛ_ВЕРТИКАЛИ                 = 10024;
      В1_КОЛ_ЭЛ_ВЕРТИКАЛИ                   = 10025;
      В1_ВЕРТИКАЛЬ_ЭЛЕМЕНТА                 = 10026;
      В1_ЭЛЕМЕНТ_ИСПОЛЬЗУЕТСЯ               = 10027;
      В1_РОДИТЕЛЬ_ВЕРТИКАЛИ                 = 10028;
      В1_ТИП_ДОП_ВЕРТИКАЛИ                  = 10029;
      В1_ШИРИНА_РОДИТЕЛЯ_ВЕРТИКАЛИ          = 10030;
      В1_Х_ВЕРТИКАЛИ_РОДИТЕЛЯ               = 10031;
      В1_Х_ДОП_ВЕРТИКАЛИ                    = 10032;
      В1_У1_ДОП_ВЕРТИКАЛИ                   = 10033;
      В1_ТИП_1_ЭЛ_ДОП_ВЕРТИКАЛИ             = 10034;
      В1_ФЛАГ_ВЕТКИ_1_ЭЛ_ДОП_ВЕРТИКАЛИ      = 10035;
      В1_ШИРИНА_1_ЭЛ_ДОП_ВЕРТИКАЛИ          = 10036;
      В1_ВЕРТИКАЛЬ_ЭЛ_КОНЦА_ВЕРТИКАЛИ       = 10037;
      В1_Х_ВЕРТИКАЛИ                        = 10038;
      В1_ТЕК_У_ДОП_ВЕРТИКАЛИ                = 10039;
      В1_КОЛ_ЭЛ_ДОП_ВЕРТИКАЛИ               = 10040;
      В1_ВЫШЕ_ЗАГОЛ_ВЕТОК                   = 10041;
      В1_ЭЛ_ЗАКРЫВАЮЩИЙ_ДОП_ВЕРТИКАЛЬ       = 10042;
      В1_ШИРИНА_ЭЛЕМЕНТА                    = 10043;
      В1_ИНД_1_ЭЛ_ДОП_ВЕРТИКАЛИ             = 10044;
      В1_ДОП_ВЕРТИКАЛЬ                      = 10045;
      В1_У1_1_ЭЛ_ДОП_ВЕРТИКАЛИ              = 10046;

ТИП

ПРОЦЕДУРА_ПАР_ЦЕЛЫЙ = ПРОЦЕДУРА(К:ЦЕЛЫЙ);
ПРОЦЕДУРА_2ПАР_ЦЕЛЫЙ = ПРОЦЕДУРА(п1,п2:ЦЕЛЫЙ);
ПРОЦЕДУРА_4ПАР_ЦЕЛЫЙ = ПРОЦЕДУРА(п1,п2,п3,п4:ЦЕЛЫЙ);
ФУНКЦИЯ_П_ЦЕЛ_Р_ЦЕЛ = ПРОЦЕДУРА(К:ЦЕЛЫЙ): ЦЕЛЫЙ;
ФУНКЦИЯ_2П_ЦЕЛ_Р_ЦЕЛ = ПРОЦЕДУРА(п1,п2:ЦЕЛЫЙ): ЦЕЛЫЙ;
ПРОЦЕДУРА_ПАР_ЦЕЛЫЙ_УСТР  = ПРОЦЕДУРА
               (Н:ЦЕЛЫЙ; У:УКАЗАТЕЛЬ НА МАССИВ ИЗ ЛИТЕР);

ПРОЦЕДУРА_10ПАР_ЦЕЛЫЙ = ПРОЦЕДУРА(п1,п2,п3,п4,п5,
                                  п6,п7,п8,п9,п10:ЦЕЛЫЙ);


ПЕРЕМЕННЫЕ


команда:           ПРОЦЕДУРА_ПАР_ЦЕЛЫЙ;
данные:            ПРОЦЕДУРА_2ПАР_ЦЕЛЫЙ;
запрос:            ФУНКЦИЯ_П_ЦЕЛ_Р_ЦЕЛ;
значение:          ФУНКЦИЯ_2П_ЦЕЛ_Р_ЦЕЛ;
адрес_формы:       ПРОЦЕДУРА_ПАР_ЦЕЛЫЙ_УСТР;

отладка:           ПРОЦЕДУРА_10ПАР_ЦЕЛЫЙ;


ПРОЦЕДУРА ^ вывод_схемы;



PROCEDURE [ccall] _zapros* (n: INTEGER): INTEGER;
ПЕРЕМЕННЫЕ
  ответ:ЦЕЛАЯ;
BEGIN
   ответ := -1;   

   IF (n = ЗАГРУЗИТЬ_БИБЛИОТЕКУ) THEN
     
      dll := WinApi.LoadLibrary( "pasdll.dll" );
      ASSERT( dll # 0, 100 );
     
      команда := S.VAL( ПРОЦЕДУРА_ПАР_ЦЕЛЫЙ,
             WinApi.GetProcAddress( dll, "_komanda" ) );
      данные  := S.VAL( ПРОЦЕДУРА_2ПАР_ЦЕЛЫЙ,
             WinApi.GetProcAddress( dll, "_dannye" ) );
      запрос := S.VAL(  ФУНКЦИЯ_П_ЦЕЛ_Р_ЦЕЛ,
             WinApi.GetProcAddress( dll, "_zapros" ) );
      значение := S.VAL(  ФУНКЦИЯ_2П_ЦЕЛ_Р_ЦЕЛ,
             WinApi.GetProcAddress( dll, "_znachenie" ) );
      адрес_формы := S.VAL(  ПРОЦЕДУРА_ПАР_ЦЕЛЫЙ_УСТР,
             WinApi.GetProcAddress( dll, "_adres_formy" ) );     

      отладка := S.VAL(  ПРОЦЕДУРА_10ПАР_ЦЕЛЫЙ,
             WinApi.GetProcAddress( dll, "_otladka" ) );   

   ELSIF (n = ОСВОБОДИТЬ_БИБЛИОТЕКУ) THEN

      ot := WinApi.FreeLibrary(dll);

   ELSIF (n = ВЫВОД_СХЕМЫ) THEN

      вывод_схемы;
   END;

   ВЕРНУТЬ  ответ;
END _zapros;


PROCEDURE [ccall] _adres_formy*
                (Н:ЦЕЛЫЙ; У:УКАЗАТЕЛЬ НА МАССИВ ИЗ ЛИТЕР);
BEGIN
   адрес_формы(Н,У);

END  _adres_formy;


ПРОЦЕДУРА  вывод_схемы;
ПЕРЕМЕННЫЕ ж, ии, и, смещение_эл_х, х1,х2,у1,у2,
           вэкв, эздв:ЦЕЛЫЙ;
НАЧАЛО
         
         ЕСЛИ (запрос(З1_НАЧАЛО_ПРОГРАММЫ) = ОТВЕТ_ДА) ТО 
           ВЫХОД;
         КОНЕЦ; 
         
         команда(К1_ПОЛУЧИТЬ_РАЗМЕРЫ_КАНВЫ);

         ЕСЛИ (запрос(З1_ТЕКСТОВАЯ_ЗАПИСЬ) = ОТВЕТ_ДА) ТО
           команда(К1_ВЫВОД_ТЕКСТА);
           команда(К1_ОБНОВИТЬ_КАНВУ);
           ВЫХОД;
         КОНЕЦ;

         команда(К1_СТИЛЬ__СОЕДИНИТЕЛЬНЫЕ_ЛИНИИ);
         команда(К1_СТИЛЬ__ЦВЕТ_ФОНА);

         команда(К1_ФОН_СХЕМЫ);       

         ЕСЛИ (запрос(З1_ПОДСЧЕТ_МАКС_КООРДИНАТ) = ОТВЕТ_НЕТ) ТО
           команда(К1_ОБНОВИТЬ_КАНВУ);
           ВЫХОД;
         КОНЕЦ;

         (** вывод главной вертикали *)         
             ж :=0;
             ии :=значение(В1_ИНД_1_ЭЛ_ВЕРТИКАЛИ, ж);
             и :=0;
         
         ЦИКЛ_ПОКА (и < значение(В1_КОЛ_ЭЛ_ВЕРТИКАЛИ, ж)) ДЕЛАТЬ
         
           ЕСЛИ (значение(В1_ВЕРТИКАЛЬ_ЭЛЕМЕНТА, ии) = ж) ТО
             ЕСЛИ (значение(В1_ЭЛЕМЕНТ_ИСПОЛЬЗУЕТСЯ, ии) = ОТВЕТ_ДА) ТО
               данные(Д1_ВЕРТИКАЛЬ, ж);
               данные (Д1_ИНДЕКС_ЭЛЕМЕНТА, ии);
               данные (Д1_ТЕК_ЭЛ_ВЕРТИКАЛИ, и);
               команда (К1_ВЫВОД_ЭЛЕМЕНТА);
               УВЕЛИЧИТЬ(и);
             КОНЕЦ;
           КОНЕЦ;       
         
           УВЕЛИЧИТЬ(ии);
         КОНЕЦ_ЦИКЛА;

         ЦИКЛ_ДЛЯ  ж := 0 ДО запрос(З1_КОЛ_ДОП_ВЕРТИКАЛЕЙ)-1  ДЕЛАТЬ
         (* цикл вывода элементов дополнительных вертикалей *)

            смещение_эл_х := 0;
           
            ЕСЛИ ((значение(В1_РОДИТЕЛЬ_ВЕРТИКАЛИ, ж) # НЕ_ЗАДАН) &
                  (значение(В1_ТИП_ДОП_ВЕРТИКАЛИ, ж) # ВЕРТИКАЛЬ_ЦИКЛА)) ТО

               смещение_эл_х := значение(В1_ШИРИНА_РОДИТЕЛЯ_ВЕРТИКАЛИ, ж);           
            КОНЕЦ;   

            х1 := значение(В1_Х_ВЕРТИКАЛИ_РОДИТЕЛЯ, ж) +
                  запрос(З1_СМЕЩЕНИЕ_СХЕМЫ_ПО_Х) + (смещение_эл_х ДЕЛИТЬ 2);
                 
            х2 := запрос(З1_СМЕЩЕНИЕ_СХЕМЫ_ПО_Х) + значение(В1_Х_ДОП_ВЕРТИКАЛИ,ж);
            у1 := запрос(З1_СМЕЩЕНИЕ_СХЕМЫ_ПО_У) + значение(В1_У1_ДОП_ВЕРТИКАЛИ,ж);                 
           
            ЕСЛИ (значение(В1_ТИП_ДОП_ВЕРТИКАЛИ,ж) = ВЕРТИКАЛЬ_ДОЧЬ) ТО
           
               ЕСЛИ (значение(В1_ТИП_1_ЭЛ_ДОП_ВЕРТИКАЛИ,ж) = т_ИНЕСЛИ) ТО
               
                 ЕСЛИ (значение(В1_ФЛАГ_ВЕТКИ_1_ЭЛ_ДОП_ВЕРТИКАЛИ,ж) = ОТВЕТ_ДА) ТО
                               
                   смещение_эл_х := значение(В1_ШИРИНА_1_ЭЛ_ДОП_ВЕРТИКАЛИ,ж);
                   
                   х2 := х2 - (смещение_эл_х ДЕЛИТЬ 2);
                   
                 КОНЕЦ;
               КОНЕЦ;

               данные(Д1_КООРД_Х1, х1);   данные(Д1_КООРД_У1, у1);
               данные(Д1_КООРД_Х2, х2);   данные(Д1_КООРД_У2, у1);
               команда(К1_ЛИНИЯ);                               

               вэкв := значение(В1_ВЕРТИКАЛЬ_ЭЛ_КОНЦА_ВЕРТИКАЛИ, ж);

               х1 := запрос(З1_СМЕЩЕНИЕ_СХЕМЫ_ПО_Х) + значение(В1_Х_ВЕРТИКАЛИ,вэкв);
               
               х2 := запрос(З1_СМЕЩЕНИЕ_СХЕМЫ_ПО_Х) +
                                           значение(В1_Х_ДОП_ВЕРТИКАЛИ, ж);
                             
               у2 := запрос(З1_СМЕЩЕНИЕ_СХЕМЫ_ПО_У) +
                     значение(В1_У1_ДОП_ВЕРТИКАЛИ,ж) +
                     значение(В1_ТЕК_У_ДОП_ВЕРТИКАЛИ,ж);
                                                           
               данные(Д1_КООРД_Х1, х1);   данные(Д1_КООРД_У1, у2);
               данные(Д1_КООРД_Х2, х2);   данные(Д1_КООРД_У2, у2);
               команда(К1_ЛИНИЯ);                               

               ЕСЛИ (значение(В1_КОЛ_ЭЛ_ДОП_ВЕРТИКАЛИ, ж) # 0) ТО   
               
                  ЕСЛИ (значение(В1_ТИП_1_ЭЛ_ДОП_ВЕРТИКАЛИ,ж) # т_ИНАЧЕ) ТО
               
                    ЕСЛИ (значение(В1_ТИП_1_ЭЛ_ДОП_ВЕРТИКАЛИ,ж) # т_ИНЕСЛИ) ИЛИ
                      (значение(В1_ФЛАГ_ВЕТКИ_1_ЭЛ_ДОП_ВЕРТИКАЛИ,ж)=ОТВЕТ_НЕТ) ТО
                     
                      у1 := запрос(З1_СМЕЩЕНИЕ_СХЕМЫ_ПО_У) +
                            значение(В1_У1_ДОП_ВЕРТИКАЛИ,ж);
                     
                      у2 := у1 + значение(В1_У1_1_ЭЛ_ДОП_ВЕРТИКАЛИ,ж);
                     
                      данные(Д1_КООРД_Х1, х2);   данные(Д1_КООРД_У1, у1);
                      данные(Д1_КООРД_Х2, х2);   данные(Д1_КООРД_У2, у2);
                      команда(К1_ЛИНИЯ);                               
                    КОНЕЦ;
                  КОНЕЦ;
               КОНЕЦ;
            КОНЕЦ;
           
            ЕСЛИ (значение(В1_ТИП_ДОП_ВЕРТИКАЛИ,ж) = ВЕРТИКАЛЬ_ЦИКЛА) ТО
             
               у1 := значение(В1_ВЫШЕ_ЗАГОЛ_ВЕТОК, у1);
                                               
               данные(Д1_КООРД_Х1, х1);   данные(Д1_КООРД_У1, у1);
               данные(Д1_КООРД_Х2, х2);   данные(Д1_КООРД_У2, у1);
               команда(К1_ЛИНИЯ);                               

               данные(Д1_КООРД_Х1, х1);
               данные(Д1_КООРД_У1, у1);
               команда(К1_СТРЕЛКА_ЦИКЛА);             

               у2 := у1 + значение(В1_ТЕК_У_ДОП_ВЕРТИКАЛИ,ж) +
                          (запрос(З1_ШАГ_ТЕКСТА_ПО_У) ДЕЛИТЬ 4);
               
               эздв:= значение(В1_ЭЛ_ЗАКРЫВАЮЩИЙ_ДОП_ВЕРТИКАЛЬ,ж);
                               (* КОНЕЦ/КОНЕЦ_ЦИКЛА *)
               смещение_эл_х := значение(В1_ШИРИНА_ЭЛЕМЕНТА, эздв);
               
               х1 := х1 + (смещение_эл_х ДЕЛИТЬ 2);
               
               данные(Д1_КООРД_Х1, х1);   данные(Д1_КООРД_У1, у2);
               данные(Д1_КООРД_Х2, х2);   данные(Д1_КООРД_У2, у2);
               команда(К1_ЛИНИЯ);                               
            КОНЕЦ;

            ЕСЛИ (значение(В1_КОЛ_ЭЛ_ДОП_ВЕРТИКАЛИ, ж) = 0) ТО
               
               у1 := запрос(З1_СМЕЩЕНИЕ_СХЕМЫ_ПО_У) +
                     значение(В1_У1_ДОП_ВЕРТИКАЛИ, ж);
               у2 := у1 + значение(В1_ТЕК_У_ДОП_ВЕРТИКАЛИ, ж);
               
               ЕСЛИ (значение(В1_ТИП_ДОП_ВЕРТИКАЛИ, ж)= ВЕРТИКАЛЬ_ЦИКЛА) ТО
                 у1 := значение(В1_ВЫШЕ_ЗАГОЛ_ВЕТОК, у1);
               КОНЕЦ;
               данные(Д1_КООРД_Х1, х2);   данные(Д1_КООРД_У1, у1);
               данные(Д1_КООРД_Х2, х2);   данные(Д1_КООРД_У2, у2);
               команда(К1_ЛИНИЯ);                               

            ИНАЧЕ
               ии := значение(В1_ИНД_1_ЭЛ_ДОП_ВЕРТИКАЛИ, ж);

               и := 0;
               
               ЦИКЛ_ПОКА (и < значение(В1_КОЛ_ЭЛ_ДОП_ВЕРТИКАЛИ, ж)) ДЕЛАТЬ
               
                 ЕСЛИ (значение(В1_ВЕРТИКАЛЬ_ЭЛЕМЕНТА, ии) =
                       значение(В1_ДОП_ВЕРТИКАЛЬ, ж)) ТО

                   ЕСЛИ (значение(В1_ЭЛЕМЕНТ_ИСПОЛЬЗУЕТСЯ, ии) = ОТВЕТ_ДА) ТО
                     данные(Д1_ВЕРТИКАЛЬ, значение(В1_ДОП_ВЕРТИКАЛЬ, ж));
                     данные (Д1_ИНДЕКС_ЭЛЕМЕНТА, ии);
                     данные (Д1_ТЕК_ЭЛ_ВЕРТИКАЛИ, и);
                     команда (К1_ВЫВОД_ЭЛЕМЕНТА);
                     УВЕЛИЧИТЬ(и);
                   КОНЕЦ;
                 КОНЕЦ;

                 УВЕЛИЧИТЬ(ии);
               КОНЕЦ_ЦИКЛА; 
            КОНЕЦ;
         КОНЕЦ_ЦИКЛА_ДЛЯ;

         команда(К1_ОБНОВИТЬ_КАНВУ);

КОНЕЦ  вывод_схемы;


END Dal2Kpdll.

(* в начале строки DevLinker ... вставить коммандер: Ctrl+Q,
    а затем щелкнуть по нему левой кнопкой мыши *)
DevLinker.LinkDll kpdll.dll := Dal2Kpdll# ~   

Фрагмент файла u_pasdll.pas из проекта pasdll:
Код:
interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ExtCtrls;


  type uchar = ^char;


procedure  _komanda(k:integer);  export;  stdcall;
procedure  _dannye(k1, k2:integer);  export;  stdcall;
function   _zapros(n:integer):integer;  export;  stdcall;
function   _znachenie(n1,n2:integer):integer;  export;  stdcall;
procedure  _adres_formy(n:integer; uch:uchar);  export;  stdcall;


implementation

uses  u_dalvj, u_ls, u_files, u_img;


var
  f1: Tform_dalvjaz;
  f2: Tform_ls;
  f3: Tfajly;
  f4: Tform_img;


procedure  _adres_formy(n:integer; uch:uchar);
begin
  if (n = 1)  then  f1 := Tform_dalvjaz(uch);
  if (n = 2)  then  f2 := Tform_ls(uch);
  if (n = 3)  then  f3 := Tfajly(uch);
  if (n = 4)  then  f4 := Tform_img(uch);
end;


procedure  _komanda(k:integer);
var ot:integer;
begin
   ot := f1.obrabotka(k,0);
end;


procedure  _dannye(k1, k2:integer);
var ot:integer;
begin
   ot := f1.obrabotka(k1,k2);
end;


function   _zapros(n:integer):integer;
var ot:integer;
begin
   ot := f1.obrabotka(n,0);

   _zapros := ot;
end;


function   _znachenie(n1,n2:integer):integer;
var ot:integer;
begin
   ot := f1.obrabotka(n1,n2);

   _znachenie := ot;
end;

Обработчик, находящийся в файле u_obr.pas проекта dal2871 (бывший
dal2851), содержит всю логику, вырезанную из исходного текста процедуры
вывода схемы. Ниже приведен фрагмент исходного кода обработчика,
содержащий одну из ветвей сложного условия для обработки вызовов
процедуры ЛВУ.

. . .

end else if (n1= K1_WYWOD_EXLEMENTA) then begin // К1_ВЫВОД_ЭЛЕМЕНТА

form_dalvjaz.wywod_elem(nil, dannye_wertikalx,
dannye_ind_exl, dannye_tek_exl_wert);

end else if (n1= K1_LINIQ) then begin // К1_ЛИНИЯ

. . .


Головной обработчик ЛВУ выглядит следующим образом:

function _obrabotka(n1, n2:integer):integer;
var ot:integer;
begin
ot := -1;

if (n1 >= 10001) and (n1 < 10100) then begin
(* 1. вывод_схемы *) ot := _obrabotka_1(n1,n2);
end;

. . .

_obrabotka := ot;
end;


ЛВУ, описывающей работу со списками или одномерными массивами, вполне
достаточно процедурных вызовов четырех типов: команда, данные, запрос,
значение (типы этих вызовов см. выше).
Каждой процедуре ЛВУ неявно (в комментарии к процедуре) присваивается
свой номер, который уже явно (в начале имени) присваивается константам,
подставляемым в процедурные вызовы ЛВУ, и обработчику этой процедуры ЛВУ.
Префиксы констант ЛВУ указывают на типы процедурных вызовов, в которых
эти константы используются:
команды (К*_) / данные (Д*_) / запросы (З*_) / значения (В*_)

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

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

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

Если ПО пишется на Delphi 2010 и выше, то нет необходимости переносить
процедуры ЛВУ в отдельную DLL. Тексты процедуры ЛВУ для вывода схемы и
обработчика для этой процедуры ЛВУ приведены в файле lvu2.txt.



Использование ЛВУ позволяет решать следующие задачи:

1) обеспечение самодокументирования процедур ЛВУ

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

2) обеспечение механизма сокрытия данных путем разбиения логики программы
на маршрутную (процедура ЛВУ) и функциональную (обработчик процедуры ЛВУ)

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

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

4) формирование унифицированной трехуровневой логики разработки программы

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

Введение унифицированной логики разработки программы (шаблона разработки
ПО) позволит упростить передачу сопровождения фрагментов программы другим
программистам за счет упрощения ознакомления с унифицированной ЛВУ того
или иного фрагмента программы по сравнению с общепринятой логикой
написания ПО с минимально возможным документированием логики программы
и размытой от постоянного внесения новых изменений иерархической и
логической структурой программы.
Вложение:
lvu2.txt [40.48 КБ]
Скачиваний: 660


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Суббота, 13 Декабрь, 2014 15:00 
Аватара пользователя

Зарегистрирован: Пятница, 25 Ноябрь, 2005 12:02
Сообщения: 8500
Откуда: Троицк, Москва
Зачем у Вас во всех охранах лишние скобки?
Как-то не чисто.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Суббота, 13 Декабрь, 2014 17:32 

Зарегистрирован: Вторник, 15 Декабрь, 2009 11:43
Сообщения: 164
По работе приходится писать на С/С++, поэтому вошло в привычку внутри if ставить скобки.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Суббота, 13 Декабрь, 2014 17:33 
Аватара пользователя

Зарегистрирован: Пятница, 25 Ноябрь, 2005 12:02
Сообщения: 8500
Откуда: Троицк, Москва
Нехорошая привычка.


Вернуться к началу
 Профиль  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 8 ] 

Часовой пояс: UTC + 3 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
cron
Вся информация, размещаемая участниками на конференции (тексты сообщений, вложения и пр.) © 2005-2024, участники конференции «OberonCore», если специально не оговорено иное.
Администрация не несет ответственности за мнения, стиль и достоверность высказываний участников, равно как и за безопасность материалов, предоставляемых участниками во вложениях.
Без разрешения участников и ссылки на конференцию «OberonCore» любое воспроизведение и/или копирование высказываний полностью и/или по частям запрещено.
Powered by phpBB® Forum Software © phpBB Group
Русская поддержка phpBB