RDM/2 The Russian Electronic Developer Magazine  
RDM/2 Русский электронный журнал разработчика  
ДомойОт редактораПишите намОбратная связьRU/2

Технология автоматического документирования ПО.

Существует общеизвестное наблюдение: чтобы научить медведя открывать дверь, достаточно десяти минут. Научить медведя закрывать дверь не удастся никогда. Почему? У него нет в этом необходимости.

Переложим его на программисткую среду: чтобы приучить программиста писать комментарии к программе, достаточно пары месяцев. Приучить программиста писать документацию к произведённому ПО не удастся никогда. Почему? У него нет на это времени.

Известно, что документация бывает двух видов -- для пользователя и для других программистов. Назначение первой -- объяснить человеку, установившему программу, что "...у нея внутре анализатор и думатель...", и как этим анализатором и думателем пользоваться. Писать документацию для пользователя -- это искусство. По этой причине программисты к составлению такой документации привлекаются довольно редко (чаще - консультируют). Эта часть документации нас в данной статье не волнует совершенно.

Вторая разновидность документации предназначена для таких же, как автор, программистов, и нужна в случае, если кто-то захочет что-то в написанной программе поправить или что-то к ней дописать.

Вообще говоря, написание документации -- работа нужная, но неблагодарная. В основном потому, что документация имеет свойство устаревать. Действительно, представим себе программу со 100% написанной документацией. Нереально? Ну хотя бы теоретически. Теперь зададим себе вопрос, сколько может программист сдерживать в себе желание чего-нибудь в этой замечательной программе поправить или улучшить. День? Неделю? Месяц? В конце концов это желание выплеснется наружу и программный код будет исправлен. Можно ли это изменение сразу отразить в документации? Конечно нет! Сначала дописанное надо отладить (и внести в программу ещё больше изменений). Потом надо поставить новую версию в эксплуатацию на паре машин, чтобы убедиться, что ошибки отловлены не все. Наконец, версия с изменениями становится основной... Тут, кажется, самое время исправить пару листов в документации, но... Но тут программист бросается исправлять ошибку в другой программе, и доументация становится чуть-чуть устаревшей. Пара-тройка таких циклов, и документация устаревает уже не "чуть-чуть". Ещё несколько изменений -- и всем становится ясно, что документацию надо писать заново, т.к. имеющаяся никакой ценности (кроме исторической) из себя не представляет. Вам знакома картина? Мне она, увы, знакома.

Между тем, в каждой программе (если, конечно, написал её нормальный программист) есть исчерпывающая документация. Где? В комментариях к исходным текстам. Начинающего программиста с детства учат (и в большинстве случаев таки приучают) внятно документировать произведения своего программистского искусства. Нормальный программист пишет и правит комментарии вместе с кодом программы, так что информация в комментариях (как правило) соответствует комментируемому коду. Информация в комментариях весьма подробна. Короче, комментарии прямо-таки просятся на роль документации. Хочется только эти комментарии собрать в одном месте и немного структурировать. Такую работу можно сделать автоматически. Для её выполнения есть специальные программы. Одной из них является DOC++.

Что такое DOC++ и где его берут.

DOC++ -- это программа, которая из комментариев делает красивую документацию на программу. Если мы начинаем наш комментарий с символов /// или /**, DOC++ использует его при написании документации. Документация может быть выдана в одном из двух форматов: TeX и HTML. Первый годится для того, чтобы показывать его начальству и требовать повышения зарплаты, второй -- для www-сайта корпоративной документации. При этом в HTML документации делаются правильные hyper-линки, так что, просматривая документацию на какую-нибудь функцию и ткнув в один из её параметров, мы можем сразу попасть на страничку, описывающую данный конкретный параметр. Это удобно.

DOC++ берут на сайте автора. Есть и порт под OS/2. Сделал его Jorg Desch. Если бы этот порт ещё и работал, цены бы ему не было. Но у меня он отказался работать начисто, вылетая по SIGSEGV во время записи результатирующих файлов. Убедившись, что колдовство над EMX runtime к положительным результатам не приводит, я понял, что предстоит большое развлечение с перекомпиляцией DOC++.

Как я заставлял работать DOC++ на своей машине под OS/2.

Первое, что я сделал - развернул среду разработки EMX 0.9d. Развернул исходники DOC++ (неправленные). Потом развернул поверх них исходники из порта под OS/2. Попытался скомпилировать. Облом. Куда-то подевался make. Ладно. Выкачиваем dmake. Пытаемся скомпилировать. Облом. Да какой! На компиляции mcsorter.h наш EMX вываливается с "Internal error". При ближайшем рассмотрении выясняется, что EMX-овый ум заходит за разум при попытке скомпилировать простейшую темплейтную функцию sort(). Не найдя ничего лучшего, я эту функцию закомментировал. Сразу скажу, что нигде эта функция не использовалась, так что никакого вреда DOC++ это не принесло. Зато компиляция прошла. Запускаем свежеоткомпилированный DOCXX и видим SIGSEGV. Таким образом, повторяемость ошибки доказана.

