Хабрахабр

EFORTH для программируемого калькулятора

Транслятор EFORTH теперь есть и на отечественном калькуляторе «Электроника МК-161»! 17 мая версия v0.5b успешно прошла мои тесты, а также пять авторских тестов TEST-TEST4. Я добился того, что можно сделать в одиночку, но считаю это лишь половиной дела. Настало время представить сообществу новый инструмент, открыв код 161eForth для публичного тестирования. У меня есть список, что улучшить и где «поработать над стабильностью». Ваши предложения и замечания будут учтены при завершении работ и выпуске версии 1.0

2. При переносе последней версии eForth на отечественную платформу успешно преодолены два препятствия — относительно низкое быстродействие 8-битной машинки, которая программируется на собственном входном языке, и скромный объём доступной двоичной памяти (см. 1), всего 4096 байт.
4.

Это технология реализации форт-машины поверх десятичной и «гарвардской» архитектур, драйверы консоли и раскладка алфавитно-цифровой клавиатуры, а также основанный на них программный терминал, работающий по последовательному порту RS-232. При написании 161eForth применялись готовые решения, подготовленные для Каллисто — входного языка нового поколения для отечественных ПМК. Буквы расположены по алфавиту построчно, слева направо и сверху вниз. Помимо «Электроники МК-161» и дистрибутива 161eForth вам может потребоваться самодельная накладная клавиатура, где на клавишах подписаны буквы русского и английского алфавитов.

Это внутренний («адресный») интерпретатор, позволяющий оборудованию исполнять шитый код Форта, и внешний («текстовый») интерпретатор, отвечающий за диалог с человеком. Доктор Чэнь-Хэнсон Тинг, автор современных версий eForth, подчёркивает в своей книге [1] важность понимания двух составляющих Форта.

Изучение этих решений может оказаться полезным и вдохновляющим для переноса eForth на другие устройства с ограниченным объёмом памяти и производительности. В двух статьях я подробно остановлюсь на наиболее радикальных решениях, использованных при реализации каждого из этих двух интерпретаторов на «Электронике». Я поясню сложные моменты, уникальные для «Электроники МК» и транслятора eForth. Пониманию статей поможет начальное знакомство с программируемыми микрокалькуляторами (ПМК) и Фортом.

Размер букв имеет значение. Начну с того, что слова eForth делятся на общеполезные и системные. Автор eForth предлагает вести основной диалог в режиме CAPS. Имена обычных слов определены заглавными буквами, а системных — строчными. Свои нововведения в eForth я также сделал строчными буквами. Когда вам нужно использовать системное слово, переключитесь на время в строчные буквы (комбинация клавиш F P).

В нескольких ранних реализациях eForth заголовки системных слов были исключены и не выводились командой WORDS. В статье все слова пишутся заглавными буквами, чтобы выделяться из текста. В 161eForth заголовки этих слов сохранены в первую очередь из-за наличия декомпилятора слов двоеточия SEE, который не покажет имена системных слов, если убрать их заголовки. Это помогало упростить внешний вид eForth и экономить внимание тех, кто впервые пользуется Фортом.

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

5b.zip Сам 161eForth выложен здесь, вместе с исходным текстом, рисунком накладной клавиатуры и справкой words.txt с описанием всех реализованных слов: http://the-hacker.ru/2019/161eforth0.

Также я выложил 5 маленьких видео на YouTube, иллюстрирующих работу 161eForth для тех, у кого нет МК-161: посмотреть видео.

eForth и его реализации

eForth разрабатывался, как современная замена широко известного транслятора фиг-Форта. Для переноса на МК-161 мною была выбрана 32-битная версия 5.2 транслятора 86eForth с косвенным шитым кодом, написанная в 2016 году на ассемблере MASM для операционной системы Windows. Эта версия подробно описана в третьем издании книги «eForth and Zen» [1]. Знающим английский советую разыскать и изучить эту книгу, она весьма полезна для понимания 161eForth.

В Интернете можно найти много англоязычной информации и по этой, и по предыдущим версиям eForth. В личном письме автор подтвердил, что 86eForth502.asm из этой книги — последняя версия eForth.

Каждая последующая версия eForth была упрощением предыдущей версии. Развитие eForth шло по научному пути, которому учит профессор Вирт на примере своего языка программирования Оберон. Остался тщательно продуманный набор сильных, выразительных языковых конструкций, чья мощь проверена на более, чем 40 реализациях eForth для разнообразных платформ. Всё, без чего можно обойтись, убиралось из языка. Теперь и на калькуляторе!

Предлагаемый им набор слов вполне практичен и может легко расширяться программистом в нужную для его задач сторону. Будучи минималистичным диалектом Форта, eForth не ставит своей целью победить в гонке на самый крохотный Форт.

