Каллисто Классик — релиз первого Форта для «Электроники МК-161».

Рад представить вам сегодня Каллисто Классик, входной язык для «Электроники МК-161». С момента задумки прошло 3 года, 2 месяца и 12 дней — и она успешно реализована. МК-161 обрела новый входной язык, день рождения которого сегодня — 7 ноября 2017 года.

Каллисто можно скачать отсюда: the-hacker.ru/2017/Callisto-1.zip (25 Мб)

Завершающее тестирование Каллисто перед публикацией заняло 1 год. Серьёзных проблем в коде транслятора не было обнаружено, поэтому версия 1.0 практически повторяет стабильную версию 1.0rc2, выпущенную год назад. Вместе с тем первые тестеры натыкались на некоторые проблемы, которые нашли своё отражение в документации. Новая глава 14 Руководства даже названа «Решение проблем».

Также была проведена оптимизация кода, включая глубокую оптимизацию межстраничных переходов. Всё это предоставило разработчикам 117 шагов памяти программ для расширения языка. Да, длина Каллисто 9883 шага, а её исходный код занимает 4173 строки на расширенном входном языке МК. Часть нового кода предназначена для облечения будущего перехода на Каллисто-2.

Важные изменения коснулись Руководства по языку (pdf, 9Мб). Все приведённые примеры не просто ещё раз проверены на работоспособность, теперь текст Руководства снабжён иллюстрациями на основе снимков экрана «железной» «Электроники МК-161». В Руководство добавлена страница с формальным описанием языка в РБНФ (18 правил). Описание не является исчерпывающим, но помогает ознакомиться с языком. Также у Руководства появилась красивая обложка. Не стоит забывать про файл words.txt, где каждое из 302 встроенных слов получило описание в одну строчку, включая стековую диаграмму.

Вики по ПМК и ЭКВМ начинает обновляться для полного соответствия с релизом.

Теперь путь для работы над Каллисто-2 расчищен. Работа над первой версией языка выявила узкие места и дала объективные цифры, помогающие улучшить его производительность.

UPDATE. По тесту «пустой цикл» Каллисто 1.0 медленнее заводского языка «Электроники МК-161» в 44,5 раз и быстрее советской «Электроники МК 56» в 18,9 раз.

Метки публикаций: 
Русский

Комментарии

Это обычный текстовый файл в кодировке UTF-8, автоматически сгенерированный из исходного текста Каллисто. Он не затачивался специально под браузеры. Его можно скачать и открыть в текстовом редакторе, можно взять из zip'а. В браузерах надо выбирать кодировку, например:
Firefox: View → Text Encoding → Unicode
Safari: View → Text Encoding → Unicode (UTF-8)

EDIT. Сейчас проверил. У меня помогает переключиться сперва на любую кодировку, потом обратно на UTF-8.

Глоссарий Каллисто 1.0


1904 ↑                ( x −− x x )                         Дублировать.
2243 !                ( y a −− )                           Присвоить. Записать y в ячейку с адресом a.
2294 !CSP             ( −− )                               Запомнить адрес вершины стека в CSP.
1760 !RP              ( −− )                               Восстановить RP. Присвоить указателю стека возвратов исходное значение из переменной R0.
1741 !SP              ( −− )                               Восстановить SP. Присвоить указателю стека данных исходное значение из переменной S0.
3615 '                ( −− т )                             Дать токен (CFA) следующего слова.
3605 'N               ( −− a )                             Искать следующее слово, вернуть его NFA.
3418 (              I ( −− )                               Комментарий. Игнорировать входные литеры до закрывающей круглой скобки.
3102 (.")             ( −− )                               Слово, компилируемое в ."
3817 (.)              ( n −− a c )                         Преобразовать целое n в строку, вернуть её адрес a и длину c.
3073 (;CODE)          ( −− )                               Записать в поле кода LAST следующий адрес и EXIT (слово без заголовка).
 740 (FIND)           ( a1 a2 −− a3 c 1 | 0 )              Поиск слова a1 в словаре a2. Если найдено, вернуть nfa и байт счётчика.
 682 (FOR)            ( n −− )                             Начало цикла со счётчиком в шитом коде (слово без заголовка).
3519 (LINE)           ( c1 c2 −− a c )                     Вернуть адрес и длину строки номер c1 с экрана c2.
 587 (LITERAL)        ( −− x )                             Код периода выполнения для литерала.
 702 (NEXT)           ( −− )                               Конец цикла со счётчиком в шитом коде (слово без заголовка).
1040 (PLAY)           ( a u −− )                           Играть музыку. Проиграть u нот, начиная с адреса a.
 831 (ИП)             ( −− x )                             Считать регистр МК−161, указанный в шитом коде.
1330 +                ( y x −− x1 )                        Сложить. x1 := y+x
2065 +!               ( y a −− )                           Увеличить на y содержимое ячейки с адресом a.
2087 ++!              ( y a −− )                           Косвенная запись y по указателю в a с предварительным автоувеличением (аналог КП4..КП6).
2201 ++@              ( a −− x )                           Косвенное чтение по указателю в a с предварительным автоувеличением (аналог КИП4..КИП6).
1110 +BOX             ( c1 c2 −− )                         Нарисовать на индикаторе прямоугольник шириной c1 высотой c2.
1120 +FRAME           ( c1 c2 −− )                         Нарисовать на индикаторе рамку шириной c1 высотой c2.
2939 ,                ( d −− )                             Скомпилировать d в первую свободную ячейку словаря.
1340 −                ( y x −− x1 )                        Вычесть. x1 := y−x
2120 −−!              ( y a −− )                           Косвенная запись y по указателю в a с предварительным автоуменьшением (аналог КП0..КП3).
2228 −−@              ( a −− x )                           Косвенное чтение по указателю в a с предварительным автоуменьшением (аналог КИП0..КИП3).
2387 −TRAILING        ( a U1 −− a U2 )                     Отсечь конечные пробелы.
3832 .                ( x −− )                             Вывести x на индикатор и дать пробел. Совпадает с I. если BASE≠10.
3112 ."             I ( −− )                               При исполнении вывести строку, ограниченную кавычкой.
3124 .(             I ( −− )                               При компиляции вывести строку, вплоть до закрывающей скобки.
3926 .S               ( −− )                               Напечатать стек, вершина справа.
1369 /                ( y x −− n )                         Делить нацело. n := Trunc [y/x]
1426 /−/              ( x −− x1 )                          Сменить знак числа. x1 := −x
1389 /MOD             ( y x −− y1 n )                      Делить y на x с частным n и остатком y1. n := Trunc [y/x], y1 := y mod x
2260 0!               ( a −− )                             Обнулить. Записывает ноль в ячейку с адресом a.
 893 0<               ( x −− f )                           Проверить на отрицательность.
 870 0=               ( x −− f )                           Проверить на равенство нулю.
 880 0>               ( x −− f )                           Проверить на положительность.
2654 1                ( −− 1 )                             Число 1.
1272 1+               ( x −− x1 )                          Увеличить. x1 := x+1
1300 1−               ( x −− x1 )                          Уменьшить. x1 := x−1
1614 1/X              ( x −− x1 )                          Обратная величина. x1 := 1/x
1564 10ˣ              ( x −− p )                           Десятичный антилогарифм. p := 10ˣ
2661 2                ( −− 2 )                             Число 2.
1279 2+               ( x −− x1 )                          Прибавить два. x1 := x+2
1323 2−               ( x −− x1 )                          Вычесть два. x1 := x−2
1315 2/               ( x −− n )                           Половина. n := Trunc [x/2]
1947 2DROP            ( y x −− )                           Убрать пару чисел.
1920 2DUP             ( y x −− y x y x )                   Дублировать пару чисел.
1892 2SWAP            ( t z y x −− y x t z )               Обменять две пары.
1307 2×               ( x −− x1 )                          Удвоить. x1 := x×2
2461 :                ( −− )                               Начать определение слова через двоеточие.
2511 ;              I ( −− )                               Закончить определение через двоеточие.
 911 <                ( y x −− f )                         Меньше. f равно −1 если и только если y меньше, чем x.
3803 <#               ( −− )                               Начать форматное преобразование целого числа.
3086 <BUILDS          ( −− )                               Начать определяющую часть порождающего слова.
3810 <F#              ( −− )                               Начать форматное преобразование десятичного числа.
3647 <MARK            ( −− a )                             Отметить текущий адрес для ссылки назад.
3654 <RESOLVE         ( a −− )                             Разрешить ссылку назад в адрес a.
 900 =                ( y x −− f )                         Равно. Проверить на равенство.
 921 >                ( y x −− f )                         Больше. f равно −1 если и только если y больше, чем x.
1434 ><               ( U −− U1 )                          Обменять старший и младший байты в 16−битном числе U.
1293 >BODY            ( т −− a )                           К телу. Преобразовать адрес поля кода в адрес поля параметров.
2826 >IN              ( −− a )                             Переменная, внутренний указатель входного буфера (0..3071).
3630 >MARK            ( −− a )                             Отметить текущий адрес для ссылки вперёд.
1795 >R               ( d −− )                             Перенести d на стек возвратов.
3637 >RESOLVE         ( a −− )                             Разрешить ссылку вперёд в адресе a.
3853 ?                ( a −− )                             Вывести значение ячейки по адресу a.
 648 ?BRANCH          ( ф −− )                             Условное ветвление. Переход в шитом коде, если ф=0.
 566 ?BREAK           ( −− )                               Проверить клавиатуру на паузу и аварийную остановку.
3012 ?COMP            ( −− )                               Сгенерировать ошибку 17, если нет состояния компиляции.
3039 ?CSP             ( −− )                               Сгенерировать ошибку 20, если указатель стека отличен от CSP.
1911 ?DUP             ( x −− 0 | x x )                     Дублировать, если x≠0.
3003 ?ERROR           ( ф c −− )                           Сгенерировать ошибку номер c, если флаг ф истинен (ф≠0).
3021 ?EXEC            ( −− )                               Сгенерировать ошибку 18, если нет состояния исполнения.
3048 ?LOADING         ( −− )                               Сгенерировать ошибку 22, если входной текст идёт не с экрана.
3030 ?PAIRS           ( y x −− )                           Сгенерировать ошибку 19, если x отлично от y.
3374 ?STACK           ( −− )                               Сгенерировать ошибку 1, если стек вычерпан (или переполнен).
2148 @                ( a −− x )                           Извлечь. Считать значение ячейки по адресу a.
3443 ABORT            ( −− )                               Очистить стек, установив набор слов FORTH, и молча сделать QUIT.
1211 ACCEPT           ( a c1 −− c2 )                       Ввести с клавиатуры строку в буфер с адресом a длиной c1. c2 −− число введённых литер.
3671 AGAIN          I ( −− )                               Перейти к началу бесконечого цикла BEGIN AGAIN.
2313 ALLOT            ( D −− )                             Занять. Сместить вершину словаря на n байт.
1462 AND              ( n1 n2 −− i )                       32−битное логическое умножение (и). i := n1 & n2
2791 APP              ( −− a )                             Переменная, токен запускающего слова.
1690 ARCCOS           ( x −− x1 )                          Арккосинус. x1 := arccos x
1682 ARCSIN           ( x −− x1 )                          Арксинус. x1 := arcsin x
1698 ARCTG            ( x −− x1 )                          Арктангенс. x1 := arctg x
1143 AT               ( c1 c2 −− )                         Установить курсор в столбец c1 строки c2.
2740 ATR!             ( c −− )                             Установить атрибут вывода на индикатор c (0..7).
2699 B/BUF            ( −− 3072 )                          Размер буфера в байтах. Число 3072.
1099 BAR              ( c1 c2 −− )                         Прочертить линию на индикаторе до точки (x,y)=(c1,c2).
2866 BASE             ( −− a )                             Переменная, основание системы счисления для ввода−вывода чисел.
1027 BEEP             ( p1 p2 −− )                         Пищать. Издать звук частотой p1 Гц и длительностью p2 × 10 мс.
3678 BEGIN          I ( −− )                               Начало циклов "BEGIN".
1019 BELL             ( −− )                               Звонок. Озвучить гудок терминала.
2683 BL               ( −− 32 )                            Пробел. Число 32.
2032 BLANK            ( a U −− )                           Опробелить. Записать U пробелов в память, начиная с адреса a.
2817 BLK              ( −− a )                             Переменная, номер интерпретируемого блока.
3499 BLOCK            ( c −− a )                           Убедиться, что в буфере блок c. Дать адрес буфера.
2287 BODY>            ( a −− т )                           От тела. От поля параметров к полю кода.
 665 BRANCH           ( −− )                               Ветвление. Безусловный переход в шитом коде.
2451 BUF#             ( −− a )                             Переменная. Номер блока, загруженного в буфер.
3484 BUFFER           ( c −− a )                           Приписать буферу блок c и дать адрес буфера. Сам блок с диска не считывать.
 523 BYE              ( −− )                               Выйти из Каллисто в калькулятор МК−161.
2273 C!               ( y a −− )                           Записать байт y по адресу a.
2947 C,               ( b −− )                             Скомпилировать b в первый свободный байт словаря.
1004 C.               ( c −− )                             Отобразить литеру, заменяя управляющие на прямоугольники.
2692 C/L              ( −− 64 )                            Длина строки. Число 64.
2187 C@               ( a −− x )                           Извлечь байт. Считать значение по адресу a.
 542 CLD              ( −− )                               Очистить RD в энергонезависимой памяти.
1964 CMOVE            ( a1 a2 U −− )                       Копировать U байтов из a1 в a2.
1984 CMOVE>           ( a1 a2 U −− )                       Копировать U байтов из a1 в a2, начиная с больших адресов.
 421 COLD             ( −− )                               Холодная перезагрузка, со сбросом словарей.
3057 COMPILE          ( −− )                               Скомпилировать токен −− пару байт, следующих за COMPILE.
2518 CONSTANT         ( D −− )                             Определить следующее слово, как константу со значением D.
2842 CONTEXT          ( −− a )                             Переменная, контекстный список слов.
3899 COPY             ( c1 c2 −− )                         Копировать блок c1 в блок c2.
1714 COS              ( x −− x1 )                          Косинус. x1 := cos x
3095 COUNT            ( a −− a1 U )                        Подсчитать. Дать адрес a1 и длину U строки со счётчиком a.
3311 CREATE           ( −− )                               Создать начало статьи (до PFA) для следующего слова.
2882 CSP              ( −− a )                             Переменная, контрольное значение указателя стека данных.
2850 CURRENT          ( −− a )                             Переменная, текущий пополняемый список слов.
1069 DARK             ( −− )                               Установить вывод на индикатор тёмным по светлому.
2379 DECIMAL          ( −− )                               Установить десятичную систему счисления для ввода−вывода.
2567 DEFER            ( −− )                               Определить следующее слово, как действие с начальным значением НОП (нет операции).
2434 DEFINITIONS      ( −− )                               Сделать контекстный набор слов текущим. Новые слова добавляются в него.
1665 DEGREES          ( −− )                               Градусы. Установить градусную меру измерения угла.
3908 DEPTH            ( −− U )                             Глубина стека. U −− количество значений на стеке данных до исполнения DEPTH.
 796 DIGIT            ( c u1 −− u2 1 | 0 )                 Цифра. Преобразовать литеру c в число u2, используя основание u1.
1171 DISKOFF          ( −− )                               Запретить дисковые операции.
2597 DOES>            ( −− a )                             Начало обработчика в порождающем слове.
1078 DOT!             ( c1 c2 −− )                         Отобразить точку на индикаторе в колонке c1 строки c2.
2874 DPL              ( −− a )                             Переменная, позиция последней запятой в последнем введённом числе от конца.
1955 DROP             ( x −− )                             Убрать. Удалить верхний элемент стека.
3915 DUMP             ( a c −− )                           Дамп. Вывести c байт от адреса a.
2908 EE               ( −− a )                             Переменная, порядок вводимого числа.
1188 EKEY             ( −− c )                             Подождать нажатия клавиши и получить её код.
3693 ELSE           I ( −− )                               Начало второй ветви ветвления IF.
 972 EMI              ( c n −− )                           Вывод нескольких литер на индикатор.
 985 EMIT             ( c −− )                             Отобразить литеру.
3456 EMPTY−BUFFERS    ( −− )                               Очистить буфер, независимо от содержания. Ничего на диск не записывать.
 931 ENCLOSE          ( a1 c −− a2 u1 u2 )                 Окружить. Выделить лексему с адреса a1 и ограничительной литерой c.
2025 ERASE            ( a U −− )                           Стереть. Записать U нулей в память, начиная с адреса a.
2916 ERB              ( −− a )                             Переменная, флаг блокировки выхода в QUIT при ошибке ERROR.
3290 ERROR            ( c −− )                             Вывести сообщение об ошибке c и уйти в QUIT если ERB=0.
 553 EXECUTE          ( т −− )                             Исполнить слово с токеном т (CFA).
1769 EXIT             ( −− )                               Закончить исполнение текущего определения.
1573 Eˣ               ( x −− p )                           Экспонента. p := eˣ
3755 F#>              ( −− a c )                           Завершить преобразование десятичного числа. Дать адрес и длину для TYPE.
2626 F#S              ( x −− )                             Преобразовать десятичное число.
2647 FALSE            ( −− 0 )                             Ложь. Число 0.
2001 FILL             ( a U c −− )                         Заполнить. Записать U байтов c, начиная с адреса a.
3196 FINDN            ( a −− a1 c 1 | 0 )                  Найти слово в активных наборах. При успехе дать NFA и байт счётчика.
3279 FL               ( n −− x )                           Преобразовать возвращённое NUMBER целое в десятичное число.
3364 FLITERAL       I ( x −− | x )                         Скомпилировать x в литерал. В режиме исполнения оставляет x на стеке.
3475 FLUSH            ( −− )                               Если буфер изменён, сохранить на диск. Очистить буфер.
1150 FONT!            ( u −− )                             Установить на индикаторе шрифт u (0−2).
3722 FOR            I ( n −− )                             Повторить n раз цикл FOR NEXT. Если n<=0, цикл не исполнять.
 459 FORTH            ( −− )                               Сделать набор слов FORTH контекстным.
2540 FVARIABLE        ( −− )                               Определить следующее слово, как десятичную переменную с начальным значением 0.
2775 H                ( −− a )                             Переменная, адрес вершины словаря.
2304 HERE             ( −− a )                             Здесь. Дать адрес текущей вершины словаря.
2368 HEX              ( −− )                               Установить шестнадцатеричную систему счисления для ввода−вывода.
2900 HLD              ( −− a )                             Переменная, указатель вершины буфера PAD.
2039 HOLD             ( c −− )                             Перенести литеру c на вершину буфера PAD.
1829 I                ( −− U )                             Значение счётчика цикла FOR.
3824 I.               ( n −− )                             Вывести целое n на индикатор и дать пробел.
3843 I.R              ( n c −− )                           Вывести целое n на индикатор в поле длиной c справа.
3303 ID.              ( a −− )                             Напечатать имя слова (по NFA) и дать пробел.
3700 IF             I ( ф −− )                             Если ф ложен (ф=0), перейти к парному THEN (или ELSE).
3397 IMMEDIATE        ( −− )                               Изменить признак IMMEDIATE последней созданной статьи.
3877 INDEX            ( c1 c2 −− )                         Вывести начальную строку экранов с номерами от c1 до c2.
1200 INKEY            ( −− b )                             Получить код нажатой клавиши или −1, если клавиши не нажаты.
3382 INTERPRET        ( −− )                               Интерпретировать входной поток.
1839 J                ( −− U )                             Значение счётчика внешнего цикла FOR.
1848 K                ( −− U )                             Значение счётчика третьего объемлющего цикла FOR.
2801 KBDFLG           ( −− a )                             Переменная, двухбайтовый флаг клавиатуры.
1181 KEY              ( −− c )                             Ввести литеру с клавиатуры.
2961 LAST             ( −− a )                             Дать NFA последней созданной статьи.
1776 LEAVE            ( −− )                               Выйти из цикла FOR досрочно.
1582 LG               ( p −− x )                           Десятичный логарифм. x := lg p
1060 LIGHT            ( −− )                               Установить вывод на индикатор светлым по тёмному.
3862 LIST             ( c −− )                             Вывести экран c и записать его номер в переменную SCR.
3352 LITERAL        I ( D −− | D )                         Скомпилировать D в литерал. В режиме исполнения оставить D на стеке.
1590 LN               ( p −− x )                           Натуральный логарифм. x := ln p
3575 LOAD             ( c −− )                             Загрузить с диска и интерпретировать экран номер c.
4146 LOAD"            ( −− )                               Восстановить сеанс из файлов D/B с именем, взятым из входного потока.
4059 LORW             ( a c −− )                           Считать/записать (c=1/0) блок из файла с именем из 4 литер по адресу a.
1553 MAX              ( y x −− x1 )                        Большее из двух чисел. x1 := max (x, y)
3530 MESSAGE          ( c −− )                             Сохранить >IN в R# и вывести сообщение номер c.
1543 MIN              ( y x −− x1 )                        Меньшее из двух чисел. x1 := min (x, y)
1379 MOD              ( y x −− x1 )                        Получить остаток от деления y на x. x1 := y mod x
2993 N>BODY           ( a1 −− a2 )                         От имени к телу. Преобразовать NFA в PFA.
2976 N>LINK           ( a1 −− a2 )                         От имени к связи. Преобразовать NFA в LFA.
2983 NAME>            ( a −− т )                           Получить токен по имени. Преобразовать NFA в CFA.
3731 NEXT           I ( −− )                               Вернуться к FOR, если ещё остались повторения цикла.
1534 NOT              ( n −− i )                           32−битная логическая инверсия (не). i := ∼n
3212 NUMBER           ( a −− n )                           Преобразовать строку в целое число n, начиная с a+1.
1487 OR               ( n1 n2 −− i )                       32−битное логическое сложение (или). i := n1 ∨ n2
1875 OVER             ( y x −− y x y )                     Дублировать второй сверху.
3158 PAD              ( −− a )                             Адрес буфера промежуточного хранения последовательности литер.
1865 PICK             ( xu .. x1 x0 u −− xu .. x1 x0 xu )  Дублировать u−ное сверху.
3135 QUERY            ( −− )                               Ввести строку с пульта в TIB, ограничив её двумя нулями.
3428 QUIT             ( −− )                               Передать управление на пульт. Ждать команд молча, без приглашения.
2890 R#               ( −− a )                             Переменная, позиция курсора при редактировании экрана или возникновении ошибки.
2759 R0               ( −− a )                             Переменная, адрес дна стека возвратов.
1808 R>               ( −− D )                             Переместить D из стека возвратов на стек данных.
1821 R@               ( −− D )                             Скопировать значение D со стека возвратов.
1673 RADIANS          ( −− )                               Радианы. Установить радианную меру измерения угла.
1856 RDROP            ( −− )                               Удалить верхний адрес со стека возвратов.
3715 REPEAT         I ( −− )                               Вернуться к самому началу цикла BEGIN WHILE REPEAT.
4011 RGRW             ( a c1 c2 −− c )                     Считать/записать (c2=1/0) десятичный/двоичный (c1=4/2) файл с именем из 20 литер по адресу a+1.
1927 ROT              ( z y x −− y x z )                   Вращать. Перенести наверх третий сверху.
1752 RP@              ( −− a )                             Считать RP. Адрес текущей вершины стека возвратов.
2708 RT               ( −− a )                             Десятичная переменная, куда сохраняется регистр T стека МК−161.
2732 RX               ( −− a )                             Десятичная переменная, куда сохраняется регистр X стека МК−161.
2724 RY               ( −− a )                             Десятичная переменная, куда сохраняется регистр Y стека МК−161.
2716 RZ               ( −− a )                             Десятичная переменная, куда сохраняется регистр Z стека МК−161.
2751 S0               ( −− a )                             Переменная, адрес дна стека данных.
1444 S>D              ( n −− u1 u2 )                       Преобразовать 32−битное число n в пару 16−битных чисел u2 u1.
4123 SAVE"            ( −− )                               Сохранить сеанс в файлы D/B с именем, взятым из входного потока.
3465 SAVE−BUFFERS     ( −− )                               Если установлен флаг UPDATE, сбросить блок на диск.
3972 SAVE−TEXT        ( −− )                               Сохранить область текста в энергонезависимую память.
2929 SAVIN            ( −− a )                             Переменная, хранит значение литеры для NUMBER и BASE для FL.
2834 SCR              ( −− a )                             Переменная, номер редактируемого экрана.
3765 SIGN             ( x −− )                             Добавить к форматной строке литеру '−', если число x отрицательно.
1706 SIN              ( x −− x1 )                          Синус. x1 := sin x
3065 SMUDGE           ( −− )                               Изменить признак невидимости последней созданной статьи.
1732 SP@              ( −− a )                             Считать SP. Адрес текущей вершины стека данных.
2968 SPACE            ( −− )                               Пробел. Вывести пробел на индикатор.
3738 SPACES           ( b −− )                             Если b>0, отобразить b пробелов шириной в цифру.
2858 STATE            ( −− a )                             Переменная, состояние текстового интерпретатора.
 473 TASK             ( −− )                               Последнее слово ядра Каллисто.
1722 TG               ( x −− x1 )                          Тангенс. x1 := tg x
3685 THEN           I ( −− )                               Конец ветвления IF.
3596 THRU             ( c1 c2 −− )                         Интерпретировать экраны с номерами от c1 до c2 включительно.
2057 TIB              ( −− a )                             Дать адрес TIB (входного буфера терминала).
3343 TO             I ( x −− )                             Записать x в десятичную величину или переменную действия.
2136 TOGGLE           ( a c −− )                           Изменить байт с адресом a по xor−маске c.
2668 TRUE             ( −− −1 )                            Истина. Число −1.
 605 TYPE             ( a u −− )                           Напечатать на индикаторе u литер от адреса a.
 625 TYPE1            ( a u −− )                           Напечатать на индикаторе в одну строку u литер от адреса a.
3777 U#               ( u −− u1 )                          Преобразовать в литеру последнюю цифру из u и добавить к форматной строке.
3747 U#>              ( x −− a c )                         Завершить преобразование целого числа. Дать адрес и длину для TYPE.
3793 U#S              ( u −− 0 )                           Выделять цифры числа u словом U# до получения нуля.
2170 U@               ( a −− U )                           Извлечь беззнаковое. Считать беззнаковое значение ячейки с адресом a.
3184 UCONVERT         ( u a −− u1 a1 )                     Преобразовать u и литеры от a+1 в u1 и a1 −− адрес первой не цифры.
1788 UNLOOP           ( −− )                               Снять со стека возвратов параметры управления циклом FOR для текущего уровня вложенности.
3664 UNTIL          I ( ф −− )                             Если ф ложен (ф=0), повторить цикл BEGIN UNTIL ещё раз.
 516 UNUSED           ( −− U )                             Оценить количество свободных байт.
2442 UPDATE           ( −− )                               Отметить блочный буфер, как изменённый.
2407 UPPER            ( a u −− )                           Перевести в верхний регистр u литер по адресу a.
2587 USER             ( −− a )                             Обработчик переменных типа USER (слово без заголовка).
2547 VALUE            ( x −− )                             Определить следующее слово, как десятичную величину с начальным значением x.
2533 VARIABLE         ( −− )                               Определить следующее слово, как переменную с начальным значением 0.
 535 VERSION          ( −− p )                             Версия Каллисто, p=1.
2783 VOC−LINK         ( −− a )                             Переменная связи, начало списка из наборов слов.
3406 VOCABULARY       ( −− )                               Определить следующее слово, как набор слов над набором CURRENT.
 493 WARM             ( −− )                               Тёплая перезагрузка, словарь сохраняется.
3708 WHILE          I ( ф −− )                             Если ф ложен (ф=0), выйти из цикла BEGIN WHILE REPEAT.
3168 WORD             ( c −− a )                           Ввести слово до стоп−литеры c. Дать его адрес, как строки со счётчиком.
3891 WORDS            ( −− )                               Слова. Отобразить имена всех слов контекста.
1514 XOR              ( n1 n2 −− i )                       32−битное сложение по модулю два (исключающее или). i := n1 ⊕ n2
1598 X²               ( x −− p )                           Квадрат числа. p := x²
1622 Yˣ               ( p x −− x1 )                        Возведение положительного числа p в степень x. x1 := pˣ
2348 [              I ( −− )                               Установить состояние исполнения.
3622 [']            I ( −− | т )                           Скомпилировать токен (CFA) следующего слова, как числовой литерал.
3334 [COMPILE]      I ( −− )                               Скомпилировать следующее слово независимо от его признака IMMEDIATE.
1646 [X]              ( x −− x1 )                          Усечение (целая часть) числа. x1 := Trunc [x]
3583 \              I ( −− )                               Комментарий. Игнорировать остаток строки.
3589 \S             I ( −− )                               Комментарий. Игнорировать остаток экрана.
2360 ]                ( −− )                               Установить состояние компиляции.
2809 _FONT            ( −− a )                             Адрес структуры терминала из 5 байт, описывающей активный шрифт.
4100 _RW              ( c1 c2 −− )                         Считать/записать (c2=1/0) блок номер c1.
1654 {X}              ( x −− x1 )                          Дробная часть числа. x1 := x − Trunc [x]
1454 |X|              ( x −− p )                           Вычислить модуль. p := |x|
3981 ВЫКЛ             ( −− )                               Сохранить сеанс работы в энергонезависимой памяти МК−161.
1130 ГРФ              ( −− )                               Вывести графическую информацию. Обновить индикатор.
2954 Д,               ( x −− )                             Скомпилировать x в первый свободный регистр десятичного словаря.
2335 ДALLOT           ( D −− )                             Сместить вершину десятичного словаря на D регистров.
2767 ДH               ( −− a )                             Переменная, адрес вершины десятичного словаря.
2326 ДHERE            ( −− a )                             Дать адрес текущей вершины десятичного словаря.
1639 ЗН               ( x −− n )                           Знак числа. n := −1 / 0 / 1
 818 ИП               ( U −− x )                           Прочесть регистр МК−161 с номером U.
 847 ИПРГ             ( U −− c )                           Прочесть байт из памяти программ.
3935 КАТ              ( c −− )                             Перейти в каталог Каллисто с литерой c. Если каталога нет, создать его.
 560 НОП              ( −− )                               Нет операции.
 806 П                ( t z y x U −− t z y )               Записать x в регистр МК−161 с номером U.
1632 СЧ               ( −− p )                             Псевдослучайное число. 0<=p<1
3147 без имени      I ( −− )                               Пустышка. Закончить интерпретацию входного потока.
1359 ÷                ( y x −− x1 )                        Разделить. x1 := y÷x
1350 ×                ( y x −− x1 )                        Умножить. x1 := y×x
1399 ×/               ( z y x −− n )                       Поделить произведение z×y на x. n := Trunc [x1×x2/x3]
1413 ×/MOD            ( z y x −− y1 n )                    Получить частное n и остаток y1 от деления произведения z×y на x.
1883 ↔                ( y x −− x y )                       Обмен.
2676 π                ( −− 3,14159265359 )                 Число пи.
1011 ↵                ( −− )                               Возврат каретки. Продолжить вывод с начала следующей строки.
1137 ↖                ( −− )                               Очистить индикатор. Курсор в левый верхний угол.
1607 √                ( p −− p1 )                          Квадратный корень. p1 := sqrt p

Легенда:
I        слово с признаком немедленного исполнения (IMMEDIATE)
a        адрес в единой адресации (от 0 до 19'999)
b        8-битное целое (от -128 до 255)
c        неотрицательное 8-битное целое (от 0 до 255)
d        16-битное целое (от -32768 до 65535)
D        16-битное целое со знаком (от -32768 до 32767)
f        флаг: −1 «истина», 0 «ложь»
ф        флаг: 0 «ложь», отлично от нуля — «истина»
i        32-битное целое в дополнительном коде (от -2'147'483'648 до 2'147'483'647)
n        целое число (от -999'999'999'999 до 999'999'999'999)
p        неотрицательное десятичное число (от 0 до 9,999'999'999'99e99)
т        выполнимый токен слова (CFA)
u        неотрицательное целое (от 0 до 999'999'999'999)
U        16-битное беззнаковое (от 0 до 65535)
x y z t  любой элемент стека (десятичное число от -9,999'999'999'99e99 до 9,999'999'999'99e99)

его портировать на микроконтроллер?

---------------------------
Истина где-то рядом
www.litres.ru/vitaliy-samurov/dozvonitsya-do-devy/

Судя по объёму микросхемы памяти в МК-161, то порядка 8кб переменные плюс 8кб программа. Прошивка вполне должна влезть в 128кб. Так что, есть смысл портировать только на ARM, вдобавок позволяющий выполнять программу из ОЗУ.

, вряд ли стоит даже пытаться на atmega368p

---------------------------
Истина где-то рядом
www.litres.ru/vitaliy-samurov/dozvonitsya-do-devy/

Зачем там Каллисто? Разве что воспроизвести десятичные стеки МК

Каллисто — успешный проект по развитию входного языка ПМК на основе Форта. Это язык калькулятора — и не целочисленного, как Форт, а десятичного («плавучка»). Структурные программы для советских ПМК пойдут на Каллисто с минимальными изменениями, см. примеры. В ядре предусмотрены как команды косвенной адресации, так и аналог цикла FL0. Ну и десятичный стек с привычным набором калькуляторных функций, конечно, важен для калькулятора.

Задумано так, чтобы владеющим и любящим советские ПМК было просто освоить и начать писать мощные программы на Каллисто. Просто же Форт найти нет особых проблем, вы правы. На него можно даже натянуть какую-либо библиотеку, превращающую его в компактный язык. Но в Каллисто компактность из коробки.

А почему компактность в форте может быть проблемой? Он такой по проекту. Всякие примитивы привычные для калькуляторов можно и так добавить. По моему мнению Каллисто из коробки ещё слишком низкоуровневый для языка Юзеров, почти уровень SysRPL. ИМХО не помешало бы допилить до юзерского уровня, чтобы HP умер от зависти, у них, я считаю, UserRPL не получился внятным из-за тяжёлого наследия слабых 28s с 16Кб памяти.

Да, Форт очень хорошо лёг на задачу и проблем особых не возникло, как только было решено несколько фундаментальных вещей.

Самое заметное, уже с первых минут знакомства с Каллисто — использование ↑ и ↔ вместо длинных DUP и SWAP. Причём вводятся эти короткие слова теми же кнопками, что в МК-61 и МК-161. В Форте уже были короткие слова @ и ! для считывания и записи в переменные. Я их бросил на клавиши ИП и П, должно быть интуитивно и быстро для владельцев ПМК.

По уровню Каллисто чуть выше и даже проще, чем советские ПМК и Форт. Её потребуется развивать, конечно, в сторону СКМ. Но пока уже существующее хорошо улучшает ситуацию с входным языком МК-161. Я участвовал в дискуссиях по критике МК-161 и мне удалось успешно решить почти все высказанные претензии — кроме, разве что, доступа к ассемблеру МК51, по понятным причинам.

В рамках текущих возможностей МК-1XX Каллисто уже стремится к идеалу, конечно недурно было бы реализовать в голом железе. Я по крайней мере при таком быстродействии не могу с ним работать. Что касается компактности и вообще языков для некого калькулятора мечты, то эта компактность IMHO должна выражаться в размере программного кода, а не в длине отдельных инструкций. Пускай даже отдельные инструкции были бы длинные, но в итоге сама программа короче. Конечно не ценой превращения языка в Brainfuck. Я думаю Каллисто не стоит списывать в этом плане со счетов, ведь это метаязык и есть живой разработчик, такие высокоуровневые конструкции недурно натягивать поверх Форта. Короче не в Каллисто проблема получается, а в том что надо идти дальше, а нет ни платформы ни достаточно быстрой реализации :-(

Сама Каллисто использует 9883b памяти программ + 7kb байтовая память (регистры и текст) + 8000b десятичные регистры = 25051 байт

К этому надо добавить всю роскошь, что предоставляет Новосибирская прошивка. Это шрифты, bcd-арифметика и функции, файловая система и низкоуровневой ввод-вывод. Оценим всё это в 32-64Кб ПЗУ + 1-2Кб ОЗУ.

Поскольку тысяча десятичных регистров (стек и десятичный словарь) избыточна, всю систему реально запихнуть в 64Кб (49±7Кб ПЗУ + 12±4Кб ОЗУ). Уже 90Кб (74Кб ПЗУ + 16Кб ОЗУ) хватит с запасом, вплоть до полной эмуляции МК-161. Сложная файловая система на данном этапе не нужна — блоки можно реализовать, как сектора. Математические функции и графика тоже важны лишь для разработчиков. Сама Каллисто пользуется только bcd-арифметикой, да и одного шрифта для начала достаточно.

esp32 (32-битный ЦПУ, 520 KB ОЗУ) вполне мог бы потянуть с большим запасом. Ввод-вывод - через serial консоль, дешевая и сердитая платформа.

---------------------------
Истина где-то рядом
www.litres.ru/vitaliy-samurov/dozvonitsya-do-devy/

Потянуть-то потянет. Но мне интересно готовое портативное устройство с индикатором и клавишами, под которое я выберу одежду с карманом нужного размера. :-) Клубок из проводов на столе, работающий по кабелю с компьютера, не так возбуждает.

Также в МК-161 остался неиспользованный запас для повышения быстродействия. Хотя и не такой большой, как в esp32. Надеюсь, что к моменту появления отечественной альтернативы МК-161 получится выпустить вполне практичную Каллисто-2.

А не 15 тыщ. К тому же на esp32 можно изготовить штуку в корпусе с клавиатурой, и сомнительно что она обойдётся в 15 тыщ. В общем не тянет людей на МК-161, слишком он уже отстаёт от ожиданий типичного пользователя. На esp32 wifi из коробки, энергосбережение, два мощных ядра, что несомненно плюс для современного устройства.

Искренне завидую наличию времени и сил. Мои серверы-трансляторы по работе отнимают до 10 часов в день, поэтому переписать Каллисто на нормальном переносимом Си не смогу при всем понимании такой потребности. Иначе это будет как в анекдоте: у человека - жена, любовница, а он еще и в туалете рукоблудит на досуге :)

Спасибо. Но, может, оно и к лучшему. Теоретически Форт можно написать на Си, такие проекты известны. Но правильный путь развития таких языков — метакомпиляция. Когда Каллисто сможет компилировать саму себя (разумеется, не на МК-161), перенос её на другие платформы будет относительно простым делом.

А пока что можно просто заглядывать на обсуждение Каллисто-2 и помогать сократить пару байт здесь, ускорить на несколько тактов там. Это уже будет существенной помощью.

И какие то вставки на Си потом писаться будут гораздо проще и быстрее. Совместимость с Сишным миром - это IMHO великое дело. Но согласен, что сама реализация должна жить и без Си, т.е. всякие адресные интерпретаторы и т.п. неплохо бы вклячить как можно ближе к железу.

Здесь вполне обнадёживающие результаты опытной оценки по эффективности сишного компилятора для ARM Cortex-M3, ориентировочно 67-83% эффективности кода по сравнению с голым ассемблером. Я думаю, смысла нет в повышении быстродействия в полтора раза ценой существенно большей трудоёмкости программирования.