Рефераты. Интерактивный интерпретатор

#вычисляет угол треугольника со сторонами

#a, b и c между сторонами a и b (в градусах)

if ~isnum[a]|~isnum[b]|~isnum[c]

println "Invalid arguments"

error

endif

if (a<=0)|(b<=0)|(c<=0)

println "Not a triangle"

error

endif

cos_alpha:=(a*a+b*b-c*c)/(2*a*b)

if (cos_alpha>=1)|(cos_alpha<=-1)

println "Not a triangle"

error

endif

alpha:=arccos[cos_alpha]

result:=alpha*180/pi[]

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

Для реализации интерпретатора было решено использовать платформу Microsoft .NET v.1.1 и язык программирования C#. Это связано с тем, что платформа .NET обеспечивает достаточно высокую производительность (быстродействие) приложений при значительном увеличении скорости разработки. Последнее обеспечивается за счет наличия удобных визуальных средств разработки, обширной и мощной стандартной библиотеки классов, использования автоматической сборки мусора, когда память из-под более неиспользуемых объектов освобождается автоматически. Язык C# же является основным языком платформы .NET, позволяющим полностью использовать все преимущества технологии Microsoft .NET, он имеет весьма гибкий синтаксис, позволяющий реализовывать достаточно сложные алгоритмы сравнительно небольшими, но легко читаемыми фрагментами кода.

В программе можно выделить две основные группы классов, две подсистемы, ответственные за логику работы интерпретатора и графический интерфейс пользователя соответственно. Поскольку первая подсистема содержит значительно большее число классов, чем вторая, было решено расположить ее в отдельном пространстве имен logic, вложенном в корневое пространство имен проекта. Классы, ответственные за графический интерфейс пользователя, расположены непосредственно в корневом пространстве имен проекта. Кроме того, в пространстве имен logic имеется два вложенных пространства имен - operators и vartypes, соответствующие двум основным иерархиям наследования в проекте - операторам программы и типам данных. Корневое пространство имен имеет имя interpr. Диаграмма пакетов проекта изображена на рис. 1.

Роль посредника между пользовательским интерфейсом и подсистемой, реализующей логику работы интерпретатора, выполняет класс Facade (фасад). Он также ответственен за создание отдельного потока для выполнения команд пользователя (вводимых с консоли). Выполнять их в том же потоке, что и обрабатывать сообщения пользовательского интерфейса нельзя так как в этом случае зациклившуюся пользовательскую функцию будет невозможно прервать. Многие методы класса Facade сводятся к простому вызову методов других классов из пространства имен logic. Этот класс в дальнейшем будет рассмотрен более подробно.

Для обработки ошибок применяется механизм структурной обработки исключений. При этом используются следующие классы пользовательских исключений (для ошибок в классах пространства имен interpr.logic):

· CalcException - ошибка по вине пользователя (синтаксическая или в вычислениях);

· SyntaxErrorException - синтаксическая ошибка, обнаруживаемая во время «компиляции», т. е. при загрузки функции или преобразования введенной команды во внутренний формат. Унаследован от CalcException;

· LineSyntaxException - синтаксическая ошибка в конкретном операторе функции. Содержит информацию об месте обнаружения (имя функции, строка).

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

· LinkedListException - ошибка в методах класса LinkedList. Унаследован от класса OtherException.

· NamespaceSerializationException - унаследован непосредственно от System.Exception. Такое исключение - генерируется если пространство имен консоли не может быть успешно восстановлено.

Соответствующая диаграмма классов изображена на рис. 2.

Можно выделить несколько групп классов в пространстве имен interpr.logic - классы, ответственные за вычисление выражений, за выполнение пользовательских функций, за преобразование текста команд и пользовательских функций во внутренний формат («компиляцию» текста программы), классы, участвующие в организации интерактивной работы интерпретатора. Эти группы классов, равно как и подсистема графического интерфейса пользователя, будут рассмотрены ниже. В пространстве имен interpr.logic также имеется один класс вспомогательного назначения - LinkedList. Он представляет двухсвязный список. В нем имеются методы и свойства добавления и чтения элементов в начале и конце списка, определения числа элементов списка. При этом, при попытке чтения из пустого списка, генерируется исключениеLinkedListException. Метод GetIterator(), существующий в двух перегруженных версиях (для первого элемента списка и для заданного индекса), возвращает объект вложенного класса LinkedList.Iterator, который представляет собой итератор, позволяющий читать элементы списка, перемещаясь по нему от начала к концу, а также двигаться в обратном направлении. Элемент списка представляется объектом частного вложенного класса Link, содержащего три поля с видимостью internal - одно для хранения значения элемента списка и два для ссылок на предыдущий и следующий элементы.