Она содержала 31 машинно-зависимое слово ядра и 191 слово высокого уровня. Первая версия eForth была выпущена в 1990 году на ассемблере MASM для процессоров 8086 и работала под MS-DOS. Идея была проста — вы переводите на свой ассемблер всего 31 слово, и сразу получаете eForth на своём компьютере.

Уже во второй версии eForth на ассемблере стало реализовываться максимальное количество слов, что выправило крен в сторону не только легко переносимой, но и практичной системы программирования. Такой подход повергся критике в Интернете, так как путь минимизации количества слов на ассемблере привёл к крайне низкому быстродействию для встроенных систем.

2, выпущенная в 2016 году, содержит 71 слово «кода» и 110 слов «двоеточия». Версия 5. При этом из соображений производительности увеличился процент слов, реализованных на низком уровне. Четверть века поиска идеала привели к значительному уменьшению общего количества слов.

Моя реализация предоставляет программисту все инструменты, присутствующие в версии 5. Предлагаемый 161eForth пользуется щедрыми плодами этого прогресса, но не претендует на дальнейшее развитие магистральной линии. Когда архитектура МК-161 делает реализацию некоторых слов 86eForth невозможной или бессмысленной, вместо выкидывания лишнего я предоставляю программистам полноценную замену, взяв её из стандарта ANSI/ISO [4]. 2. Ищущие минимализма могут самостоятельно выкинуть «лишние» слова, ведь по традиции 161eForth поставляется с исходным кодом.

Например, по моему глубокому убеждению цикл FOR NEXT с начальным значением n должен выполняться ровно n раз. При реализации eForth я придерживался авторского понимания. К сожалению, eForth использует устаревшее соглашение и выполняет такой цикл n+1 раз, со счётчиком от n до 0. К такому же выводу со временем пришёл Чак Мур, автор языков Forth и colorForth. Я не стал исправлять этот и несколько других недостатков, отдав предпочтение совместимости 161eForth с реализациями для других платформ.

Поскольку 161eForth является первой практичной системой программирования «на борту» для «Электроники МК-161», если не считать заводского языка, я проследил многолетнюю историю eForth и вернул в язык несколько слов, которые были полезными на других платформах и могут оказаться востребованными сейчас.

3. Например, новая-старая переменная ‘BOOT содержит токен (см. По умолчанию ‘BOOT содержит токен TLOAD для интерпретации кода из «области текста» (см. 1) слова, который выполняется первым после инициализации среды, но до начала диалога. 4. 2. Это позволяет программисту подстраивать eForth под себя без перекомпиляции среды, которую пока невозможно производить на борту «Электроники». 2).

2. Приоритетными задачами реализации были экономия двоичной памяти (см. 1) и повышение быстродействия. 4. 2. Их решение привело к драматичному уменьшению количества слов высокого уровня, ведь их код занимает эту драгоценную память, за счёт увеличения количества быстрых слов ядра, реализованных в дешёвой памяти программ (см. 3). 4.

Это даёт надежду на метакомпиляцию своей высокоуровневой части прямо на борту «Электроники». В итоге 161eForth содержит 129 слов кода, 78 слов высокого уровня и занимает 1816 байт двоичной памяти МК-161, то есть меньше её половины.

Написанное в системе команд МК-161 ядро содержится в файле eForth0.mkl. Исходный текст eForth для МК-161 разбит на две крупные части. Слова высокого уровня определены на языке SP-Forth и размещены в файле eForth.f.

Также в дистрибутиве есть справочный файл words.txt, в котором документированы все слова 161eForth со стековой нотацией и кратким пояснением, в одну строчку.

1.1 Исходный текст ядра eForth0.mkl

Ядро eForth содержит исполняемый код, работающий в памяти программ МК-161 (см. 2.4.3), который компилируется на компьютере в файл eForth0.mkp стандартными средствами, например фирменным компилятором MKL2MKP.

Например, команда ИПЕ для чтения регистра Е (он же R14) записывается в этой мнемонике, как RME. Исходный текст ядра, содержащийся в файле eForth0.mkl, написан в латинской мнемонике. Действительно, набрать странное FX^2 проще, чем знакомое с детства Fx². Будучи непривычной для владельцев советских ПМК, латинская мнемоника удобна для ввода с клавиатуры компьютеров.

Помимо кода примитивов он содержит заголовок ядра и таблицу имён tblNames, которую eForth.f во время компиляции переносит в десятичные регистры (см. Файл eForth0.mkp является заготовкой ядра. 4. 2. Именно на основе eForth0.mkp будет создано ядро eForth.mkp (см. 4). 4. 2. 3), поэтому eForth0.mkl должен быть откомпилирован первым.

1.2 Исходный текст слов высокого уровня eForth.f

Файл eForth.f подаётся на вход замечательного отечественного компилятора SP-Forth [5]. Файл содержит определения всех слов высокого уровня. Со временем их можно будет определить на самом eForth и, возможно, компилировать прямо на борту «Электроники МК-161».

