My favorites | Sign in
Project Home Downloads Wiki Issues Source
Search
for
implementation_ru  
Внутреннее устройство Scato
Updated Feb 4, 2010 by a.michu...@gmail.com

Внутреннее устройство Scato

Эта страница адресована тем, кто хочет поучаствовать в проекте, приложив собственные силы к его развитию.

Здесь я вкратце описываю основные идеи, алгоритмы и процедуры функционирования Scato, а так же логическое разбиение кода.

Эта информация будет полезна разработчикам, однако её может быть не достаточно. Если у вас останутся вопросы - обращайтесь.

Обзор модулей и пакетов

Модуль scato.draw_area

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

DrawArea берёт на себя заботу о масштабировании поля, о перерисовке объектов при изменении размеров поля. Так же DrawArea умеет экспортировать картинку в виде PostScript-файла.

Модуль scato.tortoise

Модуль предоставляет объект Tortoise, предоставляющий интерфейс к черепашке. Здесь хранится весь контекст черепашки: цвета, координаты, толщина линии, масштабы, повороты.

Кроме того, черепашка может клонироваться. Операторы языка transform и local эксплуатируют именно эту возможность для сохранения контекста.

Пакет scato.ui

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

Модуль scato.language

Реализация языка.

Логика языка

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

Единственный элемент, предоставляющий контекстную свободу, это блок begin/end.

Такая простота накладывает некоторые (и довольно существенные) ограничения, но мне бы не хотелось от неё отказываться по двум соображениям:

Во-первых, упомянутые ограничения не являются принципиальными, oни лишь иногда заставляют программиста использовать более длинные конструкции, но никак не сужают его (программиста) возможностей. Кроме того, это неудобство касается только реализации вычислений, но Scato и не позиционируется как средство для сложных вычислений. Все параметры, необходимые для рисования, можно вычислить отдельно.

Во-вторых, внесение дополнительных элементов, освобождающих контекст, не только усложнит Scato (что уже само по себе не очень хорошо), но и усложнит отладку и пошаговое выполнение. Придётся ответить на вопросы, какие элементы считать атомарными, а какие выполнять в несколько действий. Видимо это потребует дополнительных опций в меню, дополнительных условий в исполняющем коде и приведёт к заметному усложнению Scato не только с точки зрения разработчика, но и с точки зрения пользователя.

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

Логика интерпретации языка и выполнения программы

Обработка программы происходит в два этапа:

  • Разбор текста и создание внутреннего представления
  • Обработка внутреннего представления и создание изображения

Создание внутреннего представления

Разбор происходит классическим методом рекурсивного спуска.

На этом этапе создаются объекты Statment*.

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

Выполнение

Ключевым элементом этапа выполнения является контекст. Это контейнер с которым работают объекты операций. Он хранит черепаху, переменные, именованные функции, строку состояния (отладка) и объект, который надо выполнить следующим.

Объекты бывают двух видов -- атомарные и комплексные.

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

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

Комплексные объекты являются фабриками (это должны быть именно фабрики, иначе язык не будет поддерживать рекурсию). При каждом вызове, фабрика порождает новый объект -- исполнитель.

Исполнитель запоминает нужные аспекты контекста, в частности, указатель на следующий вызов. Фабрика устанавливает исполнителя в качестве объекта, подлежащего вызову в следующий раз. (В некоторых случаях, фабрика может сразу же вызывать первый шаг исполнителя.)

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

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


Sign in to add a comment
Powered by Google Project Hosting