Радио-86РК/Радио 07,08,10-95/Язык ФОРТ

Материал из Emuverse
Данный материал защищён авторскими правами!

Использование материала заявлено как добросовестное, исключительно для образовательных некоммерческих целей.

Автор: Н. ШИХОВ

Источник: http://retro.h1.ru/RK86/Fort_RK/Fort_RK.php

ФОРТ — один из самых молодых языков программирования, однако благодаря таким своим достоинствам как быстрота освоения (простейшие приемы программирования на нем можно освоить буквально за несколько минут) и высокая производительность, он уже приобрел во всем мире необычайную популярность. Сегодня мы предлагаем читателям версию этого языка для радиолюбительского компьютера «Радио-86РК».

«УМИРАЮТ» ЛИ ВОСЬМИРАЗРЯДНЫЕ МИКРОПРОЦЕССОРЫ

По миру победно шествуют мощные микропроцессоры I80486, MC68030 MICRO VAX, на смену им идут PENTIUM, МС680ХХ и новый сверхмощный 64 разрядный Альфа чип фирмы DEC. Сегодня можно приобрести почти все, что только пожелаешь. Иногда кажется, что для простеньких восьмиразрядных компьютеров уже не осталось места под солнцем.

Однако это не так. В микропроцессорной технике есть место и для «слона» PENTIUM и для «муравья» I8085 и как это часто бывает, эффективность применения ЭВМ зависит не столько от мощности и совершенства микропроцессора, столько от скорости и стоимости ее внедрения в производство.

По последним двум показателям восьмиразрядные «персоналки» не имеют конкурентов. Они не только не «вымирают», а даже продолжают совершенствоваться. Например, микропроцессор К580ВМ1 программно и аппаратно совместимый с К580ВМ80 обладает в 2,5 раза более высокой производительностью и расширенной системой команд, в которую входят четырех и пятибайтные команды.

Восьмиразрядные микропроцессоры прочно обосновались в микроконтроллерах, управляющих несложными технологическими процессами в измерительной технике. Мощности восьмиразрядных ЭВМ с лихвой хватает для любых бытовых целей — от управления теплицей или инкубатором, до автоматического определения номера звонящего абонента. На любительской радиостанции компьютер выполнит любую рутинную работу — от ведения журнала до автоматического управления любым «железом» и даже если нужно проведет радиосвязь без участия оператора.

Во всем этом есть, однако одна, хорошо известная тонкость, компьютер выполняет лишь то, что заложено в него программой. А вот оснащенность программным обеспечением его качество и сервисные характеристики у восьмиразрядных машин неизмеримо ниже. Особенно сказывается дефицит простых быстродействующих компактных трансляторов основных языков программирования. Об этом и пойдет речь далее.

Автор имеет опыт программирования на языках БЕЙСИК, ПАСКАЛЬ, ФОРТ и АССЕМБЛЕР для восьми и шестнадцатиразрядных процессоров. Из экономии времени и места не будем сравнивать эти языки (тот, кто с ними работал хорошо знает их достоинства и недостатки) а сразу выделим один из них. Он доводит мощность восьмиразрядных ПЭВМ до уровня шестнадцатиразрядных, позволяет выжать из машины все, на что она способна; обеспечивает доступ не только к любому байту, но и биту, находящемуся в любой ячейке памяти или регистре ЭВМ; занимает в памяти наименьший объем и в то же время обеспечивает наиболее быструю компиляцию программы в коды процессора за один проход текста программы; программирование на нем в 5 раз быстрее, чем на БЕЙСИКе, в 15 раз быстрее, чем на ПАСКАЛе и в 50 раз быстрее, чем на АССЕМБЛЕРе.

ЭТОТ ЯЗЫК — ФОРТ

ФОРТ — один из самых молодых языков программирования, однако благодаря быстроте освоения и высокой производительности программирования он уже приобрел во всем мире необычайную популярность среди ценителей красоты в этом сложном, но увлекательном искусстве. В России и за ее пределами имеется немало версии языка, но публикаций на эту тему мало.

Простейшие приемы программирования на ФОРТе можно освоить буквально за несколько минут. В отличие, например, от АССЕМБЛЕРа программирование на ФОРТе напоминает скорее игру, нежели кропотливый труд алхимика, хотя в результате можно получить программу не уступающую АССЕМБЛЕРНОЙ.

Особенностями языка ФОРТ являются обратная польская (постфиксная) запись арифметических и логических операций, а также широкое использование стеков, привычное для многочисленных владельцев программируемых калькуляторов. Но главная особенность ФОРТа в том, что его каждый пишет сам для себя, а минимальный словарь резидентной части нужно рассматривать лишь как начальный капитал, дающий большой процент годовых, причем ФОРТ как губка впитывает и усваивает лексикон и характер своего хозяина, приближаясь к обычному разговорному языку.

Предлагаемая читателям версия языка ФОРТ не единственная, адаптированная для «Радио 86РК». У автора имеется версия ФОРТ системы разработанная в НИИСЧЕТМАШ ЛГУ. Она выполнена в строгом соответствии со стандартом FORTH 83, имеет объем 14 Кбайт и словарь примерно из 500 слов. По мнению автора, владельцами «Радио 86РК» эта программа использоваться на практике не может. Ее словарь перегружен промежуточными словами, не используемыми в прикладных программах, есть слова с одинаковыми функциями. Достоинствами этой версии являются, ее соответствие стандарту, и наличие встроенного ФОРТ АССЕМБЛЕРа. Стандартный строчный редактор ничего кроме сожаления не вызывает.

Дамп предлагаемой версии языка ФОРТ для компьютера «Радио 86РК» приведен в табл. 1, блочные контрольные суммы — в табл. 2. Версия работает с удобным и привычным редактором "МИКРОН ". Отсутствие ФОРТ АССЕМБЛЕРа, компенсируется возможностью вставлять в программу машинные коды или использовать АССЕМБЛЕР из пакета «МИКРОН».

Таблица 2.

0800 - 08FF 0826
0900 - 09FF A241
0A00 - 0AFF 56F6
0B00 - 0BFF F14C
0C00 - 0CFF 4EDA
0D00 - 0DFF CF28
0E00 - 0EFF 4824
0F00 - 0FFF F954

Словарь включает в себя наиболее употребительные слова из распространенных версий ФОРТа, и позволяет писать программы обработки текстов, строк символов, битов байтов и шестнадцатиразрядных слов по алгоритмам любой степени сложности. Он наиболее приспособлен для разработки управляющих игровых и системных программ. Некоторые слова работают несколько иначе, чем в стандартных версиях.

Внутренняя структура словаря нестандартна, но именно благодаря такой структуре удалось достичь компактности и высокого быстродействия предлагаемой реализации, а также простоты генерации расширения системы модулями, написанными на АССЕМБЛЕРе.

Программирование на ФОРТе можно изучить по литературе [1—3]. После этого рекомендуется разобраться в прилагаемой демонстрационной программе (табл. 3) и тут же провести первые пусть не всегда удачные, но поучительные эксперименты. Далее будем предполагать, что читателю уже известны «азы» программирования на ФОРТе.

					Tаблица 3.
