Язык FORTH был создан Чарльзом X. Муром в конце 60-х годов в результате работы по созданию простого интерпретатора, облегчающего написание программ управления астрономическим оборудованием.
Вновь созданный язык был принят в качестве основного языка программирования в Американском астрономическом обществе. В 1973 году, Чарльз Мур и Элизабет Ратер основали компанию FORTH, Inc в котором язык был портирован на множество платформ.
В конце 1970-х годов программистами, заинтересованными в развитии языка, была создана группа FORTH Interest Group (FIG). Этой группой разработана концепция FIG Forth Model — общедоступной форт-системы. Эту эталонную форт систему — FIG-FORTH часто рассматривают как первоначальный стандарт языка.
ФОРТ система, обычно, содержит интерпретатор и компилятор языка FORTH и поддерживает диалоговый режим и режим исполнения.
Язык FORTH основан на использовании слов (команд) из словаря, который может пополняться новыми словами. Слова принимают данные из арифметического стека LIFO и туда же возвращают значения и результаты операций. Математические, логические и другие операции, выполняющие операции с данными из стека записываются в виде обратной польской нотации. Слова и значения разделяются пробелом.
Код | Слово | Перевод | Стек до операции | Стек после операции | Примечание |
---|---|---|---|---|---|
A0 | DROP | снять | abcd..... | bcd..... | |
A1 | DUP | дублировать | abcd..... | aabcd..... | |
A2 | SWAP | обменять | abcd..... | bacd..... | |
A3 | OVER | через | abcd..... | babcd..... | |
A4 | ROT | вращать | abcd..... | cabd..... | |
A5 | -ROT | вращать обратно | abcd..... | bcad..... | |
A6 | SP! | очистить стек | |||
A7 | SP@ | указатель стека | |||
A8 | 2DROP | снять 2 элемента | |||
A9 | 2OVER | через 2 | |||
B0 | 2SWAP | обменять 2 | |||
B1 | PICK | взять | |||
B2 | ROLL | повернуть | |||
B3 | DEPTH | глубина | |||
B4 | AND | И | |||
B5 | NOT | НЕ | |||
B6 | OR | ИЛИ | |||
B7 | XOR | Исключающее ИЛИ | |||
B8 | 1+ | плюс 1 | |||
B9 | 1– | минус 1 | |||
C0 | 2+ | плюс 2 | |||
C1 | 2– | минус 2 | |||
C2 | 2* | умножить на 2 | |||
C3 | 2/ | делить на 2 | |||
C4 | + | сложить | |||
C5 | – | вычесть | |||
C6 | * | умножить | |||
C7 | NEGATE | смена знака | |||
C8 | ABS | без знака | |||
C9 | MIN | меньшее | |||
D0 | MAX | большее | |||
D1 | / | делить | |||
D2 | MOD | остаток | |||
D3 | */ | умножить и разделить | |||
D4 | = | сравнить | |||
D5 | < | меньше ? | |||
D6 | > | больше ? | |||
D7 | 0= | равно 0 | |||
D8 | 0< | меньше 0 ? | |||
D9 | 0> | больше 0 ? |
Табл. 1.
Рис. 1.
Рис. 2.
#include <LiquidCrystal_I2C.h>
#include <Keypad.h>
#define DROP _DROP();
#define PICK _PICK();
LiquidCrystal_I2C lcd(0x27, 16, 2);
char hexaKeys[4][4] = {
{ '1', '2', '3', 'A' },
{ '4', '5', '6', 'B' },
{ '7', '8', '9', 'C' },
{ '*', '0', '#', 'D' }
};
byte rowPins[4] = { 6, 7, 8, 9 };
byte colPins[4] = { 5, 4, 3, 2 };
Keypad customKeypad = Keypad(makeKeymap(hexaKeys), rowPins, colPins, 4, 4);
int input_value = 0; // Вводимое число
int input_command = 0; // Номер вводимого слова
int Stack[128]; // Арифметический стек
int stack_depth = 0; // Глубина арифметического стека
int error = 0; // Номер ошибки
void _DROP() {
stack_depth--;
}
void _DUP() {
Stack[stack_depth] = Stack[stack_depth - 1];
stack_depth++;
}
void _SWAP() {
int a = Stack[stack_depth - 1];
Stack[stack_depth - 1] = Stack[stack_depth - 2];
Stack[stack_depth - 2] = a;
}
void _OVER() {
Stack[stack_depth] = Stack[stack_depth - 2];
stack_depth++;
}
void _ROT() {
int a = Stack[stack_depth - 3];
Stack[stack_depth - 3] = Stack[stack_depth - 2];
Stack[stack_depth - 2] = Stack[stack_depth - 1];
Stack[stack_depth - 1] = a;
}
void _nROT() {
int a = Stack[stack_depth - 3];
Stack[stack_depth - 3] = Stack[stack_depth - 1];
Stack[stack_depth - 1] = Stack[stack_depth - 2];
Stack[stack_depth - 2] = a;
}
void _SPi() {
stack_depth = 0;
}
void _SPa() {
Stack[stack_depth] = stack_depth;
stack_depth++;
}
void _2DROP() {
DROP DROP
}
void _2OVER() {
Stack[stack_depth] = Stack[stack_depth - 4];
Stack[stack_depth + 1] = Stack[stack_depth - 3];
stack_depth += 2;
}
void _2SWAP() {
int a = Stack[stack_depth - 1];
Stack[stack_depth - 1] = Stack[stack_depth - 3];
Stack[stack_depth - 3] = a;
a = Stack[stack_depth - 2];
Stack[stack_depth - 2] = Stack[stack_depth - 4];
Stack[stack_depth - 4] = a;
}
void _PICK() {
Stack[stack_depth - 1] = Stack[stack_depth - 2 - Stack[stack_depth - 1]];
}
void _ROLL() {
int n = Stack[stack_depth - 1];
PICK;
for (n; n > 0; n--) {
Stack[stack_depth - n] = Stack[stack_depth + 1 - n];
}
stack_depth--;
}
void _DEPTH() {
Stack[stack_depth] = stack_depth;
stack_depth++;
}
void _AND() {
Stack[stack_depth - 2] &= Stack[stack_depth - 1];
stack_depth--;
}
void _OR() {
Stack[stack_depth - 2] |= Stack[stack_depth - 1];
stack_depth--;
}
void _NOT() {
Stack[stack_depth - 1] = ~Stack[stack_depth - 1];
}
void _XOR() {
Stack[stack_depth - 2] ^= Stack[stack_depth - 1];
stack_depth--;
}
void _1PLUS() {
Stack[stack_depth - 1]++;
}
void _1MINUS() {
Stack[stack_depth - 1]--;
}
void _2PLUS() {
Stack[stack_depth - 1] += 2;
}
void _2MINUS() {
Stack[stack_depth - 1] -= 2;
}
void _2MUL() {
Stack[stack_depth - 1] <<= 1;
}
void _2DIV() {
Stack[stack_depth - 1] >>= 1;
}
void _PLUS() {
Stack[stack_depth - 2] += Stack[stack_depth - 1];
stack_depth--;
}
void _MINUS() {
Stack[stack_depth - 2] -= Stack[stack_depth - 1];
stack_depth--;
}
void _MUL() {
Stack[stack_depth - 2] *= Stack[stack_depth - 1];
stack_depth--;
}
void _NEGATE() {
Stack[stack_depth - 1] *= -1;
}
void _ABS() {
Stack[stack_depth - 1] *= Stack[stack_depth - 1] < 0 ? -1 : 1;
}
void _MIN() {
Stack[stack_depth - 2] = Stack[stack_depth - 2] < Stack[stack_depth - 1] ? Stack[stack_depth - 2] : Stack[stack_depth - 1];
stack_depth--;
}
void _MAX() {
Stack[stack_depth - 2] = Stack[stack_depth - 2] > Stack[stack_depth - 1] ? Stack[stack_depth - 2] : Stack[stack_depth - 1];
stack_depth--;
}
void _DIV() {
Stack[stack_depth - 2] /= Stack[stack_depth - 1];
stack_depth--;
}
void _MOD() {
Stack[stack_depth - 2] %= Stack[stack_depth - 1];
stack_depth--;
}
void _MULDIV() {
long a = Stack[stack_depth - 3];
a *= Stack[stack_depth - 2];
Stack[stack_depth - 3] = a / Stack[stack_depth - 1];
stack_depth -= 2;
}
void _EQUAL() {
Stack[stack_depth - 2] = Stack[stack_depth - 2] == Stack[stack_depth - 1] ? -1 : 0;
stack_depth--;
}
void _LESS() {
Stack[stack_depth - 2] = Stack[stack_depth - 2] < Stack[stack_depth - 1] ? -1 : 0;
stack_depth--;
}
void _GREATER() {
Stack[stack_depth - 2] = Stack[stack_depth - 2] > Stack[stack_depth - 1] ? -1 : 0;
stack_depth--;
}
void _IS0() {
Stack[stack_depth - 1] = Stack[stack_depth - 1] == 0 ? -1 : 0;
}
void _LESS0() {
Stack[stack_depth - 1] = Stack[stack_depth - 1] < 0 ? -1 : 0;
}
void _GREATER0() {
Stack[stack_depth - 1] = Stack[stack_depth - 1] > 0 ? -1 : 0;
}
// Словарь
void (*forth[40])() = { _DROP, _DUP, _SWAP, _OVER, _ROT, _nROT, _SPi, _SPa, _2DROP, _2OVER,
_2SWAP, _PICK, _ROLL, _DEPTH, _AND, _OR, _NOT, _XOR, _1PLUS, _1MINUS,
_2PLUS, _2MINUS, _2MUL, _2DIV, _PLUS, _MINUS, _MUL, _NEGATE, _ABS, _MIN,
_MAX, _DIV, _MOD, _MULDIV, _EQUAL, _LESS, _GREATER, _IS0, _LESS0, _GREATER0 };
PROGMEM const char words[] = "DROP DUP SWAP OVER ROT -ROT SP! SP@ 2DROP 2OVER "
"2SWAP PICK ROLL DEPTH AND OR NOT XOR 1+ 1- "
"2+ 2- 2* 2/ + - * NEGATE ABS MIN "
"MAX / MOD */ = < > 0= 0< 0> "
"?DUP";
void setup() {
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print(" FORTH");
}
String input_word(int n) {
char buf[16] = "Not Found";
int i = 0; // Счётчик букв в PROGMEM const
int j = 0; // Счётчик пробелов
int k = 0; // Счётчик букв в buf
char a = 'x';
while (a != 0) {
a = pgm_read_byte_near(words + i);
if (j == n) {
buf[k] = a;
k++;
}
if (a == ' ') {
j++;
}
if (j > n) {
buf[k] = 0;
break;
}
i++;
}
return buf;
}
void type() { // Вывод на экран
lcd.setCursor(0, 0); // Размер и содержимое стека
lcd.print(" ");
lcd.setCursor(0, 0);
lcd.print(stack_depth);
lcd.print(':');
for (int i = stack_depth - 1; i >= 0; i--) {
lcd.print(Stack[i]);
if (i != 0) {
lcd.print(',');
}
}
if (input_command == 0) { // Вывод числа или ошибки
lcd.setCursor(0, 1);
lcd.print(" ");
lcd.setCursor(0, 1);
if (!error) {
lcd.print(input_value);
} else {
lcd.print("ERROR ");
lcd.print(error);
}
} else { // Вывод слова
lcd.setCursor(0, 1);
lcd.print(" ");
lcd.setCursor(0, 1);
if (input_command < 10) {
lcd.print("Enter Word: ");
lcd.print(char(input_command + 64));
} else {
lcd.print(input_word(input_command - 10));
}
}
}
void run(int n) { // Обработка ошибок связанных со стеком
forth[n]();
}
void loop() { // Интерактивный режим
char customKey = customKeypad.getKey();
if (customKey) {
error = 0;
int x = int(customKey);
if (input_command == 0) { // Ввод числа
if (x > 47 && x < 58) {
input_value = input_value * 10 + x - 48;
}
}
if (input_value == 0) { // Ввод слова
if (input_command == 0 && x > 64 && x < 69) { // Ввод буквы
input_command = x - 64;
}
if (input_command < 10 && x > 47 && x < 58) { // Ввод цифры
input_command = input_command * 10 + x - 48;
}
}
if (customKey == '#') { // Очистить ввод
input_value = 0;
input_command = 0;
}
if (customKey == '*') { // Выполнить (Enter)
if (input_command == 0) { // Положить число на стек
Stack[stack_depth] = input_value;
stack_depth++;
input_value = 0;
}
if (input_command > 9) { // Выполнить слово
run(input_command - 10);
input_command = 0;
}
}
type();
}
}
Лист. 1.
Рис. 6.
Рис. 6.
#include <LiquidCrystal_I2C.h>
#include <Keypad.h>
#define DROP _DROP();
#define PICK _PICK();
LiquidCrystal_I2C lcd(0x27, 16, 2);
char hexaKeys[4][4] = {
{ '1', '4', '7', '*' },
{ '2', '5', '8', '0' },
{ '3', '6', '9', '#' },
{ 'A', 'B', 'C', 'D' }
};
byte rowPins[4] = { 6, 7, 8, 9 };
byte colPins[4] = { 5, 4, 3, 2 };
Keypad customKeypad = Keypad(makeKeymap(hexaKeys), rowPins, colPins, 4, 4);
int input_value = 0; // Вводимое число
int input_command = 0; // Номер вводимого слова
int Stack[128]; // Арифметический стек
int stack_depth = 0; // Глубина арифметического стека
int error = 0; // Номер ошибки
void _DROP() {
stack_depth--;
}
void _DUP() {
Stack[stack_depth] = Stack[stack_depth - 1];
stack_depth++;
}
void _SWAP() {
int a = Stack[stack_depth - 1];
Stack[stack_depth - 1] = Stack[stack_depth - 2];
Stack[stack_depth - 2] = a;
}
void _OVER() {
Stack[stack_depth] = Stack[stack_depth - 2];
stack_depth++;
}
void _ROT() {
int a = Stack[stack_depth - 3];
Stack[stack_depth - 3] = Stack[stack_depth - 2];
Stack[stack_depth - 2] = Stack[stack_depth - 1];
Stack[stack_depth - 1] = a;
}
void _nROT() {
int a = Stack[stack_depth - 3];
Stack[stack_depth - 3] = Stack[stack_depth - 1];
Stack[stack_depth - 1] = Stack[stack_depth - 2];
Stack[stack_depth - 2] = a;
}
void _SPi() {
stack_depth = 0;
}
void _SPa() {
Stack[stack_depth] = stack_depth;
stack_depth++;
}
void _2DROP() {
DROP DROP
}
void _2OVER() {
Stack[stack_depth] = Stack[stack_depth - 4];
Stack[stack_depth + 1] = Stack[stack_depth - 3];
stack_depth += 2;
}
void _2SWAP() {
int a = Stack[stack_depth - 1];
Stack[stack_depth - 1] = Stack[stack_depth - 3];
Stack[stack_depth - 3] = a;
a = Stack[stack_depth - 2];
Stack[stack_depth - 2] = Stack[stack_depth - 4];
Stack[stack_depth - 4] = a;
}
void _PICK() {
Stack[stack_depth - 1] = Stack[stack_depth - 2 - Stack[stack_depth - 1]];
}
void _ROLL() {
int n = Stack[stack_depth - 1];
PICK;
for (n; n > 0; n--) {
Stack[stack_depth - n] = Stack[stack_depth + 1 - n];
}
stack_depth--;
}
void _DEPTH() {
Stack[stack_depth] = stack_depth;
stack_depth++;
}
void _AND() {
Stack[stack_depth - 2] &= Stack[stack_depth - 1];
stack_depth--;
}
void _OR() {
Stack[stack_depth - 2] |= Stack[stack_depth - 1];
stack_depth--;
}
void _NOT() {
Stack[stack_depth - 1] = ~Stack[stack_depth - 1];
}
void _XOR() {
Stack[stack_depth - 2] ^= Stack[stack_depth - 1];
stack_depth--;
}
void _1PLUS() {
Stack[stack_depth - 1]++;
}
void _1MINUS() {
Stack[stack_depth - 1]--;
}
void _2PLUS() {
Stack[stack_depth - 1] += 2;
}
void _2MINUS() {
Stack[stack_depth - 1] -= 2;
}
void _2MUL() {
Stack[stack_depth - 1] <<= 1;
}
void _2DIV() {
Stack[stack_depth - 1] >>= 1;
}
void _PLUS() {
Stack[stack_depth - 2] += Stack[stack_depth - 1];
stack_depth--;
}
void _MINUS() {
Stack[stack_depth - 2] -= Stack[stack_depth - 1];
stack_depth--;
}
void _MUL() {
Stack[stack_depth - 2] *= Stack[stack_depth - 1];
stack_depth--;
}
void _NEGATE() {
Stack[stack_depth - 1] *= -1;
}
void _ABS() {
Stack[stack_depth - 1] *= Stack[stack_depth - 1] < 0 ? -1 : 1;
}
void _MIN() {
Stack[stack_depth - 2] = Stack[stack_depth - 2] < Stack[stack_depth - 1] ? Stack[stack_depth - 2] : Stack[stack_depth - 1];
stack_depth--;
}
void _MAX() {
Stack[stack_depth - 2] = Stack[stack_depth - 2] > Stack[stack_depth - 1] ? Stack[stack_depth - 2] : Stack[stack_depth - 1];
stack_depth--;
}
void _DIV() {
Stack[stack_depth - 2] /= Stack[stack_depth - 1];
stack_depth--;
}
void _MOD() {
Stack[stack_depth - 2] %= Stack[stack_depth - 1];
stack_depth--;
}
void _MULDIV() {
long a = Stack[stack_depth - 3];
a *= Stack[stack_depth - 2];
Stack[stack_depth - 3] = a / Stack[stack_depth - 1];
stack_depth -= 2;
}
void _EQUAL() {
Stack[stack_depth - 2] = Stack[stack_depth - 2] == Stack[stack_depth - 1] ? -1 : 0;
stack_depth--;
}
void _LESS() {
Stack[stack_depth - 2] = Stack[stack_depth - 2] < Stack[stack_depth - 1] ? -1 : 0;
stack_depth--;
}
void _GREATER() {
Stack[stack_depth - 2] = Stack[stack_depth - 2] > Stack[stack_depth - 1] ? -1 : 0;
stack_depth--;
}
void _IS0() {
Stack[stack_depth - 1] = Stack[stack_depth - 1] == 0 ? -1 : 0;
}
void _LESS0() {
Stack[stack_depth - 1] = Stack[stack_depth - 1] < 0 ? -1 : 0;
}
void _GREATER0() {
Stack[stack_depth - 1] = Stack[stack_depth - 1] > 0 ? -1 : 0;
}
// Словарь
void (*forth[40])() = { _DROP, _DUP, _SWAP, _OVER, _ROT, _nROT, _SPi, _SPa, _2DROP, _2OVER,
_2SWAP, _PICK, _ROLL, _DEPTH, _AND, _OR, _NOT, _XOR, _1PLUS, _1MINUS,
_2PLUS, _2MINUS, _2MUL, _2DIV, _PLUS, _MINUS, _MUL, _NEGATE, _ABS, _MIN,
_MAX, _DIV, _MOD, _MULDIV, _EQUAL, _LESS, _GREATER, _IS0, _LESS0, _GREATER0 };
PROGMEM const char words[] = "DROP DUP SWAP OVER ROT -ROT SP! SP@ 2DROP 2OVER "
"2SWAP PICK ROLL DEPTH AND OR NOT XOR 1+ 1- "
"2+ 2- 2* 2/ + - * NEGATE ABS MIN "
"MAX / MOD */ = < > 0= 0< 0> "
"?DUP";
void setup() {
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print(" FORTH");
}
String input_word(int n) {
char buf[16] = "Not Found";
int i = 0; // Счётчик букв в PROGMEM const
int j = 0; // Счётчик пробелов
int k = 0; // Счётчик букв в buf
char a = 'x';
while (a != 0) {
a = pgm_read_byte_near(words + i);
if (j == n) {
buf[k] = a;
k++;
}
if (a == ' ') {
j++;
}
if (j > n) {
buf[k] = 0;
break;
}
i++;
}
return buf;
}
void type() { // Вывод на экран
lcd.setCursor(0, 0); // Размер и содержимое стека
lcd.print(" ");
lcd.setCursor(0, 0);
lcd.print(stack_depth);
lcd.print(':');
for (int i = stack_depth - 1; i >= 0; i--) {
lcd.print(Stack[i]);
if (i != 0) {
lcd.print(',');
}
}
if (input_command == 0) { // Вывод числа или ошибки
lcd.setCursor(0, 1);
lcd.print(" ");
lcd.setCursor(0, 1);
if (!error) {
lcd.print(input_value);
} else {
lcd.print("ERROR ");
lcd.print(error);
}
} else { // Вывод слова
lcd.setCursor(0, 1);
lcd.print(" ");
lcd.setCursor(0, 1);
if (input_command < 10) {
lcd.print("Enter Word: ");
lcd.print(char(input_command + 64));
} else {
lcd.print(input_word(input_command - 10));
}
}
}
void run(int n) { // Обработка ошибок связанных со стеком
forth[n]();
}
void loop() { // Интерактивный режим
char customKey = customKeypad.getKey();
if (customKey) {
error = 0;
int x = int(customKey);
if (input_command == 0) { // Ввод числа
if (x > 47 && x < 58) {
input_value = input_value * 10 + x - 48;
}
}
if (input_value == 0) { // Ввод слова
if (input_command == 0 && x > 64 && x < 69) { // Ввод буквы
input_command = x - 64;
}
if (input_command < 10 && x > 47 && x < 58) { // Ввод цифры
input_command = input_command * 10 + x - 48;
}
}
if (customKey == '#') { // Очистить ввод
input_value = 0;
input_command = 0;
}
if (customKey == '*') { // Выполнить (Enter)
if (input_command == 0) { // Положить число на стек
Stack[stack_depth] = input_value;
stack_depth++;
input_value = 0;
}
if (input_command > 9) { // Выполнить слово
run(input_command - 10);
input_command = 0;
}
}
type();
}
}
Лист. 2.