forth.md

Личный сайт Go-разработчика из Казани

Форт создан Чарлзом Муром в 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

Готовы к большему?