Переводчик Го Обероны

Введение История движется по спирали.

Авторы Go, стоя на плечах авторитетной корпорации Google, смогли воплотить в жизнь свой идеальный язык программирования, подобно тому, как Никлаус Вирт когда-то принес в этот мир язык Oberon, борясь своей стойкостью и авторитетом с зарождающейся тенденцией сложность и обширное развитие основных языков.

Сегодня язык Оберон забыт, но работа Вирта совершенно неожиданно появилась на языке Го.

В некоторых аспектах реализации сходство подходов неоспоримо.

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

Время невозможно повернуть вспять.

Но в разные времена люди стремились сохранить ушедшие в прошлое технологии.

Подумайте о ценности бережно сохранившихся эмуляторов Spectrum и MSX и музеев старых компьютеров в разных странах.

«Муляция, как один из способов остановить мгновение, прочно зарекомендовала себя.

Принято считать, что язык Go нашел себя в нише сетевых сервисов.

Но мы пойдем другим путем.

Задача История языка Оберон включает несколько вариантов языка.

Каждое издание Н.

Вирт создавал под конкретный проект; его языки всегда создавались под задачу, исходя из ее целей.

Оберон-2 создавался как вариант Оберона с развитым механизмом типов данных, реализующим концепцию ООП.

Ученики Н.

Вирта решили, что «Оберон-2» пригоден для промышленного программирования.

Они добавили в язык функции, расширили систему типов для совместимости с набирающей популярность Java, реализовали идею истинной модульности и выпустили продукт BlackBox с языком Component Pascal (CP) внутри.

Шло время, корпорации из-за океана все успешнее выходили на рынок и BlackBox ушел в тень, оставаясь объектом исследования небольшой группы энтузиастов, в том числе из России и стран СНГ.

Одним из принципов CP является модульность, возможность изменять реализацию компонента без изменения его интерфейса (применительно к объектам это называется pimpl).

И вот я задумался, чем конкретный фреймворк отличается от реализации компонента.

И описание языка — его интерфейса… Проще говоря, мне пришло в голову реализовать интерпретатор с функциями фреймворка.

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

Расследование Особенностью платформы BlackBox является динамическое связывание модулей в памяти процесса.

Как известно, процесс создания программы из исходного кода состоит из нескольких этапов.

В разных реализациях разных компиляторов эти этапы могут быть скрыты, пропущены или примитивизированы.

Связывание — это приведение машинного кода к форме, приемлемой для непосредственного выполнения процессором.

Например, в Go компоновка статическая, на этапе компиляции.

А в BlackBox — динамически, на этапе загрузки тела модуля в память.

Интересной особенностью этого решения является независимость кода от операционной системы, когда один и тот же машинный код выполняется в разных ОС без перекомпиляции, при условии, что они имеют одинаковую архитектуру (например, x86).

Однако компилятор BlackBox предоставляет еще один вариант — изменение генератора кода под конкретную архитектуру.

Такой результат достигается за счет использования внутри компилятора структуры AST — абстрактного синтаксического дерева для платформонезависимого сохранения структуры программ и данных.

Нам удалось выяснить, что BlackBox изначально был написан для платформы Mac+PowerPC, а уже потом переписан для Wintel. При этом компилятор практически не изменился.

Съемный бэкенд сегодня не так уж и удивителен, но в 90-е годы это было необычно и ново.

Таким образом, эти две функции позволили мне создать свой собственный бэкэнд. Без особых усилий я преобразовал AST в формат XML, точнее, Graphml, с прицелом на красивую визуализацию процесса интерпретации.

Планов было много.

Решение Для реализации я выбрал язык Go, хотя мог бы выбрать Java, C#, Dart и другие.

Почему? Причин несколько, главная из них — информация о том, что Go по своей природе похож на Оберон, отсекает все лишнее из процесса выражения предметной области.

Взять, к примеру, исключения, эти легкие, легализованные, якобы безобидные аналоги оператора GOTO. Отличный повод изучить Го.

Я просто назвал проект: Рамки .

Небольшой экскурс в описание языка – и в бой.

Десериализация XML в структуры с использованием тегов — это здорово.

Скрывать данные в пакетах — это здорово, давайте воспользуемся нашим любимым пимплом.

Утиный набор интерфейсов меня поначалу смутил, но после пары ударов пришло понимание.

Основная ошибка здесь — сравнение интерфейсов с разными именами с одним и тем же набором методов.

Этот набор может формироваться исторически, и даже опытный разработчик может обнаружить, что typeswitch для типа A обрабатывает тип B и закономерно выходит из строя.

Итак, AST загружен в память, основные узлы описаны, правила интерпретации известны.

Как оказалось, существует множество типов узлов.

Есть еще больше типов данных.

Одним из основных принципов, которые я принял, был принцип «пусть все упадет»; в любой непонятной ситуации программа прекращает свою работу.

Конечно, проект дома допускал такие вольности.

Интерпретация алгоритмов интересна.

АСТ языка КП состоит из операторов, выражений и указателей на объекты (оператор, выражение, указатель).

Операторы следуют друг за другом, модифицируют объекты и изменяют ход программы в зависимости от подчиненных узлов (выражений или указателей).

В данном случае есть два подчиненных узла – левый и правый.

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

Каждый узел в стеке связан с фреймом, в котором хранится результат обработки дочерних узлов и инструкции от родительских узлов.

Конкретные действия для конкретного узла являются основной частью интерпретации программы.

Программа выполняется, пока операторы, управляющие потоком выполнения, помещают один или несколько следующих операторов в стек для выполнения.

Как только стек опустеет или результат итерации вернет код ошибки, программа останавливается.

Ничего сложного.

Для хранения данных в высокоуровневой среде языка Go можно описывать различные типы данных, в том числе примитивные.

Я увидел в этом еще одно преимущество языка Go для реализации интерпретатора.

Полный список правил, по которым составляется AST-дерево, можно посмотреть Здесь .

Пример Кратко опишу процесс интерпретации узлов простой программы.

   

MODULE XevDemo2; VAR

Теги: #Go #oberon #Go
Вместе с данным постом часто просматривают: