Л.БРОУДИ. СПОСОБ МЫШЛЕНИЯ - ФОРТ. часть 9 ЭПИЛОГ, ПРИЛОЖЕНИЯ А,Б,В,Г,Д --------------------------------------------------------------- - 276 - ЭПИЛОГ В О З Д Е Й С Т В И Е Ф О Р Т А ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Н А М Ы Ш Л Е Н И Е ~~~~~~~~~~~~~~~~~~~~~ ---------------------------------------------------------------- Форт подобен Дао: это Путь, и осознается он, когда ему следуешь. Хрупкость его есть его сила; его простота есть его направление. (Майкл Хэм, победитель конкурса Mountain View Press на описание Форта в двадцать пять слов или меньше.) Чтобы помочь в извлечении чего-нибудь из философии Форта, я произвел опрос нескольких пользователей Форта по вопросам: "Как Форт повлиял на Ваше мышление? Не обнаружили ли Вы, что применяете 'Фортообразные' принципы в других областях?" Вот некоторые из ответов: Марк Бернстейн является президентом фирмы Eastgate Systems Inc. в Кембридже, штат Массачусетс, и имеет докторскую степень от химического факультета Гарвардского университета. Впервые я повстречался с Фортом, когда работал в области лазерной химии. Я пытался построить довольно сложный контроллер для нового лазерного спектрометра. Первоначальные планы предусматривали большой зеленый ящик, полный электроники - Интерфейс. Никто раньше конкретно этот вид прибора не делал - поэтому мы им и занимались - и список того, что мы хотим от компьютера, менялся каждые несколько недель. Через несколько месяцев у меня были сотни страниц программ на ассемблере, три большие платы, набитые микросхемами и 70-штырьковый разъем Системной Шины. День за днем все становилось все более шатким и трудно уловимым. Надписи на печатных платах испарились, разъемы законтачили, а запутанность ассемблерного кода возросла еще больше. Форт был очевидным решением программной проблемы, поскольку давал приличное окружение, в котором можно было строить и поддерживать сложный и быстро меняющийся код. Но сущность хорошего стиля программирования на Форте состоит в искусстве разбиения процедур на полезные, - 277 - самостоятельные слова. Идея слов Форта нашла неожиданное применение для разработки лабораторного оборудования. Вместо построения большого, монолитного, всеобъемлющего Интерфейса, я обнаружил, что строю кучу простых маленьких коробочек, которые работали во многом как слова Форта: они имели фиксированный набор стандартных входов и выходов, они выполняли всего по одной функции, они проектировались для соединения друг с другом без особых усилий, и они были достаточно просты, чтобы можно было сказать, что делает такая коробочка, просто поглядев на ее этикетку. ... Идея "расширения человека", я думаю, является сегодня зародышевой идеей в концепции разработки программного обеспечения. Это касается не обязательно только для Форт-разработок; огромное удовольствие от UNIX, по крайней мере, в дни его юности, доставляло то, что его можно было прочитать (поскольку он был написан на Си), понять (поскольку он был мал) и изменить (поскольку он был прост). Форт разделяет эти преимущества, хотя он был создан для другого сорта задач. Поскольку Форт мал, и поскольку он предоставляет своим пользователям контроль над их машинами, то он позволяет и по-человечески управлять приложениями. Тоскливо наблюдать за тем, как ученые сидят перед лабораторным компьютером, играя в "двадцать-два-вопроса" с пакетным программным обеспечением. При правильном использовании Форт позволяет ученому учить компьютер вместо того, чтобы разрешать компьютеру учить ученого. Как в хоккее, где игрок ощущает клюшку расширением своей руки, так и Форт расширяется человеком и помогает выработать ощущение, что достижения или просчеты компьютера являются также и твоими. Реймонд Э. Десси является профессором химии Вирджинского политехнического института и университета в Блексбурге, штат Вирджиния. Когда я пытался понять природу и структуру языка Си, я обнаружил, что применяю свои знания по организации и методам Форта. Это позволило мне понять закрученные или труднопроходимяе места в разделах описания Си. Я обнаружил, что подход Форта является идеальной платформой, на которой можно строить смысловое и образовательное обрамление для концепций других языков и операционных систем. - 278 - Джерри Бутелль является владельцем фирмы Nautilus Systems в Санта-Круз, в Калифорнии, поставляющей фирменный кросс-компилятор Nautilus Cross-compiler. Форт изменил много сторон моего мышления. После изучения Форта я программировал на других языках, включая ассемблер, Бейсик и Фортран. Я обнаружил, что использую тот же вид декомпозиции, который мы использовали в Форте, в смысле создания слов и группирования их вместе. К примеру, для обработки строк я определил бы аналоги для CMOVE, -TRAILING, FILL и т.д. Более существенно то, что Форт воскресил мою веру в простоту. Большинство людей выходят на задачи со сложными инструментами. Но простые инструменты доступнее и полезнее. Я пытаюсь упростить все стороны своей жизни. Вот моя любимая цитата китайского философа Лао Цзы: "Чтобы достичь знания, добавляй что-то каждый день; чтобы достичь мудрости, каждый день отбрасывай что-то". ---------------------------------------------------------------- - 279 - ПРИЛОЖЕНИЕ А О Б З О Р Ф О Р Т А ~~~~~~~~~~~~~~~~~~~~~ ( Д Л Я Н О В И Ч К О В ) ~~~~~~~~~~~~~~~~~~~~~~~~~~~ ---------------------------------------------------------------- СЛОВАРЬ. На Форте (FORTH) говорят словами (и числами), которые отделяются друг от друга пробелами: ЛАДОНЬ ОТКРЫТЬ РУКА ОПУСТИТЬ ЛАДОНЬ ЗАКРЫТЬ РУКА ПОДНЯТЬ Подобные команды могут быть набраны прямо с клавиатуры или вначале набраны редактором на устройствах массовой памяти (в файлах на диске), а потом загружены ("LOAD"). Все слова, уже имеющиеся в системе или определенные пользователем, существуют в "словаре", связном списке. "Определяющие слова" используются для добавления новых имен в словарь. Одним из них является слово : (произносится "двоеточие"), которое используется для определения нового слова в терминах ранее определенных слов. Вот как можно было бы определить новое слово по имени ПОДЫМАТЬ: : ПОДЫМАТЬ ЛАДОНЬ ОТКРЫТЬ РУКА ОПУСТИТЬ ЛАДОНЬ ЗАКРЫТЬ РУКА ПОДНЯТЬ ; Слово ; заканчивает определение. Новое слово ПОДЫМАТЬ может теперь быть использовано вместо длинной последовательности слов, составляющих определение. Слова Форта могут быть вложены друг в друга неограниченно. Написание задачи на Форте состоит из построения все более мощных определений, таких, как приведенное, в терминах тех, что были определены ранее. Другим определяющим словом является CODE ("код"), которое используется вместо двоеточия для определения команды в терминах машинных инструкций используемого процессора. Слова, определенные с помощью CODE с точки зрения пользователя неотличимы от тех, что определены через двоеточие. Определения через CODE если и нужны, то только в самых критичных ко времени исполнения местах программы. - 280 - СТРУКТУРЫ ДАННЫХ. Еще одно определяющее слово - CONSTANT (конатанта) - используется так: 17 CONSTANT СЕМНАДЦАТЬ Новое слово СЕМНАДЦАТЬ может теперь быть использовано вместо настоящего числа 17. Определяющее слово VARIABLE (переменная) создает место для хранения временных данных. VARIABLE использется так: VARIABLE БАНАНЫ Создается место (ячейка) в памяти, идентифицируемое именем БАНАНЫ. Получение содержимого этой области памяти - это задача слова @ (произносится "разыменовать" или "взять"). К примеру, БАНАНЫ @ достает содержимое переменной БАНАНЫ. Его антонимом является слово ! (произносится "загрузить" или "записать"), которое загружает число в ячейку памяти, типа 100 БАНАНЫ ! В Форте есть также слово для увеличения текущего содержимого на заданное число; например, фраза 2 БАНАНЫ +! увеличивает счетчик на два, делая его равным 102. В Форте есть и много других операторов для структур данных но, что более важно, в нем содержатся также инструменты, нужные программисту для создания структур данных любого типа, требуемого в задаче. СТЕК. В Форте переменные и массивы служат для сохранения значений, которые могут быть нужны для множества программ и/или в непредсказуемые моменты времени. Они `не` используются для локальной передачи данных между определениями. Для этого Форт применяет гораздо более простой механизм: стек данных. - 281 - Когда Вы набираете число, оно кладется на стек. Когда Вы вызываете слово, имеющее числовой аргумент, то оно забирает его со стека. Так, фраза 17 SPACES выдаст семнадцать пробелов на текущее устройство вывода. "17" кладет на стек двоичный эквивалент числа 17; слово SPACES его употребляет. Константа также кладет на стек свое значение; так, фраза СЕМНАДЦАТЬ SPACES дает тот же эффект. Стек работает на основе принципа "последним вошел - первым вышел" (LIFO). Это значит, что данные могут передаваться между словами упорядоченным, модульным образом, соответствующим вложенности определений через двоеточие. К примеру, определение по имени ОСЬ могло бы вызывать фразу 17 SPACES. Это временное использование стека будет незаметно для любого другого определения, вызывающего ОСЬ, поскольку число, положенное на стек, снимается с него до того, как заканчивается определение слова ОСЬ. Такое вызывающее слово могло само положить некоторые свои числа на стек до вызова слова ОСЬ. Эти числа останутся на стеке без повреждений после того, как ОСЬ будет отработана и вызывающее определение продолжит свою работу. СТРУКТУРЫ УПРАВЛЕНИЯ. Форт предлагает все структуры управления, необходимые для структурированного программирования без использования GOTO. Синтаксис конструкции IF THEN таков: ... ( флаг ) IF СТУЧАТЬ THEN ОТКРЫТЬ ... "Флаг" - это число на стеке, которое употребляется частью IF. Ненулевое значение этого флага означает истину, а нулевое - ложь. Истинный флаг вызывает исполнение кода между IF (в данном случае, слова СТУЧАТЬ). Слово THEN отмечает конец фразы для условного исполнения; работа продолжается со слова ОТКРЫТЬ. Флаг со значением "ложь" дает `запрет` исполнения фразы между IF и THEN. В любом случае будет исполнено слово ОТКРЫТЬ. Слово ELSE позволяет создавать альтернативные фразы для условного исполнения при ложном флаге. Во фразе ( флаг ) IF СТУЧАТЬ ELSE ЗВОНИТЬ THEN ОТКРЫТЬ ... - 282 - слово СТУЧАТЬ будет исполнено, если флаг истинен, в противном случае будет исполнено слово ЗВОНИТЬ. В любом из случаев работа будет продолжена, начиная со слова ОТКРЫТЬ. Форт позволяет также создавать циклы со счетчиком в виде ( верх ) ( низ ) DO ... LOOP или неопределенные циклы в формах ... BEGIN ... ( флаг ) UNTIL и ... BEGIN ... ( флаг ) WHILE ... REPEAT ГДЕ НАЙТИ ПОЛНОЕ ОПИСАНИЕ. Полноценное введение в набор команд Форта можно прочитать в книге `Starting FORTH`, выпущенное издательством Prentice-Hall. (Эта книга выпущена на русском языке под названием "Начальный курс программирования на языке Форт" - М:Финансы и статистика, 1990.) ---------------------------------------------------------------- - 283 - ПРИЛОЖЕНИЕ Б О П Р Е Д Е Л Е Н И Е D O E R / M A K E ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ---------------------------------------------------------------- Если в Вашей системе слова DOER и MAKE еще не определены, это приложение призвано помочь Вам их ввести и, при необходимости, понять принцип их работы. Поскольку по природе своей эти конструкции системно-зависимы, я привел несколько различных реализаций в конце приложения в надежде, что одна из них будет работать и у Вас. Если же этого не произойдет, и если в этом разделе Вам не хватит информации для того, чтобы заставить все работать, то, видимо, у Вас какая-то необычная система. Пожалуйста, не обращайтесь за помощью ко мне; спросите поставщиков Вашего Форта. Вот как это работает. DOER - это определяющее слово, которое создает словарную статью с одной ячейкой памяти в поле ее параметров. Эта ячейка содержит адрес вектора и инициализируется указанием на слово, которое ничего не делает (по имени NOTHING). Потомки слова DOER исполняют код после DOES> в нем, который делает всего две вещи: достает адрес вектора и заносит его на стек возвратов. Это все. Продолжение исполнения Форта производится с этого адреса со стека возвратов, что вызывает исполнение векторизованной функции. Это все равно, что сказать (в стандарте '83) ' NOTHING >BODY >R <возврат-каретки> что даст исполнение NOTHING. (Такой трюк годится только для определений через двоеточие.) Вот иллюстрация по словарной статье, созданной после ввода DOER ДЖО +-------------------+--------------------+ | Д Ж О | pfa слова NOTHING | +-------------------+--------------------+ заголовок поле параметров Теперь предположим, мы определили : ТЕСТ MAKE ДЖО CR ; то есть мы создали слово, которое может направить ДЖО на выдачу перевода каретки. - 284 - Вот рисунок, изображающий скомпилированное определение слова ТЕСТ: +----------+--------+-------+-------+-------+-------+ | Т Е С Т | адр. | 0 | адр. | адр. | адр. | | | (MAKE) | | ДЖО | CR | EXIT | +----------+--------+-------+-------+-------+-------+ заголовок маркер Давайте глянем на код для MAKE. Поскольку мы используем его внутри определения через двоеточие, переменная STATE будет в состоянии "истина", и мы исполним фразу COMPILE (MAKE) HERE MARKER ! 0 , Можно видеть, как MAKE скомпилировало адрес программы времени исполнения (MAKE), после которого записала ноль. (Мы объясним, для чего этот ноль и почему мы записали его адрес в переменную MARKER, попозже.) Теперь посмотрим, что (MAKE) делает, когда мы исполняем новое определение ТЕСТ: R> Получает адрес со стека возвратов. Этот адрес указывает на ячейку сразу после (MAKE), где находится ноль. DUP 2+ Получает адрес следующей ячейки после (MAKE), где размещен адрес ДЖО. DUP 2+ Получает адрес третьей ячейки после (MAKE), где начинается код, который мы хотим исполнить. На стеке теперь ( 'маркера 'джо 'кода ) SWAP @ >BODY Берет содержимое адреса, указывающего на ДЖО (т.е. получает адрес самого ДЖО) и вычисляет pfa ДЖО, где хранится адрес вектора. ! Записывает адрес, по которому начинается новый код (CR и т.д.) по адресу вектора ДЖО. Теперь ДЖО указывает внутрь определения слова ТЕСТ. Если мы введем ДЖО, мы получим возврат каретки. @ ?DUP Берет содержимое ячейки, содержащей ноль. IF >R THEN Поскольку там ноль, тело IF THEN не исполняется. Вот основная идея. Но как насчет ячейки с нулем? Она - для использования слова ;AND. Предположим, мы изменили ТЕСТ так: : ТЕСТ MAKE ДЖО CR ;AND SPACE ; - 285 - То есть когда мы вызываем ТЕСТ, оно направит вектор ДЖО на CR, а затем немедленно исполнит SPACE. Вот как будет выглядеть новая версия ТЕСТ: +--------------------------- | \/ +---------+------+------+------+------+------+------+------+ | Т Е С Т | адр. | адр. | адр. | адр. | адр. | адр. | адр. | | |(MAKE)| | ДЖО | CR | EXIT | SPACE| EXIT | +---------+------+------+------+------+------+------+------+ заголовок маркер Вот определение ;AND: : ;AND COMPILE EXIT HERE MARKER @ ! ; IMMEDIATE Видно, что ;AND скомпилировало EXIT так же, как это сделало бы слово ;. Далее, припомните что MAKE сохранило адрес нуля в переменной MARKER. Теперь ;AND записывает HERE (место начала следующего участка кода, начинающегося со SPACE) в ячейку, которая содержала ноль. Теперь (MAKE) имеет указатель на место продолжения исполнения. Фраза IF >R THEN теперь положит на стек возвратов адрес кода, начинающегося со слова SPACE. Так выполнение перескочит через код между MAKE и ;AND и продолжится для остальной части определения через двоеточие. Слово UNDO получает адрес слова-DOERа и записывает в него ссылку на слово NOTHING. Одно последнее замечание: на некоторых системах может возникнуть проблема. Если Вы используете MAKE вне определения через двоеточие для создания ссылки вперед, то можете оказаться не в состоянии найти самое последнее из определенных слов. К примеру, если у Вас имеется : ПРИПЕВ ТРАМ- ПАМ- ПАМ- ; MAKE ПЕСНЯ КУПЛЕТ ПРИПЕВ ; то Ваша система может подумать, что ПРИПЕВ еще не определен. Проблема заключается в месторасположении слова SMUDGE. В качестве решения попытайтесь перегруппировать порядок определений или, при необходимости, уберите код с MAKE внутрь определения, которое потом можно исполнить: : УСТАНОВКА MAKE ПЕСНЯ КУПЛЕТ ПРИПЕВ ; УСТАНОВКА - 286 - В системе Laboratory Microsystems PC/FORTH 2.0 слово UNSMUDGE в 9-й строке устраняет эту проблему. В модели Форта Лексена/Перри/Харриса этой проблемы нет. Последний блок - это пример использования DOER/MAKE. После загрузки блока введите RECITAL а затем введите WHY? и возврат каретки столько раз, сколько захочется. (Всякий раз у Вас будет для этого своя причина.) Блок # 21 0 ( DOER/MAKE Теневой блок LPB 12/05/83 ) 1 NOTHING нет операции 2 DOER определяет слово с векторизуемым поведением 3 MARKER хранит адрес служебного указателя продолжения 4 (MAKE) устанавлиает адрес последующего кода в поле 5 параметров слова типа DOER 6 MAKE интерпретация: MAKE doer-имя Форт-код ; 7 или внутри определения: 8 : ОПР MAKE doer-имя Форт-код ; 9 векторизует слово doer-имя на Форт-код. 10 ;AND разрешает продолжение определения с MAKE. 11 UNDO использование: UNDO doer-имя делает его 12 безопасным в использовании. 13 14 15 Блок # 22 0 \ DOER/MAKE FORTH-83 Laxen/Perry/Harris LPB 12/05/83 1 : NOTHING ; 2 : DOER CREATE ['] NOTHING >BODY , DOES> @ >R ; 3 VARIABLE MARKER 4 : (MAKE) R> DUP 2+ DUP 2+ SWAP @ >BODY ! 5 @ ?DUP IF >R THEN ; 6 : MAKE STATE @ IF ( компиляция) 7 COMPILE (MAKE) HERE MARKER ! 0 , 8 ELSE HERE [COMPILE] ' >BODY ! 9 [COMPILE] ] THEN ; IMMEDIATE 10 : ;AND COMPILE EXIT HERE MARKER @ ! ; IMMEDIATE 11 : UNDO ['] NOTHING >BODY [COMPILE] ' >BODY ! ; 12 13 \ Код в этом блоке является общественным достоянием. 14 15 - 287 - Блок # 23 0 ( DOER/MAKE FORTH-83 LabMicro PC/FORTH 2.0 LPB 12/05/83 ) 1 : NOTHING ; 2 : DOER CREATE ['] NOTHING >BODY , DOES> @ >R ; 3 VARIABLE MARKER 4 : (MAKE) R> DUP 2+ DUP 2+ SWAP @ >BODY ! 5 @ ?DUP IF >R THEN ; 6 : MAKE STATE @ IF ( компиляция) 7 COMPILE (MAKE) HERE MARKER ! 0 , 8 ELSE HERE [COMPILE] ' >BODY ! 9 [COMPILE] ] UNSMUDGE THEN ; IMMEDIATE 10 : ;AND COMPILE EXIT HERE MARKER @ ! ; IMMEDIATE 11 : UNDO ['] NOTHING >BODY [COMPILE] ' >BODY ! ; 12 13 ( Код в этом блоке является общественным достоянием.) Блок # 24 0 ( DOER/MAKE FIG model LPB 10/25/84 ) 1 : NOTHING ; 2 : DOES-APF ( apf -- arf-потомка- ) 2+ ; 3 : DOER @ >R ; 4 VARIABLE MARKER 5 : (MAKE) R> DUP 2+ DUP 2+ SWAP @ 2+ DOES-APF ! 6 @ -DUP IF >R THEN ; 7 : MAKE STATE @ IF ( компиляция) 8 COMPILE (MAKE) HERE MARKER ! 0 , 9 ELSE HERE [COMPILE] ' DOES-APF ! 10 SMUDGE [COMPILE] ] THEN ; IMMEDIATE 11 : ;AND COMPILE ;S HERE MARKER @ ! ; IMMEDIATE 12 : UNDO ' NOTHING [COMPILE] ' DOES-APF ! ; 13 ;S 14 ( Код в этом блоке является общественным достоянием.) Блок # 25 0 ( DOER/MAKE Стандарт-79 MVP FORTH LPB 12/05/83 ) 1 : NOTHING ; 2 : DOER CREATE ' NOTHING , DOES> @ >R ; 3 VARIABLE MARKER 4 : (MAKE) R> DUP 2+ DUP 2+ SWAP @ 2+ ( apf) ! 5 @ ?DUP IF >R THEN ; 6 : MAKE STATE @ IF ( компиляция) 7 COMPILE (MAKE) HERE MARKER ! 0 , 8 ELSE HERE [COMPILE] ' ! 9 [COMPILE] ] THEN ; IMMEDIATE 10 : ;AND COMPILE EXIT HERE MARKER @ ! ; IMMEDIATE 11 : UNDO ' NOTHING [COMPILE] ' ! ; 12 13 14 ( Код в этом блоке является общественным достоянием.) - 288 - Блок # 26 0 ( Пример на DOER/MAKE 12/27/84 ) 1 DOER ANSWER 2 : RECITAL CR 3 ." Ваш папа стоит на столе. Спросите его 'WHY?' (почему)" 4 MAKE ANSWER ." Для замены лампочки." 5 BEGIN 6 MAKE ANSWER ." Потому что она сгорела." 7 MAKE ANSWER ." Потому что была старая." 8 MAKE ANSWER ." Потому что мы ее привинтили очень давно." 9 MAKE ANSWER ." Потому что было темно!" 10 MAKE ANSWER ." Потому что стояла ночь!!" 11 MAKE ANSWER ." Перестань спрашивать ПОЧЕМУ?" 12 MAKE ANSWER ." Потому что я с тобой свихнусь." 13 MAKE ANSWER ." Дай мне просто поменять эту лампочку!" 14 FALSE UNTIL ; 15 : WHY? CR ANSWER QUIT ; ---------------------------------------------------------------- - 289 - ПРИЛОЖЕНИЕ В Д Р У Г И Е У Т И Л И Т Ы , ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ О П И С А Н Н Ы Е В Э Т О Й К Н И Г Е ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ---------------------------------------------------------------- Это приложение призвано помочь Вам определить некоторые из слов, которые упоминались в этой книге и которые могут отсутствовать в Вашей системе. Определения даны в Стандарте-83. ИЗ ГЛАВЫ 4. Определение слова ASCII для работы в Стандарте-83: : ASCII ( -- c) \ компиляция: с ( -- ) \ интерпретация: с ( -- с) BL WORD 1+ C@ STATE @ IF [COMPILE] LITERAL TNEN ; IMMEDIATE ИЗ ГЛАВЫ 5. Слово \ можно определить как: : \ ( пропустить остаток строки ) >IN @ 64 / 1+ 64 * >IN ! ; IMMEDIATE Если Вы решили не использовать слово EXIT для прерывания интерпретации блока, то можете определить слово \S как : \S 1024 >IN ! ; Слово FH определяется просто как : FH \ ( смещение -- блок-по-смещению ) \ "from here" - "отсюда" BLK @ + ; Подобная факторизация позволяет использовать FH многими способами, типа: : TEST [ 1 FH ] LITERAL LOAD ; - 290 - или : SEE [ 2 FH ] LITERAL LIST ; Несколько более сложная версия этого слова позволяет также редактировать или загружать блоки фразами вида "14 FH LIST", работающими относительно последнего блока, который был напечатан LISTом (SCR): : FH \ ( смещение -- блок-по-смещению ) \ "from here" - "отсюда" BLK @ ?DUP 0= IF SCR @ THEN + ; Слово BL - это просто константа: 32 CONSTANT BL TRUE и FALSE могут быть определены так: 0 CONSTANT FALSE -1 CONSTANT TRUE (Слова структур управления Форта, такие, как IF и UNTIL, рассматривают нуль как "ложь" и любое ненулевое значение как "истину". До Форта-83 соглашение предусматривало показывать "истину" значением 1. Начиная с '83-го стандарта, однако, "истина" имеет значение FFFF (шестнадцатеричное), что соответствует числу со знаком -1 (все биты установлены). Слово WITHIN на высоком уровне можно определить так: : WITHIN ( n низ верх+1 -- ? ) OVER - >R - >R U< ; ИЗ ГЛАВЫ 8. Реализация слова LEAP будет зависеть от того, как Ваша система реализует циклы DO LOOP. Если DO держит два значения на стеке возвратов (индекс и ограничитель), LEAP должно их оба сбрасывать, плюс сбрасывать еще одно значение со стека возвратов для выхода: : LEAP R> R> 2DROP R> DROP ; Если DO держит `три` значения на стеке возвратов, то следует определить: : LEAP R> R> 2DROP R> R> 2DROP ; ---------------------------------------------------------------- - 291 - ПРИЛОЖЕНИЕ Г О Т В Е Т Ы Н А З А Д А Ч И ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ " Д Л Я Д А Л Ь Н Е Й Ш Е Г О Р А З М Ы Ш Л Е Н И Я " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ---------------------------------------------------------------- ГЛАВА 3. 1. Ответ зависит от того, считаете ли Вы, что другим компонентам надо будет "знать" числовое значение, связанное с каждой клавишей. Чаще этого `не` требуется. Простая, более компактная форма здесь поэтому предпочтительнее. Также в первой версии добавление нового кода клавиши потребует изменений в двух местах. 2. Проблема со словами RAM-ALLOT и THERE состоит в том, что они `зависимы по времени`: мы их должны исполнять в определенном порядке. Здесь нашим решением могло бы быть отделение от интерфейса указателя места RAM, который от порядка не зависит; это можно было бы сделать, имея `единственное` слово, которое прозрачно исполняло бы обе функции. Синтаксис наших слов получился бы таким: : RAM-ALLOT ( #байтов-для-размещения -- начальный-адрес ) ... ; Этот синтаксис останется неизменным, если мы его поменяем для размещения снизу вверх: : RAM-ALLOT ( #байтов-для-размещения -- начальный-адрес ) >RAM @ SWAP - DUP >RAM ! ; - 292 - ГЛАВА 4. Наше решение таково: \ КАРТЫ Перетасовка 12-01-84 52 CONSTANT #КАРТ CREATE КОЛОДА #КАРТ ALLOT \ одна карта на байт : КАРТА ( i -- адр ) КОЛОДА + ; : НОВАЯ-КОЛОДА #КАРТ 0 DO I I КАРТА C! LOOP ; НОВАЯ-КОЛОДА : 'CSWAP ( a1 a2 -- ) \ поменять байты по а1 и а2 2DUP C@ SWAP C@ ROT C! SWAP C! ; : ТАСОВАТЬ \ тасовать колоду карт #КАРТ 0 DO I КАРТА #КАРТ CHOOSE КАРТА 'CSWAP LOOP ; ГЛАВА 8. Будет работать и это: 20 CHOOSE 2 CHOOSE IF NEGATE THEN Но проще так: 40 CHOOSE 20 - ---------------------------------------------------------------- - 293 - ПРИЛОЖЕНИЕ Д С В О Д С Т И Л И С Т И Ч Е С К И Х ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ С О Г Л А Ш Е Н И Й ~~~~~~~~~~~~~~~~~~~ ---------------------------------------------------------------- Содержимое этого приложения находится в общественном пользовании. Мы поощряем его публикацию без ограничений при условии ссылки на первоисточник. ОТСТУПЫ И ПРОПУСКИ. 1 пробел между : и именем 2 пробела между именем и его комментарием * 2 пробела или новая строка после комментария до тела определения * 3 пробела между именем и телом определения, если комментарии не используются 3 пробела отступа для каждой из последовательных строк (или кртаные тройке отступы для выделения вложенности) 1 пробел между словами/числами внутри фразы 2 или 3 пробела между фразами 1 пробел между последним словом и ; 1 пробел между ; и IMMEDIATE (при необходимости) Не ставить пустых строк между определениями, кроме случаев разграничения существенных групп определений. * Часто наблюдаемая альтернатива - 1 пробел между именем и комментарием и 3 - между комментарием и определением. Более либеральный подход использует по 3 пробела до и после комментария. Что бы Вы ни выбрали, будьте последовательны. - 294 - АББРЕВИАТУРЫ ДЛЯ СТЕКОВЫХ КОММЕНТАРИЕВ. 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 безразлично (для структур данных) "Смещение" - это разница, выраженная в абсолютных единицах, например, байтах. "Индекс" - это разница, выраженная в логических единицах, например, элементах записи. КОММЕНТАРИИ ДЛЯ ВХОДНОГО ПОТОКА. c одиночный символ, выделенный пробелами name или имя последовательность символов, выделенная пробелами text или текст последовательность символов, выделенная не пробелами После слова "текст" ставьте требуемый символ-ограничитель, типа: текст" или текст). - 295 - ПРИМЕРЫ ХОРОШЕГО СТИЛЯ КОММЕНТИРОВАНИЯ. Вот два примерных блока для иллюстрации хорошего стиля написания примечаний. Блок # 126 0 \ Форматтер Структуры данных -- стр.2 06/06/83 1 6 CONSTANT TMARGIN \ #строки начала тела текста 2 55 CONSTANT BMARGIN \ #строки конца тела текста 3 4 CREATE HEADER 82 ALLOT 5 \ { 1счет-слева | 1счет-справа | 80заголовок } 6 CREATE FOOTER 82 ALLOT 7 \ { 1счет-слева | 1счет-справа | 80подпись } 8 9 VARIABLE ACROSS \ текущ. горизонтальная поз. форматтера 10 VARIABLE DOWNWARD \ текущ. вертикальная поз. форматтера 11 VARIABLE LEFT \ текущ. начальная левая граница 12 VARIABLE WALL \ текущ. начальная правая граница 13 VARIABLE WALL-WAS \ WALL при нач. форматирования тек. стр. 14 15 Блок # 127 0 \ Форматтер позицирование -- стр.1 06/06/83 1 : SKIP ( n) ACROSS + ; 2 : NEWLEFT \ сбросить левую границу 3 LEFT @ PERMANENT @ + TEMPORARY @ + ACROSS ! ; 4 : \LINE \ начать новую строку 5 DOOR CR' 1 DOWNWARD +! NEWLEFT WALL @ WALL-WAS ! ; 6 : AT-TOP? ( -- t=наверху) TMARGIN DOWNWARD @ = ; 7 : >TMARGIN \ переместиться от crease до TMARGIN 8 0 DOWNWARD ! BEGIN \LINE AT-TOP? UNTIL ; 9 10 11 12 13 14 15 - 296 - СОГЛАШЕНИЯ ПО ФОРМИРОВАНИЮ ИМЕН. Значение Форма Пример ------------------------------------------------------------- Арифметика ~~~~~~~~~~ целое 1 1имя 1+ целое 2 2имя 2* берет родственные входные параметры +имя +DRAW берет масштабирующие входные параметры *имя *DRAW Компиляция ~~~~~~~~~~ начало "высокоуровневого" кода имя: CASE: конец "высокоуровневого" кода ;имя ;CODE добавить что-либо в словарь имя, C, исполняется при компиляции [имя] [COMPILE] несколько отлично имя' (штрих) CR' внутреннее представление или примитив (имя) или <имя> (TYPE) часть периода исполнения компилирующего слова: где есть строчные буквы строчными if где нет строчных букв (ИМЯ) (IF) определяющее слово :имя :COLOR номер блока с оверлеем имяING DISKING Структуры данных ~~~~~~~~~~~~~~~~ таблица или массив имена ЗАНЯТЫЕ общее число элементов #имя #ЗАНЯТЫХ текущий номер (переменная) имя# ЗАНЯТЫЙ# установить текущий номер ( n) имя 13 ЗАНЯТЫЙ переход на следующий элемент +имя +ЗАНЯТЫЙ размер смещения до записи от начала структуры имя+ ДАТА+ размер (в байтах) (сокращение от БАЙТОВ/имя) /имя /ЗАНЯТОГО указатель счетчика (индекс) >имя >IN перевести адрес структуры в адрес поля (записи) >имя >BODY - 297 - Значение Форма Пример ------------------------------------------------------------- индекс в файле (имя) (ЛЮДИ) указатель в файле -имя -РАБОТА инициализировать структуру 0имя 0ЗАПИСЬ Направление, Преобразование ~~~~~~~~~~~~~~~~~~~~~~~~~~~ назад имя< СМЕСТИТЬ< вперед имя> CMOVE> от <имя имя >TAPE преобразовать в имя>имя ФУТЫ>МЕТРЫ вниз \имя \LINE вверх /имя /LINE открыть {имя {FILE закрыть }имя }FILE Логика, Управление ~~~~~~~~~~~~~~~~~~ вернуть булевский флаг имя? КОРОТКИЙ? вернуть обратный флаг -имя? -КОРОТКИЙ? адрес булевского значения 'имя? 'КОРОТКИЙ? работает условно ?имя ?DUP (быть может, DUP) включить +имя +ЧАСЫ или отсутствие символа имя МИГАНИЕ выключить -имя -МИГАНИЕ Память ~~~~~~ сохранить значение @имя @КУРСОР восстановить значение !имя !КУРСОР записать в имя! СЕКУНДЫ! считать из имя@ СЧЕТЧИК@ имя буфера |имя |ВСТАВКИ адрес имени 'имя 'S адрес указателя на имя 'имя 'TYPE обменять, особенно байты >имя< >MOVE< Числовые типы ~~~~~~~~~~~~~ длиной в байт Cимя C@ длиной 2 ячейки в двоичном дополнительном целом коде Dимя D+ смешанное 16 и 32-х разрядное Mимя M* длиной 3 ячейки Tимя T* длиной 4 ячейки Qимя Q* беззнаковая кодировка Uимя U. - 298 - Значение Форма Пример ------------------------------------------------------------- Вывод, Печать ~~~~~~~~~~~~~ напечатать .имя .S напечатать численно (имя подчеркивает тип) имя. D. U. напечатать выровненным справа имя.R U.R Количество ~~~~~~~~~~ "на" /имя /SIDE Последовательности ~~~~~~~~~~~~~~~~~~ начало <имя <# конец имя> #> Текст ~~~~~ следует строка, ограниченная " имя" ABORT" текст" текстовый или строковый оператор (в Бейсике -$) "имя "СРАВНИТЬ массив суперстрок (superstring array) "имя" "ЦВЕТА" - 299 - КАК ПРОИЗНОСИТЬ СИМВОЛЫ. ! store - записать, загрузить @ fetch - разыменовать, взять, достать # sharp, number - диез (или "число", "номер") $ dollar - рубль % percent - процент ^ caret - шапка, не & ampersand - амперсанд, и * star - звездочка ( left paren - левая скобка ) right paren - правая скобка - dash - прочерк, минус, не + plus - плюс = equals - равно {} faces, curly brackets - фигурные скобки [] square brackets - квадратные скобки " quote - кавычка ' tick, prime - штрих ~ tilde - тильда | bar - вертикальная черта \ backslash - обратный слеш (также "под", "вниз" и "пропустить") / slash - слеш (также "вверх") < less-then, left-dart - меньше чем, левая угловая скобка > greater-then, right-dart - больше чем, правая угловая скобка ? question, query - вопрос, запрос , comma - запятая . dot - точка