Смекни!
smekni.com

Особенности языка Форт (стр. 2 из 3)

4. Логические операции

В языке Форт имеется только один тип значений - 16-ти разрядные двоичные числа, которые, рассматриваются в зависимости от ситуации как целые числа со знаком, как адреса и т.д. Точно также подходят и к проблеме представления логических значений ИСТИНА и ЛОЖЬ: число 0 в двоичном представлении которого все разряды нули, представляет значение ложь, а любое другое 16-ти разрядное значение понимается как ИСТИНА. Вместе с тем стандартные слова, которые должны в качестве результата иметь логическое значение, из всех возможных представлений значения ИСТИНА используют только одно: число -1 (или, что то же самое, 65535), в двоичном представлении которого все разряды единицы. Такое соглашение связано с тем, что традиционные логические операции конъюнкции, дизъюнкции и отрицания выполняются в Форте поразрядно над всеми шестнадцатью разрядами операндов:

- AND - логическое И

- OR - логическое ИЛИ

- XOR - исключающее ИЛИ

- NOT - логиечское НЕ

Нетрудно увидеть, что для принятого в Форте стандартного представления значений ИСТИНА и ЛОЖЬ все эти слова работают, как обычные логические операции.

Логические значения возникают в операциях сравнения, которые входят в обязательный набор слов и имеют общепринятую мнемонику:

< A, B --> A < B меньше

= A, B --> A = B равно

> A, B --> A > B больше

Эти операции снимают со стёка два верхних значения, сравнивают их как числа со знаком и возвращают результат сравнения как значение ИСТИНА или ЛОЖЬ в описанном выше стандартном представлении. Возврат результата означает, что на стёк ложится соответствующее целое число.

Структуры управления

Стандарт языка предусматривает ряд слов для построения условных операторов и циклов. Эти слова используются внутри определений через двоеточие и разделяют тело определения на отрезки. Действия, соответствующие словам из этих отрезков, выполняются, или не выполняются многократно в зависимости от условий, проверяемых во время выполнения данного определения. Условные операторы и циклы могут свободно вкладываться друг в друга. Условный оператор строится с помощью слов:

IFA- исполнение

ELSE- исполнение

THEN-исполнение

Внутри определения через двоеточие отрезок текста IF <часть то> ELSE <часть иначе> THEN задаёт следующую последовательность действий: Слово IF снимает значение с вершины стёка и рассматривает его как логическое. Если это ИСТИНА (любое не нулевое значение), то выполняется часть "ТО" - слова, находящегося между IF и ELSE, а если ЛОЖЬ (равно нулю), то исполняется часть "иначе" - слова между ELSE и THEN.

В стандарт языка Форт включены циклы с условием и циклы со счётчиком. Циклы первой группы образуются с помощью слов:

BEGIN-исполнение

UNTILA- исполнение

WHILEA- исполнение

REPEAT- исполнение

И имеют две формы


BEGIN <тело цикла> UNTIL

BEGIN <тело - 1> WHILE <тело -2> REPEAT

В обоих случаях цикл начинается словом BEGIN которое служит открывающей скобкой, отмечающей начало цикла, и во время счёта не выполняет никаких действий.

Цикл BEGIN - UNTIL называется циклом с проверкой в конце. После исполнения слов, составляющих его тело, на стёке остаётся логическое значение - условие завершения цикла. Слово UNTIL снимает это значение со стёка и анализирует его. Если это ИСТИНА, то исполнение цикла завершается, а если это ложь, то управление возвращается к началу цикла от слова BEGIN.

Цикл с проверкой в начале BEGIN - WHILE - REPEAT используется если, в цикле есть действия, которые не надо выполнять в заключительной итерации. Исполнение слов, составляющих тело - 1, оставляет на стёке логическое значение - условие продолжения цикла. Слово WHILE снимает это значение со стёка и анализирует его. Если это ИСТИНА, то исполняются слова составляющие тело - 2 данного цикла до ограничивающего слова REPEAT, после чего вновь выполняется тело - 1 от слова BEGIN. Если же значение условия ЛОЖЬ то исполнение данного цикла завершается и начинают выполняться слова, следующие за REPEAT. В отличие от предыдущей формы цикла по условию, значение ИСТИНА соответствует продолжению цикла.

