Форт создан Чарлзом Муром в 70-е годы. Это императивный, стековый язык программирования и среда исполнения программ. Использовался в таких проектах как Open Firmware. Продолжает применяться в проектах. Применяется в НАСА.
Внимание: этот материал использует реализацию Форта - Gforth, но большая часть написанного будет работать в других средах.
1\ Это комментарий
2( Это тоже комментарий, но используется для предопределённых слов )
3
4\ --------------------------------- Прекурсор --------------------------------
5
6\ Всё программирование на Форте заключается в манипулировании
7\ параметрами на стеке.
85 2 3 56 76 23 65 \ ok
9
10\ Эти числа добавляются в стек слева направо
11.s \ <7> 5 2 3 56 76 23 65 ok
12
13\ В Форте всё - это слова-команды или числа. Слова разделяются любым числом
14\ пробелов и переходов на новую строку. Длина слова не больше 31 литеры.
15
16\ ---------------------------- Базовая арифметика ----------------------------
17
18\ Арифметика (фактически все ключевые слова требуют данных) - это манипуляция
19\ данными на стеке.
205 4 + \ ok
21
22\ `.` показывает верхнее значение в стеке:
23. \ 9 ok
24
25\ Ещё примеры арифметических выражений:
266 7 * . \ 42 ok
271360 23 - . \ 1337 ok
2812 12 / . \ 1 ok
2913 2 mod . \ 1 ok
30
3199 negate . \ -99 ok
32-99 abs . \ 99 ok
3352 23 max . \ 52 ok
3452 23 min . \ 23 ok
35
36\ --------------------------- Манипуляции со стеком ---------------------------
37
38\ Естественно, когда мы работаем со стеком, то используем
39\ больше полезных методов:
40
413 dup - \ дублировать верхний элемент в стеке
42 \ (1-й становится эквивалентным 2-му): 3 - 3
432 5 swap / \ поменять местами верхний элемент со 2-м элементом: 5 / 2
446 4 5 rot .s \ сменять по очереди 3-и верхних элемента: 4 5 6
454 0 drop 2 / \ снять верхний элемент (не печатается на экране): 4 / 2
461 2 3 nip .s \ снять второй элемент (подобно исключению элемента): 1 3
47
48\ ------------------ Более продвинутые манипуляции со стеком ------------------
49
501 2 3 4 tuck \ дублировать верхний элемент стека во вторую позицию:
51 \ 1 2 4 3 4 ok
521 2 3 4 over \ дублировать второй элемент наверх стека:
53 \ 1 2 3 4 3 ok
541 2 3 4 2 roll \ *переместить* элемент в заданной позиции наверх стека:
55 \ 1 3 4 2 ok
561 2 3 4 2 pick \ *дублировать* элемент в заданной позиции наверх:
57 \ 1 2 3 4 2 ok
58
59\ Внимание! Обращения к стеку индексируются с нуля.
60
61\ --------------------------- Создание новых слов -----------------------------
62
63\ Определение новых слов через уже известные. Двоеточие `:` переводит Форт
64\ в режим компиляции выражения, которое заканчивается точкой с запятой `;`.
65: square ( n -- n ) dup * ; \ ok
665 square . \ 25 ok
67
68\ Мы всегда можем посмотреть, что содержится в слове:
69see square \ : square dup * ; ok
70
71\ -------------------------------- Зависимости --------------------------------
72
73\ -1 == true, 0 == false. Однако, некоторые ненулевые значения
74\ обрабатываются как true:
7542 42 = \ -1 ok
7612 53 = \ 0 ok
77
78\ `if` это компилируемое слово. `if` <stuff to do> `then` <rest of program>.
79: ?>64 ( n -- n ) dup 64 > if ." Больше чем 64!" then ;
80\ ok
81100 ?>64
82\ Больше чем 64! ok
83
84\ Else:
85: ?>64 ( n -- n ) dup 64 > if ." Больше чем 64!" else ." меньше чем 64!" then ;
86100 ?>64 \ Больше чем 64! ok
8720 ?>64 \ меньше чем 64! ok
88
89\ ------------------------------------ Циклы -----------------------------------
90
91\ `do` это тоже компилируемое слово.
92: myloop ( -- ) 5 0 do cr ." Hello!" loop ; \ ok
93myloop
94\ Hello!
95\ Hello!
96\ Hello!
97\ Hello!
98\ Hello! ok
99
100\ `do` предполагает наличие двух чисел на стеке: конечное и начальное число.
101
102\ Мы можем назначить в цикле переменную `i` для значения индекса:
103: one-to-12 ( -- ) 12 0 do i . loop ; \ ok
104one-to-12 \ 0 1 2 3 4 5 6 7 8 9 10 11 12 ok
105
106\ `?do` работает подобным образом, за исключением пропуска начального
107\ и конечного значения индекса цикла.
108: squares ( n -- ) 0 ?do i square . loop ; \ ok
10910 squares \ 0 1 4 9 16 25 36 49 64 81 ok
110
111\ Изменение "шага" цикла проиводится командой `+loop`:
112: threes ( n n -- ) ?do i . 3 +loop ; \ ok
11315 0 threes \ 0 3 6 9 12 ok
114
115\ Запуск бесконечного цикла - `begin` <stuff to do> <flag> `until`:
116: death ( -- ) begin ." Вы всё ещё здесь?" 0 until ; \ ok
117
118\ ---------------------------- Переменные и память ----------------------------
119
120\ Используйте `variable`, что бы объявить `age` в качестве переменной.
121variable age \ ok
122
123\ Затем мы запишем число 21 в переменную 'age' (возраст) словом `!`.
12421 age ! \ ok
125
126\ В заключении мы можем напечатать значение переменной прочитав его словом `@`,
127\ которое добавит значение на стек или использовать слово `?`,
128\ что бы прочитать и распечатать в одно действие.
129age @ . \ 21 ok
130age ? \ 21 ok
131
132\ Константы объявляются аналогично, за исключем того, что мы не должны
133\ беспокоиться о выделении адреса в памяти:
134100 constant WATER-BOILING-POINT \ ok
135WATER-BOILING-POINT . \ 100 ok
136
137\ ---------------------------------- Массивы ----------------------------------
138
139\ Создание массива похоже на объявление переменной, но нам нужно выделить
140\ больше памяти.
141
142\ Вы можете использовать слова `2 cells allot` для создания массива
143\ размером 3 элемента:
144variable mynumbers 2 cells allot \ ok
145
146\ Инициализировать все значения в 0
147mynumbers 3 cells erase \ ok
148
149\ В качестве альтернативы мы можем использовать `fill`:
150mynumbers 3 cells 0 fill
151
152\ или мы можем пропустить все слова выше и инициализировать массив
153\ нужными значениями:
154create mynumbers 64 , 9001 , 1337 , \ ok (the last `,` is important!)
155
156\ ... что эквивалентно:
157
158\ Ручная запись значений по индексам ячеек:
15964 mynumbers 0 cells + ! \ ok
1609001 mynumbers 1 cells + ! \ ok
1611337 mynumbers 2 cells + ! \ ok
162
163\ Чтение значений по индексу:
1640 cells mynumbers + ? \ 64 ok
1651 cells mynumbers + ? \ 9001 ok
166
167\ Мы можем просто сделать собственное слово для манипуляции массивом:
168: of-arr ( n n -- n ) cells + ; \ ok
169mynumbers 2 of-arr ? \ 1337 ok
170
171\ Которую тоже можно использовать для записи значений:
17220 mynumbers 1 of-arr ! \ ok
173mynumbers 1 of-arr ? \ 20 ok
174
175\ ------------------------------ Стек возвратов ------------------------------
176
177\ Стек возвратов используется для удержания ссылки,
178\ когда одно слово запускает другое, например, в цикле.
179
180\ Мы всегда видим это, когда используем `i`, которая возвращает дубль верхнего
181\ значения стека. `i` это эквивалент `r@`.
182: myloop ( -- ) 5 0 do r@ . loop ; \ ok
183
184\ Так же как при чтении мы можем добавить ссылку в стек возвратов и удалить её:
1855 6 4 >r swap r> .s \ 6 5 4 ok
186
187\ Внимание: так как Форт использует стек возвратов для указателей на слово `>r`
188\ следует всегда пользоваться `r>`.
189
190\ ---------------- Операции над числами с плавающей точкой --------------------
191
192\ Многие фортовцы стараются избегать использования слов с вещественными числами.
1938.3e 0.8e f+ f. \ 9.1 ok
194
195\ Обычно мы просто используем слово 'f', когда обращаемся к вещественным числам:
196variable myfloatingvar \ ok
1974.4e myfloatingvar f! \ ok
198myfloatingvar f@ f. \ 4.4 ok
199
200\ ---------- В завершение несколько полезных замечаний и слов -----------------
201
202\ Указание несуществующего слова очистит стек. Тем не менее, есть специальное
203\ слово для этого:
204clearstack
205
206\ Очистка экрана:
207page
208
209\ Загрузка форт-файла:
210\ s" forthfile.fs" included
211
212\ Вы можете вывести список всех слов словаря Форта (это большой список!):
213words
214
215\ Выход из Gforth:
216bye