Л.БРОУДИ. СПОСОБ МЫШЛЕНИЯ - ФОРТ. часть 5 ГЛАВА 5 --------------------------------------------------------------- - 133 - ГЛАВА 5 Р А З Р А Б О Т К А : ~~~~~~~~~~~~~~~~~~~~~ Э Л Е М Е Н Т Ы Ф О Р Т - С Т И Л Я ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ---------------------------------------------------------------- Плохо написанная на Форте программа обычно выглядит как "код, пропущенный через пресс для мусора". Форт в действительности дает много свободы в выборе способа написания программ. Такая свобода обеспечивает все возможности для создания черезвычайно удобочитаемого и легко управляемого кода, что достигается сознательным применением элементов хорошего Форт-стиля. В этой главе мы просмотрим соглашения по стилистике Форта, в том числе такие вещи, как: организация текстов программы (листингов); планировка экранов (блоков), отступы и выравнивания; комментирование; выбор имен. Я думаю, что мог бы порекомендовать всем список жестких и точных соглашений. К несчастью, такой список мог бы и не подойти во многих ситуациях. В этой главе описание множества широко известных соглашений перемежается с изложением индивидуальных привязанностей, выдвижением альтернативных идей и рассказами о причинах различных предпочтений. Другими словами: : СОВЕТ ВЗЕШИВАТЬ СУЖДЕНИЯ ; Мне хотелось бы особенно поблагодарить Кима Харриса, предложившего многие из приведенных здесь соглашений, за его непрерывные усилия в приведении к общему знаменателю разнообразных взглядов на хорошую Форт-стилистику. - 134 - ОРГАНИЗАЦИЯ ЛИСТИНГОВ ~~~~~~~~~~~~~~~~~~~~~ Хорошо организованная книга разбита на ясно обозначенные главы, с четко очерченными разделами и списком содержимого, что помогает охватить ее структуру единым взглядом. Хорошо организованную книгу легко читать. Плохо же огранизованная книга затрудняет понимание и делает последующий поиск информации почти невозможным. Точно так же необходимость хорошей огранизации относится и к листингу программы. Вот три кита такой огранизации: 1. Декомпозиция 2. Составление 3. Распределение дискового пространства ДЕКОМПОЗИЦИЯ. Как мы уже видели, организация текста программы должна следовать разбиению задачи на лексиконы. В общем случае эти лексиконы надо выстраивать в порядке взаимного `использования`. Лексиконы, которые `используются`, должны предшествовать тем, которые их `используют`. В целом элементы листинга должны быть организованы в порядке возрастания сложности, при этом самые сложные построения - появляться ближе к концу. Лучше всего группировать все так, чтобы можно было не подключать близлежащие блоки (т.е. не загружать их), и все равно иметь самодостаточную, работоспособную задачу, которая не имеет только лишь некоторых сложных возможностей. Мы подробно рассмотрели искусство декомпозиции в главе третьей. СОСТАВЛЕНИЕ. Составление (композиция) состоит в складывании друг с другом кусочков для создания единого целого. Хорошая композиция требует столько же артистизма, сколько и хорошая декомпозиция. Одно из Фортовских соглашений состоит в том, что исходные тексты размещаются в "блоках" (*), которые являются порциями массовой памяти по 1К каждый. В Форте можно сцеплять каждый блок исходного текста со следующим, получая весь листинг линейным, в виде некоего длинного пергаментного свитка. Такой подход не хорош. Вместо него: (*) - в оригинале использовался термин "экран" ("screen"). В соответствии с более современными соглашениями здесь и далее "экраны" заменены на "блоки" ("blocks") (термин "экран" применялся ранее для обозначения блока, содержащего исходный текст). - 135 - ------------------------------------------------------------ СОВЕТ Стройте текст Вашей программы как книгу: иерархически. ------------------------------------------------------------ Задача может состоять из: `Блоков:` мельчайших частей текста на Форте; `Лексиконов:` от одного до трех блоков, достаточных для размещения компонента; `Глав:` серий родственных лексиконов; `Загрузочных блоков:` аналогичных оглавлению, такой блок загружает главы в нужной последовательности. БЛОК ЗАГРУЗКИ ПРОГРАММЫ. Рисунок 5-1 - это пример загрузочного блока. Поскольку этот блок имеет номер 1, можно загрузить всю задачу, введя 1 LOAD Отдельные команды LOAD внутри блока загружают главы задачи. К примеру, блок 12 - загрузочный для главы видео-примитивов. Рис.5-1. Пример загрузочного блока. Блок # 1 0 \ QTF+ Загрузочный Блок 07/09/83 1 : RELEASE# ." 2.01" ; 2 9 LOAD \ инструментарий компилятора, примитивы языка 3 12 LOAD \ видео-примитивы 4 21 LOAD \ редактор 5 39 LOAD \ отображение строки 6 48 LOAD \ форматтер 7 69 LOAD \ окна 8 81 LOAD \ предопределения 9 90 LOAD \ обрамление 10 96 LOAD \ надписи, рисунки, таблицы 11 102 LOAD \ генератор оглавления 12 13 14 15 - 136 - В блоке загрузки программы говорится о том, где найти все ее главы. Так, если Вам захочется посмотреть на программы для обрамления, можете найти их в секции, начинающейся с блока 90. Каждый из блоков загрузки главы, в свою очередь, загружает все блоки, входящие в эту главу. Мы вкратце изучим некоторые форматы блоков загрузки глав. Первый выигрыш от такой иерархической схемы состоит в том, что можно загружать любой участок или любой блок поодиночке, без необходимости компиляции всей задачи. Модульность исходного текста является одной из причин скорости Фортовского цикла редактирования, загрузки и проверки (необходимых для итеративного подхода). Как и страницы книги, каждый из блоков может быть доступен индивидуально и быстро. То есть имеет место "произвольный доступ" к управлению исходным текстом. Можно также заменять любой пассаж кода новой, испытанной версией с помощью простой замены чисел в блоке загрузки. Нет нужды в передвижении протяженных отрезков исходного текста внутри файла. В маленьких задачах может не быть таких вещей, как главы. Блок управления загрузкой задачи будет напрямую загружать все лексиконы. В то же время в более крупных задачах дополнительный уровень иерархии позволяет улучшить управляемость программы. Блок должен быть либо загрузочным, либо содержать программу, но не быть смешанным. Избегайте внедрения команд LOAD и THRU в середину блока с определениями только потому, что Вам "что-то нужно" или поскольку у Вас "не хватает места". КОМАНДЫ ОБХОДА (SKIP). Две команды облегчают управление тем, что загружается, а что игнорируется в блоке. Вот они: \ \S (иногда ;S , а также EXIT) \ произносится "пропустить-строку". Команда вызывает игнорирование интерпретатором Форта всего, что находится справа от нее в той же строке. (Поскольку \ является словом Форта, после него должен быть пробел.) Слову \ не требуется символ-ограничитель. На рисунке 5-1 слово \ используется двумя способами: в начале строки-комментария (строки 0) блока и для начала комментариев в отдельных строках, в которых справа больше нет кода. При отладке слово \ также служит для "закомментирования" строк, уже содержащих закрывающую круглую скобку в имени или - 137 - комментарии. К примеру, два таких значка пропуска строки предохраняют от компиляции определение ОРЕХИ без возникновения проблем в деле учета закрывающих скобок: \ : ОРЕХИ ( x y z) \ SWAP ROT (ОРЕХИ) ; \S произносится как "пропустить-страницу". Оно заставляет интерпретатор Форта полностью прекратить работу с текущим блоком, как будто в этом блоке больше ничего нет. Во многих Форт-системах эта функция по действию аналогична слову EXIT, которое является программой времени исполнения для слова ;. В этих системах возможно использование слова EXIT. В то же время некоторые Форт-системы по внутренним причинам требуют другого определения для функции "пропустить-страницу". Исходные тексты для \ и \S можно найти в приложении В. БЛОКИ ЗАГРУЗКИ ГЛАВ. На рисунке 5-2 продемонстрирован типичный блок загрузки главы. Загружаемые им блоки имеют относительный отсчет, а не абсолютный, как в блоке загрузки задачи. Рис.5-2. Пример блока загрузки главы. Блок # 100 0 \ Графика Загрузка главы 07/11/83 1 2 1 FH LOAD \ примитив рисования точки 3 2 FH 3 FH THRU \ примитивы рисования линий 4 4 FH 7 FH THRU \ масштабирование, вращение 5 8 FH LOAD \ прямоугольник 6 9 FH 11 FH THRU \ круг 7 8 9 10 УГОЛ \ инициализация относительной позиции в нижний левый 11 \ угол 12 13 14 15 - 138 - Это сделано потому, что такой блок является первым в последовательном наборе блоков этой главы. Вы можете перемещать всю эту главу вперед и назад по листингу; относительные указатели в блоке загрузки главы не зависят от конкретной позиции. Все, что Вам требуется поменять - это одно число в блоке загрузки задачи так, чтобы оно указывало на начало данной главы. ------------------------------------------------------------ СОВЕТ Используйте абсолютные номера блоков в блоке загрузки задачи. Используйте относительные номера в блоках загрузки глав или разделов. ------------------------------------------------------------ Есть два способа реализации относительной загрузки. Наиболее часто определяют: : +LOAD ( смещение -- ) BLK @ + LOAD ; и : +THRU ( смещение-от смещение-до -- ) 1+ SWAP DO I +LOAD LOOP ; Лично мне кажется более целесообразным иной путь, при котором требуется только одно слово, FH (его определение смотрите в приложении В). Фраза 1 FH LOAD читается как "1-й отсюда (From Here) загрузить" и эквивалентно 1 +LOAD. Точно так же 2 FH 5 FH THRU читается как "от 2-го отсюда до 5-го отсюда сквозь". Некоторые программисты начинают каждую главу с подставного слова типа : ВИДЕО-ПРИМИТИВЫ ; и указывают имя этого слова в строке комментария блока загрузки задачи, из которого загружается данная глава. Это позволяет выполнять FORGET выборочно для любой главы и перезагружаться с этой точки без необходимости просмотра текста этой главы. - 139 - Внутри главы первая группа блоков обычно будет определять те переменные, константы и другие структуры данных, которые будут нужны по всей главе. Следование такому принципу приводит к появлению цепи лексиконов, загружаемых в порядке "использования". Последние строки в блоке загрузки главы обычно содержат необходимые команды инициализации. Некоторые из наиболее озабоченных стилистикой Фортовых писателей начинают каждую главу с "преамбулы", в которой в общих словах обсуждаются основы работы компонентов этой главы. Рисунок 5-3 - это пример блоков-преамбул, показывающих формат, принятый на фирме Moore Products Co. Рис.5-3. Формат преамбулы главы в фирме Moore Products Co. 0 CHAPTER 5 - ORIGIN/DESTINATION - MULTILOOP BIT ROUTINES 1 2 DOCUMENTS - CONSOLE STRUCTURE CONFIGURATION 3 DESIGN SPECIFICATION 4 SECTIONS - 3.2.7.5.4.1.2.8 5 3.2.7.5.4.1.2.10 6 7 ABSTRACT - File control types E M T Q and R can all 8 originate from a Regional Satellite or a 9 Data Survey Satellite. These routines allow 10 the operator to determine whether the control 11 originated from a Regional Satellite or not. 12 13 14 15 0 CHAPTER NOTES - Whether or not a point originates from 1 a Regional Satellite is determined by 2 the Regional bit in BITS, as follows: 3 4 1 = Regional Satellite 5 2 = Data Survey Satellite 6 7 For the location of the Regional bit 8 in BITS, see the Design Specification 9 Section - 3.2.7.5.4.1.2.10 10 11 HISTORY - 12 13 14 15 - 140 - ---------------------------------------------------------------- Чарльз Мур (Charles Moore - не имеет никакого отношения к фирме Moore Products Co.) уделяет меньше, чем я, внимания хорошо организованному иерархическому листингу. Вот что говорит Мур: Я структурирую иерархически `задачу`, а не обязательно `листинги`. Мои листинги организованы несколько неряшливо, не иерархически в том смысле, чтобы примитивы шли первыми. Я использую слово LOCATE (известное также под именем VIEW; смотрите "Начальный курс...", стр.91). В результате листинг можно организовывать гораздо менее аккуратно, поскольку у меня есть LOCATE, которое мне все ищет. Я никогда не просматриваю листинги. ---------------------------------------------------------------- --> ПРОТИВ THRU. При относительной загрузке одним из популярных способов загрузки серии смежных блоков является использование слова --> (читается "следующий блок"). Оно заставляет интерпретатор намедленно прекратить работу с текущим блоком и начать интерпретацию следующего (со следующим номером). Если в Вашей системе есть -->, Вам придется делать выбор между использованием команды THRU в блоке загрузки главы и связыванием каждой последовательности воедино посредством стрелок и загрузкой с помощью LOAD лишь первого блока из серии. (Не следует делать и то, и другое; все закончится загрузкой многих блоков более одного раза.) Стрелочки хороши следующим: предположим, Вы меняете блок в середине серии, а затем перезагружаете его. Остальная часть серии также автоматически загружается. Вам не нужно помнить номер последнего нужного блока. Есть у стрелок и недостатки: нет способа прервать процесс загрузки после его начала. Вам придется скомпилировать гораздо больше блоков, чем это нужно для тестирования Вашего единственного кусочка. Если проанализировать все возможности, то обнаружатся три действия, которые Вам может понадобиться выполнить после внесения очередного изменения: 1. загрузить только один блок для проверки изменения, 2. загрузить всю секцию, в которую входит этот блок или 3. загрузить весь остаток задачи. - 141 - Использование слова THRU дает, кажется, наилучшие возможности управления. Кое-кто считает, что стрелки полезны для того, чтобы позволить определению через двоеточие пересечь границу одного блока. Действительно, единственный путь для компиляции высокоуровневого определения (через двоеточие) изрядной длины - это использование слова -->, поскольку оно имеет признак "немедленного исполнения". Но НИКОГДА не может считаться хорошим стилем пересечение таким определнием границы блока. (Оно никогда не должно быть столь длинным!) С другой стороны, чрезвычайно сложный и критичный ко времени исполнения кусок ассемблерного кода способен занимать несколько последовательных блоков. В этом случае все равно обычная загрузка вполне подходит, поскольку ассемблер не использует режим компиляции и поэтому не требует слов с признаком немедленного исполнения. Наконец, стрелки требуют наличия дополнительной строки в каждом блоке. Мы не рекомендуем их применение. АЛЬТЕРНАТИВА БЛОКАМ: ТЕКСТ В ИМЕНОВАННЫХ ФАЙЛАХ. Некоторые пользователи Форта предпочитают хранение исходных текстов в именованных текстовых файлах переменной длины, намеренно имитируя подход, используемый в обычных компиляторах и редакторах. Такой путь может становиться все более и более распространенным, однако его полезность остается спорной. Верно, хорошо не беспокоиться о том, что блока может не хватить, но ведь вынужденность использования ограниченного пространства блока компенсируется сохранением контроля над дискретными кусками кода. При разработке задачи Вы проводите гораздо больше времени, загружая и удаляя блоки, чем на переделывание их содержимого. Файлы с "безграничной длиной" позволяют мыслить неорганизованно и беспорядочно и плохо разбивать задачу. При отсутствии дисциплины, налагаемой границами 1К-байтного блока, определения становятся длиннее. Появляется тенденция писать 20-ти килобайтовые файлы или, что еще хуже, 20-ти килобайтовые определения. Быть может, лучшим компромиссом будет основанная на файлах система, позволяющая вложенную загрузку и вдохновляющую на использование очень маленьких именованных файлов. При этом наиболее вероятно, что опытные Форт-программисты не будут использовать именованные файлы с длиной более, чем в 5-10К. Так в чем же выигрыш? - 142 - Кое-кто высказывает следующее утверждение: "легче запоминать имена, чем числа". Если это так, то достаточно лишь предопределить номера блоков как константы: 90 CONSTANT ОБРАМЛЕНИЕ а затем для загрузки секции "обрамление" вводить ОБРАМЛЕНИЕ LOAD Или, для просмотра блока загрузки секции: ОБРАМЛЕНИЕ LIST (По соглашению, имена секций должны иметь окончания на "ИЕ" или аналогичные, соответствующие отглагольным существительным, в английском языке - на "ING" типа "framing".) Конечно, для уменьшения ограничений подхода, основанного на использовании блоков, Вам нужны хорошие инструменты, включая команды редактора, перемещающие строки исходного текста из одного блока в другой и слова, передвигающие серии блоков вперед или назад внутри листинга. РАЗБИЕНИЕ ДИСКА НА ЧАСТИ. Последний аспект хорошо организованного листинга включает в себя стандартизацию соглашения, по которому определяется, что где происходит на диске. Такие стандарты должны вырабатываться на каждом предприятии или в отделе или индивидуальным программистом, в зависимости от сущности работы. На рисунке 5-4 показана типичная для подразделения схема распределения места. Рис.5-4. Пример схемы распределения дискового пространства внутри одного отдела. Блок 0 - титульный блок, на нем показано наименование задачи, текущий номер версии и автор. Блок 1 - блок загрузки задачи. Блок 2 - зарезервирован для возможного продолжения блока 1. Блоки 4 и 5 - содержат системные сообщения. Блоки с 9 по 29 - утилиты общего назначения, нужные для отработки, но не для использования внутри задачи. Блок 30 - начало блоков задачи. - 143 - На многих предприятиях, работающих с Фортом, считается важным начинать секции кода на блоках, номера которых нацело делятся на три. Основные разделы на диске должны иметь границы, проходящие по номерам, кратным тридцати. Причина? По соглашению, блоки Форта распечатываются по три на страницу, причем начальный блок обычно имеет номер, кратный трем. Такая страница называется "триадой"; многие Форт-системы имеют слово TRIAD для формирования таких страниц, получая в качестве аргумента номер любой из трех страниц в триаде. К примеру, если набрать 77 TRIAD то будет напечатана страница блоков с номерами 75, 76 и 77. Основным преимуществом такого соглашения является то, что, если Вы исправляете один блок, то можете вложить новую триаду прямо в папку с распечаткой текущего листинга, заменяя при этом ровно одну страницу бумаги без перекрывающихся блоков. Аналогично, слово INDEX показывает первые строчки из каждого блока, содержащегося в 60-ти блочной странице, если границы проведены на линиях, кратных 60-ти (*). ------------------------------------------------------------ СОВЕТ Начинайте секции или лексиконы на блоках, чьи номера кратны трем. Начинайте задачи или главы на номерах, кратных тридцати. ------------------------------------------------------------ ВЫБОРКИ. Изготовители Форт-систем сталкиваются с такой проблемой: если они включат в систему все команды, которые могут потребоваться покупателю - слова для графики, принтеров и другие штучки - то зачастую обнаруживается, что съедено более половины емкости памяти компьютера и осталось не так уж много места для того, чтобы серьезные программисты могли компилировать свои задачи. Выходом для поставщика является разработка скелетного ядра с предварительно скомпилированными основными определениями, и отдельно - `исходных тестов` расширений. Этот путь позволяет программисту выбрать и скомпоновать действительно нужные ему специальные программы. (*) - это утверждение не соответствует описанию, приведенному в Приложении Б к стандарту Форт-83. - 144 - Такие загружаемые пользователем программы называются "выборками" (по-английски - "electives"). Арифметика двойной длины, поддержка печати даты и времени, конструкция CASE или DOER/MAKE (будут описаны позже) - это некоторые из тех вещей, которые Форт-система должна предлагать в качестве выборок. ОФОРМЛЕНИЕ БЛОКА ~~~~~~~~~~~~~~~~ В этом разделе мы обсудим правила оформления каждого из блоков с исходным текстом. ------------------------------------------------------------ СОВЕТ Оставляйте строку 0 в качестве строки комментария. ------------------------------------------------------------ Строка комментария служит как для заголовка блока, так и для получения информации по диску словом INDEX. Она должна описывать назначение блока (но не содержать список определяемых в нем слов). Как минимум, такая строка должна включать в себя наименование блока. В более крупных задачах можно также включить в нее и название главы. Если блок представляет собой часть серии блоков, реализующих лексикон, сюда же следует включить и "номер страницы". Верхний правый угол резервируется для "штампа". В него входит дата последнего изменения и, когда это имеет значение, инициалы программиста (три буквы слева от даты), т.е.: ( Имя главы Имя блока -- стр. # АБВ 06/10/83 ) Некоторые Форт-редакторы сами проставляют штамп при нажатии специальной клавиши. Обычной формой для представления даты (в Америке) является: мм-дд-гг то есть, февраль, 6-е число, 1984 года выражается как 02-06-84 Все возрастающую популярность приобретает такая альтернатива: ддМммгг - 145 - где "Ммм" - это трехбуквенное сокращение месяца. К примеру: 22Окт84 Для нее требуется большее количество разных символов, чем для 10-22-84 и возникают возможности для перепутывания чисел и букв. (Для российских систем рекомендуется принятая в Европе и обычная у нас форма "дд-мм-гг" или, еще лучше, "дд.мм.гг".) Если Ваша система имеет слово \ ("пропустить-строку" - см. приложение В), то можно писать строку комментария так: \ Имя главы Имя блока -- стр. # АБВ 06/10/83 Как и во всех других примечаниях, используйте маленькие буквы или смесь из букв нижнего и верхнего регистров для текстов строки комментария. Одним из путей достижения того, чтобы индекс приносил больше информации об организации файла - это установка отступа в строке комментария на три пробела для тех блоков, которые продолжают лексикон. На рисунке 5-5 показана порция распечатки, произведенной словом INDEX, в которой строки комментария для блоков-продолжений выполнены с отступом. Рис.5-5. Результат работы слова INDEX, показывающий отступы в строках комментария. 90 \ Графика Загрузка главы АБВ 06/10/83 91 \ Примитивы рисования точки АБВ 06/10/83 92 \ Примитивы рисования линий АБВ 06/10/83 93 \ Примитивы рисования линий АБВ 06/10/83 94 \ Примитивы рисования линий АБВ 06/11/83 95 \ Масштабирование, ротация АБВ 09/02/83 96 \ Масштабирование, ротация АБВ 06/10/83 97 \ Масштабирование, ротация АБВ 02/19/84 98 \ Масштабирование, ротация АБВ 02/19/84 99 \ Прямоугольники АБВ 02/19/84 100 \ Круги АБВ 06/10/83 101 \ Круги АБВ 06/10/83 102 \ Круги АБВ 06/10/83 - 146 - ------------------------------------------------------------ СОВЕТ Начинайте все определения с левого края блока, и определяйте не больше одного слова на строке. ------------------------------------------------------------ `Плохо:` : ПРИБЫТИЕ ." ПРИВЕТ" ; : ОТБЫТИЕ ." ДО СВИДАНИЯ" ; `Хорошо:` : ПРИБЫТИЕ ." ПРИВЕТ" ; : ОТБЫТИЕ ." ДО СВИДАНИЯ" ; Это правило облегчает поиск определения в листинге. (Когда определения распространяются более, чем на одну строку, последующие строки всегда должны набираться с отступом.) Переменные и константы (VARIABLE, CONSTANT) также следует определять по одной на строку. (См. "Примеры хорошего стиля комментирования" в приложении Д.) При этом остается место для объясняющего комментария в той же строке. Исключение составляют большие "семейства" слов (задаваемых специальным определяющим словом), для которых не требуются уникальные комментарии: 0 ОТТЕНОК ЧЕРНЫЙ 1 ОТТЕНОК СИНИЙ 2 ОТТЕНОК ЗЕЛЕНЫЙ 3 ОТТЕНОК ГОЛУБОЙ 4 ОТТЕНОК КРАСНЫЙ 5 ОТТЕНОК МАЛИНОВЫЙ ------------------------------------------------------------ СОВЕТ Оставляйте много места в конце блока для дальнейших добавлений. ------------------------------------------------------------ При первичном написании программы заполняйте каждый блок кодом не более, чем на половину. Итеративный подход предполагает, что Вы вначале набрасываете компоненты задачи, а затем итеративно оживляете их до тех пор, пока все требования не окажутся выполненными. Обычно это означает добавление новых команд или поддержку особых случаев в существующих блоках. (Не `всегда`, однако. Новая итерация может привести к упрощению кода. Или добавленная сложность может в действительности относиться к другому компоненту и будет выделена в другой блок.) Просторное размещение делает позднейшие добавления более приятными. Один писатель рекомендует при первом проходе заполнять блок кодом на 20-40 процентов и оставлять пустыми 80-60 процентов [1]. - 147 - Не пропускайте строку между каждыми двумя определениями. При этом все же можно пропустить строку между `группами` определений. ------------------------------------------------------------ СОВЕТ Все блоки должны оставлять систему счисления десятичной (DECIMAL). ------------------------------------------------------------ Даже если у Вас встречаются подряд три блока, в которых используется шестнадцатеричная (HEX) система (к примеру, три блока на ассемблере) каждый из них должен начинаться с HEX на вершине и возвращаться к DECIMAL внизу. Это правило дает уверенность в том, что каждый блок может быть загружен отдельно для тестирования без привнесения грязи в положение дел. Кроме того, при чтении листинга Вы всегда знаете, что номера блоков - десятичные, независимо от потребностей самих блоков в системе счисления HEX. На некоторых предприятиях это правило проводят даже дальше. Вместо того, чтобы по-простому исполнять DECIMAL в конце, на них возвращают основание системы счисления к `тому, каким оно было вначале`. Этот дополнительный предохранительный элемент может быть выполнен таким способом: BASE @ HEX \ сохранить исходн. состояние на стеке 0A2 CONSTANT ЗВОНКИ 0A4 CONSTANT СВИСТКИ ... и т.д. ... BASE ! \ восстановить сост. системы счисления Порой аргументы передаются через стек от блока к блоку, например, числа, возвращаемые словом BEGIN или IF в многоблочном ассемблерном определении, или базовый адрес, передаваемый от одного определяющего слова к другому - см. "Разбиение При Компиляции" в главе 6. В этих случаях лучше сохранять значение основания на стеке возвратов: BASE @ >R HEX ... и т.д. ... R> BASE ! В некоторых организациях такой подход обязателен для любого блока, который меняет основание системы счисления, поэтому им не нужно об этом беспокоиться. Мур предпочитает определять слово LOAD так, чтобы оно вызывало DECIMAL после загрузки. Такой подход упрощает содержимое блока, поскольку Вам самим не нужно заботиться о восстановлении основания. - 148 - ПРОПУСКИ И ОТСТУПЫ. ------------------------------------------------------------ СОВЕТ Без пропусков и отступов не может быть читаемости. ------------------------------------------------------------ Примеры в этой книге соответствуют широко распространенным соглашениям по стилю пропусков и отступов. Читаемость обеспечивается правильно используемыми пустыми местами. При этом нет никакого проигрыша, кроме увеличенного расхода дешевой дисковой памяти. Для тех, кто любит четко изложенные правила, в таблице 5-1 указаны основные постулаты. (Но помните, что для интерпретатора Форта не ничего менее значительного, чем Ваши отступы и пропуски.) Таблица 5-1. Основные отступы и пропуски. ---------------------------------------------------------------- 1 пробел между : и именем 2 пробела между именем и его комментарием * 2 пробела или новая строка после комментария до тела определения * 3 пробела между именем и телом определения, если комментарии не используются 1 пробел между словами/числами внутри фразы 2 или 3 пробела между фразами 1 пробел между последним словом и ; 1 пробел между ; и IMMEDIATE (при необходимости) Не ставить пустых строк между определениями, кроме случаев разграничения существенных групп определений. * `Часто наблюдаемая альтернатива - 1 пробел между именем и комментарием и 3 - между комментарием и определением. Более либеральный подход использует по 3 пробела до и после комментария. Что бы Вы ни выбрали, твердо этого придерживайтесь.` Последняя позиция в каждой строке должна быть пуста, кроме случаев, когда: а) надписи в кавычках продолжаются на следующую строку, или б) это - конец комментария. - 149 - Комментарий, начинающийся с \, может продолжаться до правого конца строки. Комментарии, начинающиеся с (, могут также иметь ограничительную ) в последней позиции строки. Вот некоторые частые ошибки при выполнении отступов и пропусков: `Плохо` (имя не отделено от тела определения): : ТОЛКАТЬ ВЗЯТЬСЯ НАЛЕЧЬ ; `Хорошо:` : ТОЛКАТЬ ВЗЯТЬСЯ НАЛЕЧЬ ; `Плохо` (последовательные строки без отступа в три пробела): : СЛАВА ( то-что-никогда-не-померкнет -- ) НЕ МЕРКНУТЬ НИКОГДА ; `Хорошо:` : СЛАВА ( то-что-никогда-не-померкнет -- ) НЕ МЕРКНУТЬ НИКОГДА ; `Плохо` (нет разбиения на фразы): : ГЕТТИСБУРГ 4 СЧЕТ 7 ЛЕТ + НАЗАД ; `Хорошо:` : ГЕТТИСБУРГ 4 СЧЕТ 7 ЛЕТ + НАЗАД ; Разбиение на фразы - искуство субъективное; я затрудняюсь предлагать какие-нибудь формальные правила. СОГЛАШЕНИЯ ПО КОММЕНТАРИЯМ ~~~~~~~~~~~~~~~~~~~~~~~~~~ Правильное составление комментариев обязательно. Имеются пять типов комментариев: комментарии по состоянию стека, по структуре данных, по входному потоку, по цели и повествовательные комментарии. `Комментарий по стеку` показывает, какие аргументы определение берет со стека, а какие возвращает на стеке (если такие есть). `Комментарий по структуре данных` показывает позицию и значение элементов этой структуры. К примеру, текстовый буфер может содержать счетчик в первом байте и 63 байта для текста. - 150 - `Комментарий по входному потоку` относится к тем строкам, которые слово собирается получить из входного потока. К примеру, слово Форта FORGET ищет имя словарного определения во входном потоке. `Комментарий по цели определения` описывает, по возможности кратко, что делает данное определение. То, как оно работает, не должно заботить целевой компонент. `Повествовательные комментарии` появляются внутри определения для объяснения того, что происходит, обычно строка за строкой. Такие комментарии используются исключительно в "вертикальном формате", который мы опишем в другом разделе. Комментарии обычно записываются буквами нижнего регистра для отделения их от текста программы. (Большинство слов Форта записываются буквами верхнего регистра, маленькие буквы используют лишь в некоторых специальных случаях.) В следующих разделах мы рассмотрим все стандартизованные форматы этих типов комментариев и дадим примеры на каждый из типов. СТЕКОВАЯ НОТАЦИЯ. ------------------------------------------------------------ СОВЕТ Каждое определение через двоеточие или на ассемблере, которое снимает или кладет аргументы на стек, должно сопровождаться стековым комментарием. ------------------------------------------------------------ "Стековая нотация" относится к соглашениям для представления того, что происходит на стеке. Формы такой нотации включают в себя "картинки стека", "изменения на стеке" и "комментарии изменений на стеке". СТЕКОВАЯ КАРТИНКА. Такая картинка изображает то, что предполагается находящимся на стеке в данный момент. Вещи перечисляются слева направо, причем слева находится дно стека, а справа - его вершина. К примеру, стековая картинка n1 n2 показывает лежащие на стеке два числа, причем наверху лежит n2 (в самой доступной позиции). - 151 - Это - тот же порядок, в котором Вы могли бы набрать эти числа, т.е. если n1=100, а n2=5000, можно было бы набрать 100 5000 для того, чтобы правильно положить их на стек. Стековая картинка может содержать либо аббревиатуры типа "n1", либо полностью прописанные слова. Обычно используют первое. Некоторые из стандартных аббревиатур показаны в таблице 5-2. Независимо от того, используются ли аббревиатуры или полные слова, каждое из них должно быть отделено пробелом. Если стековый комментарий описывается фразой (типа "адрес-последней-связи"), слова в такой фразе должны быть объединены черточками. К примеру, картинка адрес текущий-отсчет макс-предел показывает три элемента, находящихся на стеке. ИЗМЕНЕНИЯ НА СТЕКЕ. "Изменения на стеке" показывают две стековые картинки: первая изображает то, что определение может `потребить` со стека, а вторая - то, что оно на нем `возвращает`. Картинка "до" идет первой, после нее - два тире, а затем - картинка "после". К примеру, вот стековые изменения для оператора сложения Форта - слова + : n1 n2 -- сумма Слово + берет два числа со стека и возвращает их сумму. Помните, что изменения на стеке описывают лишь `чистый результат` выполняемой операции. Числа, которые, возможно, располагаются под используемыми аргументами, показывать не надо. Точно так же на надо показывать и те числа, которые появляются и исчезают на стеке во время исполнения определения. Если слово возвращает какие-нибудь входные аргументы неизмененными, то они должны быть повторены в выходной картинке: 3-й 2-й 1-входной -- 3-й 2-й 1-выходной И наоборот, если слово изменяет какие-нибудь аргументы, то стековая картинка должна использовать другое изображение: n1 -- n2 n -- n' - 152 - Изменения на стеке могут показываться и в сформатированном глоссарии. КОММЕТАРИИ ИЗМЕНЕНИЙ НА СТЕКЕ. "Комментарии изменений на стеке" - это описание таких изменений, появляющееся в исходном тексте в круглых скобках. Вот стековый комментарий для слова COUNT: ( адрес-строки-со-счетчиком -- адрес-текста длина ) или: ( 'строки-со-счетчиком -- 'текста длина ) ("Длина" после исполнения слова располагается на вершине стека.) Если определение не оказывает влияния на стек (то есть, с точки зрения пользователя эффекта не наблюдается, независимо от того, насколько интенсивно используется стек внутри определения), то стековый комментарий не нужен: : ПЕЧЬ ЦЫПЛЯТА ПЕЧКА ! ; С другой стороны, Вам может захотеться использовать пустой стековый комментарий - т.е.: : ПЕЧЬ ( -- ) ЦЫПЛЯТА ПЕЧКА ! ; для подчеркивания отсутствия влияния слова на состояние стека. Если определение берет аргументы, но ничего не возвращает, двойное тире необязательно, к примеру запись ( адрес длина -- ) может быть укорочена до ( адрес длина ) Такое соглашение принято на основании следующего наблюдения: гораздо чаще встречаются определения, которые берут аргументы и ничего не возвращают, чем те, которые ничего не берут, но возвращают на стеке результат. СТАНДАРТНЫЕ АББРЕВИАТУРЫ ДЛЯ СТЕКОВЫХ КОММЕНТАРИЕВ. Обозначения для стековой нотации должны быть содержательны. В таблице 5-2 показано большинство из наиболее часто - 153 - используемых аббревиатур. (Эта таблица повторяется и в приложении Д.) Термины "одинарная длина", "двойная длина" и т.д. относятся к размеру "ячейки" данной Форт-системы. (Если система использует 16-разрядные машинные слова, то "n" представляет 16-битное число; если система работает с 32-мя разрядами, то "n" представляет 32-х разрядное число.) ИЗОБРАЖЕНИЕ ФЛАГОВ. В таблице 5-2 показаны три способа изображения булевских флагов. Для иллюстрации: вот три версии одного и того же стекового комментария для слова -TEXT: ( a1 u a2 -- ? ) ( a1 u a2 -- t=не-равны ) ( a1 u a2 -- f=равны ) Таблица 5-2. Обозначения для стековых комментариев. ---------------------------------------------------------------- n чило одинарной длины со знаком d число двойной длины со знаком u чило одинарной длины без знака ud число двойной длины без знака t тройная длина q учетверенная длина c 7 (или 8)-битный символ b 8-ми битный байт ? булевский флаг, или: t= (true) истина f= (false) ложь a или adr или адр адрес acf адрес поля кода apf адрес поля параметров ' (в качестве префикса) адрес чего-либо s d (как пара) источник приемник lo hi нижняя- верхняя-граница (включительно) # число (количество) o (offset) смещение i индекс m маска x безразлично (для структур данных) ---------------------------------------------------------------- "Смещение" - это разница, выраженная в абсолютных единицах, например, байтах. "Индекс" - это разница, выраженная в логических единицах, например, элементах записи. - 154 - Знак равенства после символов "t" и "f" показывает, что этот флаг имеет определенное значение. Результат во втором варианте примера можно прочесть как "истина означает отсутствие равенства". ЗАПИСЬ ДЛЯ РАЗЛИЧНЫХ ВАРИАНТОВ. Некоторые определения при различных обстоятельствах по-разному воздействуют на стек. Если количество чисел на стеке в любом случае остается неизменным, а меняются лишь функции этих чисел, можно использовать вертикальную черту (|) для обозначения "или". Следующий комментарий изменения стека описывает слово, возвращающее либо адрес файла, либо нуль, если файл не найден: ( -- адрес|0=файла-нет) Если количество чисел на стековой картинке может меняться - как на картинке "до", так и "после", - Вам следует писать обе версии полной стековой картинки, каждую - со своим двойным тире, разделенные символом "или". К примеру: -FIND ( -- apf len t=найдено | -- f=не-найдено ) Этот комментарий показывает, что если слово найдено, то на стеке возвращаются три аргумента (с флагом на вершине); иначе возвращается только флаг "ложь". Обратите внимание на важность второго появления "--". Если его опустить, то это будет означать, что определение всегда возвращает три аргумента с флагом на вершине стека. При желании можно записывать весь стековый комментарий дважды, либо в одной строке, отделяя записи тремя пробелами: ?DUP \ если 0: ( n -- n) если не-0: ( n -- n n ) либо по вертикали: -FIND \ найдено: ( -- apf len t ) \ не-найдено: ( -- f ) КОММЕНТАРИИ К СТРУКТУРАМ ДАННЫХ. "Комментарий к структуре данных" изображает элементы такой структуры. Для примера, вот определение буфера для вставки по имени |ВСТАВКА: CREATE |ВСТАВКА 64 ALLOT \ { 1# | 63текст } - 155 - Фигурные скобки начинают и заканчивают комментарий к структуре; вертикальные черточки отделяют различные элементы в структуре; числа представляют байты на элемент. В вышеприведенном комментарии первый байт содержит счетчик, остальные 63 отведены для текста. "Битовый комментарий" использует такой же формат для отображения значения битов в байте или слове. К примеру, битовый комментарий { 1занят? | 1принят? | 2x | 6входное-устройство | 6выходное-устройство } описывает формат 16-ти битового регистра состояния коммуникационного канала. Первые два бита - флаговые, следующие два бита не используются и последняя пара 6-ти битных полей показывает, к какому входному и выходному устройству присоединен этот канал. Если одну и ту же последовательность элементов использует более, чем одна структура данных, выпишите комментарий только один раз (возможно, в преамбуле), и дайте имя этой последовательности для последующих ссылок. К примеру, если в преамбуле вышеприведенной битовой последовательности дано имя "статус", то это имя можно употреблять в стековых комментариях для указания функции соответствующих чисел: : СТАТУС? ( -- статус) ... ; Если переменная двойной длины типа 2VARIABLE содержит одно число двойной длины, то комментарий должен быть стековой картинкой, показывающей это содержимое: 2VARIABLE ЦЕНА \ цена в копейках Если 2VARIABLE содержит два элемента одинарной длины, стековая картинка должна отображать то, что окажется на стеке после исполнения 2@. То есть: 2VARIABLE ИЗМЕРЕНИЯ ( высота масса ) Это отличается от того, каким был бы комментарий, если бы ИЗМЕРЕНИЯ были бы определены через CREATE: CREATE ИЗМЕРЕНИЯ 4 ALLOT \ { 2масса | 2высота } (Хотя в словаре оба определения будут представлены одинаково, использование 2VARIABLE предполагает, что значения будут обычно извлекаться и загружаться туда одновременно, с помощью 2! и 2@, - 156 - и поэтому мы используем `стековый` комментарий. Число, появляющееся на вершине стека, указывается справа. При использовании CREATE имеется в ввиду, что эти значения будут извлекаться и загружаться по-отдельности - и мы используем комментарий для `структуры данных`. При этом 0-й элемент показывается слева.) КОММЕНТАРИИ ДЛЯ ВХОДНОГО ПОТОКА. Эти комментарии показывают, какие слова и/или строки предполагается извлекать из входного потока. В таблице 5-3 приведены сокращения, используемые для обозначения аргументов во входном потоке. Таблица 5-3. Обозначения аргументов во входном потоке. ---------------------------------------------------------------- c одиночный символ, выделенный пробелами name или имя последовательность символов, выделенная пробелами text или текст последовательность символов, выделенная не пробелами ---------------------------------------------------------------- После слова "текст" ставьте требуемый символ-ограничитель, типа: текст" или текст). Комментарий входного потока приводится `до` стекового комментария и `не` заключается в собственную пару круглых скобок, а просто отделяется тремя пробелами с каждой стороны. К примеру, вот один способ комментирования определения слова ' (штрих), в котором вначале идет комментарий входного потока, а затем - комментарий стека: : ' \ имя ( -- а) Если Вы предпочитаете использовать (, комментарий будет выглядеть так: : ' ( имя ( -- а) - 157 - Есть три различных способа получения входной строки. Для ясности обозначим соответствующие термины: * `Сканирование` означает просмотр вперед по входному потоку, либо для получения слова или числа в случае ', либо для поиска ограничителя, как для слов ." или (. * `Ожидание` означает использование слов EXPECT и KEY, а определения, которые их используют - "ожидают" ввода. * `Предположение` показывает, что обычно что-то должно последовать. Слово : "сканирует" входной поток для получения имени определения и "предполагает", что последует тело этого определения. Комментарий входного потока подходит только для случая использования сканирования. ЦЕЛЕВЫЕ КОММЕНТАРИИ. ------------------------------------------------------------ СОВЕТ Каждое определение должно иметь целевой комментарий, кроме случаев, когда: а) его работа ясна из стекового комментария, или б) оно состоит из трех или меньшего числа слов. ------------------------------------------------------------ Целевой комментарий должен иметь минимальные размеры - никогда не быть длиннее одной строки. К примеру: : COLD \ сбросить систему в исходное состояние ... ; Используйте повелительное наклонение: "установить цвет фона", а не "устанавливает цвет фона". С другой стороны, назначение слова может быть зачастую описано в терминах его стекового комментария. Нужда в обоих комментариях одновременно всречается не часто. Пример: : SPACES ( #) ... ; или : SPACES ( #пробелов-напечатать -- ) ... ; Это определение получает в качестве входного аргумента число, представляющее количество пробелов, которые надо напечатать. - 158 - : ЭЛЕМЕНТ ( #элемента -- 'элемента ) 2* ТАБЛИЦА + ; Это определение преобразует получаемый им индекс в адрес внутри таблицы 2-х байтных элементов, относящийся к нужному элементу. : PAD ( -- 'временного-буфера) HERE 80 + ; Это определение дает адрес района памяти для временного использования. Иногда читабельность лучше обеспечивается применением обоих типов комментариев. В этом случае целевой комментарий должен появляться последним. К примеру: : BLOCK ( n -- a) \ закрепить блок n в буфере по адресу а ------------------------------------------------------------ СОВЕТ Показывайте тип комментария, соблюдая следующий порядок: вначале - комментарий по входному потоку, затем - комментарий изменений на стеке, последний - целевой комментарий. ------------------------------------------------------------ К примеру: : ДАТЬ \ имя ( -- а) дать первое совпадение Если Вы предпочитаете использовать (, можно записать: : ДАТЬ ( имя ( -- а) ( дать первое совпадение) При необходимости можно расположить целевой комментарий в следующей строке: : WORD \ имя ( с -- а) \ сканировать с символом-ограничителем с, получить по а ... ; КОММЕНТАРИИ К ОПРЕДЕЛЯЮЩИМ СЛОВАМ. При определении определяющего слова надо описывать два типа поведений: определяющего слова, когда оно создает своего "потомка", и самого потомка (работу в режиме исполнения). - 159 - Эти два вида поведения следует комментировать по-отдельности. ------------------------------------------------------------ СОВЕТ Пишите комментарий к определяющему слову в режиме компиляции обычным образом; в режиме же исполнения отдельно, после слова DOES> (или ;CODE). ------------------------------------------------------------ К примеру, : CONSTANT ( n ) CREATE , DOES> ( -- n ) @ ; Комментарий изменений на стеке для поведения времени исполнения (т.е. потомка) показывает действие, производимое словом-потомком. При этом он не включает в себя изображение адреса, возвращаемого словом DOES>, хотя этот адрес и находится на стеке в начале исполнения потомка. `Плохо` (комментарий времени исполнения содержит apf): : МАССИВ \ имя ( #ячеек -- ) CREATE 2* ALLOT DOES> ( i apf -- 'ячейки) SWAP 2* + ; `Хорошо:` : МАССИВ \ имя ( #ячеек -- ) CREATE 2* ALLOT DOES> ( i -- 'ячейки) SWAP 2* + ; Слова, определенные через МАССИВ, будут производить следующие действия на стеке: ( i -- 'ячейки) Если определяющее слово не специфицирует поведения во время исполнения, это время все равно существует и может быть описано: : VARIABLE ( имя ( -- ) CREATE 2 ALLOT ; \ does> ( -- адр) - 160 - КОММЕНТАРИИ ДЛЯ КОМПИЛИРУЮЩИХ СЛОВ. Так же, как и для определяющих слов, большинство компилирующих слов дают два типа поведения: 1. Поведение компилирующего слова, когда оно появляется при компиляции очередного определения; 2. Поведение программы периода исполнения, когда вызвано слово, скомпилированное через данное компилирующее слово. И вновь нам нужно писать комментарии раздельно для каждого из типов. ------------------------------------------------------------ СОВЕТ Пишите комментарий для поведения компилирующего слова в период исполнения обычным образом; комментируйте его поведение в режиме компиляции отдельно, начиная с пометки "Compile:" ("Компиляция:). ------------------------------------------------------------ Пример: : IF ( ? -- ) ... \ Компиляция: ( -- адр-неразрешенной-ссылки) ... ; IMMEDIATE В компилирующих словах первая строка комментария описывает поведение в режиме исполнения, которое обычно и является `синтаксисом при использовании` слова. Второй комментарий описывает, что слово `в действительности делает` при компиляции (что менее важно для пользователя). Еще примеры: : ABORT" ( ? -- ) \ Компиляция: текст" ( -- ) Иногда компилирующее слово может по-другому вести себя при вызове `вне` определения через двоеточие. Такие слова (они вызывают брезгливость) требуют три строки комментария. К примеру: : ASCII ( -- c) \ Компиляция: с ( -- ) \ Интерпретация: с ( -- с ) ... ; IMMEDIATE В приложении Д приведены два блока, демонстрирующие хороший стиль комментирования. - 161 - ВЕРТИКАЛЬНЫЙ ФОРМАТ ЗАПИСИ ПРОТИВ ГОРИЗОНТАЛЬНОГО. Целью комментирования является сделать читателю Вашего кода происходящее хорошо понятным. Однако сколько же нужно примечаний? Для понимания того уровня комментирования, который соответствует Вашим обстоятельствам, надо задать себе два вопроса: Кто будет читать мой код? Насколько удобочитаемы мои определения? На выбор имеются два основных стиля комментирования. Первый, называемый "вертикальным форматом", содержит пошаговое описание процесса - так, как это делается в хорошо документированных ассемблерных программах. Такие построчные комментарии называются "повествовательными". \ КЦК Контрольная сумма 07/15/83 : НАКОПИТЬ ( старКЦК символ -- новКЦК ) 256 * \ сдвинуть символ в старший байт XOR \ и искл.-ИЛИ со старым КЦК 8 0 DO \ затем восемь раз DUP 0< IF \ если старший бит равен "1" 16386 XOR \ искл.-ИЛИ с маской DUP + \ и сдвинуть влево на 1 разряд 1+ \ установить "1" в младшем бите ELSE \ иначе, т.е. если старший бит - "0" DUP + \ сдинуть влево на 1 разряд THEN \ LOOP ; \ завершение цикла При другом подходе кодовые фразы не перемежаются повествовательными комментариями. Он называется "горизонтальным форматом". : НАКОПИТЬ ( старКЦК символ -- новКЦК ) 256 * XOR 8 0 DO DUP 0< IF 16386 XOR DUP + 1+ ELSE DUP + THEN LOOP ; Вертикальный формат предпочтителен, когда над задачей работает большая команда программистов. Обычно такая группа включает в себя несколько программистов начального уровня, способных делать небольшие коррекции. При таком окружении по-строчное комментирование может сэкономить много времени и нервов. Как говорит Джонсон из Moore Products Co.: "При сопровождении программы обычно интересен один небольшой кусочек кода, и чем больше информации в нем написано, тем выше Ваши шансы быстро во всем разобраться". - 162 - Вот несколько уместных правил для Форт-программистов из Moore Products Co. (я перефразирую): 1. Должен использоваться вертикальный формат. Комментарии должны располагаться справа от исходного текста, но при необходимости могут занимать и всю следующую строку. 2. В комментариях должно быть больше символов, чем в относящимся к ним коде. (Фирма поощряет использование длинных описательных имен, более чем по десять символов длиной, и позволяет засчитывать имена в качестве комментариев.) 3. Любая структура управления или высокоуровневое слово должно появляться на отдельной строке. "Шумовые слова" могут группироваться вместе. Для показа вложенных условных переходов используются отступы. Однако с таким форматом есть и некоторые сложности. С одной стороны, по-строчное комментирование отнимает много времени, даже при наличии хорошего экранного редактора. Продуктивность может резко упасть, особенно если остановки для написания комментариев прерывают ход Ваших мыслей. Кроме того, приходится тщательно следить за тем, чтобы комментарии соответствовали действительности. Часто код меняется, версия проверяется, изменение работает - и программист при этом забывает поменять комментарий. Чем больше комментариев, тем больше вероятность того, что они неверны. Если же они неверны, то они более чем бесполезны. Эта проблема может быть уменьшена, если руководитель проекта тщательно проверяет код и убеждается в точности примечаний. Наконец, подробное комментирование может дать ложное чувство безопасности. Не надейтесь на то, что, поскольку каждая `строчка` имеет примечание, `задача` хорошо прокомментирована. По-строчные примечания не подчеркивают важные аспекты работы определения. Что, к примеру, за мысль заложена в использованном алгоритме подсчета контрольной суммы? Как ее понять из повествовательных комментариев? Для хорошего описания словами сущности данной процедуры требуется обычно много параграфов, а вовсе не одна фраза. Такие описания, скорее всего, должны быть представлены в иной документации или в преамбуле к главе. Несмотря на все это, многие компании считают необходимым применение вертикального формата. Очевидно, что команда, начинающая работать с Фортом, должна его применять, так же, как и любая очень большая рабочая группа. А как же горизонтальный формат? Быть может, это дело практики или личного искуства, но я просто обязан защитить горизонтальный формат как не менее ценный и, в некоторых случаях, более выигрышный. - 163 - Если Форт-код хорошо написан, то в нем не должно быть неясностей. Это означает, что: * лексиконы поддержки имеют хорошо спроектированный синтаксис * преобразования на стеке закомментированы * выполнен целевой комментарий (если он не ясен из имени определения или стекового комментария) * определения не слишком длинны * не слишком много аргументов передается через стек одному определению (смотрите "Шикарный стек" в главе 7). Форт просто не таков, как другие языки, в которых по-строчные примечания - это одна из немногих вещей, которые можно сделать для повышения читаемости программ. Мастерски написанный на Форте код подобен поэзии, он содержит точное значение, которое и программист, и машина легко читают. Вашей `целью` должно быть написание такого кода, к которому примечания не нужны, даже если Вы захотите его комментировать. Проектируйте свои задачи так, чтобы код, а не примечания, нес в себе смысл. Если Вы пойдете таким путем, то сможете устранить горы кропотливого комментирования, достигая чистоты выражения без избыточных объяснений. ------------------------------------------------------------ СОВЕТ Самой аккуратной и наименее дорогостоящей документацией является самодокументированный код. ------------------------------------------------------------ Рисунок в тексте: Программист Уиггинс, гордящийся своей техникой комментирования. Быстрая ( установка для лисы; быстро движется) коричневая ( и имеет цвет шоколада) лиса ( исполнить лисицу) прыгает через ( дать действие лисицы) ленивого ( установка для собаки) пса ( то, через что лисица перепрыгнула) К сожалению, даже лучшие программисты под давлением обстоятельств могут писать работающий код, который без примечаний читается нелегко. Если Вы пишете для себя, или работаете в маленькой группе, в которой есть взаимопонимание (на уровне слов), горизонтальный формат идеален. В иных случаях придерживайтесь вертикального формата. - 164 - ВЫБОР ИМЕН: ИСКУССТВО ~~~~~~~~~~~~~~~~~~~~~ Кроме математических склонностей, исключительно хорошее владение своим родным языком - это одно из наиболее жизненно необходимых компетентному программисту качеств. (`Проф. Эдсжер У. Дийкстра [3]`). Мы говорили о важности использования имен для обозначения идей или объектов в задаче. Выбор имен оказывается важной частью процесса проектирования. Новички недооценивают вклад имен. "В конце концов," - думают они, - "компьютеру безразлично, какие наименования я выбираю". Однако хорошие имена неотделимы от читабельности. Более того, мысленная попытка исполнения названного одним словом определения производит психологический эффект на Ваше представление о том, что должно, а что не должно делать целое. Вот некоторые правила для выбора имен: ------------------------------------------------------------ СОВЕТ Выбирайте имена в соответствии с тем, `что`, а не с тем, `как`. ------------------------------------------------------------ Определение должно скрывать от других определений сложности своей реализации. Кроме того, имя должно прятать детали процедур, описывая вместо них внешнее поведение или воздействие на стек. К примеру, слово Форта ALLOT просто увеличивает указатель вершины словаря (называемый в большинстве систем DP или H). Однако имя ALLOT лучше имени DP+! тем, что пользователь думает о резервировании места, а не увеличении указателя. В стандарте-83 принято имя CMOVE> вместо использовавшегося раньше функционально такого же R произносят "на-эр"; R> зовется "с-эр"). ------------------------------------------------------------ СОВЕТ Любите короткие слова. ------------------------------------------------------------ При выборе между трех-сложным и одно-сложным словом, означающим одно и то же, останавливайтесь на кратчайшем. ЯРКОСТЬ лучше, чем ИНТЕНСИВНОСТЬ. ВКЛЮЧИТЬ - более приемлемое имя, чем АКТИВИЗИРОВАТЬ; ПУСК, GO, RUN или ON могут оказаться еще лучше. Короткие имена легче набирать. Они экономят место в блоке с исходным текстом. Что более важно, они делают код живым и чистым. ------------------------------------------------------------ СОВЕТ Чрезмерно усложненные имена могут быть признаком плохого качества разбиения. ------------------------------------------------------------ ---------------------------------------------------------------- Мур: В Форт-среде встречаются разнообразные стили программирования. Некоторые используют сверхдлинные слова, выражающие по-английски свое назначение. Вы составляете вместе строчки из таких больших длинных слов и получаете что-то крайне хорошо читабельное. Однако я тут же начинаю подозревать, что программист недостаточно хорошо продумал свои слова, что тире надо было бы разбить и составные части определить по-отдельности. Это не всегда возможно и не всегда приносит выгоду. Но я все равно подозреваю многочленное слово в смешивании двух концепций. ---------------------------------------------------------------- - 169 - Сравните две следующие стратегии для одних и тех же вещей: ВКЛЮЧИТЬ-ЛЕВЫЙ-МОТОР ЛЕВЫЙ МОТОР ПУСК ВКЛЮЧИТЬ-ПРАВЫЙ-МОТОР ПРАВЫЙ МОТОР ПУСК ВЫКЛЮЧИТЬ-ЛЕВЫЙ-МОТОР ЛЕВЫЙ МОТОР СТОП ВЫКЛЮЧИТЬ-ПРАВЫЙ-МОТОР ПРАВЫЙ МОТОР СТОП ВКЛЮЧИТЬ-ЛЕВЫЙ-МАГНИТ ЛЕВЫЙ МАГНИТ ПУСК ВКЛЮЧИТЬ-ПРАВЫЙ-МАГНИТ ПРАВЫЙ МАГНИТ ПУСК ВЫКЛЮЧИТЬ-ЛЕВЫЙ-МАГНИТ ЛЕВЫЙ МАГНИТ СТОП ВЫКЛЮЧИТЬ-ПРАВЫЙ-МАГНИТ ПРАВЫЙ МАГНИТ СТОП Синтакис левой части требует восьми словарных статей; синтаксис правой - только шести, и некоторые из этих слов, скорее всего, могут быть использованы и в других частях задачи. Если у Вас появятся "средние" мотор с магнитом, то число слов для описания всех 16-ти возможных ситуаций возрастет только до семи. ------------------------------------------------------------ СОВЕТ Не внедряйте числа в имена. ------------------------------------------------------------ Следите за появлением имен, начинающихся или заканчивающихся цифрами, таких, как 1КАНАЛ, 2КАНАЛ, 3КАНАЛ и т.д. Такое сращивание имен и чисел может указывать на плохо выполненное разбиение. Здесь состав преступления тот же, что и в сверхдлинных словах, только отделить нужно было не слово, а число. Лучше было бы разбить вышеуказанное так: 1 КАНАЛ 2 КАНАЛ 3 КАНАЛ В этом случае необходимые три слова сократились до одного. Зачастую скрещивание чисел со словами может означать недостаток фантазии при выборе имен. В вышеприведенном случае более описательными могли бы оказаться, например, имена МИКРОФОН ТЕЛЕМЕТРИЯ ГИТАРА Мы еще дадим развитие всем этим соображениям в следующей главе при "фрагментации". - 170 - СТАНДАРТЫ ПРИ ВЫБОРЕ ИМЕН: НАУКА ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ------------------------------------------------------------ СОВЕТ Изучите и используйте соглашения по выбору имен в Форте. ------------------------------------------------------------ Для создания коротких, но наполненных значением слов Форт-программисты приняли некоторые соглашения. В приложении Д приводится наработанный за многие годы список из таких наиболее полезных соглашений. Примером мощи соглашений может служить использование "точки" для обозначения "печати" или "вывода". Сам Форт имеет слова . D. U.R для вывода различных типов чисел в разных форматах. Соглашения также распространяются и на целевые слова. Если у Вас имеется переменная по имени ДАТА, и Вам нужно слово, которое печатает эту дату, используйте имя .ДАТА Замечание: чрезмерное увлечение префиксами и суффиксами делает слова уродливыми и совсем нечитаемыми. Не пытайтесь описать все, что делает слово только в его имени. В конце концов, имя - это просто символ, а не краткое содержание кода. Что звучит лучше и лучше читается?: Эдипов комплекс (что само по себе ничего не означает), или подсознательное-влечение-к-родителю-иного-пола комплекс Наверное, первое, хотя оно и предполагает, что Вы в курсе дела. ------------------------------------------------------------ СОВЕТ Используйте префиксы и суффиксы для подчеркивания отличий между похожими друг на друга словами вместо того, чтобы с их помощью расписывать значения слов внутри имен. ------------------------------------------------------------ К примеру, фраза ... ГОТОВО IF ЗАКРЫТЬ THEN ... - 171 - так же читаема, как и ... ГОТОВО? IF ЗАКРЫТЬ THEN ... и при этом выглядит более чистой. Поэтому она предпочтительна, если только нам не требуется дополнительное слово ГОТОВО (например, в качестве флага). Последний совет по именам: ------------------------------------------------------------ СОВЕТ Начинайте все шестнадцатеричные числа с "0" (нуль) для исключения потенциальной путаницы с именами. ------------------------------------------------------------ Например, пишите 0ADD, а не ADD. Между прочим, не очень расчитывайте на то, что Ваша Форт-система поддерживает все эти соглашения. Предполагается, что такие соглашения должны применяться для новых разработок. Форт был создан и многие годы улучшался людьми, которые использовали его в хвост и в гриву. В те времена было не нужно, да и невозможно воздвигать стандарты на имена для инструмента, который все еще рос и углублялся. Если бы Форт был спроектирован каким-нибудь комитетом, мы бы его так не любили. ЕЩЕ СОВЕТЫ ПО ЧИТАБЕЛЬНОСТИ ~~~~~~~~~~~~~~~~~~~~~~~~~~~ Вот несколько заключительных предложений для повышения удобочитаемости Вашего кода. (Определения приводятся в приложении В). Всегда окупающей себя в большинстве задач константой является BL (код ASCII для "пробела"). Слово ASCII применяется, в основном, внутри определений через двоеточие для того, чтобы освобождать нас от необходимости знания численного значения символов ASCII. К примеру, вместо того, чтобы писать : ( 41 WORD DROP ; IMMEDIATE помня, что 41 - это код ASCII для закрывающей скобки, можно написать : ( ASCII ) WORD DROP ; IMMEDIATE Сделать работу с булевскими значениями более наглядной могут - 172 - слова TRUE и FALSE (ИСТИНА и ЛОЖЬ). Эти добавления позволят Вам писать выражения типа TRUE 'МАРКА? ! для установки флага, или FALSE 'МАРКА? ! для его очистки. (Когда-то я использовал T и F, но они мне нужны так редко, что теперь я осмотрительно придерживаюсь соглашения против сокращений.) Частью Вашей задачи (не обязательно частью Вашей Форт-системы) может стать следующий шаг в развитии этой идеи: : ON ( a) TRUE SWAP ! ; : OFF ( a) FALSE SWAP ! ; Эти слова позволят Вам писать: 'МАРКА? ON или 'МАРКА? OFF Эти определения встречаются и под другими именами, типа SET и RESET (УСТАНОВИТЬ и СБРОСИТЬ), хотя обычно слова с такими именами используют маски для манипуляций отдельными битами. Слово WITHIN (МЕЖДУ) также используется часто. Оно определяет, находится ли данное значение в интервале между двумя другими числами. Синтаксис его таков: n lo hi WITHIN Число "n" подлежит проверке, а "lo" и "hi" представляют диапазон. Слово WITHIN возвращает истину (TRUE), если "n" `больше или равно` "lo" и `меньше` "hi". Такое использование верхнего ограничителя (его исключение) соответствует аналогичному синтаксису циклов DO LOOP. Мур рекомендует использовать слово UNDER+ (ПОД+). Оно полезно для складывания между собой чисел не на вершине стека, а под его вершиной. На высоком уровне его можно было бы определить так: : UNDER+ ( a b c -- a+b c ) ROT + SWAP ; - 173 - ИТОГИ ~~~~~ Поддерживаемость задачи требует ее удобочитаемости. В этой главе мы перечислили много путей для того, чтобы делать код более читабельным. Мы одобрили курс на написание сколь это только возможно более самодокументированных программ. Технические приемы при этом касаются организации листингов, отступов и пробелов в тексте, комментирования, выбора имен и дополнительных слов, повышающих ясность кода. Мы только вскользь упомянули внешнюю документацию, которая представляет собой все, что не входит в собственно листинг. Мы не будем ее в дальнейшем обсуждать, однако она все равно остается неотъемлемой частью процесса создания программного обеспечения. ЛИТЕРАТУРА ~~~~~~~~~~ 1. Gregory Stevenson, "Documentation Priorities," `1981 FORML Conference Proceedings`, p. 401. 2. Joanne Lee, "Quality Assurance in a FORTH Environment," (Appendix A), `1981 FORML Proceedings,` p.363. 3. Edsger W. Dijkstra, `Selected Writings on Computing: A Personal Perspective,` New York, Springer Verlag, Inc., 1982. 4. Henry Laxen, "Choosing Names," `FORTH Dimensions,` vol. 4, no. 4, FORTH Interest Group.