DAL_VJAZ_2 0.83
Вложение:
dal2_083.rar [378.46 КБ]
Скачиваний: 425
Как обычно, примерно раз в полгода выкладываю обновления.
Не могу сказать, что в этот раз получилось создать что-то революционно
новое, типа того, что предлагается в теме "КУБ-СИЛУЭТ ...".
Скорее наоборот, попробовал собрать вместе старые заделы.
Ну и перелистал на досуге книгу С.Макконнела "Совершенный код", главу 9,
"Процесс программирования с псевдокодом":
"* Избегайте синтаксических элементов языков программирования. Псевдокод
позволяет проектировать на несколько более высоком уровне, чем код.
Применяя конструкции языка программирования, вы мыслите на более низком
уровне и теряете преимущества проектирования на высоком уровне, загружая
себя ненужными синтаксическими ограничениями.
* Пишите псевдокод на уровне намерений. Описывайте назначение подхода,
а не то, как этот подход нужно реализовать на выбранном языке
программирования.
* Пишите псевдокод на достаточно низком уровне, так чтобы код из
него генерировался практически автоматически.
[При описаниии метода] начните с основных моментов, а затем детализируйте
их. Самая главная часть метода - заголовок-комментарий, описывающий
действия метода, так что начните с краткой формулировки назначения метода.
Написание этой формулировки поможет вам прояснить ваше понимание метода.
Написав общий комментарий, добавьте высокоуровневый псевдокод.
Написав псевдокод, вы окружаете его кодом, а псевдокод превращаете в
комментарии программы. Если вы руководствуетесь перечисленными правилами
создания псевдокода, комментарии в вашей программе будут полными и ясными."
Конечно, эти утверждения не бесспорны. Например, если взять книгу "Проект
Оберон", то из приведенных там листингов видно, что Н.Вирт и Ю.Гуткнехт
скорее придерживаются идеи о самодокументировании хорошо написанных
программ.
Но такие почти идеальные тексты ПО в жизни встречаются не слишком часто.
Поэтому наличие достаточно подробных комментариев (а насколько подробных
я постараюсь ответить) в тексте программы представляется мне желательным
даже с точки зрения самого программиста, если он планирует сколько-нибудь
длительное время сопровождать написанный им код.
Итак, DAL_VJAZ_2 0.83, основные изменения:
1) изменение формата служебных комментариев при работе с текстом программы;
все служебные комментарии в файлах u_dalvj.pas, u_ls.pas, u_fajly.pas и
u_red.pas программы dalvjaz2 приведены к новому формату;
2) возвращение полноценной функциональности минимизированной схеме и
улучшение взаимодействия между минимизированной и полной формами визуальной
схемы;
3) выполнена предварительная подготовка к переносу проекта dalvjaz2
в Delphi 2009 и выше (будет транслироваться, но с множеством warning-ов).
Пункт 1:
Я решил начиная с версии 0.83 изменить формат служебных комментариев
dalvjaz2 для работы с исходным кодом программы
Код:
параметры конфигурации версия 0.82 версия 0.83
в файле dalvjaz.cfg
; заголовки программных и текстовых записей задаются как раньше:
__загол_прог_записи "(* i." "(* i."
__загол_текст_записи "(* t." "(* t."
__строка_док_IF "(*i*) if" "(** если"
__строка_док_EI "(*i*) end else if" "(** иначе если"
__строка_док_EB "(*i*) end else begin" "(** иначе"
__строка_док_END "(*i*) end;" "(** конец"
__строка_док_CB "(*i CB *)" "(** цикл"
__строка_док_CE "(*i CE *)" "(** конец цикла"
__строка_док_A "(*i*)" "(**"
__проверка_ветки "if (wetka = " "if (wetka = "
__переход_к_ветке "wetka := " "wetka := "
__строка_док_RET "(*i ВЫХОД *)" "(** выход"
__строка_док_STOP "(*i КОНЕЦ *)" "(** КОНЕЦ СХЕМЫ"
Также в версии 0.83 теперь в конфигурации явно задаются открывающий
и закрывающий комментарии для языка программирования.
Исходный код для 0.82
(* i.3. простой силуэт *)
(*i*) begin
(*i*) wetka := 1;
(*i CB *) while (wetka <> 0) do begin
(*i*) if (wetka = 1)
(*i*) if (что-нибудь) then begin
(*i*)
(*i*) end else if (что-нибудь) then begin
(*i*)
(*i*) end else begin
(*i*)
(*i*) end;
(*i*) wetka := 2;
(*i*) end else if (wetka = 2)
(*i*)
(*i*) wetka := 3;
(*i*) end else if (wetka = 3)
(*i*) if (что-нибудь) then begin
(*i*)
(*i*) end else if (что-нибудь) then begin
(*i*)
(*i*) end else if (что-нибудь) then begin
(*i*)
(*i*) end;
(*i*) wetka := 0;
(*i*) end;
(*i CE *) end;
(*i ВЫХОД *)
end;
(*i КОНЕЦ *)
Исходный код для 0.83
(* i.3. простой силуэт *)
(**) begin
(**) wetka := 1;
(** цикл для ветки *)
while (wetka <> 0) do begin
(** если *)
if (wetka = 1)
(** если *)
if (что-нибудь) then begin
(**)
(** иначе если *)
end else if (что-нибудь) then begin
(**)
(** иначе *)
end else begin
(**)
(** конец *) end;
(**) wetka := 2;
(** иначе если *)
end else if (wetka = 2)
(**)
(**) wetka := 3;
(** иначе если *)
end else if (wetka = 3)
(** если *)
if (что-нибудь) then begin
(**)
(** иначе если *)
end else if (что-нибудь) then begin
(**)
(** иначе если *)
end else if (что-нибудь) then begin
(**)
(** конец *) end;
(**) wetka := 0;
(** конец *) end;
(** конец цикла *) end;
(** выход *)
end;
(** КОНЕЦ СХЕМЫ *)
Из сравнения вышеприведенных фрагментов исходного кода для версий 0.82 и 0.83
видно, что хотя в версии 0.83 текст процедуры стал немного длиннее, но
служебные комментарии, нужные для формирования схемы из текста исходного
кода, теперь по внешнему виду почти не отличаются от обычных комментариев,
встречающихся в тексте программы.
Так что при использовании программы dalvjaz2 0.83 можно сказать, что обычные
комментарии теперь нужны не только для пояснения смысла действий, выполняемых
в процедуре, но и для формирования программой dalvjaz2 визуальной схемы этой
процедуры.
ДАЛВЯЗ 2 дает программистам возможность создавать визуальные схемы из уже
существующих процедур и загружать уже существующие проекты из нескольких
модулей на языках семейств Pascal и С/С++. Для этого один или несколько
модулей проекта разбиваются на текстовые записи заголовками вида:
(* t. имя записи *) - для семейства Pascal
/* t. имя записи */ - для семейства C/C++
после чего модуль может быть считан в программу dalvjaz2.
Программные записи могут отображаться как текст или как схема, в зависимости
от того, взведен или сброшен флажок <схема>.
Для преобразования текстовой записи в программную нужно:
1) вставить в процедуру служебные комментарии dalvjaz2 (подробнее см. ниже,
п. "Постепенное документирование процедуры");
2) поменять в заголовке записи t на i ;
3) взвести флажок <схема> - после этого запись отобразится как схема.
ВНИМАНИЕ:
Т.к. я не могу поручиться, что генерация кода в dalvjaz2 отлажена на 100%, то
РЕЖИМ РАБОТЫ "ТЕКСТ -> СХЕМА"
(т.е. автоматическое считывание программой dalvjaz2 измененных файлов
исходного кода программы и построение новых версий визуальных схем процедур
после нажатия кнопки, пункта меню или горячей клавиши "Сохранить" в текстовом
редакторе)
ЯВЛЯЕТСЯ СЕЙЧАС ОСНОВНЫМ РЕЖИМОМ РАБОТЫ ПРОГРАММЫ dalvjaz2.
В режиме "ТЕКСТ -> СХЕМА" модули исходного кода в файле dalvjaz.cfg должны
быть заданы с параметром ПРОСМ во избежание непреднамеренного изменения
программой dalvjaz2 просматриваемых файлов исходного кода.
После установки флага "Nстр" на рабочей панели dalvjaz2 рядом с верхним
левым углом каждого блока схемы отображается номер строки в файле исходного
кода, соответствующий началу описания этого блока схемы.
Постепенное документирование процедуры
Допустим вы хотите документировать процедуру размером более 30 строк,
написанную вами более полугода назад (или вообще написанную не вами).
Что делается в процедуре в лучшем случае в общих чертах понятно из ее
названия, т.к. комментариев к тексту процедуры нет.
Тогда вставка в процедуру служебных комментариев dalvjaz2 выполняется в
несколько этапов:
Код:
1) разбейте процедуру на несколько обособленных логических блоков при помощи
комментариев действий, причем названия этих действий сейчас не важны:
procedure proc;
(**)
begin
...
(**)
...
(**)
...
(**)
...
(** выход *)
end;
(** КОНЕЦ СХЕМЫ *)
2) с той степенью подробности, какая вам нужна, проявите логическую
структуру процедуры (ЛСП), например:
procedure proc;
(**)
begin
...
(** если *)
...
(** иначе если *)
...
(** конец *) end;
(**)
...
(** цикл *)
...
(** конец цикла *) end;
(** выход *)
end;
(** КОНЕЦ СХЕМЫ *)
Теперь ЛСП проявлена и dalvjaz2 может построить визуальную схему процедуры,
| КОТОРАЯ ПОЗВОЛИТ ВАМ РАССМОТРЕТЬ ДЕЙСТВИЯ, ВЫПОЛНЯЕМЫЕ В ПРОЦЕДУРЕ, БОЛЕЕ
| ВНИМАТЕЛЬНО, ЧЕМ В ТЕКСТОВОМ ФОРМАТЕ, Т.К. НА СХЕМЕ КАЖДОЕ ИЗ ВЫДЕЛЕННЫХ
| ВАМИ ДЕЙСТВИЙ БУДЕТ ОБВЕДЕНО РАМКОЙ И БУДУТ ПОКАЗАНЫ ЛОГИЧЕСКИЕ СВЯЗИ
| МЕЖДУ ВЫПОЛНЯЕМЫМИ ДЕЙСТВИЯМИ.
Код:
3) теперь, когда после изучения текста процедуры стало понятно, что в ней
происходит, нужно все это записать, чтобы потом снова не забыть:
procedure proc;
(** начальные действия *)
begin
...
(** если выполняется условие 1 *)
...
(** иначе если выполняется условие 2 *)
...
(** конец *) end;
(** промежуточные действия *)
...
(** цикл для всех элементов массива *)
...
(** конец цикла *) end;
(** выход *)
end;
(** КОНЕЦ СХЕМЫ *)
Что касается оператора switch, то т.к. этот оператор является аналогом
сложного условия, то для его описания можно использовать служебные
комментарии dalvjaz2, используемые для описания сложного условия:
(** если
(** иначе если
(** иначе
(** конец
Как обычно, привожу исходный код и графический файл для процедуры
b_sozdatx_shemuClick:
Код:
(* i.9. создать из списка ЛСП визуальную схему *)
procedure Tform_ls.b_sozdatx_shemuClick(Sender: TObject);
var wetka, i, tw:integer;
begin
(**) wetka := 1;
(** цикл *)
while (wetka <> 0) do begin
(** если *)
if (wetka = 1) then begin
(** устанавливаем параметры главной вертикали схемы *)
tek_alg.m_wert[dalvjaz_tek_wetka]._type := T_WERT_GLAWNAQ;
tek_alg.m_wert[dalvjaz_tek_wetka].used := YES;
tek_alg.m_wert[dalvjaz_tek_wetka].x :=
tek_alg.m_x_wetok[dalvjaz_tek_wetka];
tek_alg.m_inew[dalvjaz_tek_wetka] := -1;
tek_alg.m_el_wert[dalvjaz_tek_wetka] := 0;
tek_alg.m_wert[dalvjaz_tek_wetka].tyel := 0;
tek_alg.m_wert[dalvjaz_tek_wetka].y1 :=
DALVJAZ_Y_ZAGOL;
(** инициализация массива
открытых вертикалей схемы *)
mow__init(dalvjaz_tek_wetka); //_>.42.
(** начальная инициализация переменных *)
tek_str_lsp := 0; // текущая строка списка ЛСП = 0
osh_sozd_shemy := SHEMA_OK; // номер ошибки сброшен
pred_bl_el_sh._type := t_A; // предидущий блочный эл-т
//при построении схемы = действие
(** удаляем вертикали для схемы *)
udal_wert_tek_wetki(Sender); //_>.10
(** если РИС .e? *)
if (osh_sozd_shemy <> SHEMA_OK) then begin
(**) wetka := 50;
(** иначе *)
end else begin
(**) sbros_steka_lsp; //_>.37.
(** инициализация цикла сканирования ЛСП *)
i := 0;
(**) wetka := 2;
(** конец *) end;
(** иначе если
начало цикла сканирования ЛСП *)
end else if (wetka = 2) then begin
(** задание текущей строки ЛСП *)
tek_str_lsp := i;
(** запомнить блочный элемент схемы *)
if ((i > 0) and
((tek_alg.m_el[i]._type = t_IF) or
(tek_alg.m_el[i]._type = t_EI) or
(tek_alg.m_el[i]._type = t_EB) or
(tek_alg.m_el[i]._type = t_E) or
(tek_alg.m_el[i]._type = t_CB) or
(tek_alg.m_el[i]._type = t_CE))) then
pred_bl_el_sh := tek_el_shemy;
(** получить текущий элемент схемы из ЛСП *)
tek_el_shemy.ind := tek_alg.m_el[i].ind;
tek_el_shemy._type := tek_alg.m_el[i]._type;
tek_el_shemy.n_strz := tek_alg.m_el[i].n_strz;
tek_el_shemy.ind_m_el := i;
tek_el_shemy.n_str := i;
(** получить вершину стека ЛСП *)
give_stek_lsp(0); //_>.36.
(** проверка ошибок ЛСП *)
prow_oshibki_struktury(Sender); //_>.12.
(** если РИС .e? *)
if (osh_sozd_shemy <> SHEMA_OK) then begin
(**) wetka := 50;
(** иначе *)
end else begin
(**) wetka := 3;
(** конец *) end;
(** иначе если - окончание цикла сканирования ЛСП *)
end else if (wetka = 3) then begin
(** если начало IF/EI/цикла *)
if ((tek_el_shemy._type = t_IF) or
(tek_el_shemy._type = t_EI) or
(tek_el_shemy._type = t_CB)) then begin
(** обработка t_IF //_>.14. *)
if (tek_el_shemy._type = t_IF) then obr_shemy_dlq_IF(Sender);
(** обработка t_EI //_>.16. *)
if (tek_el_shemy._type = t_EI) then obr_shemy_dlq_EI(Sender);
(** обработка t_CB //_>.19. *)
if (tek_el_shemy._type = t_CB) then obr_shemy_dlq_CB(Sender);
(** проверка ошибки РИС .e? . *)
if (osh_sozd_shemy <> SHEMA_OK) then begin
wetka := 50; continue;
end;
(** заносим текущий элемент в стек ЛСП *)
push_stek_lsp; //_>.34.
(** иначе если *)
end else if (tek_el_shemy._type = t_EB)
then begin
(** обработка t_EB *)
obr_shemy_dlq_EB(Sender); //_>.17.
(** проверка ошибки РИС .e? *)
if (osh_sozd_shemy <> SHEMA_OK) then begin
wetka := 50; continue;
end;
(** иначе если *)
end else if (tek_el_shemy._type = t_E)
then begin
(** обработка t_E *)
obr_shemy_dlq_E(Sender); //_>.18.
(** проверка ошибки РИС .e? *)
if (osh_sozd_shemy <> SHEMA_OK) then begin
wetka := 50; continue;
end;
(** цикл ДО *)
repeat
(** если РИС .e?
эл. стека не используется *)
if (el_steka_lsp.used = NO) then begin
(** ошибка "нет ЕСЛИ для КОНЕЦ" *)
osh_sozd_shemy := SHEMA_no_IF_for_E;
break; // а не continue, потому что
// мы во внутреннем цикле
(** иначе *)
end else begin
(** извлечь элемент из стека ЛСП *)
pop_stek_lsp; //_>.35.
(** конец *) end;
(** конец цикла если в стеке t_IF *)
until (el_steka_lsp._type = t_IF);
(** проверка ошибки РИС .e? *)
if (osh_sozd_shemy <> SHEMA_OK) then begin
wetka := 50; continue;
end;
(** иначе если *)
end else if (tek_el_shemy._type = t_CE) then begin
(** обработка t_CE *)
obr_shemy_dlq_CE(Sender); //_>.20.
(** проверка ошибки РИС .e? *)
if (osh_sozd_shemy <> SHEMA_OK) then begin
wetka := 50; continue;
end;
(** если РИС .e?
эл. стека не используется *)
if (el_steka_lsp.used = NO) then begin
(** ошибка "нет начала для конца цикла" *)
osh_sozd_shemy := SHEMA_no_CB_for_CE;
wetka := 50; continue;
(** конец *) end;
(** извлечь элемент из стека ЛСП *)
pop_stek_lsp; //_>.35.
(** иначе *)
end else begin
(** обработка для действия *)
obr_shemu_dlq_A(Sender); //_>.21.
(** проверка ошибки РИС .e? *)
if (osh_sozd_shemy <> SHEMA_OK) then begin
wetka := 50; continue;
end;
(** конец *) end;
(** если не все эл. ЛСП *)
if (i < (tek_alg.kol_elem - 1)) then begin
(** переход к следующему шагу
цикла сканирования ЛСП *)
inc(i);
(**) wetka := 2;
(** иначе *)
end else begin
(**) wetka := 4;
(** конец *) end;
(** иначе если - завершающие действия *)
end else if (wetka = 4) then begin
(** получить вершину стека ЛСП *)
give_stek_lsp(0); //_>.36.
(** если РИС .e?
эл. стека используется *)
if (el_steka_lsp.used = YES) then begin
(** ошибка "в стеке ЛСП есть эл." *)
osh_sozd_shemy := SHEMA_el_w_steke_LSP;
wetka := 50; continue;
(** конец *) end;
(** обработка после сканирования ЛСП *)
obr_shemy_w_konce_lsp(Sender); //_>.25.
(** если нет ошибок создания схемы *)
if (osh_sozd_shemy = SHEMA_OK) then begin
(** если схема считана *)
if (dalvjaz_shema_schitana = YES) then begin
(** сейчас никаких действий *)
(** конец *) end;
(** сейчас никаких действий *)
(** конец*) end;
(**) wetka := 50;
(** иначе если - обработка ошибки *)
end else if (wetka = 50) then begin
(** обработка ошибки РИС .er *)
if (osh_sozd_shemy <> SHEMA_OK) then begin
obrabotka_oshibok(Sender);
fl_oshibki := YES;
if (komanda_ot = 1) then begin
form_dalvjaz.komanda_ot := 2;
form_dalvjaz.zagruzka_shemy(Sender);
form_dalvjaz.komanda_ot := 1;
end;
end
else begin
if (komanda_ot = 1) then
m_fajlow[fajly.tek_fajl].fl_red := YES;
end;
(**) wetka := 0;
(** конец *) end;
(** конец цикла для ветки *) end;
(** выход *)
end;
(** КОНЕЦ СХЕМЫ *)
Вложение:
shema.JPG [ 543.19 КБ | Просмотров: 12587 ]
Пункт 2:
У мини-формы схемы при наведении мыши на элементы, как это было
раньше, опять появляются всплывающие окна с активными ссылками.
Чтобы избавиться от мельтешения всплывающих окон при быстром
перемещении мыши по мини-схеме, нужно при перемещении мыши по схеме
держать нажатой клавишу Shift.
Чтобы выйти мышью на ссылку всплывающего окна, нужно навести мышь
на элемент с края противоположного тому, где должно появится
всплывающее окно, а затем не торопясь перевести мышь на всплывающее
окно и щелкнуть по ссылке.
Чтобы перейти от мини-формы схемы к нужному месту полной схемы,
нужно навести мышь на элемент и нажать клавишу F2. После перехода
к полной форме схемы у выбранного элемента рядом с его верхним
левым углом будет отображаться зеленым цветом номер начальной
строки этого элемента в файле исходного кода.
Теперь номера начальных строк элементов в файле исходного кода
отображаются не только для полной формы схемы, но также и для
мини-формы схемы.
Включением/отключением этой опции управляет флажок "N стр" на
рабочей панели программы dalvjaz2.
Пункт 3:
Основная проблема была в том, что начиная с D2009 присвоение вида
stro[0] := chr(23)
стало ошибочным - предлагается использовать процедуру SetLength.
Но т.к. я в своей программе иногда заполнял строки достаточно
экзотическими способами, то предпочел написать для себя свою
процедуру задания длины строки:
procedure set_len_stro(var s:s_dl_stro; n:integer);
var i:integer; st:s_dl_stro; st2:string[10];
begin
st := ''; st2 := '0';
for i:=1 to n do begin
st2[1] := s[i]; st := st + st2;
end;
s := st;
end;
Пусть не слишком оптимально, зато работает.
----------------------------------
По поводу подробного документирования программы.
Я думаю, что с введением нового формата служебных комментариев
для работы с исходным кодом программы это дело наконец стронулось
с места и будет рано или поздно сделано.