Применяя редактор, компилятор и printf в качестве основного средства отладки, через полтора часа устанавливаем виновника торжества -- это функция MAKE_DOC. При ближайшем рассмотрении MAKE_DOC() обнаруживается в файле doc.h и оказывается вот таким макроопределением (кстати, HAS_BASES() - это тоже макро):

  #define  MAKE_DOC(entry) \
    (  entry->sub != 0                                \
    || entry->see.size() > 0                          \
    || entry->author.length() > 0                     \
    || entry->author.length() > 0                     \
    || entry->version.length() > 0                    \
    || entry->param.size() > 0                        \
    || entry->retrn.length() > 0                      \
    || entry->exception.size() > 0                    \
    || entry->doc.length() > 0                        \
    || entry->proChilds.size() > 0                    \
    || entry->pubChilds.size() > 0                    \
    || (entry->pubChilds.size() > 0	 &&  withPrivate) \
    || entry->parent->parent == 0                     \
    || HAS_BASES(entry) )
Мысленно сказав авторам, кто они после этого такие, конвертируем макроопределение в функцию. Компилируем. Запускаем. Работает.

Вдоволь поигравшись с html документацией, замечаем странную любовь DOCXX к большим твердым знакам. Кажется, эта буква русского алфавита нравится ему больше маленькой русской 'с', и он, недолго думая, заменяет 'с' на 'Ъ'. Думаем. Находим в doc2html.cpp фрагмент:

  #line 264 "doc2html.l"
  {if (is_IBM_PC) Output("ß"); else Output("Ъ");}
Правим на :
  #line 264 "doc2html.l"
  {if (is_IBM_PC) Output("ß"); else Output("с");}
Теперь слово "клаЪЪ" опять становится "класс"-ом.

Поигравшись еще немного, я обнаруживаю странную нелюбовь моего Netscape к html страничкам в 866 кодировке. У меня на них съезжают шрифты. Нет проблем. Берем редактор, компилятор и меняем в doc2html функцию Output() на следующее :

  void Output(const char *o)
  {
  char *from,*to,*p1,*p2;
  const char *c;
  
  char str[2];
  static char cp866[]="йцукенгшщзхъфывапролджэячсмитьбюЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭЯЧСМИТЬБЮ";
  static char cp1251[]="щ÷≤ъхэу°∙ч⌡·⌠√тряЁюыфц² ≈ёьш≥©с■╔╓╙╩┼═├╪┘╟╒┌╘█┬└╧╨╬╦─╞▌▀╫╤╠╚╥▄┴▐";
  static char koi8r[]="╩├╒╦┼╬╟█▌┌╚▀╞┘╫┴╨╥╧╠─╓▄╤▐╙═╔╘╪┬└ъу⌡ыхюч√²·ш ц∙≈сЁ≥яьф÷©ё■≤эщ⌠°тр";
  
  if(recode==0)
     {
     outStr+=o;
     return;
     }
  
  from=cp866;
  to=cp866;
  if(recode==1)
     {
     from=cp866;
     to=cp1251;
     }
  
  if(recode==2)
     {
     from=cp866;
     to=koi8r;
     }
  
  c=o;
  while(*c!=0)
     {
     p1=from;
     p2=to;
     while(*p1!=0)
        {
        if(*p1==*c) break;
        p1++;
        p2++;
        }
  
     if(*p1!=0)
        {
        str[0]=*p2;
        }
     else
        {
        str[0]=*c;
        }
  
     str[1]=0;
     outStr+=str;
     c++;
     }
  }
Соответственно, добавляем ключики -Rw и -Rk в main.cpp, чтобы оттуда устанавливать переменную recode. Теперь я могу делать тексты html в кодировке koi, против которой мой браузер ничего не имеет.

В принципе, на этом можно было бы и закончить, но меня понесло и я решил добить такую возможность DOCXX, как генерация единообразных текстов в HTML и TEX. Т.е. пишем мы в тексте комментария /** \TEX{\frac{A}/{B}} */ И имеем в html страничке красивую дробь A/B. За механизм такой генерации автору надо поставить памятник или убить -- кому как нравится. Короче, алгоритм следующий.

  1. Создается .tex файл, содержащий формулу, которую надо будет вставить в .html документ.
  2. Вызывается latex, который делает нам .dvi файл.
  3. Вызывается dvi2ps, чтобы получить .ps и .eps файлы.
  4. Вызывается ghostscript, чтобы получить картинку в формате ppm.
  5. Вызываются pnmscale, pnmgamma, pbmtogif, чтобы получить желаемый фрагмент в виде .gif файла.
Для работы этого добра надо установить у себя :
  1. EmTeX.
  2. Ghostscript
  3. pbmplus.
Все есть на hobbes и ftp.cdrom.com. NB! Русификацию к TeX надо искать самим -- у меня стоял уже русифицированный EmTeX под DOS.

Неочевидные моменты, над которыми мне пришлось поломать голову.

Где брать поправленный вариант?

Тут: mydocxx.zip, 780k. Берите и пользуйтесь! Но имейте в виду: за работоспособность этого изделия я никакой ответственности не несу.
Sergey Kogan

---
Интересные ссылки:

---

---
Комментариев к странице: 0 | Добавить комментарий
---
Редактор: Дмитрий Бан
Оформление: Евгений Кулешов
(C) Russian Underground/2