HEX
: IMMEDIAT ' I - DUP CR 40 OR SWAP C! ;
: [COMPILE] CD C, ' , ; IMMEDIAT [COMPILE] 
: (" HERE " ; IMMEDIAT ("
: ) HERE ALLOT ; IMMEDIAT )
: ") DUP TYPE DROP [COMPILE] ) ; IMMEDIAT ")
: .. SPACE SPACE SPACE SPACE ; ("ПЕЧАТЬ ЧЕТЫРЕХ ПРОБЕЛОВ")
..    (" ИДЕТ КОМПИЛЯЦИЯ ДЕМОНСТРАЦИОННОЙ ПРОГРАММЫ")
: WHILE [COMPILE] IF ; IMMEDIAT WHILE
: UNTIL [COMPILE] IF
[COMPILE] ELSE [COMPILE] REPEAT ;  IMMEDIAT UNTIL
: DUMP CR
BEGIN DUP DUP
[ 78 C, CD C, F815 , (" так можно вставить кусок прямо в кодах ассемблера, это соответствует
MOV A,B 
CALL 0F815H
Или в кодах 78 CD 15 F8 ") ] DROP
[ 79 C, CD C,  F815 , ] DROP
SPACE SPACE (" ПЕЧАТЬ ДВУХ ПРОБЕЛОВ ")
DUP DUP E + SWAP 2
(" СЕЙЧАС В СТЕКЕ   КОНЕЧНОЕ И НАЧАЛЬНОЕ ЗНАЧЕНИЯ ПАРАМТРА ЦИКЛА СО СЧЕТЧИКОМ, А  НА ВЕРШИНЕ - ШАГ ПРИРАШЕНИЯ ПАРАМЕТРА ")
+DO (" ЭТО КАЧАЛО ЦИКЛА СО СЧЕТЧИКОМ ") 
I (" А ЭТО ПАРАМЕТР ЦИКЛА ")
@ [ 79 С, СD С,  F815 , 78 С, СD С, F815 , ] DROP SPACE
REPEAT (" эта конец цикла, ЕСЛИ ДОСТИГНУТО РАВЕНСТВО НАЧАЛЬНОГО И КОНЕЧНОГО ЗНАЧЕНИИ ") SPACE
DUP DUP F + SWAP 1
+DO I C@ DUP 20 < OVER 7F > OR IF
DROP 5F (" ПЕЧАТЬ ПРОЧЕРКА (5F) ВМЕСТО СИМВОЛА С КОДОМ МЕНЬШЕ 20H или БОЛЬШЕ 7FH ")
THEN EXIT
REPEAT CR
10 + OVER OVER > IF
REPEAT DROP DROP ;
СR .. (" ТАК РАБОТАЕТ DUMP РАСПЕЧАТКА ОТ АДРЕСА 1100 ДО КОНЦА КОДОФАЙЛА, Т. Е. ДО HERE "") HERE 1100 DUMP
CR .. (" КОМПИЛЯЦИЯ ЗАМЕДЛЕНА ИЗ-ЗА МНОЖЕСТВА КОММЕНТАРИЕВ, КОТОРЫЕ ТОЖЕ КОМПИЛИРУЮТСЯ, А ЗАТЕМ УНИЧТОЖАЮТСЯ "")
CR .. (" УБЕРИТЕ ВСЕ КОМЕНТАРИИ, ОГРАНИЧЕННЫЕ СКОБКАМИ И ПРОГРАММА СТАНЕТ ПРОСТОЙ И ПОНЯТНОЙ "") CR
: 1+ 03 С, ; IMMEDIAT 1+ (" КОМПИЛИРУЕТ INX BC ")
: 2+ 0303 ,  ; IMMEDIAT 2+ (" ТАК КАК ПАРА BC ЭТО ВЕРШИНА СТЕКА ")
: 1- 08   С, ; IMMEDIAT 1- (" КОМПИЛИРУЕТ DCX BC ")
: 2- 08008 , ; IMMEDIAT 2-
: R0 1040 ; CR . . R0 . (" ЭТО СТЕК ВОЗВРАТ0В, ИМЕННО ЭТО ЗНАЧЕНИЕ ЗАПИСЫВАЕТСЯ В SP в СЛОВАХ COLD и QUIT "")
: $0 R0 3E + ; СR CR . . $0 . (" .., А ЭТО УКАЗАТЕЛЬ АРИФМЕТИЧЕСКОГО СТЕКА, ЗАПИСЫВАЕТСЯ В ПАРУ HL УСТАНАВЛИВАЕТСЯ ТОЛЬКО СЛОВОМ COLD "")
: ТI$ $0 2+ ; CR CR . . (" AДРЕС НАЧАЛА КОМАНДНОЙ СТРОКИ "") TI$ . СR
: (KEY) R0 1+ ; СR ..  (КЕТ) @ . (" МАШИННО ЗАВИСИМЫЙ АДРЕС ПОДПРОГРАММЫ ВВОДА  = F803 "") CR
: (ENIT) R0 2+ 2+ ; CR .. (ENIT] @ . (" МАШИННО ЗАВИСИМЫЙ АДРЕС ПОДПРОГРАММ ВЫВОДА F809 "") CR
: (LAGT)  (ENIT) 2+ ; CR CR .. (" АДРЕС НАЧАЛА ПОСЛЕДНЕГО СЛОВА В СЛОВАРЕ НАХОДИТСЯ В ЯЧЕЙКЕ "") (LAST) .
: (H) (LAST) 2+ ; CR CR ..  (" АДРЕС ПЕРВОЙ СВОБОДНОЙ ЯЧЕЙКИ, Т. I. KOHЦA  КОДОФАЙЛА НАХОДИТСЯ В ЯЧЕЙКЕ "") (Н) .
CR ..  (" (H) @ АНАЛОГИЧНО НERE "")
: (ВАSE) (H) 2+ ; CR CR ..   (" БАЙТ С АДРЕСОМ (ВАSE) ХРАНИТ ОCHOBAНИЕ СИСТЕМЫ СЧИЛЕНИЯ "") 
.. (" ПРИМЕР : 55 2 (BASE) C! . ") 55 2 {BASE) С! .
HEX (" -ШЕСТНАДЦАТИРИЧНАЯ СИСТЕМА, A DECIMAL ДЕСЯТИЧНАЯ ")
: BINARY 2 (BASE) C!  ; (" BIMARY УСТАНОВИТ ДВОИЧНУЮ СИСТЕМУ СЧИСЛЕНИЙ ")
: OCTAL 2 (BASE) C! ; (" OCTAL УСТАНОВИТ ВОСЬМИРИЧНУЮ СИСТЕМУ СЧИСЛЕНИЯ ")
: (?STAT) (ВАSE) 1+ ; СR CR .. (" В БАЙTE С АДРЕСОМ (?STAT) ПРИЗНАК РЕЖИМА 00 - ЗНАЧИТ ИНТЕРПРЕТАЦИЯ FF ЗНАЧИТ КОМПИЛЯЦИЯ ""}
: (IN) (BASE) 2+ ; (* В  ЯЧЕИКЕ (IN) АДРЕС ОБРАБАТЫВАЕМОГО В ДАННЫЙ МОМЕНТ СИМВОЛА ПРОГРАММЫ ")
: (OUT) (IN) 2+ ; (" В ЯЧЕЙКЕ (OUT) АДРЕС, В КОТОРЫЙ БУДЕТ ЗАПИСАН СЛЕДУЮЩИЙ ВВЕДЕННЫЙ С УСТРОЙСТВА ВВОДА СИМВОЛ Т. Е С КЛАВИАТУРЫ,  ЕСЛИ В (KEY) АДРЕС F803 ")
: EDIT (" слово : КОМПИЛИРУЕТ ЗАГОЛОВОК СЛОВА EDIT ")
0 (" КЛАДЕМ В СТЕК 0 ")
EXECUT (" ИСПОЛНИТЬ ПРОГРАММУ ПО АДРЕСУ, ЛЕЖАЩЕМУ В СТЕКЕ ")
; (" ; КОМПИЛИРУЕТ КОМАНДУ RET И УСТАНАВЛИВАЕТ РЕЖИМ ИHTЕPПPETAЦИИ ")
: ?TERM DUP [ СD С, F812 , 4F47 , ] ; (" ТАК МОЖНО ОБРАТИТСЯ к МОНИТОРУ по АДРЕСУ F812 ")
: ?КЕY 0 [ CD С,  F81B , 4F С,  ]  ; ("    ., А ТАК ПО АДРЕСУ F81B ")
: CMOVE 1  1 +DO OVER C@ OVER C!  1+ SWAP 1+ SWAP REPEAT DROP DROP ;
(" CMOVE И CMOVE> ЭTO СТАНДАРТНЫЕ СЛОВА ЯЗЫКА ФОPT ")
: CMOVE> ROT OVER + -ROT DUP ROT + SWAP
1 1 +DO 1- SWAP 1- SWAP OVER C@ OVER C!
REPEAT DROP DROP ;
: PRINT 1 1 +DO DUP C@ ENIT 1+ REPEAT DROP ; 
CR СR (IN) @
DECIMAL 1048 PRIHT (" РАСПЕЧАТАТЬ 1048 ВАЙТ ИЗ ВХОДНОГО ВУФЕРА ")
CREAT BUFF
HEX 40 ALLOT (" ТАК СОЗДАЮСЯ МАССИВЫ РАЗМЕРОМ 64 БАЙТА ")
: INPUT CR . " # ЖДУ? " (" СЛОВО INPUT ВВОДИТ ЧИСЛО ИЛИ СЛОВО БЕЗ ВЫХОДА В CUIT ")
(" ИСПОЛЬЗУЯ СВОЙ БУФЕР РАЗМЕРОМ В 64 БАЙТА ")
BUFF QUERY (IN) @ [ C5 С, ] DROP
BUFF INTERPRET DUP  [ C1 С, ]  (IN)  !  ;
(" ДОПУСТИМ У НАС ОТДЕЛЬНЫЙ ТЕРМИНАЛ, С КОТОРЫМ ЕСТЬ СВЯЗЬ ЧЕРЕЗ 580ВВ55 КАНАЛ А В PEЖИМЕ 2 ")
: PPAINI  -1 A003 C! 0D A00З C! 9 А00З C! AOOO C@ DROP ;
PPAINI  (" ИНИЦИАЛИЗАЦИЯ ПОРТА ")
:  INT7 BEGIN A002 C@ 8 AND IF ELSE REPEAT ; (" ОЖИДАНИЕ БИТА ПРЕРЫВАНИЯ ")
TRMO INT7 BEGIN A002 C@ 80 AND IF A000 C! ELSE REPEAT ; ("  ПОДПРОГРАММА ВЫВОДА БАЙТА В КАНАЛ А ")
: TRMI INT7 BEGIN A002 C@ 20 AND IF AOOO C@ 7F AND ELSE REPEAT ; (" ПОДПРОГРАММА ВВОДА БАЙТА из КАНАЛА А ")
(" СЕЙЧАС ДОСТАТОЧНО ЗАПИСАТЬ АДРЕСА ПОДПРОГРАММ TRMI В (КЕY), A TRMO В (ENIT)
НАПРИМЕР, ТАК ' ТRMI (KEY) | '  TRMO (ENIT)  | И ВАША МАШИНА БУДЕТ РАБОТАТЬ БЕЗ МОНИТОРА ДИСПЛЕЯ И КЛАВИАТУРЫ ")
: КОNST1  12 ;      ("ТАК ООЗДАЮТСЯ КОНСТАНТЫ ")
CREAT VAR1 13 ,  (" А ТАК - ПЕРЕМЕННЫЕ ")
CREAT VAR$ " ABRACADABRA" (" А ТАК МACCИВЫ ЗАПОЛНЕНЫЕ ЛИТЕРАМИ ")
СREAT АRR1 1 , 2 , 3 , (" А TАК МАССИВ ИЗ ТРЕЗХ СЛОВ ")
CREAT ARR2 4 С, 5 C, 6 С, (" ТАК МАССИВ ИЗ ТРЕХ БАЙТ ")
(" ИМЯ МАССИВА ИЛИ ПЕРЕМЕННОЙ ВОЗВРАЩАЕТ в Арифметическом СТЕКЕ ЕГО AДPEC ")
: := ' 2+ 2+ ! ;
(" это слово может изменить ЗНАЧЕНИЕ КОНСТАНТЫ В РЕЖИМЕ ИНТЕРПРЕТАЦИИ прамер ") 18 := KONST1 
: TO DUP 
[C1 C, 3 C, 3 C, 3 C, C5 C, B C, B C, ] @
[ 3 С, 3 С, 3 С, 3 С   ]  ! ;
(" А ЭТО СЛОВО МОЖЕТ ИЗМЕНИТЬ ЗНАЧЕНИЕ КОНСТАНТЫ, ЕСЛИ ЕГО СКОМПИЛИРОВАТЬ ВНУТРИ ДРУГОГО СЛОВА, НАПРИМЕР: ") 
: PRIMER1 19 TO KONST1 ; 
(" СЛОВО РRIMER1 ЗАПИШЕТ 19 В КОNST1 ")
: PICK DUP [ C1E5 , ] OVER + SWAP + 2+ @ ;
(" PICK СНИМАЕТ ИЗ СТЕКА НОМЕР ЭЛЕМЕНТА СТЕКА И КЛАДЕТ В СТЕК КОПИЮ ЭТОГО ЭЛЕМЕНТА ")
("  НИЖЕ ОПИСАНЫ НЕКОТОРЫЕ КОМАНДЫ АССЕМБЛРА, КОТОРЫЕ МОЖНО ПРИМЕНЯТЬ ВНУТРИ ОПИСАНИЙ ДРУГИХ СЛОВ ВMЕTO КОДОВ, ЭТОТ СПИСОК МОЖНО УВЕЛИЧИТЬ   ОН ЗАМЕНИТ ФОPT-АССЕМБЛЕР КОГДА НЕОБХОДИМО НАПИСАТЬ ПРОГРАММУ МАКСИМАЛЬНОГО БЫСТРОДЕЙСТВИЯ ")  
: OUT 79 С, D3 С, NUMBER С, ;  IMMEDIAT OUT (" полезное слово если необходимо вывести БАЙТ в ПОРТ НАХОДЯЩИЙСЯ В ПРОСТРАНСТВЕ ВВОДА/ВЫВОДА ")
: IN DB C NUMBER с, 4F с, ; IMMEDIAT IN (" IN и OUT можно приенять только ВНУТРИ ДРУГИХ слов как и все СЛОВА С ПРИЗНАКОИ IMMEDIAT ")
(" ПРИМЕР: ")
: OUIA0 OUT А0 ;  (" ВЫВОД В ПОРТ А0 СТЕК БЕЗ ИЗМЕНЕНИЙ ")
: INА0   IN   А0 ; (" ВВОД ИЗ ПОРТА А0 В МЛАДШИЙ БАЙТ ЧИСЛА, ЛЕЖАЩЕГО В APИФМЕТИЧЕСКОМ СТЕКЕ ")
: A,# 3E С , NUMBER С,  ;  (" A,#11 КОМПИЛИРУЕТ MVI А,11  ") IMMEDIAT A,#
: А,0 AF C , ;  (" КОМПИЛИРУЕТ ХRA A ОЧИСТКА АККУМУЛЯТОРА  ") IMMEDIAT A,0
: A,C 79 C , ; (" КОМПИЛИРУЕТ MOV A,C ") IMMEDIAT А,С
; С,А 4F C , ; (" КОМПИЛИРУЕТ MOV С,А ") IMMEDIAT С,А
: A,B 78 C , ; IMMEDIAT   A,B
WORDS HERE LAST) & DUMP       
CR .. (" A,B СООТВЕТСТВУЕТ ТЕКСТУ НА АССЕМБЛЕРЕ ")
CR       
CR .. (" DW @AB "")
CR .. (" DW 'А,В' ,83H+40H; 40H = IMMEDIAT "")
CR .. (" CALL 0882H, DUP "")	
СR .. (" LXI B,78H ; Замена кода в вершине стека на 78H "")
СR .. (" CALL ODO9H  ; C, "")
CR .. (" RET "") 
CR .. (" @AB: "")
CR .. (" и компилирует КОМАНДУ MOV А,В или 78H "")
QUIT


ОСОБЕННОСТИ ПРЕДЛАГАЕМОЙ ВЕРСИИ

Большинство слов резидентной части словаря от COLD до (точки) работают, так же как и в стандартном FORTH 83, поэтому есть смысл описать только отличия от этого стандарта.

Итак, несколько иначе работают:

'
TYPE
QUERY
INTERPRET
″ 
Отсутствуют слова DO LOOP и +LOOP.

Слово ' (апостроф) в отличии от стандартного в FORT-83 не является словом немедленного исполнения, но если это необходимо, его можно сделать таким командой IMMEDIAT.

Слово ' возвращает значение адреса исполняемой части слова (поля кода, CFA), стоящего после него, или −1, если слово не найдено. Коренное же отличие работы этого слова в том, что оно производит поиск слов в словаре от начала к концу, что связано с особенностями реализации, которая, прежде всего, оптимизирована по быстродействию. Повторное описание слов с уже имеющимся именем бессмысленно, так как это слово никогда не будет найдено, пока не будет переименовано более раннее определение.

Слово TYPE берет из стека адрес строки, имеющей в конце либо нулевой байт, либо байт с кодом более 7FH, распечатывает эту строку и возвращает адрес байта ограничителя, стоящего в конце строки. Таким образом, это слово может распечатывать текст, порожденный не только в системе ФОРТ, но и другими компиляторами.

Слово QUERY берет из стека адрес буфера, и заносит в него символы с устройства, ввода пока не будет введен код <ВК>или CTRL+C. Так как это слово берет адрес буфера из стека то входной буфер можно расположить в любом месте ОЗУ. QUERY — это встроенный редактор системы ФОРТ. Весь порожденный этим словом текст является одной большой строкой, в которой допускаются любые печатные символы, в том числе <ПС>. Редактирование внутри QUERY возможно с использованием клавиш курсора <— и —>.

Слово INTERPRET берет из стека адрес буфера и интерпретирует текст из этого буфера, пока не встретит слово QUIT или два нулевых байта, которые заносятся QUERY при вводе кода <ВК>. Так как адрес текста берется из стека то можно интерпретировать программу, расположенную в любом месте ОЗУ или ПЗУ.

Слово " (кавычки) берет из входного буфера символы расположенные после него и компилирует их на вершину кодофайла, (для начинающих мы несколько позднее дадим определение этого понятия) пока снова не встретит символ ". На этом символе компиляция заканчивается, а на вершину кодофайла компилируется байт-ограничитель, имеющий код более 7FH в младших семи битах которого хранится информация о длине строки. Символ " в конце строки не компилируется, а используется в качестве разделителя, то есть очередное слово может быть записано после него без обязательного пробела, разделяющего слова в тексте программы.

И, наконец, слова DO LOOP и +LOOP. Они просто не нужны, так как в предлагаемой версии имеется только одна универсальная форма организации цикла со счетчиком:

: 
XX <ОПЕРАТОРЫ> КККК NNNN ММММ +DO <ОПЕРАТОРЫ ЦИКЛА> REPEAT <ОПЕРАТОРЫ>,

где КККК — конечное значение параметра цикла 
NNNN — его начальное значение, 
ММММ — приращение параметра цикла (шаг цикла). 

Шаг может быть как положительным, так и отрицательным. Цикл выполняется последний раз, когда параметр цикла достигает конечного значения.

Если в программе имеются вложенные циклы со счетчиком, то доступ к параметру внутреннего цикла обеспечивает слово I, а к параметру внешнего цикла слово J

Все остальные слова выполняют абсолютно те же функции, что и в стандартном FORTH 83, и подробно описаны в [1]. Это короткое, но полное описание языка ФОРТ и первые 18 с полностью относятся и к предлагаемой реализации.

НЕСКОЛЬКО СЛОВ О ЦИКЛАХ С УСЛОВИЕМ

Вместо: BEGIN <УСЛОВИЕ> WHILE <ОПЕРАТОРЫ ЦИКЛА> REPEAT
Рекомендую: BEGIN <УСЛОВИЕ> IF <ОПЕРАТОРЫ ЦИКЛА> REPEAT
Вместо: BEGIN <УСЛОВИЕ> UNTEL
Рекомендую: BEGIN <УСЛОВИЕ> IF ELSE REPEAT 

НЕМНОГО О НАЧАЛЬНОЙ СТАДИИ РАБОТЫ ПРОГРАММЫ

Первое, что делает ФОРТ — заполняет некоторые ячейки ОЗУ константами, 10 байт — с адреса 806Н по 80FH — в том же порядке переносятся в ОЗУ, начиная с адреса 1040H: первые 3 байта — это команда JMP 0F803H на подпрограмму ввода символа с клавиатуры, следующие 3 байта — команда JMP 0F809H на подпрограмму вывода символа на экран, еще 2 байта — адрес поля связи последнего слова в словаре (фактически это адрес первого байта последнего слова в словаре). И, наконец, последние 2 байта — адрес первой свободной ячейки кодофайла. Этот же адрес записывается и в поле связи последнего слова в словаре (обычно он указывает на байт, следующий за последним байтом последнего слова в словаре). Если возникнет необходимость расширить ФОРТ систему словами, написанными на АССЕМБЛЕРе, эти два адреса необходимо будет скорректировать.

Затем инициируются стек возвратов (занесением в регистровую пару SP адреса 1040H) и стек параметров (занесением в пару НL адреса 103ЕН) автоматически компилируется содержимое текстового буфера, начиная с адреса 2100Н. Если стартовый файл находится по другому адресу, то его следует занести в ячейки с адресами 841Н и 842Н.

Стартовый файл должен содержать хотя бы одно слово QUIT <ПРОБЕЛ> или два нулевых байта (см. демонстрационную программу в табл. 3).

Для выхода в МОНИТОР достаточно нажать клавишу <F4> или ввести команду F86C EXECUT. Клавишу <F4> можно перепрограммировать, записав по адресам А59Н и А5АН другое значение адреса перехода.

СОВЕТЫ ПО ПРОГРАММИРОВАНИЮ. РАБОТА С ЯЗЫКОМ В РЕЖИМЕ ИНТЕРПРЕТАЦИИ

Язык ФОРТ может работать без текстового редактора, однако гораздо удобнее его использовать с одним из текстовых редакторов, например, из пакета «МИКРОН». При этом отпадает проблема сохранения текстов программ. Еще лучше если обе эти программы «зашиты» в ROM-диск и загружаются одновременно. В статье описывается работа с версией адаптированной для персонального компьютера «Радио-86РК».

Предположим, что читатель уже ввел коды интерпретатора и редактора «МИКРОН» в свой компьютер и запустил редактор командой G0. Теперь следует проверить работоспособность системы. В редакторе необходимо набрать строку:

: EDIT 0 EXECUT, WORDS QUIT.

и нажатием клавиши <СТР> выйти в ФОРТ, аналогично выходу в АССЕМБЛЕР. На экране дисплея появится список доступных в данный момент слов (их можно называть командами или операторами в зависимости от вкуса) и символ >, приглашающий к вводу этих слов. Последним в словаре будет слово EDIT. Набрав его и нажав затем клавишу <ВК>, вы снова перейдете в текстовый редактор «МИКРОН». Если все получилось, как описано, вас можно поздравить с первым успехом, вы написали первую программу на языке ФОРТ. Дело в том, что в словаре не было слова EDIT, и вы только что описали его, используя слово EXECUT.

В языке ФОРТ всего три основных правила:

  • использовать только известные системе слова,
  • строго следить за состоянием стеков,
  • соблюдать парность парных слов

Изучение ФОРТА лучше всего построить на экспериментальной проверке работы всех слов базового словаря. Кроме них в языке имеются еще и числа, которые не должны выходить за пределы шестнадцати двоичных разрядов, причем старший разряд является знаковым.

Пожалуй, первое, что должен сделать программист — это установить систему счисления, для чисел, вводимых с клавиатуры и выводимых на дисплей. Командой ", " устанавливают шестнадцатиричную систему счисления (при «холодном» запуске эта система устанавливается автоматически), командой — привычную для всех десятичную систему. С этой команды и можно начать. Надо сказать, что числа и команды можно вводить как по одному, нажимая после ввода каждого клавишу <ВК>, таки группами. Буфер ввода с клавиатуры вмещает до 128 символов. Введенные символы можно редактировать перемещением курсора и перепечаткой символов, введенных с ошибкой между всеми вводимыми словами и числами должно быть не менее одного пробела. После нажатия клавиши <ВК>, все числа помещаются в стек, а все слова немедленно исполняются, причем большинство слов работает с арифметическим стеком, являющимся универсальным средством передачи, как числовых, так и логических операндов. Арифметическим стеком или стеком параметров в данной версии ФОРТа называется совокупность памяти и регистров процессора, обеспечивающая хранение двухбайтных чисел и безадресный доступ к верхнему элементу стека.

Кроме арифметического, в фОРТ-системах имеется еще и стек возвратов, но о нем разговор особый.

Логические операнды могут принимать значение либо, либо TRUE. Логическое значение (ложь) — шестнадцатиразрядное число, в котором все разряды равны нулю (то есть 0), TRUE (истина) — любое шестнадцатиразрядное число, не равное 0.

Для распечатки (в текущей системе счисления) числа, лежащего на вершине стека, имеется слово . (точка).

Например:
1 2 3 . . . <ВК>
распечатает 
3 2 1
1 2 3 . . 4 . <ВК>
распечатает: 
3 2 4 

Первое число лежит на самом дне стека, и мы его еще не сняли. Взять число из стека может слово line'DROP или . (точка), то есть При наборе:

. <ВК>
распечатается: 1
Если же еще раз внести
. <ВК>
распечатается:
СТЕК ПУСТ 

Это же сообщение мы получим при работе некорректно написанной программы, пытающейся извлечь число из пустого стека, кроме того, в этом случае произойдет аварийное прекращение работы программы, и выход в . Еще, более худшие результаты получим если будем помещать числа в стек и не будем их снимать стек «наедет» на рабочие ячейки интерпретатора и мы не получим никаких сообщений, а просто разрушим ФОРТ систему.

Следовательно, при программировании на ФОРТе, пользователь должен строго следить за всеми изменениями, происходящими на стеках (их два, но о втором — стеке возвратов — мы пока не говорим). Для надежной работы интерпретатора не следует помещать в стек более шестнадцати чисел к тому же большие объемы чисел и символов лучше хранить в виде массивов, а стек оставить только для сверхоперативных переменных, число которых обычно не превышает трех.

Для трех верхних элементов стека в словаре имеется несколько слов обеспечивающих быстрый доступ к любому из ЭТИХ чисел. Для уяснения их работы проведем несколько экспериментов.

Наберем:
1 2 DUP  . . . <ВК>
получим:
2 2 1
Слово DUP положило в стек копию верхнего элемента.
Наберем:
1 2 3 DROP  . . <BK>
получим:
2 1
Слово DROP уничтожило (безвозвратно) верхний элемент стека.
Наберем:
1 2 3 SWAP  . . .<BK>
получим:
2 3 1

Слово SWAP поменяло местами два верхних элемента стека.

Таблица 4.

Имя Состояние стека Коментарии
DUP N1 > N1 N1 Дублирует верхний элемент стека
DROP N1 > - Снимает верхний элемент стека
SWAP N1 N2 > N2 N1 Меняет местами два верхний элемента
ROT N1 N2 N3 > N2 N3 N1 Поднимает третий элемент стека (N3) на его вершину
-ROT N1 N2 N3 > N3 N1 N2 Кладет верхний элемент под два элемента, лежащих под ним
OVER N1 N2 > N1 N2 N1 Кладет на вершину стека второй элемент

Коротко, это можно описать в виде таблицы, в левой части которой находится само слово, а в правой — вначале состояние стека до введения этого слова, а затем (после разделителя в виде стрелки) — его состояние после того, как это слово введено. Пустой стек можно обозначить прочерком. В крайней правой колонке удобно поместить комментарии. Составим такую таблицу для слов, оперирующих верхними элементами стека (табл. 4). Попробуйте, используя эти слова и уже известное слово (точка), убедиться в верности комментариев приведенных в правой части таблицы. Если простые операции с элементами стека уже наскучили, то можно перейти к более сложным экспериментам в области целочисленной арифметики (табл.8). Последнее слово в этой таблице кроме действий указанных в комментарии проверяет частное от деления на переполнение и если оно имеет более шестнадцати двоичных разрядов, то происходит аварийное прерывание программы и выход в QUIT. Результат умножения может быть и 32 разрядным.

Убедиться в правильности комментариев можно, так же как и в предыдущем случае, вводом чисел и слов из табл. 5, проверяя полученные результаты словом (точка). Для усложнения опытов можно вводить по несколько операторов сразу.

Таблица 5.

Имя Состояние стека Коментарии
= 1 2 > 3 Снимает со стека два верхних слагаемых и кладет в стек их сумму
- 4 5 > −1 Снимает со стека вычитаемое и уменьшаемое и кладет в стек их разность
NEGATE 8 > −8 Меняет знак числа на вершине стека
2* 3 > 6 Умножает число на 2
2/ 8 > 4 Делит число на 2 без остатка
*/WCO 7 3 5 > 4 1 Умножает третий элемент (7) на второй (3) и делит с остатком на первый, оставляя в вершине стека остаток от деления и под ним частное от деления
Например:
1 2 3 4 5 + + SWAP - . .>
получим:
10 1 

Когда почувствуете что с арифметикой у вас все в порядке и обратная польская бесскобочная запись арифметических действии (когда сначала пишутся операнды, а затем операторы выполняющие арифметические действия) уже не вызывает затруднений можно перейти к освоению логических операций.

Так как логических операторов всего три, имеет смысл свести их в одну таблицу с операторами сравнения (табл. 6).

Таблица 6.

Имя Состояние стека Коментарии
AND A B > C Производит поразрядное логическое умножение 16 разрядного числа А на 16 разрядное число В то есть в числе С останутся только еденицы совпадающие в числах А и В
OR A B > C В числе С устанавливаются в 1 все разряды, установленные в 1 в числах А и В
XOR A B > C В числе С устанавливаются в 1 только разряды, не совпадающие в числах А и В
> A B > C С=-1, если А>B C=0, если A<=B
< A B > C C=-1, если A<B C=0, если A>=B
= A B > C C=-1, если A=B C=0, если A>=B
0= A > C C=-1,если A=0 C=0, если A>=0
0> A > C C=-1,если A>0 C=0, если A<=0
0< A > C C=-1, если A<0 C=0, если A>=0

Попробуйте (желательно в шестнадцатиричной системе счисления) произвести необходимые действия над числами, лежащими на стеке с помощью слов из табл. 6, проверяя полученные результаты словом (точка). Для примера приведем некоторые возможные результаты:

7 1 AND>
1
7 1 OR .<>
7
7 1 ХОR  . <ВК>
6
7 1 > . <ВК>
-1
7 1 < . <ВК>
0
7 1 = .<ВК>
0 

Если ваши результаты совпадают с приведенными и вы поняли, почему это происходит, то можно считать, что освоение работы интерпретатора закончено. Прежде чем перейти к наиболее трудной части приведем таблицу слов, которые часто употребляются при работе с интерпретатором (табл. 7).

Таблица 7.

Имя Состояние стека Коментарии
COLD XXXX > - Холодный старт, очистка стеков, установка системных переменных иконфигурации системы, выполнение стартового файла
QUIT XXXX > XXXX Очистка стека возвратов ипереход в бесконечный цикл ввода (QUERY) и интерпретации (INTERPRET) коман с терминала
QUERY ADR > - Снимает со стека адрес и вводит с терминала в ОЗУ строку символов, начиная с этого адреса
INTERPRET ADR > - Снимает со стека адрес и интерпретирует текст, начиная с указанного адреса
KEY  — > COD Ожидает нажатия клавиши и кладет в стек код символа в виде 16 разрядного числа
EXIT COD > - Снимает ASCII код и распечатывает его на терминале в виде символа
WORDS  — > - Распечатывает словари FORT — системы
SPACE  — > - Печатает на терминале один символ пробела
CR  — > - Выдает на терминал коды <ВК> и <ПС>
TYPE ADR1 > ADR2 Снимает со стека адрес и распечатывает все символы с кодами >0, на коды <80H, если втречается другой код, возвращает его адрес(ADR2)
HEX  — > - Устанавливает шестнадцатиричную систему счисления
DECIMAL  — > - Устанавливает десятичную систему счисления
NUMBER  — > N Преобразует строку символов, следующую после него в число на вершине стека с учетом действующей системы счисления
= N > - Преобразует число в вершине стека в строку символов с учетом системы счисления
@ ADR > N Снимает со стека адрес и кладет в стек два байта, считываемые с этого адреса
C@ ADR > N Снимает со стека адрес и кладет в стек байт, считываемый с этого адреса
N ADR > - Записывает двухбайтовое число N по адресу ADR
N ADR > - Записывает младший байт числа N по адресу ADR
,  — > - Записывает двухбайтовое число N на вершину кодофайла
C, N ADR > - Записывает младший байт числа N на вершину кодофайла
HERE  — > ADR Кладет в стек, адрес вершины кодофайла
'  — > ADR (Апостроф) по имени слова находит адрес исполняемой части () слова или −1, если слово не задано
EXECUT ADR > - Снимает со стека адрес и передает управление программе или подпрограмме по указанному адресу
CREAT  — > - Создает в словаре новое слово с именем, стоящим после CREAT, то есть CREAT <ИМЯ>
ALLOT N > - Резервирует N байт на вершине кодофайла для переменных и массивов
"  — > - Копирует строку символов на вершину кодофайла
!<ИМЯ>  — > - Подобно CREAT создает слово и переводит интерпретатор в режим компиляции; используется для описания новых слов

Немного о самой процедуре интерпретации, которую производит слово. Вначале любое встретившееся слово, с помощью слова ' (апостроф), отыскивается в словаре и если оно найдено его адрес передается слову, которое тут же его исполняет. Если же, слово не найдено, то с помощью слова NUMBER оно преобразуется в число, которое кладется в стек, а если слово не является и числом, то интерпретация прекращается, печатается знак вопроса, распечатывается весь текст исходной программы, начиная с ошибочного слова, а затем — словарь системы, напоминая, что можно использовать только известные системе слова.

ПОДПРОГРАММНЫЙ ШИТЫЙ КОД

В предыдущем разделе мы рассмотрели работу системы ФОРТ в режиме интерпретации программы, вводимой с клавиатуры или из входного файла. У читателя, возможно, возник вопрос, как интерпретатор находит слова в словаре системы? Дело в том, что все слова входящие в ФОРТ систему представляют собой единый список называемый шитым кодом. Занимаемое им адресное пространство, называется кодофайлом. В версии для «Радио 86РК», применен предложенный автором подпрограммный шитый код, который мы и будем разбирать.

Для примера приведем распечатку дампа двух рядовых слов, например, и DECIMAL.

ADDR. LFA NFA CFA
0F89 0FA5 HEX 83 3E 10 32 4A 10 C9
0FA5 0FB5 DECIMAL 87 ЗЕ 0A 32 4A 10 C9 

Как видим, слово HEX начинается не с имени, а с некоторого двухбайтного адреса, указывающего на начало слова DECIMAL, которое в свою очередь также начинается с двухбайтного адреса, указывающего на начало следующего за ним слова.

Будем называть адреса, с которых начинается каждая словарная статья полем связи, так как именно они, обеспечивают связь всех слов в словаре и позволяют, зная адрес первого и последнего слова, отыскать и все остальные. Заметим, что в описываемой версии, список слов связан от начала к концу. Обычно поле связи обозначают аббревиатурой. За следуют ASCII коды имени и один стоп-байт. Поле имени кратко называют NFA.

Стоп байт отличается от ASCII кода имени тем, что имеет установленный в 1 старший (восьмой) знаковый бит. В младших шести разрядах стоп-байта, указывается длина имени ASCII кодов), а в седьмом бите — признак немедленного исполнения (IMMEDIAT), о котором мы поговорим позже. У слова HEX признака IMMEDIAT нет, и стоп-байт имеет значение 83Н, а у слова DECIMAL — 87Н. Так как под имя отведено только шесть бит его длина не может превышать 63 символов. За NFA следует поле кодов, состоящее из машинных команд процессора. Заметим, что именно адрес , возвращает слово (апостроф). CFA слева HEX состоит из трех машинных команд которые на языке АССЕМБЛЕРа выглядят так:

MVI А, 10Н ;записать в аккумулятор число 16
SТА 104АН  ;переписать его в ячейку с адресом 104АН
RET        ;возврат через стек возвратов 

Рабочая ячейка с адресом 104АН, хранит текущее основание системы счисления, которое используется словами NUMBER и . (точка).

Если необходимо установить восьмеричную систему счисления, то следует подать команду:

НЕХ 8 104А С!<ВК>

или ввести в словарь новое слово OCTAL. Как это сделать, мы узнаем из следующего раздела.

За полем CFA может находиться поле параметров PFA. У переменных оно состоит из одного или двух байт, а у массивов быть любого размера. У констант и других слов ФОРТ системы отсутствует, то есть имеет нулевой размер, хотя командой N , можно создать такое поле у любого слова, описанного последним. Следует отметить, что в других версиях языка ФОРТ поле LFA обычно следует за NFA, а последнее не заканчивается стоп-байтом, а начинается с байта-счетчика. Такую конструкцию называют строкой со счетчиком. Автор данной версии отказался от строки со счетчиком, так как использование строки со стоп-байтом имеет некоторые преимущества и более распространено в других системных и прикладных программах. Расположение LFA в начале словарной статьи, также имеет преимущества при генерации и расширении языка подпрограммами, написанными на АССЕМБЛЕРе.

РАБОТА ЯЗЫКА В РЕЖИМЕ КОМПИЛЯЦИИ

Как мы заметили работа с языком в режиме интерпретации, позволяет вводить с клавиатуры или из входного файла числа и слова, имеющиеся в словаре, но в отличие от других языков программирования ФОРТ не имеет фиксированного словарного запаса и открыт для пополнения списка слов самими пользователями. Попробуем проверить это на практике. Для начала опишем какое-нибудь простое слово, например, OCTAL. Для этого введем с клавиатуры следующую строку:

: OCTAL 8 [ HEX ] 104А ! ; WORDS “B”

После распечатки словаря мы увидим, что в нем появилось новое слово OCTAL, которым можно пользоваться так же, как словами HEX и DECIMAL.

Каким же образом новые слова включаются в словарь? Это делает слово : (двоеточие), которое генерирует в конце кодофайла LFA и NFA нового слова, причем в NFA оно заносит имя слова, стоящего после двоеточия (через пробел, разумеется). Затем интерпретатор переключается в режим компиляции, и число 8 не кладется в стек, а в кодофайл компилируются машинные команды, которые при исполнении слова OCTAL будут помещать в стек число 8, затем если была установлена десятичная система счисления, необходимо установить шестнадцатиричную (чтобы ввести число 104АН) для чего необходимо временно снова выйти в режим интерпретации. В подобных случаях помогает слово [, которое не компилируется, а немедленно исполняется, потому, что в стоп-байте имени этого слова, имеется установленный в 1 бит признака IMMEDIAT.

Словом HEX устанавливаем нужную систему счисления и снова переводим интерпретатор в режим компиляции словом ]. Все следующие за ним слова, если они не имеют признака IMMEDIAT, будут скомпилированы на вершину кодофайла в виде машинных команд. Все числа компилируются в виде двух трехбайтовых команд типа:

CFA (слова DUP)
LXI В, <число>, а все слова — в виде одной трехбайтовой команды
CFA (слова)

И, наконец, слово; (точка с запятой) скомпилирует команду RET, и вновь переведет компилятор в режим интерпретации. Таким образом, будет сформировано CFA слова (в данном случае — OCTAL). Надо сказать, что слово включается в словарь немедленно, после описания и NFA словом : (двоеточие). Это сделано специально для написания сложных рекурсивных программ, когда слово немедленно может обратиться к самому себе правда программист должен позаботиться о том, чтобы глубина вложенных обращений не превышала 32, так как подстек возвратов отведено только 64 байта.

Итак, на примере слова OCTAL мы разобрали, как пополнить список слов. Это и есть программирование на языке ФОРТ, когда вы пополняете его словарь словами, которые затем можно использовать в описаниях других слов, пока, наконец, не опишете слово, которое и будет выполнять необходимые действия. Тогда можете сразу исполнить это слово, введя его имя и нажав клавишу «ВК». Как видите, программа составляется снизу вверх, когда сначала пишутся мелкие фрагменты, а затем окончательное слово, собирающее их воедино. Это впрочем, не мешает конструировать программу или ее алгоритм и сверху вниз.

Для тренировки напишите слово, которое вводит, интерпретирует и распечатывает текст, расположенный по адресу 2100Н. Вот одно из возможных решений:

: ПРИМЕР [HEX]
2100 QUERY 2100 INTERPRET
2100 TYPE CR ."КОНЕЦ ТЕКСТА". ; 

СТРУКТУРНОЕ ПРОГРАММИРОВАНИЕ

Как и подобает любому солидному языку, а в этом он превзошел, пожалуй, и ПАСКАЛЬ, язык ФОРТ позволяет писать структурированные программы любой степени сложности, без использования меток. Хотя словарь ФОРТа не фиксирован и даже начинающий программист может описать слово, вводящее понятие метки, он быстро убедится, в полной бесполезности этого открытия, так как в базовом словаре, имеются все необходимые слова, для описания ветвлений, циклов с проверкой условия, как в начале, так и в конца цикла, а также циклов со счетчиком. Основным словом позволяющим реализовать упомянутые структуры, является слово IF.

Как и прежде, рассмотрим его работу на простом примере.

: ПРИМЕР1 KEY DUP [HEX] 20 = 
IF  "ПРОБЕЛ" DROP 
ELSE ENIT 
THEN ."-ЭТА КЛАВИША ИСПРАВНА"; 

Как работает это слово? Слово KEY ожидает нажатия клавиши и помещает в стек код символа введенного с терминала. Затем слово DUP кладет в стек число 20Н, а слово = сравнивает эти числа и возвращает в стек либо TRUE (то есть −1) если эти числа равны, либо FALSE (то есть 0) если они не равны. Слово IF берет логическое значение, оставленное словом =, и если оно имеет значение TRUE, то выполняются операторы, следующие за словом IF (см пример 1), если был введен код пробела 20Н, то будет напечатано слово «ПРОБЕЛ». Затем слово ELSE передаст управление на операторы стоящие после слова THEN. Если же слово IF возьмет из стека значение FALSE, то оно передаст управление на операторы стоящие после слова ELSE. Слово THEN не выполняет никаких действий, а лишь расставляет на этапе компиляции правильные адреса для ссылки вперед в слове ELSE или IF (если ELSE отсутствует). Конечно же, парность операторов IF THEN абсолютно необходима и хотя в данной версии она и не проверяется самим компилятором, программист должен сам строго следить за соблюдением этого правила. В общем, виде структуру слов с операторами ветвление можно описать примерно так:

полная альтернатива: 
имя <операторы, оставляющие в стеке условие> 
IF <операторы выполняются, если в стеке было TRUE> 
ELSE <операторы выполняются, если в стеке было FALSE> 
THEN <операторы выполняются всегда>; 

или неполная альтернатива:
имя <операторы, оставляющие в стеке условие> 
IF <операторы выполняются, если в стеке было TRUE> 
THEN <операторы выполняются всегда>; 

или неполная альтернатива с инверсией: 
имя <операторы оставляющие в стеке условие> 
IF ELSE <операторы выполняются, если в стеке было FALSE> 
THEN <операторы выполняются всегда>. 

Для инверсии логического значения на стеке можно применить и слово 0=, но это несколько медленнее, чем ELSE После столь подробного описания операторов ветвления желательно поупражняться в написании слов с их использованием. Заметим, что все структурные операторы имеют признак IMMEDIAT и могут использоваться только в описаниях других слов в режиме компиляции. В режиме интерпретации они не выполняют того, о чем было сказано выше. На самом деле эти слова только компилируют на вершину кодофайла несколько машинных команд, которые будут исполняться, только при исполнении слова, внутри которого они скомпилированы. В табл. 8 приведен список слов, которые также используются только в режиме компиляции.

Таблица 8.

Имя Состояние стека Коментарии
[  — > - Переключает систему в режим интерпретации
]  — > - Переключает систему в режим компиляции
;  — > - Копирует команду RET и переключает систему в режим интерполяции
IF XXX C > - Если C=TRUE, то исполняется XXX
ELSE YYY  — > - Если C=FALSE, то исполняется YYY
THEN ZZZ  — > - ZZZ исполняется всегда
BEGIN ZZZ  — > - Начало цикла с условием, ZZZ исполняется всегда и оставляяет в стеке логическое значение
IF XXX C > - Если C=TRUE, то исполняется XXX, если C=FALSE, то выход из цикла
REPEAT  — > - Операторная скобка, парная к BEGIN IF, ограничивает операторы цикла ZZZ и XXX
+DO XXX N1 N2 N3  — > - Снимает со стека конечное N1 и начальное N2 значения параметра цикла N3 и выполняет XXX(N2-N1)/N3+1 раз при значении параметра >N1 выход из цикла
REPEAT  — > - Операторная скобка, парная к +DO, ограничивает операторы цикла XXX
I  — > N Кладет в стек значение оператора цикла
J  — > N Кладет в стек значение внешнего (обьявленного) цикла при вложенных циклах типа +DO +DO XXX REPEAT REPEAT
, «сообщение»  — > - Распечатывает на терминале сообщение


Для демонстрации работы операторов цикла приведем несколько примеров.

: ПРИМ2 BEGIN KEY DUP 20 = IF 
ELSE . REPEAT DROP ."ПРОБЕЛ"; 

Это слово циклически опрашивает клавиатуру и печатает ASCII коды нажатых клавиш, при нажатии клавиши с кодом 20H (пробел), цикл заканчивается. Следующее слово работает примерно так же, но цикл заканчивается при нажатии на клавишу управления с кодом < 20Н.

: ПРИМ3 BEGIN KEY DUP 19 > IF EMIT 
REPEAT SPACE . .”Это код управления";  

Следующее слово сразу после написания поздравит вас три раза.

DECIMAL  : HELLO 22 10 6 
+DO СR .'ПОЗДРАВЛЯЮ ' 
REPEAT; HELLO <BK> 

ПРОГРАММИРОВАНИЕ В МАШИННЫХ КОДАХ

До этого мы использовали только примитивы базового словаря, но подпрограммный шитый код позволяет вставлять в описания слов непосредственные машинные команды. Например, слово S, включает команды PUSH H и РОP В и распечатывает содержимое арифметического стека без его изменения.

:S DUP .[HEX Е5 С, С1 С, ]107A -2 +DO|(r) . REPEAT;
или то же самое
: S DUP .[HEX C1E5 .] 107A -2
+DO |(c) .REPEAT;

Таблица 9.

Адрес (hex) Назначение
0800H — 0FFFH Кодофайл базового словаря
1000H — 103FH Стек операторов
1040H — 1043H JMP F809H вектор на подпрограмму вывода символа
1044H — 1047H Хранит адрес LFA последнего слова в словаре
1048H — 1049H Хранит переменную HERE
104AH Хранит основание текущей системы счисления
104BH Хранит режим работы, 00 — интерпретатор, FF — компилятор
104CH — 104DH Хранит адрес вектора
104E — 104FH Хранит адрес, по которому запишет очередной выводимый символ
1050H — 1057H Буфер для преобразования чисел в строку символов . (точка)
1058H — 107BH Арифметический стек
107CH — 107FH ??????? адреса
1080H — 10FFH Буфер для ввода символа с терминала
1100H Начальный адрес области кодофайла слов пользователя

Программирование в машинных кодах является обоюдоострым свойством данной реализации, поэтому, для того чтобы не нанести непоправимого вреда ФОРТ системе (особенно если в программе происходят обращения по абсолютным адресам) приведем распределение адресного пространства адреса рабочих ячеек интерпретатора и назначение регистров процессора (табл. 9 и 10). Как видим верхнее число лежащее в стеке, на самом деле находится в регистровой паре ВС, чем и объясняется высокая скорость работы ФОРТ системы с вершиной стека (вспомните S).

Таблица 10.

Регистр Назначение
PSW Используется произвольно
DE Используется произвольно
BC Вершина арифметического стека
HL Указатель арифметического стека
SP Указатель стека возвратов
PC Счетчик команд

Слово DUP делает копию содержимого регистровой пары ВС примерно так

      MOV M, В 
      DCX H 
      MOV M, C 
      DCX H 

а слово DROP снимает число с вершины

      INX H
      MOV C,M
      INX H
      MOV B,M 

Регистровыми парами PSW и DE пользуются почти все слова базового словаря, поэтому сохранность информации в этих регистрах не гарантируется.

Для упражнения попробуйте написать в машинных кодах слова повторяющие функции слов DUP и DROP. Следует избегать повторного использования слов, так как в данной версии их поиск производится сначала словаря, и исполняться будет слово, написанное раньше. В версиях языка, где список связан от конца к началу, повторное описание слова делает недоступным более раннее описание. В заключение приведем текст небольшой вирусной программы, которая, будучи один раз исполненной, перехватывает вектор вывода на дисплеи и обрабатывает код 09Н как команду горизонтальной табуляции. Для ее написания потребовалось всего несколько минут. Читателю предлагается обратить внимание на действие слов ограниченных словами [ и ]. И расшифровать их смысл.

      CREAT CUR 0 ,
      : TAB DUP TAB [ 01 HERE 3 C!] 1044 < DUP 9 =
      IF 20
      BEGIN
      F809 EXECUT
      CUR @ 1 + DUP CUR ! 7 AND
      IF REPEAT DROP
      ELSE 
      DUP 0D = 
      IF 0 CUR !
      ELSE CUR (r) 1 + CUR !
      THEN F809 EXECUT
      THEN;

Как видим написание вируса не такое уж и сложное дело. Но вряд ли стоит этим заниматься. Гораздо полезнее написать дельную программу. Вручая читателям свой труд, автор надеется, что именно этому они посвятят свое время и безграничную фантазию.

ПЕРЕМЕННЫЕ

В предыдущем примере мы использовали слово CUR, которое описано не через двоеточие, а словом CREAT. Что это за слово? Это — переменная. Переменными в языке ФОРТ называют слова, оставляющие на вершине стека адрес этой переменной (точнее адрес PFA в котором и хранится информация). Переменные могут быть одно и двухбайтными и образуются следующим образом:

однобайтные переменные
CREAT <ИМЯ ПЕРЕМЕННОЙ> 1 АLLOТ
или
CREAT <ИМЯ ПЕРЕМЕННОЙ> N С

Двухбайтные переменные
CREAT <ИМЯ ГЕРЕМЕННОЙ> 2 ALLOT
или
CREAT <ИМЯ ПЕРЕМЕННОЙ> N В 

последних примерах переменной еще и присваивается начальное значение N. Доступ к переменным обеспечивают слова:

  • С! — запись байта из стека в переменную
  • ! — запись числа из стека в переменную
  • С@ — чтение байта из переменной в стек
  • @ — чтение числа из переменной в стек

Попробуйте практически ознакомиться с переменными, так как личный опыт, к сожалению, ничем заменить нельзя.

МАССИВЫ

Массивы — более общий случай переменных и отличаются от последних только большим размером. Например, команда

CREAT ARR3 0 0 0 
или 
GREAT ARR3 6 ALLOT 

создает массив из трех слов (то есть Шесть байт), Особый интерес представляют массивы, заполненные литерами. Попробуем создать такой массив командой:

СREАТ ARR$ “МАССИВ, ЗАПОЛНЕННЫЙ ТЕКСТОМ”

Попробуйте распечатать этот массив командой

ARR$ TYPE CR.

Слово TYPE распечатает текст, записанный в массив, и вернет, адрес стоп-байта записанного в конце массива словом « (кавычки). Так как в стоп-байте семь бит несут информацию о длине массива, то не рекомендуется записывать в массив более 128 символов (хотя этим правилом иногда можно пренебречь). Эти же рекомендации относятся и к слову.», которое пользуется услугами слова ".

КОНСТАНТЫ

Константы в данной версии языка проще всего описывать, так же как и другие ФОРТ слова, через двоеточие. Например: TRUE −1; : FALSE 0; и так далее.

Но иногда необходимо создать константу со значением, взятым из стека. В этом случае можно поступить двояко;

  • либо создать константу и записать в нее новое значение
  • либо описать слово, которое будет само создавать константы.

Одно из возможных решений — слово CONST:

: CONST CREAT HERE 3 - ! ;

Обращение к этому слову имеет вид:

<ЗНАЧЕНИЕ> CONST <ИМЯ КОНСТАНТЫ>

Например:

1 CONST TRUE 0 CONST FALSE

РАСШИРЕНИЕ системы ФОРТ

Конечно, расширение языка ФОРТ происходит и без вашего желания, хотя и не без вашего участия. Чтобы не изобретать велосипед старайтесь больше читать и использовать большее число слов уже достаточно устоявшихся или стандартизованных в других версиях. Это облегчит чтение ваших программ и позволит использовать программное обеспечение, написанное другими.

Начать легче всего с включения в ФОРТ систему стандартных подпрограмм МОНИТОРа и программ или подпрограмм написанных на АССЕМБЛЕРе. Для примера опишем процедуры ввода кода нажатой клавиши и опроса состояния клавиатуры:

: ?KEY 0 F81B EXECUT [4F С,]; 
: ?TERM DUP F812 EXECUT [4F47 ,]; 

Подобным же образом используя вставки в машинных кодах можно описать обращения к любым программам и подпрограммам (например, так подключен редактор МИКРОН)/ Следует только позаботиться о стандартной передаче параметров через арифметический стек, то есть регистровую пару ВС и область памяти, адресуемую парой HL. Следует также позаботиться и о том, чтобы внешние программы не нарушали работы стеков. Исходные тексты программ написанных на АССЕМБЛЕРе можно включить в ФОРТ систему и другим способом, используя тот факт, что область кодофайла пользователя, и область трансляции АССЕМБЛЕРа МИКРОН расположены в одном и том же месте ОЗУ начиная с адреса 1100Н. Снабдите все ваши подпрограммы заголовком аналогичным полям LFA и NFA других слов ФОРТ-системы.

На ассемблере это выглядит так:

LFA: DW @PFA ;поле LFA
NFA: DB 'ИМЯ' ;ASCII коды
STB: DB STB-NFA+80H ;стоп-байт коды программы
CFA …
…
……
RET
PFA: …. ;параметры программы
…
@PFA: ;конец описания слова

Загрузите АССЕМБЛЕР «МИКРОН» откомпилируйте программу, а затем, загрузив в ФОРТ, занесите в ячейки памяти по адресу 80СН адрес LFA последнего слова, а по адресу 80ЕН — слово, записанное по этому адресу, то есть @PFA (см. выше). Запустив или перезапустив ФОРТ командой COLD, вы включите описанное слово в ФОРТ систему. Подобным образом можно унифицировать и включить в систему любую программу, написанную на АССЕМБЛЕРе. Еще один способ позволяет написать программу, которая может использоваться и без ФОРТа. Введите команды:

HEX 7400 HERE - ALLOT
2F3E, C23D, 7402, 0021, 
ЗЕ21, CD08, F806, 00FA,
7774, С323, 7409, 

После этого по адресу 7400Н будут записаны коды программы, которую можно запустить командой 7400 EXECUT или из МОНИТОРа командой G7400 <ВК>. Не вдаваясь в подробности, отметим, что эта программа позволяет вводить с кассеты тексты, записанные в формате редактора «МИКРОН» не только с начала, но и с любого места даже с середины. На этом описание работы с ФОРТом можно закончить. Остается только добавить, что после того, как написано и отлажено какое либо слово в пультовом режиме желательно командой 0 EXECUT выйти в редактор, и увековечить находку в виде текста который затем будет автоматически исполняться после входа в ФОРТ систему или после «холодного» старта словом COLD.

Желаю успехов.

ЛИТЕРАТУРА

  1. 1 Бураго А. Ю., Кириллин В. А., Роменовский И. В., ФОРТ — язык для микропроцессоров — Л. Знания 1989.
  2. Семенов Ю. А., Программирование на языке ФОРТ. — М. Радио и связь 1991.
  3. Библиотека информационной технологии Вып. 2. Под ред. Г. Р. Громова — М. Инфоарт1991.

Отсканировано с журнала Радио № 7, № 8 и № 10 1995 год.
Отредактировано Лесных Ю. 2001 год.