Именно eForth.mkb содержит тела слов высокого уровня, хотя их заголовки размещены в файле eForth.mkd. Во время компиляции eForth.f считывает заготовку ядра eForth0.mkp и с её помощью создаёт в текущем каталоге три файла для последующей загрузки в МК-161: eForth.mkp, eForth.mkd и eForth.mkb.

Каждый из этих четырёх файлов я подробнее разберу ниже (см. Четвёртый файл, eForth.mkt, написан на eForth вручную и может редактироваться на борту МК-161 с помощью встроенного редактора текста. 4). 2.

2. Электроника МК-161

Производитель из Новосибирска называет МК-161 старинным сокращением ЭКВМ. Так назывались в СССР самые первые калькуляторы. Система команд МК-161 наследует системе команд советских калькуляторов «Электроника Б3-34» и «Электроника МК-61». Это означает, что программы, написанные для советских калькуляторов, пойдут на МК-161 без изменений или с незначительными изменениями.

eForth не пойдёт на советских ПМК, т.к. Обратное неверно. задействует множество ресурсов, появившихся впервые в МК-152/161 и отсутствовавших в предыдущих моделях серии.

Рассмотрим особенности входного языка и архитектуры МК-161, повлиявшие на 161eForth (далее просто eForth) и давшие обсуждаемой реализации eForth «русский акцент».

Например, число 1000=3×256+232 будет записано в двух последовательных байтах, как 3 и 232. Первая из этих особенностей — последовательно выдерживающееся в МК-161 соглашение «старшее по младшему адресу».

2.1 Косвенная адресация

Программировавшие советские ПМК слышали про косвенную адресацию. При прямой адресации мы явно указываем номер регистра, к которому обращаемся. Например Р ИП 44 считает содержимое регистра 44. Клавиша Р, появившаяся в МК-152, используется для обращения к регистрам с номером 15 и больше — эти регистры отсутствовали в советских ПМК.

Этот номер содержится в другом регистре. При косвенной адресации номер нужного регистра заранее не известен. Например, если регистр 8 содержит число 44, команда К ИП 8 считает содержимое регистра 44 (R44).

Например, команда Р К БП 20 передаст управление (GOTO в латинской мнемонике) на адрес, хранящийся в R20. Клавиши К и Р можно комбинировать.

Эта особенность унаследована от советских ПМК. Особенность, оказавшаяся важной для внутреннего интерпретатора eForth, связана с предварительным увеличением / уменьшением регистров при косвенной адресации.

Команды К ИП 4, К ИП 5 и К ИП 6 перед считыванием увеличивают на единицу содержимое регистров 4, 5 или 6. Например, команды косвенного чтения К ИП 0, К ИП 1, К ИП 2 и К ИП 3 перед обращением к нужному регистру уменьшают на единицу содержимое регистров 0, 1, 2 или 3.

Она похожа на ++R и --R в Си. Такая «модификация» адресного регистра позволяет обрабатывать в цикле целые группы регистров. Именно он определяет, произойдёт его увеличение (регистры 4-6) или уменьшение (регистры 0-3) при косвенной адресации. Номер регистра-указателя важен.

В результате указатель интерпретации (IP), размещённый в R6, всегда указывает на последний считанный байт шитого кода. На архитектуру 161eForth повлияло то, что увеличение регистров 4-6 при косвенной адресации — предварительное. В 86eForth IP всегда указывает на последующий байт, ещё не считанный.

R2 всегда указывает на вершину стека возвратов. Это верно и для указателя стека возвратов (RP), хранящегося в регистре 2.

Например, РКИП02 считает число с вершины стека возвратов, не меняя указатель. Полезной особенностью МК-161 является отсутствие увеличения / уменьшения регистра, если косвенная адресация происходит с новой клавишей Р. Из написанного выше следует, что считанное значение на единицу меньше, чем адрес следующего токена, который выполнится после возврата из слова «двоеточия». Это готовая команда Форта R@.

Когда вам придётся разрабатывать или изучать слова, тесно взаимодействующие с внутренним интерпретатором eForth — убедитесь, что до конца поняли этот тонкий момент, связанный с предувеличением.

2.2 Таблицы, упорядоченные и ассоциативные

Таблицы МК-161 размещаются в памяти программ (см. 2.4.3). Они появились в новосибирской «Электронике МК» и совершенно незнакомы экспертам по советским ПМК. Адрес используемой таблицы всегда хранится в регистре 9042, а вот обращение к ним различается.

eForth содержит такую таблицу tblTokens с адресами примитивов (см. Упорядоченная таблица это массив беззнаковых 16-битных целых. 1. 3. Адресный интерпретатор (см. 1) — слов Форта, написанных в системе команд МК-161. 2) использует tblTokens для быстрого исполнения шитого кода, поэтому eForth старается, чтобы в R9042 всегда содержался адрес этой таблицы. 3.

