Язык программирования Форт


Ввод и вывод


Ввод и вывод символов

Каким образом информация выводится из компьютера на дисплей и принтер и как ее ввести с клавиатуры? Конечно, вы уже вводили и выводили данные, нажимая клавиши и пользуясь словами. (точка), D., EMIT и т.д. Но имеются и другие возможности. Поскольку форт не предназначен для конкретного типа микрокомпьютера, его слова для операций ввода и вывода - универсальные (большинство версий Бейсика, напротив, приспособлены для определенных типов ЭВМ). Правда, во многих версиях Форта также имеются специальные слова для управления вводом-выводом, чтобы максимально использовать возможности конкретного микрокомпьютера. Мы рассмотрим как стандартные слова, так и, в качестве примера, некоторые слова для осуществления ввода-вывода из MMSFORTH. Некоторые вопросы мы отложим до гл. 9, потому что все подробности ввода чисел и символьных строк при исполнении программ будет проще понять после того, как вы изучите ввод символьных строк. Здесь полезно вспомнить, что буквы и числа вводятся в ЭВМ и выводятся одинаково в виде кодов ASCII. Это объясняется историческими причинами, знание которых поможет вам лучше понять методы ввода и вывода в Форте.

До появления персональных компьютеров ввод и вывод на ЭВМ производился через терминал. В своем простейшем виде терминал был малоинтеллектуальным устройством. Хороший терминал представляет в сущности пишущую машинку, и фактически в 1960-1970 гг., наиболее распространенной была модель электрической пишущей машинки типа IBM Selectric, Другая распространенная модель типа Teletype тоже представляла собой пишущую машинку, но с необычной механикой. Рассмотрим, что может делать пишущая машинка. Она может выводить на бумагу буквы, цифры и пробелы и, кроме того, передвигать с помощью валика бумагу. Перемещение бумаги может быть построчное и, кроме того, постраничное. При некотором умении можно продвинуть бумагу на половину строки или даже перемотать ее в обратную сторону- Конечно, возможно также переместить каретку на одну позицию по строке назад и перебить символ.
Но это почти все, что может делать терминал как пишущая машинка. Клавиатура терминала также подобна клавиатуре пишущей машинки, т.е. у нее есть клавиши для букв и цифр, пробела, перевода строки и возврата на позицию влево. И только двух дополнительных клавиш, которые есть у терминала, нет на пишущей машинке. Это клавиша управления и клавиша спецсимвола Escape (отказ). Для простого механического терминала при небольшом количестве функций было вполне достаточно кодов управления ASCII. Фактически терминалы ЭВМ и коды ASCII были прямо заимствованы из телетайпной техники 1930 - 1950 гг. Но с изобретением видеодисплейных терминалов открылись новые возможности.
Первые видеотерминалы работали так же, как и их механические прототипы. Они печатали символы в нижней части экрана и продвигали строки на экране вверх, подобно листу бумаги в пишущей машинке. Но возможности видеотерминалов были гораздо богаче. Например, они обладали возможностью разделять экран на две половины по горизонтали или по вертикали с различной информацией в каждой части или, например, выделять слова, меняя яркость. На более сложных терминалах, например Tektronix graphics, можно с высокой разрешающей способностью, отображать рисунки линиями. Однако по-прежнему они общаются с управляющей ЭВМ, фактически используя старый код ASCII. (В действительности есть два важных исключения - еще один код для телекоммуникаций, код Бодо, названный по фамилии его изобретателя, пионера в области автоматической телеграфии; кроме того, до сих пор при работе с ЭВМ фирмы IBM используется предложенный ею код EBCDIC.)
Более высокий уровень сложности стал возможен с изобретением персонального компьютера, содержащего в себе все оборудование ЭВМ. Его экран может рассматриваться как экран телевизора, отображающего сложные графические образы в цвете, с набором различных шрифтов, символов, с окнами, в которых отображаются выходные данные различных программ, включая графические, и многое другое. Достаточно одного взгляда на экран персональной ЭВМ Apple Lisa или Mackintosh, чтобы убедиться в их огромных возможностях.


Конечно же, и возможности клавиатуры также усложнились с введением специальных функциональных клавиш, клавиши для перемещения курсора и т.д. Однако проблема состоит в том. что по-прежнему ввод и вывод производятся по стандарту ASCII, хотя в большинстве случаев добавляется еще 127 символов и, таким образом, используется полный, набор из 256 символов, каждый из которых может быть представлен одним из 8-разрядных чисел, так называемым байтом. Другая проблема состоит в том, что почти в любой модели терминала и компьютера используются различные способы.управления функциями экрана. Определенные управляющие коды, например стирание влево, перевод строки, возврат каретки, т.е. те коды, которые применялись для управления телетайпами, оставили стандартными. Но другие были произвольно изменены. Можно ли в свете сказанного создать язык, способный работать на разнообразных ЭВМ? Сделать это чрезвычайно трудно. Поэтому стандарт языка Форт должен ограничивать только ввод-вывод кодов ASCII в расчете на использование простых терминалов, Для конкретных ЭВМ должны быть разработаны расширенные и нестандартные версии языка. Кроме вывода символов кодами ASCII терминал должен управляться также либо кодами ASCII, либо так называемыми Еsс-последовательностями. Мы рассматривали управляющие коды в гл. 3, здесь уместно вкратце упомянуть об Esc-последовательностях.
Код ASCII 27 называется Esc-префиксом или Esc-клавишей (отказ). Его можно ввести с клавиатуры ЭВМ, нажимая клавишу . (Некоторые ЭВМ не имеют специальной Esc-клавиши, в этом случае она имитируется некоторой комбинацией других клавиш; например, ввод кода Esc, если нет специальной клавиши, производится одновременным нажатием управляющей клавиши Ctrl, клавиши Shift (переключение регистров) и .) Назначение клавиши Esc состоит в том, чтобы сигнализировать, что некоторая последовательность символов после Esc должна рассматриваться как команда управления, а не код символа ASCII. Например, последовательность Esc С (27,67) должна произвести очистку экрана терминала и помещение курсора в левый верхний угол.