Следует также отметить интерфейс interpr.logic.IConsole, представляющий нечто, что может быть использовано для вывода текста. Он имеет два метода - void Print(string str) и void PrintLn(string str), назначение которых понятно из названия.

Основные классы пространства имен interpr.logic показаны на диаграмме на рис. 3.

Рис. 3.

Классы пространства имен interpr.logic.

Внутреннее представление и выполнение программы.

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

Обычная математическая запись арифметических выражений представляет собой так называемую инфиксную запись, в которой знаки операций располагаются между операндами. При этом для уточнения порядка вычисления операций используются приоритеты операций и круглые скобки. Такая форма записи удобна для человека, но неудобна для ЭВМ. Поэтому часто используют так называемую постфиксную или обратную польскую запись. В этом случае знак операции записываются после всех ее операндов, а вычисление производится по довольно простому алгоритму: выражение в ОПЗ последовательно просматриваем слева направо. Если встречаем операнд, то заносим его в стек, если же встречаем операцию, то выбираем ее операнды из стека, выполняем операцию и заносим результат в стек. В начале вычисления выражения стек пуст. Если выражение записано корректно, то при выполнении каждой операции число элементов стека будет не меньше числа ее операндов, и в конце процесса в стеке останется ровно одно значение - результат вычисления выражения. Особенностью ОПЗ является отсутствие необходимости в использовании скобок.

Например, выражение a+(b*c-d)/e в ОПЗ имеет вид abc*d-e/+. Применим к нему описанный выше алгоритм вычисления.

1. Заносим в стек a.

2. Заносим в стек b.

3. Заносим в стек c.

Состояние стека на этот момент: a, b, c - вершина.

4. Извлекаем из стека операнды операции умножения - b и c и заносим в стек результат.

Стек: a, b*c.

5. Заносим в стек d.

Стек: a, b*c, d.

6. Извлекаем из стека операнды, производим вычитание, заносим в стек результат.

Стек: a, b*c-d.

7. Заносим в стек e.

Стек: a, b*c-d, e.

8. Извлекаем из стека операнды, производим деление, заносим в стек результат.

Стек: a, (b*c-d)/e.

9. Извлекаем из стека операнды, производим сложение, заносим в стек результат.

Итого получаем в стеке a+(b*c-d)/e, что и требовалось.

Для представления выражений в интерпретаторе используется класс Expression. Он содержит обратную польскую запись выражения в виде связанного списка (однонаправленного). Звено этого списка, равно как и стека, используемого при вычислении выражения, представляется объектом вложенного класса Expression.Element, содержащим ссылки на следующее звено и на объект, реализующий интерфейс IComputable, который содержит один метод logic.vartypes.VarBase Compute() - получить значение. Вычисление значения выражения по рассмотренном выше алгоритму производится в методе VarBase Expression.Calculate(). Строка, содержащая запись выражения, обрабатывается в конструкторе этого класса. Интерфейс IComputable реализован тремя классами:

· VarBase - абстрактный класс, представляющий значение любого типа данных;

· VarName - представляет переменную по ее имени;

· Call - представляет вызов операции либо функции.

Вначале рассмотрим классы, представляющие значения различных типов. Все они являются потомками только что названного класса VarBase. Как было сказано выше, в языке существует четыре типа данных - целое число, вещественное число, строка и массив. При этом числовые и строковый типы, в противоположность массиву, называются простыми типами. Для простых значений базовым является абстрактный класс SingleVar. Целый и вещественный типы также особо выделяются как числовые, и для них существует свой базовый абстрактный класс NumVar. Наконец, каждому из четырех типов данных соответствует свой конкретный класс - IntVar, RealVar, StringVar и ArrayVar. Эта иерархия классов находится в пространстве имен interpr.logic.vartypes. Она изображена на диаграмме на рис. 4.

Страницы: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17



2012 © Все права защищены
При использовании материалов активная ссылка на источник обязательна.