Число n в регистре X заменится на значение элемента таблицы с номером n, отсчёт начинается с нуля. Для обращения к упорядоченной таблице надо записать номер нужного элемента в R9210.

Также ассоциативная таблица tblCHPUT используется при выводе литеры на экран, чтобы обрабатывать перевод строки и другие управляющие коды. Ассоциативные таблицы («поиск по значению») активно используются eForth, в первую очередь примитивом (FIND), ищущим слово по его имени.

Число n в регистре X (руководство его называет «индексом») заменится на 16-битное значение, записанное в таблице сразу после его «индекса» n. Для поиска элемента n в ассоциативной таблице требуется записать n в R9212.

Конечно, для этого пришлось разработать не самые простые таблицы распознавания имени, «заточенные» под эту функцию. Наличие этой быстрой, хотя и простенькой функции поиска, реализованной на ассемблере в «прошивке» МК-161, помогло eForth добиться приемлемого быстродействия при распознавании имён слов и компиляции программ. Об этом поговорим подробней во второй статье.

2.3 Прерывания и консоль

«Электроника МК» позволяет её владельцам писать программы на входном языке, реагирующие на определённые события — такие, как нажатие или отпускание кнопки, окончание счёта таймера.

eForth активно использует эту систему прерываний как для ввода с клавиатуры и отображения мигающего курсора при запросе такого ввода, так и для ввода-вывода через универсальный последовательный порт (RS-232).

Это очень удобно и экономит время на системах с низким быстродействием. Введённые с клавиатуры литеры ставятся в очередь bufKbd по мере нажатия клавиш. Долгое нажатие на клавишу вызывает автоповтор. Переключения алфавитов и регистра обрабатываются прерыванием KeyPress и не занимают место в очереди.

Конечно, всю эту естественную работу клавиатуры хотелось бы не реализовывать в трансляторе, а получить «из коробки» МК-161, как сервис встроенной программы (прошивки). Когда очередь из 8 литер заполнена, а eForth ещё не готов обработать ввод (ситуация очень редкая), МК-161 издаст недовольный писк. Но уж чем, как говорится, богаты.

Вывод литеры на него осуществляет относительно простая подпрограмма ChPut. После начала работы весь вывод eForth направлен на графический экран МК-161. МК-161 использует пропорциональный шрифт. Единственная сложность здесь связана с реализацией управляющего кода BS, «пробела назад». Поэтому в специальном буфере tblBS приходится запоминать позиции выведенных символов, откуда их позже берёт код вывода BS.

Слово CON> возвращает управление на консоль калькулятора. Во время диалога пользователь может с помощью слова IO> перенаправить весь ввод-вывод в последовательный порт RS-232, что даёт возможность программировать МК-161 с привычной клавиатуры компьютера или с другой МК-161.

2.4 Области памяти и установка eForth на МК-161

Память «Электроники МК-161» состоит из отдельно адресуемых памяти программ и регистровой памяти данных. В свою очередь, регистровая память неоднородна и делится на три большие области.

Регистры с номерами от 0 до 999 хранят «десятичные числа».

Последние 3 Кбайта этой области с адресами от 5096 до 8167 называются областью текста. Регистры с номерами от 1000 до 8167 хранят целые от 0 до 255.

Эта служебная область адресного пространства напоминает порты ввода-вывода микропроцессоров. Регистры с номерами от 9000 до 9999 называются регистрами функций. С помощью команд записи и чтения по этим адресам реализуется доступ к устройствам ввода-вывода, системе прерываний и т.п.

EXE:
Чтобы установить eForth на «Электронику МК-161», достаточно передать в калькулятор четыре файла, например с помощью программы производителя MK.

  • Записать eForth.mkp в память программ, начиная со страницы 0. Версия 0.5b занимает 74 страницы.
  • Записать eForth.mkd в память десятичных данных
  • Записать eForth.mkb в память двоичных данных
  • Записать eForth.mkt в память текста

После передачи на калькулятор рекомендую тут же сохранить эти четыре файла в отдельном каталоге встроенного «электронного диска». Поскольку имя у них одинаковое, загрузить eForth можно сразу за один раз, как «пакет».

2.4.1 Двоичная память МК-161: eForth.mkb

Регистры «Электроники МК» с номерами от 1000 до 5095 используются для хранения чисел от 0 до 255. Эта область регистровой памяти калькулятора называется двоичной. К двум последовательным двоичным регистрам можно обращаться из eForth, как к одной 16-битной «ячейке», причём (как везде на МК-161) старшие 8 бит находятся в регистре с меньшим номером.