Для организации циклов с целочисленной переменной - счётчиком цикла - используются слова:

DOA, B-исполнение

LOOP- исполнение

+LOOPA- исполнение

I-A исполнение

J-A исполнение

LEAVE- исполнение

Такие циклы записываются в одной из следующих двух форм : DO <тело> LOOP или DO <тело> + LOOP. В обоих случаях цикл начинается словом DO, которое снимает со стёка два значения: начальное и конечное и запоминает их. Текущее значение счётчика полагается равным начальному значению, после чего исполняются слова, составляющие тело цикла. Слово LOOP увеличивает текущее значение счётчика на единицу и проверяет условие завершения цикла. В отличие от него слово +LOOP прибавляет к текущему значению счётчика значение шага, которое вычисляется на стёке телом цикла и рассматривается как число со знаком. В обоих случаях условием завершения цикла является пересечение границы между А-1 и А при переходе от прежнего значения счётчика к новому, где А - конечное значение, снятое со стёка словом DO. Если пересечения не произошло, то тело цикла исполняется вновь с новым значением счётчика в качестве текущего.

Внутри тела цикла слово I кладёт на стёк текущее значение счётчика. Слово LEAVE, употреблённое внутри цикла вызывает прекращение исполнения его тела; управление переходит к словам следующим за словом LOOP или +LOOP. В программировании часто применяется конструкция цикл в цикле. Чтобы во внутреннем цикле получить текущее значение счётчика объемлющего цикла, используется слово J.

5 Примеры программ

Пример 1: Вычисление факториала

Dup 2 if drop 1 1 если N <2 то N! = 1
Else N иначе
Dup S, K, S=N, K=N
Begin S, K
1 - S, K, K = K -1
Swap over K, S, K
* swap S, K, S=S*K
Dup 1 = S, K, K=1
Until S, 1, S = N!
Drop then; N!

Пример 2: Вычисление наибольшего общего делителя

2dup < swap then Теперь A>=B
Begin dup A, B, B
While Пока В не ноль
2dup mod А, В, С: остаток
Rot B, C, A
drop A, B, A=B, B=C
Repeat drop; НОД

Пример 3: Вычисление суммы квадратов

0 swap 0, N S[0] = 0
1+ 1 S[0], N+1, 1
Do I S[I-1], I
Dup * + S[I] S[I]=S[I] + I*I
Loop S[N]

6 Организация диалога в Форте

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

Пример 4: Упорядочение массива по возрастанию

Это пример, мы разберём подробно.

Выше уже было разъяснено, как организуется ввод. Поэтому договоримся о том, что перед вводом текста программы, мы уже осуществили ввод данных таким образом, что на вершине стека лежит число - количество элементов массива и под ним лежат все элементы массива.

Мы воспользуемся циклом DO. Для него на вершине стека должны лежать два значения начальное значение параметра и его конечное значение. Запишем команды, которые создадут необходимую структуру стёка.

DUP

1

SWAP

1


Запишем изменения вершины стека, которые происходят в процессе выполнения этих команд.

Команда 1: NN

Команда 2: 1 NN

Команда 3: N 1 N

Команда 4: 1 N 1 N

Таким образом, требуемая структура сформирована и можно записать заголовки цикла

DO

DO

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

2DUP

>

Первый оператор дублирует одно двойное слово или что-то же самое два одинарных, то есть дублирует на вершине стёка два значения. Затем операция "больше" снимает два значения, назовём их А, В и если А > В то кладёт на вершину стёка единицу иначе кладёт ноль. Если на вершине стека единица, то А и В находятся в нужном порядке и ничего делать не надо, иначе их нужно поменять местами

IF

ELSE

SWAP

THEN

Оператор IF снимает со стека 1 или 0 (результат операции сравнения), если снята единица то ничего не происходит иначе два верхних элемента, а это опять А и В меняются местами. И теперь осталось провернуть стёк. Для этого необходимо выполнить команду NROLL. Если N - количество элементов массива, то команда осуществит необходимый нам сдвиг стёка. Ясно, что нам опять нужно значение N, но оно было безвозвратно снято со стёка и забыто (о нём сейчас помнят только заголовки циклов). Вот тут мы сможем с пользой применить понятие переменной. Чтобы запомнить в оперативной памяти значение N мы в самом начале программы должны выполнить следующее