ПРЕОБРАЗОВАНИЕ ВВОДИМЫХ ЧИСЕЛ
Как было показано в гл. 7, с помощью слов <# и #> можно преобразовать число, находящееся в стеке, в строку символов в коде ASCII. Слово CONVERT (ПРЕОБРАЗОВАТЬ) выполняет обратную функцию: оно переводит строку символов ASCII, представляющих некоторое число, в двоичную форму и заносит его в стек.
CONVERT |
( ud1 a1 -- ud2 а2) | Начиная с адреса a1+1 (байт, содержащий длину, пропускается), CONVERT преобразует строку в двоичное значение, которое зависит от текущей системы счисления (значения BASE). Полученное значение накапливается в ud1, и остается на стеке как ud2. Процесс продолжается до тех пор, пока не встретится символ, который не может выть истолкован как цифра в текучей системе счисления. Адрес этого символа заносится на стек как а2. |
Приведем несложный пример:: ПЛЮС \ n2 ( n1 -- сумма ) 0 0 BL WORD CONVERT 2DROP + ;
Это определение можно использовать следующим образом: 12 ПЛЮС 23 . 35 ок
Слово ПЛЮС является лучшим доказательством (для скептиков) того, что в Форте можно применять инфиксную запись выражений. Это слово начинает выполняться при одном занесенном в стек в двоичной форме аргументе 12. В первую очередь, занося в стек нуль двойной длины, мы очищаем место для накопления, после чего слово WORD сканирует входной поток для чтения второго аргумента n2 и оставляет адрес прочитанного фрагмента в вершине стека. Слово CONVERT преобразует строку по заданному адресу (пропуская первый байт со счетчиком) в число двойной длины и заносит его в стек на место нуля. 2DROP удаляет из стека последний адрес, помещенный в него словом CONVERT вместе со старшей ячейкой преобразованного числа, превращая последнее тем самым в число одинарной длины. Наконец, + складывает два верхних числа в стеке.
Если бы слово CONVERT функционировало с такими аргументами: ( а -- ud)
то его можно было бы применять повторно, выполняя преобразования строки, содержащей различные нецифровые символы. Например, строку 6/20/85
можно преобразовать в три числа одинарной длины, трижды подряд обращаясь к CONVERT.
Адрес, оставленный в вершине стека при первом применении CONVERT передавался бы аргументом второму CONVERT и т. д.
В большинстве систем имеется слово NUMBER (число), которое выполняет те же функции, но зачастую проще в употреблении. В Стандарте-83 (слова несогласованного набора) это слово определено следующим образом:
NUMBER |
( a -- d) |
Преобразование текста, начинающегося с адреса а+1, в двоичное значение с учетом текущей системы счисления (значения BASE). Строка может предваряться знаком минус, что делает полученное значение отрицательным. |
Слово NUMBER используется и самой ФОРТ-системой. Это «обработчик чисел», к которому обращается текстовый интерпретатор, если искомое слово не найдено в словаре. NUMBER пытается преобразовать полученный фрагмент в число и в случае удачи заносит его значение в стек, при неудаче же осуществляется ABORT.
В каждой Форт-системе процесс преобразования чисел происходит по-своему, так как способов их введения существует очень много. Ниже будет показано одно из возможных определений слова NUMBER, которое воспринимает символы : , - . /
как правильные пунктуационные знаки, указывающие, что данный фрагмент нужно считать числом двойной длины. Если внутри какого-либо числа появился один из перечисленных символов, то в переменную DPL (положение десятичной точки) заносится количество цифр в числе справа от точки. Например, при вводе фрагмента 200.2 DPL содержит единицу. Если в числе нет знаков пунктуации, то значение DPL окажется равным -1.\ Определение слова NUMBER : NUMBER? ( адр - d t-успешное-завершение) DUP 1+ С@ Получение первой цифры ASCII - = Это знак минус? DUP >R Запоминать флага в стеке возвратов - Если первым символом является "-" , то к адр добавляется 1, чтобы тот указывал на первую цифру ( вычитание -1 равносильно прибавлению 1) -1 DPL ! Отметка того, что знаков пунктуации пока нет. 0 0 ROT В качества первоначального накапливаемого значения берется 0 двойной длины.
BEGIN CONVERT Преобразование до первого символа, не являющегося цифрой DUP C@ DUP ASCII : = SWAP ASCII . ASCII / 1+ Это запятая, дефис, точка или слэш? WITHIN OR WHILE 0 DPL ! REPEATE Если да, то переустановить DPL и продолжать -ROT R> IF DNEGATE THEN Перемещение d в вершину. Если значение в стеке возвратов указывает минус, то число делается отрицательным. ROT С@ BL = ; Является ли последний, непреобраэованный, символ пробелом, как это и должно быть?
: NUMBER ( адр -- d) NUMBER? NOT ABORT" ?" ; Если преобразование завершилось неудачей, то аварийный выход посредством ABORT.
В приведенном определении учитывается, что CONVERT вычитает из DPL по единице при обработке каждой цифры до тех пор, пока значение переменной не станет равным -1. Кроме того, в определении используется слово WITHIN, аналогичное слову ВНУТРИ (см. упражнение к гл. 4).
В качестве «истины» принято арифметическое значение -1, как это определено Стандартом-83. Для более ранних систем, где значением истины является единица, в строке 4 нужно заменить «-» на «+».
В Форте число, вводимое без знаков пунктуации, заносится в стек как число одинарной длины. При рассмотренном здесь определении слова NUMBER текстовый интерпретатор должен обращаться к нему примерно так: ... NUMBER DPL @ -1 = IF DROP THEN ...