Именно с ней работают слова! eForth использует эту крошечную «двоичную память», как свою основную. 3. и @, HERE и ALLOT, только отсюда исполняет шитый код адресный интерпретатор (см. Здесь расположены переменные eForth, буфер ввода текста (TIB), словарь и стек откатов tblBS для реализации пробела назад. 2).

Поэтому огромные усилия были затрачены, чтобы вынести в другие области памяти всё, что только возможно. 4096 байт это очень скромно, по современным меркам.

2.4.2 Область текста: eForth.mkt

Сразу за двоичной памятью следует область текста, регистры с номерами от 5095 до 8167. Технически это такие же байтовые регистры, но возможность их записывать на диск и считывать отдельным файлом делают эту область особенной.

Оно подаёт всю эту область на вход текстового интерпретатора, как строку, длиной в 3072 литеры. Для работы с «текстом» в eForth служит слово TLOAD.

Редактор, встроенный в «Электронику МК», настаивает на длине строки в 24 литеры. Существуют разногласия, как текст разбивать на строки. eForth предоставляет выбор пользователю, считая весь текст одной длинной строкой. Каллисто использует соглашение Форта, где строка содержит 64 литеры. Можете написать свой, совместимый с Каллисто. Можете использовать встроенный редактор МК-161.

Вот начальное содержимое eForth.mkt, для удобства разбитое на три строчки:

: hi ." Привет, %user%!" CR ;
‘ hi ‘boot !
hi \

Вторая строка берёт токен этого слова (см. Первая строка определяет новое слово hi, приветствующее пользователя. 1) и размещает в переменной ‘BOOT (см. 3. Теперь область текста перестанет компилироваться при каждом запуске eForth. 1). Вместо этого выполнится уже скомпилированное приветствие.

Слово \ заканчивает интерпретацию текста, возвращая управление на пульт. Последняя строка запускает слово hi, выводя приветствие на экран.

Также можно передать файл mkt с компьютера. Чтобы скомпилировать произвольный файл текста, вам надо выйти в калькулятор командой BYE, выйти в главное меню и загрузить нужный файл в режиме ДОС. Клавиша С/П вернёт вас в eForth, после чего командой TLOAD вы сможете откомпилировать файл, загруженный в область текста.

2.4.3 Память программ: eForth.mkp

Память программ МК-161 — изолированное адресное пространство. Оно тоже хранит байты, но они доступны только для чтения. Память программ содержит 10000 «шагов», что оказалось избыточным для eForth. Больше четверти памяти программ оказалась свободной, что даёт неплохой задел для развития транслятора.

Также сюда вынесены таблицы распознавания имени и все известные текстовые строки, что экономит двоичную память. Только в памяти программ могут быть реализованы «слова кода».

Например, фраза 0 C@ считает «шаг» (байт) с адреса 0 памяти программ. Некоторые слова, например C@, COUNT и TYPE, могут адресовать память программ, если адрес не является положительным числом.

2.4.4 Десятичная память: eForth.mkd

Регистры «Электроники МК» с номерами от 0 до 999 называются десятичными и содержат числа, используемые для обычных расчётов на калькуляторе — 12 десятичных знаков «мантиссы» и 2 десятичных знака «порядка». Форт рассчитан на работу с целыми числами до 4 байт длиной, такой ресурс явно избыточен для eForth.

Сюда вынесены стеки данных и возвратов. Десятичная память использована для экономии драгоценной двоичной памяти. Такой подход позволяет переопределять даже слова, имеющие стандартные имена. Здесь же хранятся заголовки слов — как определяемых пользователем, так и встроенных, по одному регистру на заголовок.

Во-первых, диапазон значений элементов стека огромен, он способных вмещать 32-битные целые. Стек в десятичной памяти приводит к ряду особенностей, характерных для Форта на МК-161. «Двойные целые» представлены на МК-161, как два элемента стека, содержащие числа от 0 до 65535, кодирующие одно 32-битное целое со знаком в дополнительном коде. Необходимость «двойных целых» на МК-161 отпадает, хотя ради совместимости соответствующие слова eForth мною реализованы. Старшие 16 бит такого числа размещается сверху, то есть по младшему адресу.

Результат от 32768 до 65535 преобразуется в отрицательные числа от -32768 до -1. Побитовые логические операции AND, OR, XOR и NOT рассматривают свои аргументы, как 16-битные целые. Также истиной считается любое значение, отличное от нуля. В eForth ложь кодируется нулём, а истина минус единицей.

Когда слово @ считывает число 65535 из 16-битной «ячейки», оно автоматически преобразовывается в -1. Вторая особенность стека данных 161eForth — он содержит числа со знаком. Предусмотрено специальное «беззнаковое» слово U@ для того, чтобы считать непосредственно 65535, со знаком «плюс».

Упомяну, что ради быстродействия два верхних элемента стека данных расположены не в десятичной памяти, а непосредственно в регистрах X и Y.