Печатающее устройство также, как правило, управляется Esc-последовательностями, например последовательность кодов (27,28) дает принтеру Centronics 739 команду продвинуть бумагу на полстроки вперед; (27,30) - на полстроки назад, а последовательность кодов (27,47,48) переводит устройство в режим, при котором следующие байты воспринимаются не как символы, а как графические команды. Ради чего мы приводим здесь это описание терминалов? Только ради того, чтобы принести извинения за отсутствие подробных объяснений, как управлять терминалом вашего компьютера или принтером. Вам нужно практически проверить, как реагирует на Esc-последовательности оборудование вашей ЭВМ. Мы расскажем здесь, как организовать посылку символов из Форта, а вы сами посмотрите, что они делают на вашем дисплее или принтере.


Вывод символов
В конце гл. 3 вы уже видели, что самое необходимое слово для вывода символов - EMIT, которое посылает на экран дисплея символ, соответствующий числу, которое хранится в стеке.' Попробуйте посмотреть, что делают различные управляющие коды, экспериментируя со словом EMIT. Например, если вы введете 48 EMIT 49 EMIT 10 EMIT 50 EMIT то скорее всего увидите 01 на одной строке и 2 - на следующей. Почему? Потому, что 48, 49 и 50 представляют собой соответственно ASCII-коды цифр 0, 1 и 2, а 10 - перевод строки, который при интерпретации обычно сопровождается возвратом каретки. Если вы напечатаете 48 EMIT 49 EMIT 8 EMIT 50 EMIT то увидите 02. Цифра 1 была стерта, так как код 8 представляет команду перемещения курсора на позицию влево, или стирания влево (Backspace). Испробуйте другие управляющие коды, чтобы установить их действие на вашем оборудовании, при этом могут возникнуть некоторые сюрпризы, например в MMSFORTH на машине IBM PC или на TRS-80 команда 27 EMIT приводит к обратной подаче строки, в то время как 12 EMIT очищает экран и возвращает курсор "домой" (т.е. в левый верхний угол экрана). Вы можете также попробовать коды ASCII от 128 и более, которые не являются стандартными и могут выводить странные символы и необычные буквы или продемонстрируют, что будет на экране, если из кода ASCII вычесть 127, т.е.


если игнорировать значение старшего бита.
Можно определить через EMIT два стандартных слова, действие которых столь очевидно, что мы приводим только их определение: : SPACE 32 EMIT ; (пробел) и : CR 13 EMIT 10 EMIT ; (перевод строки + возврат каретки) Не столь очевидно определение стандартного слова "пробелы": : SPACES 0 DO SPACE LOOP ;
Оно выводит пробелы, количество которых определяется числом на вершине стека. Нестандартное слово BL (пробел) включено во многие версии Форта. Оно помещает на вершину стека 32, т.е. ASCII-код пробела. Таким образом, можно дать иное определение пробела: : SPACE BL EMIT ;
Более сложное слово с использованием EMIT - это TYPE (печать). Его подробное описание вы найдете в гл. 9, где мы объясним символьные строки, но, чтобы начать пользоваться им раньше, мы рассмотрим его уже сейчас. Слово TYPE просматривает последовательность однобайтовых (8-разрядных) чисел (символов) из памяти и посылают их ASCII-эквивалент на экран. Для него требуется число на вершине стека, а ниже него - адрес. Слово TYPE выводит указанное число символов, начинающихся с этого адреса, на экран. Рассмотрим пример. Может быть, вам потребуется освежить в памяти счетные циклы DO-LOOP (гл. 1) и слово PAD из гл. 4. Слово I помещает текущее значение параметра цикла на вершину стека. Определим слово : PUTTEST 84 83 69 84 4 0 DO PAD I + С! LOOP ; , которое поместит символы ASCII символьной строки "TEST" в памяти, начиная с адреса, выдаваемого словом PAD. Теперь введите с клавиатуры PAD 4 TYPE и на экране появится строка "TEST". Обратите внимание, что коды ASCII должны быть помещены в стек в обратном порядке. А вот одно из возможных определений слова TYPE; попробуйте разобраться, как оно работает : : TYPE (адр n --) 0 DO DUP I + С@ EMIT LOOP DROP ;
Теперь нам следует познакомиться с символьными строками, о которых более подробно вы узнаете из гл. 9. Чтобы напечатать или сделать что-нибудь еще с символьной строкой, нам надо знать не только входящие в нее символы, но также их количество.


Один из способов запоминания строки, стандартный для Форта, состоит в использовании счетной строки (иногда ее называют нумерованной строкой). Счетная строка представляет собой область памяти, первый байт которой содержит число символов строки, за которым следуют собственно коды ASCII. Мы можем переопределить слово PUTTEST, помещающее строку "TEST" в PAD, следующим образом: : PUTTEST 84 83 69 64 4 PAD С! 4 0 DO PAD I 1+ + С! LOOP ;
4 PAD С! помещает число символов (счетное число) в PAD. Остальная часть определяемого слова размещает строку символов в более старшие адреса. Чтобы посмотреть строку, нужно, ввести с клавиатуры PAD 1+ PAD С@ TYPE
После этого в стеке будет находиться адрес начала строки и на вершине стека - число символов, т.е. стек подготовлен для распечатки словом TYPE. Поскольку этот принцип широко используется, предусмотрены стандартные слова для получения числа символов и адреса символьной строки: : COUNT (адр - адр+1 n) DUP 1+ SWAP C@ ; Поэтому вы сможете увидеть тестовое слово в PAD с помощью PAD COUNT TYPE
В гл. 9 вы увидите, что счетные строки обеспечивают большую гибкость при манипулировании с символьным текстом. Для примера скажем, что эта книга была набрана с помощью редактора текста, написанного на Форте, и эта программа редактора работает не хуже любой подобной программы, написанной на языке ассемблера.
В гл. 1 вы познакомились с более простым способом вывода строк с помощью слова ." (точка-кавычка), т.е. ." This is a test" (Это тест) выведет на дисплей строку "This is a test" (Это тест). Закрывающая кавычка не является словом Форта, это просто символ, который указывает слову ." на необходимость прекращения вывода строки на дисплей. В языке Форт-79 слово ." работает как в определении нового слова, так и вне его, с той лишь разницей, что вне определения строка выводится немедленно, в то время как, находясь внутри определяемого слова, она не выводится, пока определяемое слово не будет исполнено.


В версии Форт- 83 имеется незначительное отличие. Здесь не требуется, чтобы слово ." исполнялось вне определения. Для немедленного вывода строки зарезервировано другое слово .( (точка-скобка), которое выводит символьную строку, ограниченную правой круглой скобкой.)
Оно работает так же, как слово ." в Форт-79 вне определения, немедленно выводя текст, однако внутри определения .( так же выводит немедленно. Так, если ввести : TEST .(This is a test) : на экране будет немедленно выведена строка "This is a test" (Это тест). Таким образом, слово TEST в данном случае ничего не делает.
* Упражнения
1. Определите слово BS (стирание влево) по аналогии со словом CR (возврат каретки) так, чтобы при исполнении слова BS на выходе происходило бы стирание ранее выведенного предшествующего символа. 2. В MMSFORT есть слово PAGE (страница), которое производит стирание экрана и помещает курсор в левый верхний угол. Определите слово PAGE, имея в виду действие управляющего кода 12 в MMSFORTH. 3. Определите слово CRS, которое должно перемещать строки на экране вверх на величину, определяемую числом в стеке, т.е. слово CRS должно действовать как возврат каретки вверх, так же, как слово SPACES действует над пробелами. 4. Определите слово DASHES (черточки), которое выводило бы на экран число черточек, которое задается числом в стеке. 5. Определите семь слов для вывода текста "MAIN MENU" (основное меню). Теперь, пользуясь этим словом и словами, определенными вами в упражнениях 2-4, определите слово MENU, которое выводило бы на экран следующее меню (не забудьте о слове ." ):
----- ОСНОВНОЕ МЕНЮ ----- --------------------------------------- A ------ Это первый вариант выбора B ------ Это второй вариант выбора C ------ Это третий вариант выбора D ------ Это выбор Форта --------------------------------------- ------ ЧТО ВЫ ВЫБИРАЕТЕ ? --------
6. В MMSFORTH есть слово $. (вывод символьной строки), которое выводит на экран содержимое строки, если задать адрес счетной строки.


Дайте определение слова $..
Управление экраном дисплея
Как вы, возможно, догадываетесь, в языке Форт не предусмотрены стандартные слова для управления содержимым экрана дисплея; имеется множество других способов, с помощью которых компьютеры и дисплеи осуществляют это. Однако мы увидим некоторые дополнительные возможности, рассмотрев некоторые слова MMSFORTH, которые предназначены для работы с компьютерами типа TRS-80 и IBM PC. Вы сможете определить такие же слова для вашей машины, если поймете, как она исполняет управляющие коды, а возможно, в вашей версии Форта уже имеются подобные слова. Наиболее важная функция управления экраном состоит в возможности перемещения курсора по экрану. Если вы можете делать это, то сможете сделать почти все. Представьте себе экран как таблицу из символов с определенным числом строк и столбцов. Вам хотелось бы иметь возможность поместить курсор в любую строку и столбец. В MMSFORTH для этого служит слово РТС (put cursor - поместить курсор). Для него номер строки ожидается вторым в стеке, а номер столбца - на вершине стека. Таким образом, 0 0 РТС передвинет курсор в левый верхний угол экрана, в то время как 10 30 РТС поместит его в 11 строку и введет 31 пробел. Содержимое экрана не изменится (кроме того, что на месте курсора и сообщения "ok" прежние символы будут стерты). Указанную возможность можно рассматривать как форму, содержащую пустые места, которые должны быть заполнены. Для примера, пусть меню задает вопрос, ответ на который должен начинаться в строке номер 10 и столбце номер 30, а для текста вопроса отводится 10 пустых мест. Тогда слово, которое поместит курсор и вставит в пустые места пробелы, выглядит так: : FILL-IN 10 30 РТС 10 SPACES 10 30 РТС : (Заполнить) Конечно, слово должно печатать вопрос вместо того, чтобы оставлять пробелы. Приведем другое определение слова PAGE из последних упражнений, которое будет исполняться более медленно предполагается, что экран содержит 16 строк по 64 символа в строке, т.е. всего 1024 символа): : PAGE 0 0 РТС 1024 SPACES 0 0 РТС ; (Страница)


Для экрана с 80 символами на строке и 25 строками число 1024 должно быть заменено на 2000 SO * 25). (Очевидно, что скорость будет выше, если использовать какие-либо управляющие коды, которые предоставляет компьютер или дисплей, например 12 EMIT в MMSFORTH.)
В гл. 12 и 13, где представлен и рассматривается экранный редактор, вы увидите, как может быть определено слово РТС в других версиях Форта. Со словом РТС связано слово GTC (get_cursor, т.е. определить, где находится курсор). Оно помещает в стек номер строки, затем номер столбца. Приведем пример слова, подобного FILL-IN, которое поместит на экране после курсора 10 пробелов, если это возможно : : 10BLANKS GTC 10 SPACES РТС : (10 пробелов)
Слово GTC выдает положение курсора, 10 SPACES перемещает его на 10 позиций вправо, заполняя пробелами все, что находится на этих местах, и слово РТС снова возвращает курсор на старое место, используя имеющуюся в стеке от GTC информацию о положении курсора. При небольшой изобретательности слова РТС и GTC позволят вам делать впечатляющие и "дружественные" подсказки для ввода в программы ответов пользователя, которому остается только вводить их на месте пробелов. Можно практически обойтись без "перелистывания" экрана, если ввод и вывод информации производить на одном и том же месте экрана.
Чем больше возможностей имеет дисплей компьютера, тем более специализированные слова Форта требуются для использования этих возможностей. MMSFORTH совместно с IBM PC показывают хороший пример того, что может быть сделано, но не будем их здесь описывать, поскольку их много и они очень специфичны. Наиболее сложная возможность - это использование так называемых "окон". Они позволяют выделять на экране различные области, в каждой из которых появляются различные текстовые или графические изображения. Например, результат работы одной программы может быть представлен в основном окне, а меньшее окно может быть выделено для вывода листинга программы при отладке либо в одном окне можно помещать данные, вводимые в программу, а в другом - выходные данные.


С помощью программы векторной графики MMSFORTH можно задать несколько окон для отображения выходной графической информации, в то время как другие окна могут быть оставлены для вывода алфавитно-цифровой информации. Цвет содержимого каждого окна и границ окон и даже цвет отдельных слов могут быть заданы независимо. Если в IBM не установлена плата адаптера цветного монитора, тогда можно изменить вид курсора, ввести подчеркивание и т.д. Этим достигается большая гибкость. Другие версии Форта могут обладать подобными возможностями, но лишь немногие работают с окнами. К примеру, очень впечатляет использование окон MMSFORTH на ЭВМ Apple Macintosh.)
Вывод на печатающее устройство (принтер)
Стандарты Форта не определяют слова для осуществления вывода на принтер. Однако имеется много возможностей для стандартизации. В Форте имеются способы передать выходную информацию на принтер или одновременно на принтер и на экран. Мы опишем, каким образом это реализовано в MMSFORTH. Почти наверняка в вашей версии Форта вы найдете эквивалентные слова. Управление принтером реализуется с помощью слов PRINT, PCRT и CRT. После исполнения слова PRINT вся информация, которая передавалась на экран, передается на принтер. После исполнения слова PCRT вывод передается как на экран, так и на принтер, а после CRT прекращается вывод на принтер, информация выводится на экран. Это так просто. Другой способ управления предоставляют слова PRINTER (принтер), SCREEN (экран), ON (включено), OFF (выключено), используемые в контексте: PRINTER ON (вывод_на_принтер) SCREEN ON (вывод_на_экран) PRINTER OFF (выключить_вывод_на_принтер) SCREEN OFF (выключить_вывод_на_дисплей)
Указанные предложения производят несколько неожиданные действия. По идее это также должно быть просто, но не торопитесь, так как все несколько сложнее. Что произойдет, если послать 12 EMIT при разрешенном выводе на принтер (PRINT)? Код 12 для большинства принтеров является управляющим кодом, который заставляет принтер продвинуть бумагу на целую страницу (протяжка листа).


А это, очевидно, не то же самое, что очистка экрана и возвращение курсора в левый верхний угол экрана. Или предположим, что вы посылаете управляющий код перевода строки назад при активизации экрана командой CRT. Как отреагирует на этот код экран дисплея? До тех пор, пока вы передаете алфавитно-цифровой текст и простой перевод каретки, никаких проблем с выводом не возникает. Но если вы делаете всякие замысловатые операции с дисплеем или принтером, используя их управляющие коды, нужно быть очень осторожным при включении и выключении вывода на эти устройства, чтобы предотвратить нежелательную интерпретацию этих кодов. Это может привести к дополнительным осложнениям.
Построение простейших графиков из линий
До появления в составе компьютеров хороших видеографических дисплеев и координатных построителей вывод графических данных приходилось делать на построчное печатающее устройство или знаковый терминал. Действительно, вывод в такой форме и в настоящее время можно запрограммировать и выполнить гораздо быстрее, чем вывод в графическом виде. Идея того, как это делается, очень проста, в особенности для Форта. Вы уже видели демонстрационную программу построения линий в гл. 1. В данном разделе мы более подробно рассмотрим детали этого способа и, что более важно, предложим вам несколько упражнений на построение линейных графиков. Допустим. что вы хотите построить гистограмму , отображающую величины чисел, находящихся в стеке, Прежде всего нам потребуется слово, которое делает высоту столбика пропорциональной величине числа. Определим слово : XS 0 00 88 EMIT LOOP ; (выводить_"Х") печатающее ряд литер "X", длина которого зависит от числа в стеке, это и есть наш столбик. Теперь определим слово : PLOT (Нарисовать_график) CR (Начало с новой строки) DEPTH (Сколько чисел находится в стеке?) 0 (Нижний предел цикла) DO (Начало циклического повторения DEPTH раз) XS (Печатает строку из n литер 'х'; n - из стека) CR (Переходит в начало следующей строки) LOOP (Конец цикла; конец определения) ;


Теперь, если вы напечатаете 5 10 20 30 30 25 8 2 PLOT на экране дисплея, получится следующий график :
XX XХХХХХХХ ХХХХХХХХХХХХХХХХХХХХХХХХХ ХХХХХХХХХХХХХХХХХХХХХХХХХХХХХХ ХХХХХХХХХХХХХХХХХХХХ ХХХХХХХХХХ ХХХХХ
Он должен быть вам знаком по гл. 1 и, конечно, не лишен недостатков. Числа должны быть помещены в стек в порядке, обратном тому, в каком они должны быть выведены. Длина столбика должна быть не больше ширины экрана дисплея. Существуют, однако, пути обхода этих проблем и способы построения более сложных диаграмм. С некоторыми мы познакомимся на следующих упражнениях и в последующих разделах.
Упражнения
1. Измените слово PLOT (вызов: PLOT1) так, что если число больше ширины экрана, то столбик будет доходить только до края экрана. (Указание: используйте слово MIN.) 2. Переделайте слово PLOT в PLOT2 так, чтобы вывод направлялся не на экран, а на принтер. По окончании вывода оно должно переключить вывод снова на экран. 3. Измените слово PLOT в PLOT3 так. чтобы оно печатало пары значений чисел в стеке литерами Х и Y одно под другим, т.е. если в стеке находятся числа 12 10 8 5, то слово PLOT3 выведет на экран гистограмму YYYYY ХХХХХХХХХХ YYYYYYYY ХХХХХХХХХХХХ Вам потребуется определить слово YS (литеры Y). 4. Измените слово PLOT в PLOT4 так, чтобы кроме вывода гистограммы оно выводило бы номера каждого столбика от 0 до 9 и между номером и началом гистограммы было бы три пробела. На выходе должна быть такая гистограмма 0 ХХХХХХ 1 ХХХХХХХХХХХХ 2 XX 3 ХХХХХХХХХХХХХХХХХХ 5. Измените слово упражнения 3 (назовите его PLOT5) так. чтобы вместо столбиков печаталась точка в конце каждого столбика, т.е. таким образом : 0 Х 1 Х 2 Х 3 X и т.д. 6. Во всех предыдущих программах построения гистограмм числа должны быть не больше числа позиций в ширину экрана. Измените программу упражнения 5 на PLOT6 так, чтобы можно было задавать числа до 1000 и чтобы числу 1000 соответствовал символ в 75-й позиции на строке экрана (считая, что 0 соответствует 1-я позиция). Если нужно, просмотрите раздел о масштабировании в гл. 4.


Не забудьте, что четыре позиции нужно предусмотреть для чисел и пробелов. 7. Измените слово упражнения 3 на PLOT? таким образом, чтобы вместо печати столбиков друг под другом получалась бы печать их рядом. Тогда на выходе должно быть XXXXXXXXXXYYYYY XXXXXXXXXXXXYYYYYYYY 8. Измените слово упражнения 7 на PLOTS, чтобы вместо столбиков печатались только их конечные точки, как показано: Х Y Х Y 9. Измените программу упражнения 8 на PLOT9, чтобы в конце каждой строки литер "Y" печаталась величина, как показано : Х Y5 Х Y8 10. Измените программу упражнения 9 на PLOT10. чтобы допустимыми были значения Х от 0 до 30, а значения Y от О до 1000. Считайте, что в строке 64 символа. 11. Это трудное упражнение. Предположим, что у вас есть пары значений х и у, которые вы хотите отобразить в виде графика зависимости у от х. Пусть значения х рассортированы так, что наименьшее значение находится на вершине стека, а пары значений в стеке расположены в порядке у, х. Например, в стеке может быть пара 30, 10, причем 30 - у, а 10 - х. Теперь предположим, что в стеке имеются числа 30 10 20 7 15 5 10 4 2 1 10 .
При исполнении слова PLOT должна получаться следующая картина : .X 0 1 .X 1 2 . . X 4 10 . X 5 15 . . X 7 20 . . . X 10 30
Таким образом, нулевое значение у должно быть представлено точкой, величина х должна быть отображена расстоянием по направлению вниз, величина у - расстоянием от левого края и после каждой отображаемой точки должны быть напечатаны значения х и у. Вам придется использовать вложенные счетные циклы типа DO-LOOP.
Вывод чисел
Вы уже знаете, конечно, как выводить числа на экран с помощью слов . (точка), U. и D., но это очень примитивно. Предположим, что вы хотите представить таблицу, в которой числа были бы выровнены по крайнему правому разряду, например: 1956 34215 343 23 5555 33333 21965 2 23
Или вы хотите напечатать число со знаком денежной единицы, например $294. Либо вам нужно напечатать число с десятичной точкой (в известном месте, поскольку предварительно вы сделали масштабирование), например, "$294.32".


Форт предоставляет превосходный выбор для отображения чисел в специальных форматах. Можно получить таблицу чисел с помощью печати, выровненной по правому краю. $294.32 можно напечатать, используя форматный вывод (иногда называемый выводом по шаблону). Печать в форме таблицы делается просто, вывод со знаком денежной единицы - более сложно.
Слово R. позволяет печатать число в формате выравнивания вправо. Это означает, что число печатается так, как будто бы его все время сдвигают вправо в поле некоторой определенной длины. Длина поля должна быть положена на вершину стека. Так, если вы введете CR 256 6 .R то увидите 256 (123456) (цифры в скобках не будут напечатаны, они приводятся, чтобы показать позицию печатаемого числа 256 в поле, отведенном для его вывода). Число 256 сдвигается на три позиции вправо и выводится своим последним разрядом в последней позиции б-местного поля. Если вы напечатали CR 256 8 ,R то увидите 256 (12345678) Это значит, что число будет выровнено вправо в поле длиной 8 мест. Пусть теперь вы вводите CR 211 10 .R -5 10 .R 23 10 .R CR 2 10 .R -231 10 .R 256 10 .R CR
Во всех случаях поле будет иметь ширину 10 позиций, выводимые числа будут выровнены вправо в этом поле, и вы увидите 211 -5 23 2 -231 256
Каждое слово CR начинает вывод с новой строки, и каждое число представлено сдвинутым до предела вправо в поле из 10 мест. В результате получается очень аккуратная таблица. Обратите внимание, что знаки "-" отрицательных чисел были учтены. Имейте в виду, что в отличие от. (точки) слово.R не выводит пробел после напечатанного числа. Поэтому CR 256 6.R 9 выдаст на экран: 2569 (1234567)
Слово.R не оговорено стандартами Форта, но нам не известна ни одна версия языка, в которой оно, равно как и слово D.R, отсутствовало бы. Во многих версиях Форта есть еще набор слов, как, например U.R, которое печатает числа одинарной длины без знака с выравниванием вправо. Предполагается, что всем этим словам должна предшествовать на вершине стека длина поля в виде числа одинарной длины, а ей должно предшествовать число, которое нужно напечатать как в случае чисел одинарной, так и двойной длины.


Если в вашем Форте нет слова U.R, то вскоре мы определим его вместе с другими полезными словами.
Форматный вывод чисел
Форматный вывод чисел (вывод по шаблону) наиболее сложный и все же наиболее гибкий способ отображения чисел на экране дисплея или печати на принтере. Он используется также для определения таких слов, как. (точка) и.R, и позволяет вводить в число, например, знак денежной единицы, десятичную точку, предшествующие незначащие нули, производить выравнивание в поле и т.д. Слова форматного вывода фактически преобразуют числа в последовательность кодов ASCII в форме, удобной для вывода на экран дисплея с помощью слова TYPE. Форматный вывод работает только с числами двойной длины. Чтобы применить его к числам одинарной длины, последние необходимо преобразовать в двойные.
Процесс форматного вывода начинается словом . Между этими двумя словами могут быть какие-то другие слова, описывающие, как должно выполняться форматирование. Слово #> оставляет в стеке адрес символьной строки и число символов в ней, подготавливая вывод для слова TYPE. Простейшее форматирование производит слово #S, которое преобразует все разряды числа в символьную строку. Приведем определение слова UD., которое, как ни удивительно, не включено во многие версии Форта: : UD. ( d - ) ( - адр счет ) (Завершает преобразование, помещает в стек адрес и значение счетчика) TYPE ( - ) (Выводит строку на экран) SPACE (Вставляет после числа пробел) ; (Заканчивает определение)
А как обращаться с числами одинарной длины? Достаточно преобразовать их в числа двойной длины. Для этого предусмотрено слово S-D. Чтобы понять его, вспомните, как представляется в стеке отрицательное число: : S-D ( n -- d) DUP 0< IF -1 ELSE 0 THEN ; (одинарное_в_двойное) Еще более изящно определяется это слово в Форт-79 : : S-D (n - d) DUP 0< NEGATE ; Если число одинарной длины в стеке отрицательное, то слово 0< возвращает 1, которую слово NEGATE превращает в -1 в качестве старшей половины числа двойной длины.


В случае, если число положительное, 0< возвращает 0, который словом NEGATE никак не изменяется. Определением слова S-D в Форт-83 будет : S-D ( n - d) DUP 0< ; поскольку в Форт-83 0< возвращает -1, если число отрицательное, или 0 в противном случае (см. гл. 7).
Приведем определение слова U. : : U. ( n -- ) S-D TYPE SPACE ;
Так как слово #> возвращает число символов в символьной строке, мы можем определить также слово UD.R: : UD.R ( d n - ) (Печать_беэ_энака_с_выравниванием_вправо) ROT ROT ( n d ) (Помещает значение длины поля на дно стека) ( n адр счет ) (Форматирует выводимое число) ROT OVER ( адр счет п счет ) - ( адр счет пробелы ) (Помещает перед числом пробелы) SPACES ( адр счет ) (Перемещает курсор на число пробелов) TYPE ( ) (Выводит число) ; (Конец определения)
А вот определение для U.R : ; U.R ( n n --) SWAP S-D ROT OVER - SPACES TYPE ;
Вы можете представить себе, как оно работает по аналогии с UD.R. Понимаете ли вы, почему лучше было бы определить некоторое слово, которое использовалось бы как для определения слова U.R, так и UD.R?
Как это ни удивительно, U.R, UD.R и UD. не включены в большинство версий Форта. Возможно, вы пожелаете добавить их к своему Форту.
Как быть с печатью чисел со знаком7 Для них нам потребуется слово SIGN (знак), которое вставляет знак - (минус) в символьную строку, если число, находящееся на вершине стека, отрицательное. Если вы напечатали 1245. TYPE на экране появится число -1245.
Более полезно определение слова D., которое позволяет выводить числа двойной длины со знаком. : D. ( d - ) SWAP ( мл# ст# -- ст# мл# ) OVER ( ст# мл# -- ст# мл# ст# ) DABS (Берет из стека абсолютное значение двойного числа, оставляя старшую часть исходного числа на дне стека, включая знак) (Заканчивает преобразование) TYPE SPACE (Выводит число) ; (Конец определения)
Почему слово SIGN применяется после #S, а не перед ним? Потому что строка символов при форматировании получается в результате просмотра справа налево. Это значит, что первым преобразуется наименее значащий (младший) разряд, поэтому после исполнения слова #S к строке символов будет добавлен символ знака перед наиболее значащим (старшим) разрядом, где ему и следует быть.


Обратите внимание, что перед SIGN необходимо слово ROT, потому что слово #S не удаляет число из стека, а заменяет его числом 0 двойной длины. Процедуры форматного вывода еще более неудобны для чисел- со знаком. Поэтому для большего удобства желательно определить еще два новых слова: : TYPE SPACE : Для полноты дадим еще определение слова . (точка) : ; . ( n -) S-D TYPE SPACE ;
Как оно работает, должно быть понятно. В большинстве версий Форта. (точка) определена как операция форматного вывода, т.е. очень близко к этому определению- Мы обещали еще научить вас выводить числа в формате с десятичной точкой и символами денежных единиц. Это делается с помощью слова HOLD, которое помещает символ ASCII, заданный его кодом, в символьную строку. Так, например, 12.34 TYPE выведет на экран $1234. Или 12.34 TYPE представит на экране 1234%. Снова обратим внимание на то, что строка формируется в обратном порядке, т.е. в конец помещается символ, встречающийся первым, и наоборот.
Мы также обещали, что вы сможете вводить разделители, например десятичную точку, в выводимое число. Чтобы сделать это, вам потребуется другое слово #. Слово # выталкивает разряды числа по одному справа налево и помещает их в выходную строку. После того как группа разрядов преобразована, можно использовать #S для завершения преобразования. Попробуйте ввести 1234. TYPE и на экране должно появиться $12.34. Цифры 4 и 3 были помещены в выходную строку двумя словами #, операция 46 HOLD поместила в строку десятичную точку, слово #S поместило в строку оставшиеся два разряда 12, а 36 HOLD на вершину строки помещает знак денежной единицы $. Снова обратите внимание, что процесс форматного преобразования происходит справа налево.
Теперь вы можете самостоятельно определить слово для представления чисел в долларах и центах, и так как мы показали, что оно должно отображать числа со знаком, то с помощью этого слова вы сможете записывать долги: : D$. ;
Можно определить другие слова для более сложного вывода.
Здесь приведены все средства форматного вывода.


Фактически форматирующими словами являются только #S, SIGN, HOLD и #, но, как вы увидите из упражнений, они позволяют решать довольно сложные задачи форматного вывода. Следует напомнить, что между могут использоваться любые "правильные" слова Форта. Прежде чем перейти к упражнениям, небезынтересно рассмотреть, как работает слово #. Вот его определение: мы предполагаем, что в стек положено число двойной длины 123, а содержимое стека представлено в десятичной системе, чтобы комментарии были более понятными : : # (123 0) (Начало определения) BASE @ (123 0 10) (Извлекает основание) S-D (123 0 10 0) (Преобразует в число двойной длины) D/MOD ( 3 0 12 0) (Остаток - это последняя цифра. частное - остальная (непреобразованная) часть числа) ROT DROP (3 12 0) (Превращает остаток в одинарное число) ROT (12 О 3) (Помещает на вершину последний разряд) 48 + (12 0 51) (Добавление 48 преобразует число в код ASCII) HOLD (12 0) (Помещает в строку код ASCII) ; (12 0) (Конец определения)
Процесс состоит в отделении разрядов от числа с конца (младшего разряда) по одному с помощью операции D/MOD, преобразовании каждого из них в код ASCII путем добавления десятичного числа 48 и, наконец, помещении кодов ASCII в символьную строку словом HOLD. Слово #S можно определить через слово #, используя цикл, прекращающийся, когда частное станет равным нулю; в этот момент все разряды числа будут отделены. Приводимой слово может выполнить все указанные функции : : #S BEGIN OVER WHILE # REPEAT ;
Поскольку вы еще не изучили конструкцию BEGIN..WHILE...REPEAT, это определение может вам показаться или не показаться лишенным смысла, но главное, что делает #S: - повторяет операцию # до тех пор, пока возвращаемое число двойной длины не станет равным нулю. Материал гл. 8 сделает эту конструкцию более понятной.
Упражнения
1. Определите слово UD$. для печати чисел двойной длины без знака в формате долларов и центов, т.е. 1234. UD$. должно давать на экране $12.34. 2. Определите слово US$. для печати чисел одинарной длины в долларах и центах. 3.


Определите слово S$. для печати чисел одинарной длины со знаком в долларах и центах (включая, конечно, отрицательные числа). 4. Определите слово S$.R для печати чисел одинарной длины со знаком в долларах и центах, выровненных вправо в поле. длина которого находится в стеке, и работающее как R.. 5. Определите слово.L для печати чисел, выровненных влево. Числа со знаком, если таковые присутствуют, должны быть сдвинуты влево, но курсор, который показывает позицию, куда должно помещать следующее число, должен переместиться в поле вправо. Это значит, что после числа должно следовать некоторое количество пробелов. 6. Определите слово .DATE для форматного вывода даты. Так, 122388. DATE н а экране должно напечатать 12/23/88. 7. Определите слово .MDY, подобное .DATE, для печати даты в формате m. 12 d. 23 у. 88 месяц 12 день 23 год 88 8. Определите слово.PHONE (телефон), которое при вводе 824 959 2345. будет выводить номер телефона в формате (824) 959-2345 9. Переменная #РТ в MMSFORTH содержит в себе указатель места десятичной точки в последнем введенном числе двойной длины (считая справа налево). Определите слово FL. для печати числа с десятичной точкой в том же месте, что и во введенном числе. Так, при вводе 12.34 FL. на выходе должно быть напечатано 12.34 , в то время как при вводе 1.234 FL. должно получиться 1.234. Воспользуйтесь счетным циклом DO-LOOP между .
Ввод с клавиатуры
В Форте предусмотрено несколько слов для управления вводом с терминала. Некоторые из них стандартные, другие - расширяющие возможности языка. Здесь мы рассмотрим наиболее простые из этих слов.В Форте имеются достаточно мощные средства для определения других слов, управляющих вводом, однако вам будет проще с ними разобраться после того, как мы рассмотрим символьные строки в гл. 9. Дальнейшее изложение имеет целью дать вам необходимый на данной ступени минимум.
Со словом KEY мы познакомились раньше. После ввода этого слова программа приостанавливается, пока не будет нажата какая-либо клавиша, затем код ASCII выбранного символа помещается в стек.


Слово KEY удобно для того, чтобы выяснить код ASCII нажатой клавиши [ попробуйте ввести KEY. ]; но используется оно чаще всего для ввода одной литеры ответа на вопрос, тогда в зависимости от значения кода клавиши программа будет выполнять какие-либо действия. В MMSFORTH имеется родственное слову KEY слово и ?KEY. Оно обычно используется в цикле. Если ни одна из клавиш не нажата при очередном исполнении ?KEY в цикле, в стек кладется 0, если клавиша нажата, то в стек кладется значение кода ASCII этой клавиши. Таким образом программа выполняет какую-то задачу, пока не будет нажата клавиша, с этого момента программа будет выполнять другую задачу, в зависимости от кода клавиши. Как KEY, так и ?KEY позволяют осуществить выбор вариантов исполнения программы, но в то время как KEY ожидает ввода, слово ?KEY позволяет продолжать исполнение программы, пока не будет нажата клавиша. Очевидно, слово KEY может быть использовано в цикле для ввода строк символов, но более удобным для этой цели является слово EXPECT. Для него необходимо, чтобы в стеке был адрес, начиная с которого будет запоминаться символьная строка, и вторым в стеке - число символов, которое "ожидается". Когда встречается слово EXPECT, исполнение программы приостанавливается либо до ввода ожидаемого числа символов, либо до нажатия клавиши . Испытайте действие приведенного ниже слова : : WHATWORD ." Какое Слово ? " PAD 10 EXPECT ;
Когда вы введете WHATWORD, исполнение программы приостановится после печати на экране вопроса "What is the word?" "(Какое слово?). Теперь введите 10 букв, и, когда вы введете десятую букву, исполнение программы продолжится. Теперь введите PAD 10 TYPE и вы увидите те 10 букв, которые были записаны, начиная с адреса PAD. А теперь введите с клавиатуры 5 символов и после этого нажмите , затем введите 10 PAD TYPE. Вы увидите 5 напечатанных вами символов. То, что будет происходить далее, зависит от версии Форта, с которой вы работаете. Во всяком случае, прекращает действие слова EXPECT, т.е.


ввод.
Слово EXPECT имеет дополнительные возможности, о которых вы узнаете из гл. 9. В МMSFORTH имеется слово IN$, основанное на слове EXPECT, которое имеет аналогичное действие. Это слово ничего не ожидает из стека и помещает все, что было введено с клавиатуры, в строку со счетчиком, начиная с адреса PAD, до нажатия клавиши , оставляя в стеке адрес PAD. введите IN$, потом , а затем строку символов и снова . Теперь если вы наберете COUNT TYPE, то увидите строку, которую ввели. Адрес PAD был оставлен в стеке словом IN$, слово COUNT кладет в стек длину строки, и TYPE печатает ее. Нестандартные слова IN$ и ему подобные являются основными средствами для ввода текста в программу. Вы многое сделаете с их помощью в главе, посвященной литерным строкам.
До сих пор мы рассматривали только ввод и вывод литер и литерных строк. А как быть с числами? Конечно, можно записать их в стек с клавиатуры, перед тем как будет исполнено какое-либо слово или начнет работать программа. Ну а что делать, если числа нужно вводить во время исполнения программы? Это одна из наиболее слабых сторон стандарта Форт или по крайней мере одно из неудобств для программиста. К счастью, в большинстве версий эта проблема решается с помощью специальных слов. В MMSFORTH такими словами служат #IN и D#IN. Оба они приостанавливают исполнение программы и печатают на экране знак вопроса ?. Вводимые с клавиатуры до нажатия клавиши символы воспринимаются затем как число либо одинарной, либо двойной длины, в зависимости от слова, и помещаются в стек. Если используются недопустимые символы или число имеет недопустимую длину, появляется сообщение "Redo" (повторите), разрешая повторение ввода числа.
Попробуем ввести следующее определение : : TEST ." Какое число " #IN ." Вы ввели " . ;
Если в вашей версии слова #IN или эквивалентного ему нет, потребуется некоторая изобретательность. Прием состоит в том, чтобы ввести литерную строку и затем преобразовать ее в число, используя стандартное слово CONVERT (в некоторых версиях имеется эквивалентное ему слово >BINARY).


Достаточно мощное слово CONVERT работает только с числами одинарной длины без знака, и применение его вызывает некоторые трудности. Вы еще убедитесь в больших возможностях слова CONVERT в гл. 9.
Выводы
Проблемы ввода и вывода показывают суть замысла стандартов языка Форт. Они предназначены для обеспечения минимально необходимых средств для конструирования того, что вам может потребоваться, но не оговаривают все детали и свойства, которые вы бы хотели иметь. Например, слова форматного вывода, такие как EXPECT и CONVERT, в свою очередь, можно использовать для определения слов типа UD.R, $IN и #IN. Форт подвергается критике за небогатые возможности вво да-вывода, и, что касается стандартов, - это справедливо. Однако не представляет сложности добавить необходимые вам возможности, и в большинстве коммерческих реализациях языка они предусмотрены. Вам нужно внимательно ознакомиться с документацией на тот вариант языка, которым вы располагаете, чтобы узнать, что он может делать. Кроме того, в гл. 9 мы приведем определение еще нескольких полезных слов.

Содержание раздела