Американский стандартный код для обмена информацией (ASCII)
Кроме представления чисел разряды в памяти могут представлять алфавитно-цифровые символы. Символы просто кодируются числами, при этом наиболее распространенным является код ASCII, полное наименование которого приведено в заголовке. Первоначально код ASCII предназначался не для компьютеров, а для телекоммуникаций. Это привело к тому, что некоторые коды имеют странные названия. Например, код 7 (называемый BEL -- звонок) предназначался для звонка в момент возврата каретки с целью привлечения внимания оператора. Код 5 называется WRU (от Who aRe yoU -- кто там?), предназначался для запроса служебного позывного оператора на другом конце линии, код 25 -- ЕМ (End of Media -- конец носителя) может быть использован для индикации конца телеграфной ленты. Хотя мы еще увидим в , как Форт обращается со строками символов сейчас мы рассмотрим, как он воспринимает отдельные символы. Несмотря на то, что код ASCII не предназначался для ЭВМ, символы в нем все же упорядочены логично с точки зрения ЭВМ т.е. в порядке расположения букв алфавита. Полный набор кодов ASCII приведен в . В показано только, как он организован.
Таблица 3.3, Сводка кодов ASCII в десятичной и двоичной форме
От До Десятичный Двоичный Десятичный Двоичный Назначение
000 00000000 031 00011111 Коды управления ЭВМ 032 00100000 064 01000000 Цифры и знаки пунктуации 065 01000001 090 01011010 Буквы A-Z 091 01011011 096 01100000 Разные знаки 097 01100001 122 01111010 Буквы a-z 123 01111011 127 01111111 Разные символы 128 10000000 255 11111111 Кодами ASCII не являются
Вы можете заметить, что в стандартном коде фактически используется только 7 разрядов из байта. Это объясняется тем, что для телетайпов использовалась семидорожечная бумажная лента с семью отверстиями поперек ленты. (Она же использовалась для хранения программ и данных до сравнительно недавнего времени.) Числа с восьмым разрядом, установленным в 1 (128 - 255), не являются кодами ASCII как в Форт-79, так и в Форт-83, но в некоторых версиях Форт и большинстве микрокомпьютеров частично используются.
Например, в MMSFORTH с ЭВМ TRS-80 и IBM PC они используются для графических и специальных символов. Первые 31 код называются управляющими кодами. Хотя их назначение стандартизовано для передачи данных, но в микрокомпьютерах они применяются для разных целей, т.е. стандарт нарушается. Тем не менее некоторые из них все же стандартизованы, как, например, 8 -- код возврата на позицию влево, 13 -- возврат каретки, 10 -- перевод строки.
Управляющие коды посылаются с клавиатуры путем нажатия клавиши "Control" (управление, иногда обозначается "Ctrl") и одновременно какой-то литерной клавиши, например для возврата влево на позицию -- это Ctrl-H. Если на клавиатуре нет клавиши "Ctrl", то в вашей версии Форта должна быть предусмотрена какая-либо другая клавиша, которая действует как "Ctrl", например в MMSFORTH с ранними моделями ЭВМ TRS-80 использовалась клавиша "Clear" (очистка). Вам нужно посмотреть по своей документации, какие управляющие коды используются в вашей версии форта и какую клавишу нужно использовать, если у вас нет клавиши "Ctrl". Чтобы узнать как в вашей версии Форта используются коды ASCII, воспользуйтесь двумя словами EMIT и KEY.
Введите
65 EMIT
и на экране должно появиться
A ok.
Слово EMIT берет число с вершины стека и посылает его ASCII-эквивалент на экран. Испытайте со словом EMIT другие числа, сравнивая получаемые результаты с таблицей в , чтобы получше прочувствовать, как ваше оборудование обращается с кодами ASCII. Некоторые особые символы, такие как тильда "~", "стрелка вверх" (^), квадратные скобки ([]) на различных компьютерах могут выглядеть по-разному, и то, что печатает ваш принтер, также может отличаться от того, что выводится на экране. (Предупреждение: использование чисел меньше 32 может привести к неожиданным результатам, так как это управляющие коды.)
Если слово EMIT позволяет вывести символы ASCII, соответствующие числу, находящемуся в стеке, то слово KEY позволяет выдать в стек код символа ASCII, вводимого с клавиатуры.Введите слово
KEY
Ничего заметного при этом не случится, даже сообщение "ok" не появится. Теперь нажмите клавишу "В", а потом . ; после этого вы увидите, что в стек было положено число 66. Слово KEY приказало Форту приостановить то, что он делал, и подождать, когда будет нажата какая-либо клавиша, тогда код, соответствующий символу клавиши, кладется в стек. Когда вы нажали клавишу "В", вы поместили значение кода ASCII в стек и увидели этот код, когда ввели . (точку). Что вы увидите, если введете с клавиатуры
KEY EMIT
Попробуйте после этого нажать какую-либо клавишу. Можете ли вы объяснить результат ? Если у вас нет компьютера под рукой, то вот, что вы должны увидеть, если, скажем, нажмете Z после :
Z ok
Полезно уметь делать преобразования кодов ASCII, например, для представления вместо букв нижнего регистра букв верхнего регистра и наоборот. Посмотрим, как это делается в упражнениях.
Буфер ввода
В действительности числа, которые вы вводите, не попадают в стек сразу. Все, что вы вводите с клавиатуры, сначала запоминается в небольшой области памяти, которая называется буфером ввода, в том же виде, как вы потом видите на экране. Когда вы нажимаете клавишу , буфер ввода интерпретируется, т.е. сканируется слева направо. Интерпретатор просматривает каждую строчку символов, разделенных пробелами. Если он опознает символ(ы) как слово, он принимает его и просматривает следующий набор символов. Если символы не опознаются как слово, интерпретатор пробует, не являются ли они числом, и, если это так, помещает в стек число. Если же символы не воспринимаются ни как слова, ни как числа, Форт выдает сообщение об ошибке. Попробуйте ввести
159 ZZZZZ
(либо другое бессмысленное слово) вы увидите:
zzzzz ?
или какое-либо сообщение, свидетельствующее о том, что Форт вас не понял. Если теперь вы введете . (точку), Форт напечатает сообщение "Stack empty !" (стек пуст).
Когда Форт не может интерпретировать слово, он производит очистку стека. Это необходимо помнить потому, что иначе вы будете обескуражены результатом, а отчасти потому, что таким путем удобно очищать стек. Помните также, что, если Форт встречает неизвестное ему слово, он игнорирует все, что следует за ним в строке ввода.
Буфер ввода имеет определенную длину, которая зависит от используемой версии Форта. В соответствии с требованиями стандартов буфер должен принимать не менее 80 символов.
Что такое Форт ?
Из всего сказанного может показаться, что у нас есть только два выбора среди языков программирования: либо быстрые, но громоздкие компиляторы, либо медленные, но зато общительные интерпретаторы. К счастью, Форт является еще одной альтернативой. Программы, написанные на языке Форт, по быстродействию не уступают, а то и превосходят программы, написанные на компилирующих языках. Форт-программы очень легко изменяются и отлаживаются. Еще одним их достоинством является то, что они обычно занимают в памяти меньше места, чем программы на других, как компилирующих, так и интерпретирующих языках. Дополнительное преимущество языка заключается в том, что он дает возможность программисту определить некоторые слова на языке ассемблера, когда требуется максимальное быстродействие, т.е. в нем совмещаются преимущества языка высокого уровня и языка ассемблера. Чем объясняются все эти достоинства языка Форт ? Тем, что он является интерпретирующим языком с шитым кодом. Чтобы разобраться, что это значит, нужно рассмотреть, что происходит при определении Форт-слова. В поставляемом потребителям виде базовая Форт-система содержит множество слов, которые были определены не с помощью других слов, а непосредственно на машинном языке (они составляют часть, называемую ядром языка). Эти слова используются для описания других слов, и их называют примитивами. Примерами примитивов являются слова *, +, DUP, SWAP и т.д. Если вы компилируете слово SQUARE, вводя
: SQUARE DUP * ;
в компьютер не вводится никакого нового машинного кода, вы только предлагаете ему соединить вместе коды слова DUP и * под именем SQUARE. Точно также и CUBE:
: CUBE DUP SQUARE * :
не вводит нового машинного кода. Аналогично и слово POWER4, которое вы определили в одном из упражнений. Компиляция состоит как бы в протаскивании одной нити через различные определения с исполнением встречающихся по пути примитивов и машинных команд. Когда исполняется слово POWER4, "нить" проходит так, как показано на . Все необходимые действия, кроме ввода в память, были выполнены с помощью двух примитивов DUP и *, входящих в ядро и определенных на машинном коде.
Если вы знакомы с компиляцией в других языках программирования, то заметите, что форт осуществляет ее совершенно по-другому. В и мы подробно рассмотрим, как работает компилятор шитого кода. В книге Лулигера (1981) рассматриваются некоторые теоретические вопросы разработки интерпретирующих языков, использующих шитый код. Теперь мы можем понять причину многих достоинств языка Форт: программирование в диалоговом режиме, гибкость, большая скорость, минимальные потребности памяти и такое же полное управление оборудованием компьютера, какое доступно ассемблеру или машинному языку. Вы уже убедились в больших возможностях общения с языком на примерах и упражнениях этой главы. Большое преимущество в скорости работы перед другими интерактивными языками объясняется тем, что последние, как правило, интерпретирующие.
рис. 1.3
Поскольку интерпретация включает в себя преобразование кода программы в машинный код строчка за строчкой во время исполнения программы, то и Форт, и любой другой компилирующий язык должны работать намного быстрее. Скорость их работы складывается из нескольких компонент. Во-первых, использование стека позволяет сэкономить время на извлечение переменных из памяти, если выполняются операции с числами. Во-вторых, переход от примитива к примитиву и от слова к слову также занимает очень мало времени. В-третьих, в процессе исполнения программы Форт делает только минимальную проверку ошибок, поэтому не подключаются никакие "скрытые" программы для их обнаружения, например, если вы пытаетесь разделить число на 0. Проверка ошибок целиком возлагается на программиста. Поскольку Форт-программа составляется и отлаживается слово за словом, это может при отладке сильно мешать, поэтому проверку ошибок можно предусматривать "по обстоятельствам". Наконец, программируя на Форте, приходится отчетливо представлять себе и учитывать, что и как делает компьютер, поэтому программа получается более эффективной.
Очень малая потребность в памяти, присущая Форту, вызывается применением шитого кода.
В отличие от других интерпретирующих языков не требуется, чтобы код исходной программы всегда находился в памяти. И в отличие от любого компилирующего языка каждый примитив и процедуры, определенные на машинном языке, хранятся в памяти в единственном экземпляре. Большинство же компиляторов добавляют к программе модули машинного кода при каждом обращении к этому модулю. Когда компилятор встречает в исходном коде вызов функции, он отыскивает в библиотеке определенные на машинном коде процедуры и размещает их в памяти, поэтому, если функция вызывается несколько раз, то в память будет помещено несколько копий процедуры. Интерпретирующий язык с шитым кодом записывает процедуру в память только один раз и делает переход к ней из любого места, где она потребуется. Поэтому Форт-программа может занимать в памяти значительно меньше места, чем эквивалентная программа, написанная, скажем, на Фортране.
Наконец, Форт обладает потрясающей способностью управлять компьютером, поскольку на нем довольно легко определить новые примитивы, т.е. процедуры в машинных кодах. Если определение слова начинается с CODE, то все, что следует после этого слова, описывается на языке ассемблера и при ассемблировании превращается в машинный код, который становится частью определения этого слова. Описание вы найдете в . Поскольку слова Форта можно легко комбинировать с мнемоникой ассемблера, он обладает мощью ассемблера и удобством языка высокого уровня. Очевидно, что программирование на Форт-ассемблере не является обязательным, но приятно сознавать, что такая возможность имеется при необходимости.
Что такое машинный язык ?
Чтобы задать вопрос, почему Форт работает не так, как другие языки программирования, надо сначала спросить, а что такое язык ЭВМ ? Компьютер -- это машина, которая может производить включение и выключение переключающих устройств с очень большой скоростью (миллион или более раз в секунду). Каждое переключающее устройство может представлять "1" (включено) или "0" (выключено), большая часть этих переключающих устройств находится в памяти ЭВМ. Компьютер может хранить числа, буквы и другие данные в памяти, поскольку он обладает способностью переводить их в последовательность из единиц и нулей (включенных и выключенных состояний переключающих устройств). Так, например, буква R обычно хранится в ЭВМ в виде 01010010, буква S -- в виде 0101011, а буква r -- как 01110010. Но еще важнее, что и инструкции, которые указывают компьютеру, что он должен делать, также хранятся в памяти в виде последовательности из единиц и нулей. Центральное процессорное устройство (ЦПУ) считывает эти последовательности, определяя, что делать. Эта последовательность единиц и нулей, на которую отзывается центральный процессор, представляет собой программу самого низкого уровня, и фактически только такую программу процессор может непосредственно исполнять.
В отличие от компьютеров человек не обладает способностью мыслить категориями единиц и нулей. Поэтому он нуждается в языке для общения с компьютером. Самый простой язык, который называется машинным языком, представляет собой попросту процессорные инструкции в виде последовательностей из многоразрядных чисел, которые хранятся в компьютере представленными в виде единиц и нулей. Однако и такое представление трудно для человеческого восприятия, поэтому пользуются языком более высокого уровня, в котором каждая инструкция представляется некоторой аббревиатурой (или, как говорят, мнемоникой), которая, к примеру может указывать, что компьютер должен переслать число из памяти в регистр ЦПУ. Каждая мнемоническая инструкция, в свою очередь, ассемблируется (размещается) с помощью программы, которая написана на машинном языке так, чтобы сформировать в памяти последовательность из единиц и нулей.
Программа, предназначенная для этой цели, называется ассемблером, а язык этого уровня также называется ассемблером, или языком ассемблера.
Язык ассемблера обладает тем достоинством, что он может управлять всеми доступными данному процессору операциями и, кроме того, создает очень компактные программы, которые эффективно используют запоминающее устройство и обеспечивают максимально возможную скорость работы ЭВМ. Недостатком же его является то, что программист должен описать действия ЭВМ вплоть до самых мелких деталей. Например, нельзя на языке ассемблера дать команду компьютеру перемножить два числа, необходимо расчленить процесс умножения на ряд более простых шагов. Программа умножения двух чисел, записанная на языке ассемблера, может вылиться в некоторое количество строчек. Поэтому на языке ассемблера обычно пишут те программы, которые должны работать с максимально возможным быстродействием с учетом мельчайших подробностей работы компьютера, например программы для управления запоминающим устройством на магнитных дисках.
Язык ассемблера все же неудобен для решения большинства практических задач, поэтому в основном его используют для написания других языков программирования, чтобы еще на одну ступень подняться над машинным языком ЦПУ. Языки такого рода называют языками программирования высокого уровня. К ним относятся Фортран, Бейсик, Кобол, АПЛ, Паскаль и тот, который нас здесь больше всего интересует -- Форт. Они преобразуют понятные человеку символы (например, * -- обозначение операции умножения двух чисел) в последовательность понятных компьютеру инструкций из единиц и нулей. Следовательно, языки высокого уровня выполняют роль переводчиков между человеком и ЭВМ.
Языки высокого уровня традиционно разделяются на два класса: интерпретирующие и компилирующие. Компилирующим языком называют такой язык, который целиком преобразует исходную программу в машинный язык, исполняющуюся так же, как программа, написанная непосредственно на машинном языке. Текст программы, написанный на языке близком к обычному английскому, называется исходным кодом, инструкции на машинном языке -- скомпилированным кодом.
Часто текст программы называют просто кодом, будь то язык машины, ассемблера или язык высокого уровня. Компилирующие языки появились первыми, самыми старыми среди них являются Фортран, Алгол и Кобол, которые еще и сейчас применяются преимущественно на больших ЭВМ.
Достоинство компилирующих языков состоит в том, что громадный исходный код программы не нужно размещать в машине, она транслируется в машинный код один раз, а исполняемая программа работает обычно очень быстро и для ее размещения требуется меньше места в памяти. Недостаток же состоит в том, что сам процесс компиляции очень трудоемок, трудоемок также процесс внесения исправлений и изменений в программу (отладки программы), потому что при внесении любого изменения ее приходится заново компилировать целиком.
Интерпретирующий язык транслирует исходный код программы (интерпретирует) строчку за строчкой при каждом исполнении программы. Интерпретирующим языком является Бейсик, хотя также существуют и компилирующие версии этого языка. Очевидно что при исполнении программы на интерпретацию расходуется время, поэтому интерпретирующие языки по своей природе работают медленнее, чем компилирующие. С другой стороны, исходный текст программы можно легко изменить, потому что он всегда находится в компьютере, а скорректированную программу можно быстро и просто проверить. Обычно интерпретирующие языки поощряют при их изучении и программировании к применению метода проб и ошибок. Кстати, язык Бейсик был первоначально разработан в Дартмутском колледже как раз для изучения компьютерных языков. Интерпретирующие языки обычно общительны, в том смысле, что они делают общение между программистом и программой (и, следовательно, компьютером) относительно несложным.
Что такое память ?
Представьте себе, что имеется 8 переключателей, каждый из которых может быть включен или выключен. Можно их закодировать так, чтобы состояние переключателей представлялось числами. Будем считать, что единице соответствует включенный переключатель, нулю --- выключенный. В показаны числа, построенные таким образом. Восемь переключателей могут представлять до 256 чисел (от 0 до 255). Если немного подумать, вы сможете доказать, что с помощью n переключателей можно запомнить 2^n чисел (2^8=256).
С помощью 16 переключателей или двух банков по 8 переключателей могут быть представлены 65536 чисел (от 0 до 65535).
Предполагается, что для чисел в стеке имеется два банка по 8 переключателей. Вследствие этого наибольшее число, которое можно записать в стек и которое мы называем числом одинарной длины, равно 65535. Для представления чисел двойной длины нужно уже 32 переключателя, и диапазон представляемых чисел увеличивается до 65535 х 65535 = 4271406736.
Итак, мы видим, что память микрокомпьютера -- это не что иное, как большое количество переключателей, которые могут включаться и выключаться с огромной скоростью. Вот так. И все, и ничего больше. Сложность здесь состоит в том, чтобы организовать переключатели для хранения чисел и, следовательно, данных. (Алфавитно-цифровой текст также можно представить в виде закодированных чисел. Например, буква А представляется числом 65.) Каждый переключатель в памяти называется битом, от английского Binary digiT (двоичный разряд, а почему -- мы вскоре узнаем).
А теперь можете забыть о всяких переключателях, будем говорить только о битах. Если значение содержимого бита равно 1, то говорят, что он взведен или установлен; если значение равно 0, то говорят, что он сброшен или выключен. Многие недорогие ЭВМ, например Commodore 84, TRS-80 модель 4, Apple II, используют ЦПУ, которое работает с 8-разрядными числами; их называют 8-разрядными машинами, они обеспечивают доступ к 65536 8-разрядным ячейкам памяти, т.е. к 524288 битам. Более дорогие 16-разрядные машины, например IBM PC и Tandy 2000, работают с 16 разрядами одновременно, обеспечивают доступ к большему числу ячеек памяти, объем памяти здесь, скорее, ограничивается потребностями пользователя и его финансовыми возможностями. 8-разрядный элемент памяти называют байтом, в байтах принято оценивать емкость памяти.
В ЭВМ ранних моделей за единицу емкости принималось четыре разряда.
16 разрядов иногда называют словом, однако, так как слово на больших ЭВМ может быть 32-разрядным или даже 64-разрядным и, кроме того, понятие "слово" в языке Форт имеет совсем другой смысл, будем называть 16-разрядное число ячейкой либо просто числом. Это число -- целое, ибо оно используется для хранения в стеке чисел одинарной длины. Для обозначения больших объемов памяти применяются слова с префиксами кило и Мега-, которые в метрической системе означают соответственно 1000 и 1 миллион.
Например, километр -- это 1000 метров, 1 МегаГерц -- это 1000000 Гц, или 1 млн. колебаний/с. В вычислительной технике применяются другие единицы (не столь строгие). Килобайт (сокращается как Кбайт) -- это приблизительно 1000 байтов, на самом деле он равен 210 = 1024 байта. Мегабайт (сокращенно Мбайт) используется еще более нечетко. Иногда считают его равным 1000 Кбайтам, т.е. 1024000 байтам, а иногда 1024 Кбайтам, т.е. 1048576 байтам. Последнее число представляется как 220 байтов. Это полезная единица для обозначения объема памяти, и мы будем использовать именно это определение. Так, например, модели ЭВМ TRS-80 Modell III и Apple II обычно называют машинами с объемом памяти 64 Кбайта или б4К- машинами; они могут работать с памятью объемом 64 х 1034 = 65536 байтов; IBM PC может работать с памятью объемом до 1 Мбайта, или 1048576 байтов.
Таблица 3.1 Двоичная запись и основание системы счисления
Состояния переключателей |
число | Состояния переключателей |
число |
00000000 | 0 | 00000110 | 6 |
00000001 | 1 | 00000111 | 7 |
00000010 | 2 | 00001000 | 8 |
00000011 | 3 | 00001001 | 9 |
00000100 | 4 | .... | ..... |
00000101 | 5 | 11111111 | 255 |
с двоичной системой. Как мы вскоре увидим, иногда (но не очень часто) удобно работать с числами, использующими для записи 8 цифр (от 0 до 7), т.е. восьмеричную форму, а очень часто удобнее использовать 16 чисел (от 0 до 9 и от А до F), или так называемую шестнадцатеричную форму представления. В шестнадцатеричной форме число 10 обозначается буквой А, 11 -- буквой В и т.д., число 15 -- буквой F, число 16 обозначается как 10. Давайте снова рассмотрим таблицу двоичных чисел. Посмотрите, сможете ли вы объяснить, почему для обращения с байтом оказывается удобной шестнадцатеричная система (для этого продолжите таблицу до 16). Если вы не догадались, то через некоторое время это станет понятнее. Хорошее практическое обсуждение оснований систем счисления и других аспектов представления чисел вы можете найти в книге Липшуца "Арифметические основы компьютеров" (1982).
Количество различных цифр, используемых для представления чисел, называется основанием системы счисления или просто основанием. При двоичной записи основание равно 2, при восьмеричной -- 8, при десятичной -- 10, при шестнадцатеричной -- 16 (обозначение ее в Форте HEX происходит от английского названия hexadecimal). Прелесть Форта состоит в том, что, хотя все числа он хранит в двоичной форме (впрочем, как и многие другие языки, что определяется требованиями компьютера), он может принимать их и отображать с любым основанием вплоть до 72. Нам потребуются некоторые слова Форта, которые позволяли бы отображать числа из стека в различных системах счисления, но прежде чем мы с ними познакомимся, необходимо немного отвлечься, чтобы рассмотреть, как мы можем извлекать байты и числа, которые хранятся в памяти. С каждым байтом сопоставляется число, начиная с нуля и больше, которое соответствует его положению в памяти и называется адресом. Таким образом, первый байт имеет 0-й адрес в памяти, в то время как для 8-разрядной ЭВМ адрес самого верхнего байта равен 65535. Для осуществления доступа к содержимому указанного адреса в Форте предусмотрено несколько слов.
Наиболее важными из них являются @ (извлечь) и ! (занести, запомнить). Если в стеке на вершине находится адрес, то слово @ замещает адрес 16-разрядным (двухбайтовым) числом, которое хранится по этому адресу. Если так же на вершине находится адрес, а вторым элементом стека является число, то оператор ! производит запоминание этого числа по указанному адресу. Слово ! следует употреблять осмотрительно, так как можно изменить содержимое важной части памяти, если вы запишете не в то место памяти. Можно использовать слова @ и ! для того, чтобы узнать систему счисления или изменить ее при вводе и выводе чисел. В памяти имеется ячейка (адрес), в которой хранится основание системы счисления, которое действует в настоящий момент при вводе-выводе чисел. Этот адрес выдается в стек когда вы вводите слово BASE. Давайте его испытаем. Вначале дадим компьютеру задание принимать и выводить числа в десятичной системе счисления с помощью слова DECIMAL (десятичный). Слово DECIMAL изменяет число, которое хранится по адресу, возвращаемому в стек словом BASE, на 10 (десятичная система). Теперь основание может быть сделано шестнадцатеричным (основание 16), если ввести
16 BASE !
Слово BASE помещает на вершину стека соответствующий адрес, затем в этот адрес записывается число 16. Заметим, кстати, что слово BASE -- это особая переменная, так называемая переменная пользователя. Переменная -- это слово, которое выдает адрес, где может храниться число; мы обсудим ее более детально в . Форт не нуждается в большом количестве переменных, как другие языки программирования, так как он может хранить числа в стеке. Теперь, когда компьютер использует шестнадцатеричную систему счисления, вы можете ввести
1В DECIMAL .
и получите
12 Ok
Число 12 в десятичной записи -- это то же самое, что 1В в шестнадцатеричной. Следующий пример произведет обратное действие:
13 16 BASE ! .
выдаст на экране 1С, т.е. шестнадцатеричный эквивалент числа 13. Слово HEX, которое не является стандартным, включено в большинство версий Форта.
Оно устанавливает шестнадцатеричную систему счисления так же, как DECIMAL устанавливает десятичную. Во многих версиях есть слова OCTAL и BINARY, которые устанавливают систему счисления 8 и 2 соответственно. Можно проиллюстрировать один важный момент с помощью следующих экспериментов. Попробуем ввести
DECIMAL 2 BASE ! BASE @ .
потом
DECIMAL 8 BАSЕ ! BASE @ .
и
DECIMAL 16 BASE BASE @ .
Во всех случаях вы увидите 10. Почему ? Основание числа во всех случаях представляется как 10, так как это -- два (в двоичной системе), 8 (десятичное) -- это 10 в восьмеричной системе и 16 (десятичное) представляется так же, как 10 в шестнадцатеричной системе. Как же тогда узнать, в какой системе мы находимся ? Вот слово, которое поможет это сделать:
: BASE? BASE @ DUP DECIMAL . BASE ! ;
Вы должны понимать, как оно работает. Если вы введете
16 BASE ! BASE?
то увидите, что на экране будет число 16, и после этого мы попрежнему останемся в шестнадцатеричной системе счисления. Вместе с тем, когда вы вводите
n BASE !
нужно быть внимательным и твердо знать, от какого основания мы переходим. Например, если мы находимся в двоичной системе, то при вводе
10 BASE !
ничего не произойдет. 10 в двоичной системе -- это десятичное число 2, но мы уже находимся в двоичной системе. А что произойдет, если ввести
10 BASE !
в шестнадцатеричной системе ? Как снова вернуться к основанию 10 ? Если вы были в шестнадцатеричной системе, можете ввести
A BASE !
А -- это шестнадцатеричное число, которое равно 10 (десятичное). Если вы забыли текущее основание, то слово DECIMAL всегда возвратит вас к основанию 10, независимо от того, в какой системе вы были до этого.
Приведем слово, которое показывает в двоичной системе счисления число, находящееся на вершине стека. Обратите внимание, что при этом оно не изменяет содержимое стека:
: .BIN (n - n) DUP BASE @ 2 BASE ! SWAP . BASE ! ;
Вы должны догадаться, как оно работает.
В качестве упражнения (и для использования впоследствии) опишите три слова: .ОСТ, .DEC и .HEX, которые будут печатать число из стека в восьмеричной, десятичной и шестнадцатеричной системе соответственно.Для этого вам надо изменить в слове .BIN всего один символ. Теперь мы сможем написать еще одно слово, которое даст возможность представить число в стеке одновременно в двоичной, восьмеричной, десятичной и шестнадцатеричной системах :
: .NUMS (n -) .BIN .ОСТ .DEC .HEX DROP ;
Слово .NUMS можно использовать для того, чтобы посмотреть, как различные числа представляются в различных системах счисления. Но давайте проделаем это в следующих упражнениях. Если у вас нет компьютера, проверьте ваши ответы по .
Что такое стек ?
Можно представить стек попросту как стопку чисел, положенных друг на друга, либо, если хотите, как колоду карт, описанную в . Первое число, которое было введено в стек, будет находиться на дне, последнее введенное число -- на вершине стека. Числа из стека можно брать только с вершины. В тексте мы будем показывать стек в виде столбика чисел, положенного горизонтально, т.е. в строчку, причем дно стека находится слева, а его вершина -- справа. Загрузите в компьютер Форт и введите
1 2 3
(обязательно отделите числа друг от друга пробелами, как показано).
Теперь в стеке находятся числа
З (вершина ) 2 1 (дно)
аналогия с картами представлена на . Можно представить этот стек таким образом:
рис. 2.1
Теперь, если ввести
. . .
компьютер выдаст на экран
3 2 1 ok
Первым из стека было взято и напечатано число 3, затем то же самое было сделано с числом 2, а потом с числом 1. Теперь стек пуст. Обратите внимание, что числа на экране расположены в обратном порядке по сравнению с тем, как они представлены в стеке. Вы поняли, почему ? Стек языка Форт называется стеком с организацией "последним пришел -- первым вышел" (по-английски - LIFO). Когда стек пуст, попробуйте ввести еще раз . (точка).
Тогда вы увидите
хххх . ? Stack empty ! (стек пуст !)
Форт отреагировал сообщением об ошибке; вы попросили его что-то напечатать, а он не знает, что напечатать (ххххх обычно бессмысленное число, а вид сообщения зависит от версии Форта, с которой вы работаете, мы, привели сообщение, которое выдает MMSFORTH). Обратите внимание, что Форт не выдает сообщение "ok", потому что выполнение вашей последней команды не было завершено (а значит, не все в порядке).
Еще раз нажмите , чтобы получить на экране новое приглашение "ok", хотя в этом нет особой необходимости.
Фактически Форт готов к вводу новой информации, даже если он не дал сообщение "ok".
Форт ... Почему он такой необычный ?
В оставшейся части этой главы мы хотели бы познакомить вас с тем, что такое язык ЭВМ и с некоторыми абстрактными, теоретическими и концептуальными особенностями языка Форт. Если даже вы знакомы с компьютерами и языками программирования, вам следует прочитать это, чтобы узнать о некоторых уникальных свойствах языка Форт.
Что такое Форт ?
Язык Форт сильно отличается от других языков программирования для ЭВМ. Но он дает возможность программисту очень просто общаться с компьютером, и это облегчает его изучение. Форт практически мгновенно реагирует на все, что вы вводите с клавиатуры, и изучать его лучше всего, непосредственно работая на компьютере. Чаще всего считают его сложным опытные программисты, которые имеют сложившиеся представления о том, как должен работать язык программирования, они привыкли, что сначала надо написать длинную программу, прежде чем проверить ее работу. Поэтому постарайтесь забыть то, что вы знаете о других языках, садитесь за клавиатуру и давайте начнем.
Стек
Основная задача состояла в первом знакомстве с языком Форт. Но для того, чтобы пользоваться этим языком практически, мы должны вернуться немного назад и снова, но уже более внимательно, рассмотреть то, с чем мы кратко ознакомились в предыдущей главе. Мы приносим вам извинения за неизбежный повтор некоторых уже известных вопросов, но повторение способствует лучшему пониманию. Первый объект, на который мы должны посмотреть более внимательно, это стек.
Хотя мы уже говорили, что компьютеры применяются не только для арифметической и математической обработки данных, но и во многих других областях, все равно работа производится с числами в той или иной форме. Форт выполняет манипуляции с числами главным образом в стеке. Как мы уже видели, стек -- это одно из необычных и мощных средств языка Форт. Поначалу стек может показаться вам странным, однако пользоваться стеком очень просто, если вы поймете, что это такое и как с ним можно работать. И нельзя овладеть Фортом, не овладев сначала стеком. Стек -- это динамическая область памяти для чисел, которая постоянно используется языком Форт. В самом использовании стека нет ничего особенно удивительного, поскольку многие языки также им пользуются (правда, незаметно для нас). Исключительно необычным делает Форт то, что в нем стек всегда доступен для вас как с клавиатуры, так и из программы. Все числа, вводимые вами с клавиатуры или поступающие с магнитного диска, фактически попадают в стек. И большая часть чисел, которые передаются из одного слова в другое, также проходят через стек. Большая часть выгод, присущих языку форт, также связана с постоянным использованием стека. (Этот стек обычно называют стеком пользователя, стеком параметров или стеком данных. В действительности Форт использует еще один стек, который называется стеком возвратов и применяется для специальных целей, о нем вы узнаете позже в другой главе.) В этой главе мы объясним, что такое стек, как в нем реализуются арифметические операции, как он используется в Форте, а также рассмотрим слова для перестановки чисел в стеке с целью упрощения решения сложных задач.
Память, числа, символьная информация
Вы можете работать с языком Форт, даже очень мало понимая, как работает сам компьютер, но это будет вам постоянно мешать. Чтобы понимать, что в нем происходит, вы должны по крайней мере понимать, как работает память ЭВМ и как в ней хранятся числа. Это не так уж сложно, как многие думают, а с помощью языка Форт еще проще. Не пропускайте эту главу, даже если у вас уже есть опыт работы с ЭВМ. Можно, если хотите, бегло просмотреть более простые вопросы. Обратите, однако, внимание на возможности Форта, касающиеся его обращения с системами счисления и операциями в памяти, которые являются его привлекательными сторонами. Возможно, что у вас возникнет также желание узнать функции слов BASE и DECIMAL.