Виртуальная машина eForth использует эти регистры для хранения 12-разрядных десятичных целых со знаком. Тот факт, что десятичные регистры могут содержать дробные числа и числа с плавающей запятой, никак не используется eForth. — те же самые, что работают с любыми одиночными регистрами. Обращение к десятичным регистрам осуществляют слова C@ и C!

3. Внутренний интерпретатор

Ядро eForth это программа, написанная на входном языке МК-161. Её первая команда БП MAIN передаёт управление коду MAIN, который первым делом выясняет обстоятельства перезагрузки. Если её вызвал неправильный токен, МК-161 пискнет. При первом запуске, а также после включения МК-161, экран очищается. Далее MAIN вызывает подпрограмму Init для инициализации системы прерываний и всего, что нужно драйверам консоли МК-161.

Происходит невероятное для машин с гарвардской архитектурой — eForth переходит к исполнению «шитого кода» из байтовой памяти. После инициализации стеков данных и возвратов низкоуровневая часть старта завершена. Обычно это слово COLD. Честь быть первым принадлежит слову, адрес заголовка которого записан в R43.

Любое слово состоит из двух частей, тела и заголовка. Как же устроены слова высокого уровня (СВУ)? Он помогает внешнему интерпретатору и декомпилятору найти имя и тело слова. Заголовок хранится в десятичном регистре. Внутреннему интерпретатору намного важнее тело СВУ, расположенное в двоичной памяти и хранящееся в словаре. Заголовок также содержит поле «лексикона» — набор флагов, помогающих внешнему интерпретатору правильно обработать найденное слово. Он способен даже исполнять слова, у которых заголовок отсутствует.

Четыре обработчика СВУ написаны на входном языке МК-161 и начинаются на первой странице памяти программ. Тело СВУ начинается с байта поля кода, который содержит адрес обработчика данного слова. 3. Мы разберём их все (см. Этот обработчик исполняет слова Форта, определённые с помощью двоеточия. 3), но главный из них называется DOLST и расположен по адресу 02, сразу после уже рассмотренной команды БП MAIN.

В «словах двоеточия» поле параметров содержит «шитый код» — последовательность 16-битных токенов, каждый из которых обозначает одно, закреплённое за ним действие. После байта поля кода идёт поле параметров, произвольной длины.

Потом изучим внутренний интерпретатор INEXT, осуществляющий переход от одного токена к исполнению следующего. Сперва мы рассмотрим токен подробнее. Завершим мы эту экскурсию по внутреннему интерпретатору разбором всех четырёх обработчиков СВУ. Автор eForth называет INEXT обработчиком примитивов.

3.1 Токены

Токен представляет слово в шитом коде и стеке, позволяя его быстро выполнить. Токен — указатель на тело слова, но суровая архитектура МК-161 внесла в эту простую идею свои коррективы. Разберём все виды токенов, начиная с токена примитивов.

3.1.1 Токен примитива

Всё слова, входящие в дистрибутив eForth, пронумерованы от 0 до 206. Эта нумерация сквозная, учитывающая как примитивы, так и СВУ. Так сделано, чтобы по номеру слова было легко восстановить его имя. Эти имена хранятся в памяти программ. Ссылку на нужное имя легко найти через таблицу заголовков.

Как любой токен, примитив занимает в шитом коде два байта. Номер примитива и является его токеном. Второй содержит его номер. Первый равен нулю. Адрес tblTokens постоянно хранится в R9042 (см. Таблица tblTokens позволяет быстро найти адрес кода примитива по этому номеру. 2), то есть для исполнения примитива всё всегда под рукой. 2.

Так как код примитивов всегда располагается в памяти программ, полученный адрес всегда отрицательный (см. Слово XT> позволяет узнать адрес кода примитива по его номеру (токену). 4. 2. 3).

3.1.2 Токен СВУ

СВУ может иметь свой номер и связанное с ним стандартное имя, а может быть совершенно новым, созданным пользователем. Во всех случаях токен СВУ — адрес его поля кода (см. 3), то есть число от 1000 до 5095.

В первый байт записывается число сотен (число от 10 до 50), во второй — остаток от деления токена на 100 (число от 0 до 99). В шитом коде токен СВУ записывается весьма необычным образом.

Компиляцию такого, да и любого другого токена осуществляет взятое из стандарта ANSI слово COMPILE,. Например, токен 1234 будет представлен двумя байтами 12 и 34. Они же осуществляют доступ к адресам (см. Для чтения и записи токенов СВУ в шитый код служат слова XT@ и XT!.. 1. 3. 4), а слово XT@ способно также считать токен примитива.

3.1.3 Целые литералы

Целые литералы — разновидность токенов примитивов. Они достаточно необычны, чтобы рассмотреть их отдельно.

Первые два байта содержат уже рассмотренный токен примитива, то есть 0 и номер примитива. В шитом коде токены DOLIT и DOLITM занимают четыре байта. Последующие два байта содержат целое, которое данный литерал при исполнении положит на стек данных.

Он предназначен для реализации отрицательных чисел. DOLITM отличается тем, что меняет знак числа перед тем, как положить его на стек.

3.1.4 Адресные литералы

Подобно целым литералам, три адресных литерала BRANCH, ?BRANCH и DONXT занимают в шитом коде по 4 байта каждый. Первые 2 байта содержат токен примитива, последние два — адрес перехода.

3. Адрес записывается в том же формате, что и токен СВУ (см. 2). 1. Напомню, что из-за предувеличения (см. В первом байте идёт количество сотен, во втором — остаток от деления адреса на 100. 1) адрес перехода содержит не адрес нужного токена, а число, на единицу меньшее. 2.

1). Токен DONXT помогает реализовать «конечный цикл» FOR-NEXT (см. Условный переход ? Безусловный переход BRANCH нужен для реализации бесконечного цикла BEGIN-AGAIN. Он служит для реализации условного оператора IF-THEN, выходов из «неопределённых циклов» BEGIN-UNTIL и BEGIN-WHILE-REPEAT. BRANCH передаёт управление, если на вершине стека данных находится ноль («ложь»).

3.1.5 Строковые литералы

Строковые литералы — разновидность токенов СВУ. В шитом коде строкового литерала после токена идёт байт с длиной строки, после которого — сама строка, от первого байта до последнего.

Они определены в файле eForth.mkl, как токены STRQP, DOTQP и ABORQ соответственно. В eForth три строковых литерала: $"|, ."| и abort"|. Основную «литеральную» работу выполняет за них слово do$, токен DOSTR.

Чтобы сделать размер статьи разумным, я не могу останавливаться слишком подробно на этой интересной теме, но неплохо знать об их наличии в eForth.

3.2 Адресный интерпретатор

Пришло время рассмотреть интерпретатор адресов, адрес которого всегда записан в регистре 9. Большинство примитивов завершают свою работу командой К БП 9, которая передаёт управление на метку INEXT.

INEXT: КИП6 Fx≠0 NPrime
NData: ВП 2 КИП6 + П7 F⟳
КИП7 П8 F⟳ КБП8

Если он нулевой, это примитив и обработкой токена займётся код под меткой NPrime. Первым делом адресный интерпретатор считывает командой КИП6 первый байт очередного токена.

Первый байт умножается на сто командой ВП 2, после чего КИП6 + прибавляет к результату второй байт токена (см. Меткой NData обозначена обработка токена СВУ. 1. 3. Считанный токен заносится командой П7 в «рабочий регистр» WP (R7). 2).

Команды КИП7 П8 считывают байт поля кода в R8, а команда КБП8 передаёт управление обработчику СВУ. Мы знаем, что токен СВУ это адрес его поля кода, в котором содержится адрес обработчика. Обработчик знает, что в R7 находится число, на единицу меньшее адреса поля параметров обрабатываемого слова.

Дело в том, что eForth хранит два верхних элемента стека данных непосредственно в регистрах X и Y стека МК-161. Команды F⟳ с кодом 25 «прибираются» в стеке. Такое решение ускоряет работу, но заставляет следить, чтобы эти важные данные не потерялись.

Осталось разобрать, как адресный интерпретатор исполняет примитивы.

NPrime: F⟳ КИП6 РРП9210 П8 F⟳ КБП8

Команды РРП9210 П8 считывают из таблицы tblTokens адрес этого примитива (см. Команда КИП6 считывает второй байт токена примитива. 2 и 3. 2. 1), а КБП8 передаёт этому примитиву управление. 1.

Как и выше, F⟳ убирают лишнее из стека, восстанавливая содержимое регистров X и Y.

Основная копия исполняется по команде К БП 9, которой завершается большинство примитивов. Адресный интерпретатор eForth такой крохотный, что он несколько раз продублирован в памяти программ.

Это вариант INEXT, который считывает токен не из шитого кода, а берёт его со стека данных. В качестве упражнения рекомендую изучить реализацию слова EXECUTE, размещённую после метки EXECU.

3.3 Обработчики СВУ

Четыре разновидности СВУ имеют четыре разных обработчика: DOLST, DOVAR, DOCON и DOCONM. Выше мы уже видели, что адресный интерпретатор перед вызовом обработчика оставляет в R7 адрес поля кода обрабатываемого слова.

Это помогает ему правильно компилировать СВУ для «Электроники МК-161», размещая результат в файле eForth.mkb. eForth.f узнаёт адреса этих обработчиков, считав заголовок ядра из файла eForth0.mkp.

3.3.1 Работа слов двоеточия: DOLST и EXIT

Следующая после INEXT важная тема — что делает внутренний интерпретатор, встретив токен слова, определённого через двоеточия. Поле кода такого слова содержит число 2, поэтому INEXT передаёт управление на обработчик DOLST, который и выполняет нужную работу по началу интерпретации нового списка токенов.

DOLST: ИП6 КП2 F⟳
ИП7 П6 F⟳
INEXT:

2. Регистр 2, как мы уже разбирали (см. Команды ИП6 КП2 записывают в стек возвратов значение R6 — указателя интерпретации (IP). 1) содержит указатель стека возвратов RP. Теперь же ИП7 П6 переставляет IP на начало нового списка. Позже это поможет вспомнить текущую позицию в старом списке токенов, где INEXT наткнулся на слово двоеточия.

Как везде, команды F⟳ помогают сохранить два верхних элемента стека данных. Сразу после кода DOLST размещён код INEXT, который исполнит первое слово нового списка токенов.

Слова двоеточия обычно завершаются токеном EXITT, который делает обратную работу, в сравнении со DOLST — достаёт со стека возврата старое значение IP и возвращается к интерпретации старого списка токенов.

EXITT: РКИП02 П6 Сx 1 ИП2 + П2 F⟳
INEXT:

2. Команды РКИП02 П6 считывают старое значение IP с вершины стека возвратов (см. После чего команды Сx 1 ИП2 + П2 исправляют значение RP, увеличивая его на единицу. 1). Команда F⟳ восстанавливает стек, после чего INEXT исполняет очередное слово из старого списка токенов.

Чтобы так сделать, мною применён один древний трюк времён СССР. Конечно же, INEXT не может одновременно идти и после DOLST, и после EXITT. Вы тоже можете его освоить, изучив соответствующие строки файла eForth0.mkl

3.3.2 DOVAR, обработчик переменных и массивов

Слова, порождённые словами CREATE и VARIABLE, используют одинаковый обработчик DOVAR. Этот обработчик кладёт на стек адрес переменной, размещённой в поле параметров, которое идёт сразу после байта поля кода. Переменные VARIABLE занимают 2 байта, а созданные с помощью CREATE массивы содержат столько байт, сколько захочет программист.

DOVAR: КП3 Сx 1 ИП7 + КБП9

Одновременно в RY заносится число с вершины стека, освобождая RX под новое значение. Команды КП3 сохраняют в стеке данных содержимое регистра Y. КБП9 передаёт управление INEXT, безо всяких трюков осуществляя переход к следующему слову. После команд Сx 1 ИП7 + этим новым значением на вершине стека становится адрес поля параметров исполняемого слова.

3.3.3 Обработчики констант: DOCON и DOCONM

В отличии от DOVAR, обработчик констант обращается к полю параметров своего слова сам. DOCON считывает из него 16-битное значение константы. Это значение всегда положительно.

DOCON: КП3
ИП7 П5 Сx 256
КИП5 × КИП5 + КБП9

Но на этот раз старая вершина стека данных возвращается в RX. Команды КП3 сохраняют RY в стеке данных. Далее Сx 256 заменяет мусор в регистре X на число 256. Команды ИП7 П5 вытесняют её обратно в RY, одновременно готовя регистр-указатель R5 к считыванию значения константы.

Как мы помним, в МК-161 первый байт всегда старший. Команды КИП5 × КИП5 + считывают константу из поля параметров на вершину стека данных, то есть в RX. Вся работа сделана, КБП9 передаёт управление следующему слову. Он и умножается на 256, после чего к произведению прибавляется младший байт константы.

Отрицательные константы реализованы на МК-161 отдельным обработчиком ради быстродействия: DOCONM работает точно также, только знак константы после считывания изменяется на противоположный.

DOCONM: КП3
ИП7 П5 Сx 256
КИП5 × КИП5 + /-/ КБП9

3. Теперь мы полностью разобрались, как eForth исполняет свой код на «Электронике МК-161» из области данных, даже чуть затронув более глубокую тему строковых литералов (см. 5). 1.

Эта часть транслятора потребовала от меня разработки значительно более радикальных решений, на фоне которых разобранное выше — традиционный Форт, старый и добрый. Во второй статье цикла я разберу внешний «текстовый» интерпретатор 161eForth, структуру таблиц заголовков и распознавания имени.

Счастливого программирования на Форте!

Литература

  1. Dr. Chen-Hanson Ting. eForth and Zen — 3rd Edition, 2017. Есть на Amazon Kindle.
  2. Баранов С.Н., Ноздрунов Н.Р. Язык Форт и его реализации. — Л.: Машиностроение. Ленингр. отд-ние, 1988.
  3. Семёнов Ю.А. Программирование на языке ФОРТ. — М.: Радио и связь, 1991.
  4. Стандарт ANS Forth. X3.215-1994. Перевод: http://oco.org.ua/download/forth/dpans94_ru.html
  5. Документация по SP-Forth: http://spf.sourceforge.net/docs/readme.ru.html
Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть