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

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

Рубрика Программирование, компьютеры и кибернетика
Вид курсовая работа
Язык русский
Дата добавления 17.09.2008
Размер файла 287,3 K

Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже

Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.

· строковая константа;

· идентификатор;

· число (целое или вещественное, возможно, в экспоненциальной форме);

· служебный символ;

· составной служебный символ (`:=', `<=', `>=', `~=', `<>').

Метод GetCurrent() выделяет в строке длинную возможную лексему, начинающуюся с текущей позиции.

Кроме того, класс Parser имеет два открытых статических метода: bool IsID(string) - является ли данная строка корректным идентификатором и bool IsUserID(string) - является ли данная строка корректным идентификатором, не совпадающим с именем какой-либо из встроенных функций.

Преобразование выражений в описанное ранее внутреннее представление производится в конструкторе класса Expression, который имеет две перегруженные версии, принимающие параметры типа string и Parser соответственно. В обеих вызывается private-метод Analyse(), в котором лексемы из строки заносятся в список типа LinkedList (этот класс был рассмотрен выше), который затем передается в качестве параметра другому private-методу OPZ(). В последнем и сосредоточена основная часть алгоритма разбора выражения. Этот алгоритм относится к так называемым восходящим методам синтаксического разбора, в которых дерево разбора строится «снизу вверх». Синтаксический анализ здесь совмещен с семантической обработкой - построением обратной польской записи выражения. Преобразование выражения в ОПЗ производится следующим образом:

· Вначале создается пустой стек операций (объект класса LinkedList).

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

· Каждая бинарная операция имеет свой приоритет (можно получить в виде числа с помощью private-функции Expression.Priority()).

· Бинарная операция выталкивает из стека в результат операции с большим или равным приоритетом (с вершины стека), затем сама записывается в стек. Для символов `+' и `-' производится проверка, являются они в каждом конкретном случае знаком бинарной операции или унарной - в случае унарной операции перед ее знаком находится открывающая скобка либо другая операция, или операция находится в начале строки.

· Унарная операция сразу записывается в стек.

· Открывающая круглая скобка сразу записывается в стек.

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

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

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

· После обработки вызова функции или обращения к элементу массива в результат выталкиваются с вершины стека унарные операции, если они присутствуют.

· В конце разбора в результат выталкивается все содержимое стека.

· Константы записываются в результат как объекты классов, представляющих соответствующие типы данных, переменные - как объекты VarName, операции и вызовы функций - как объекты Call.

Рассмотрим пример. Пусть имеется строка (a*c+-b{а+с})/а. Применим описанный алгоритм.

1. Вначале стек операндов и результат пусты.

2. Первая лексема - открывающая круглая скобка. Записываем ее в стек.

Стек: (Результат: <пусто>.

3. Вторая лексема - идентификатор «а». За ним нет открывающей квадратной или фигурной скобки, поэтому записываем его в результат.

4. Стек: (Результат: а

5. Следующая лексема - операция умножения. Записываем ее в стек. На вершине стека нет операций с большим или равным приоритетом, ничего выталкивать не нужно.

6. Стек: (*Результат: а

7. Вторая лексема - идентификатор «с». За ним нет открывающей квадратной или фигурной скобки, поэтому записываем его в результат.

Стек: (*Результат: ас

8. Следующая лексема - знак «+». Перед ним находится идентификатор, поэтому он является знаком операции сложения. Он выталкивает из стека операцию умножения как имеющую более высокий приоритет, затем сам дописывается в стек.

9. Стек: (+ Результат: ас*

10. Следующая лексема - знак «минус». Перед ним нет ни закрывающей скобки ни идентификатора, поэтому он является знаком операции унарный минус (обозначим ее как «_»), записываем ее в стек.

11. Стек: (+_Результат: ас*

12. Следующая лексема - идентификатор b. За ним следует фигурная скобка, поэтому он рассматривается как имя массива. В фигурных скобках находится строка «а+с», которая, будучи преобразованной по рассматриваемому алгоритму, даст в результате «ас+». Допишем это в результат разбора исходного выражения. Затем допишем в результат имя массива («b») и операцию индексации (обозначим ее «{}»). И, наконец, вытолкнем находящуюся на вершине стека операцию унарный минус.

13. Стек: (+Результат: ас*ас+b{}_

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

Стек; <пусто>Результат: ac*ac+b{}_+

15. Следующая лексема - операция деления. Она дописывается в стек (перед этим стек пуст, ничего выталкивать не нужно).

Стек: /Результат: ac*ac+b{}_+

16. Последняя лексема - идентификатор «а». После него нет никаких скобок, поэтому он сразу же добавляется к результату.

Стек: /Результат: ac*ac+b{}_+a

17. В конце выталкиваем из стека оставшуюся в нем операцию умножения в результат. Итого получаем ac*ac+_b{}+a/, что является обратной польской записью исходного выражения.

При загрузке функции обработка ее текста осуществляется в конструкторе класса Subroutine, который принимает два параметра - имя функции и текст функции (в виде массива строк). При этом отдельно рассматривается первая строка - заголовок функции. Для ее анализа используется private-метод Subroutine.AnalyseHeader(), в котором проверяется соответствие этой строки требуемому формату и извлекается список формальных параметров. Также проверяется соответствие имени функции в заголовке требуемому (первому параметру конструктора). При этом используется объект класса Parser. Затем по очереди подвергаются разбору с помощью метода LineCompiler.CompileOperator() остальные строки, результат «компиляции» каждой из которых добавляется в список операторов функции. При этом используется стек вложенности операторов (применяется объект класса System.Collections.Stack). После обработки каждой строки проверяется тип полученного оператора с помощью метода IOperator.GetType(). Если оператор открывает блок кода (if, elseif, else, while, for), то его номер заносится в стек. Если оператор закрывает блок кода, то из стека извлекается номер парного оператора и присваиваются необходимые значения свойствам NextPos, LoopPos и т. д. соответствующих объектов. Операторы elseif и else рассматриваются одновременно и как закрывающие расположенный выше блок кода, и как открывающие следующий. Нужно отметить, что в первый элемент списка операторов функции (с нулевым индексом) в объекте Subroutine помещается пустой оператор (объект EmptyCommand), благодаря чему каждой строке текста функции соответствует элемент этого списка с индексом, равным номеру этой строки. Основная часть кода конструктора класса Subroutine находится в блоке try, при возникновении исключения SyntaxErrorException в котором генерируется исключение класса LineSyntaxException, объект которого содержит информацию о месте ошибки (имя функции и номер строки).

Графический интерфейс пользователя.

Главной форме приложения, которая изображена на рис. 7, соответствует класс Form1. Основную часть формы занимает компонент ConsoleBox, созданный на основе класса UserControl. Он включает в себя один экземпляр компонента RichTextBox, «растянутый» с помощью свойства Dock на всю доступную площадь. Компонент ConsoleBox представляет собой окно консоли, в которой пользователь вводит команды, и на которую выводятся результаты работы команд. Класс ConsoleBox является единственным классом в окончательной версии проекта, реализующим рассмотренный выше интерфейс IConsole. Важнейшие члены класса ConsoleBox:

· методы Print(string) и PrintLn(string) - реализуют методы интерфейса IConsole, производят вывод текста в окно консоли.

· метод Prompt() - выводит приглашение командной строки (“>>>”) и переводит консоль в режим ожидания команды.

· событие GetCommand (object sender, ConsoleBoxGetCommandEventArgs e) - возникает, когда в режиме ожидания команды была нажата клавиша Enter. При этом в параметре e, имеющем тип класса ConsoleBoxGetCommandEventArgs, который унаследован от System.EventArgs, в свойстве Command содержится введенная пользователем команда в виде строки.

Методы Print, PrintLn и Prompt рассчитаны на безопасное использование из другого потока. В них используется вызов private-методов через объект класса System.Windows.Forms.MethodInvoker. Возможны два состояния компонента консоли - режим ожидания ввода команды и режим работы команды. Ввод текста в поле RichTextBox допускается только в режиме ожидания ввода команды и только после последнего приглашения командной строки, что обеспечивается с помощью свойства RichTextBox.SelectionProtected. Вызов метода Prompt() переводит консоль в режим ожидания команды. При нажатии Enter в режиме ожидания команды, помимо генерации события GetCommand, происходит переход из режима ожидания в режим работы команды.

Рис. 7.

Главная форма.

При нажатии кнопки «Функции» на главной форме выводится диалоговое окно, которому соответствует класс FunctionsForm (см. рис. 8). В этом окне в верхнем поле отображается список успешно загруженных функций, в нижнем - функций, загрузка которых прошла неудачно по причине наличия синтаксических ошибок. Кнопки позволяют редактировать, удалить (в этом случае требуется подтверждение) выбранную функцию, создать новую функцию (в этом случае будет запрошено имя функции, и, если оно не является корректным идентификатором, функция создана не будет). Для запроса имени при создании функции используется форма, описывающаяся классом InputForm (см. рис. 9). Если функция создана успешно, она открывается для редактирования. При двойном щелчке по имени функции в любом из списков в окне «Функции» также она открывается для редактирования. Окно «Функции» является модальным диалогом и должно быть закрыто для продолжения работы с интерпретатором. Оно закрывается при открытии функции для редактирования. При этом вместо него на экране появляется окно редактора кода.

Рис. 8.

Окно «Функции»

Рис. 9.

Окно ввода имени создаваемой функции.

Окну редактора кода соответствует класс EditorForm (см. рис. 10). Кнопка «Сохранить» в нем сохраняет функцию в файле, расположенном в подкаталоге subroutines рабочего каталога интерпретатора, с именем, совпадающим с именем функции (без расширения). Кнопка «Выход» - закрывает окно редактора (с запросом на сохранение). В метке справа от кнопок отображается номер строки текущего положения курсора (начала выделения) в тексте. В ее текст номер текущей строки заносится приблизительно 10 раз в секунду, что обеспечивается с помощью таймера (компонент System.Windows.Forms.Timer).Окно редактора кода не является модальным - в любой момент работы с интерпретатором может быть открыто сколько угодно таких окон для разных функций. Заблокированы открытие функции второй раз (в двух окнах одновременно) и выход из интерпретатора до закрытия всех окон редактора кода. Основную часть окна редактора кода составляет компонент SourceBox, который также как и ConsoleBox, унаследован от классаUserControl. Он содержит элемент управления RichTextBox, в котором, собственно, и осуществляется редактирование текста функции, и элемент TextBox, расположенный за RichTextBox на заднем плане и невидимый для пользователя. На него переключается фокус на время выполнения синтаксического цветовыделения, так как для изменения цвета фрагмента текста в RichTextBox необходимо этот фрагмент выделить, что приводило бы к заметному мерцанию текста, если бы фокус ввода оставался у поля RichTextBox. Такой подход к решению проблемы позволяет реализовать синтаксическое цветовыделение с использованием свойств класса RichTextBox небольшим объемом кода (иначе бы пришлось производить «ручную» перерисовку с непосредственным использованием GDI+). Но к сожалению, заметно снижается быстродействие, в связи с этим были введены следующие ограничения: синтаксическое цветовыделение производится только при изменении номера строки, в которой находится курсор, например, при нажатии Enter, а также при щелчке левой кнопкой мыши в окне редактора (в RichTextBox). При этом обрабатываются только строки текста, отображаемые в данный момент времени в окне. Конечно, это несколько неудобно для пользователя, подобное можно наблюдать, например, в такой среде программирования, как MS Visual Basic 6. Для выполнения синтаксического цветовыделения используется вложенный private-класс HighlightParser, который имеет методы для разбора строки на отдельные лексемы, для определения положения в строке и типа этих лексем. Применить класс interpr.logic.Parser здесь нельзя, так как он работает с преобразованной строкой (удалены лишние пробелы и комментарии). Класс SourceBox также имеет методы для чтения текста функции из файла и сохранения текста в файле.

Рис. 10.

Окно редактора кода.

При нажатии на кнопку «Переменные» в главном окне интерпретатора отображается диалоговое окно со списком переменных среды консоли (см. рис. 11). Переменные отображаются вместе с их значениями (приведенными к строковому типу). Данное окно позволяет удалить выбранную или все переменные из памяти. Этому окну соответствует класс VariablesForm. При нажатии кнопки «Перезапуск» производится перезапуск интерпретатора (возможно, с прерыванием зациклившейся или долго работающей пользовательской функции). При перезапуске не восстанавливаются измененные значения переменных среды консоли, поэтому предусмотрена возможность сохранения значений переменных. Сохранение переменных происходит автоматически при выходе из интерпретатора и вручную при нажатии кнопки «Сохранить переменные». Переменные сохраняются в двоичном файл variables, который автоматически создается в рабочем каталоге интерпретатора, и считываются из него при запуске или перезапуске интерпретатора. Сохранять переменные вручную имеет смысл перед запуском пользовательской функции, которая может зациклиться или слишком долго работать, чтобы можно было прервать ее работу, не опасаясь потерять результаты предыдущих вычислений. Работа с переменными осуществляется с помощью методов класса Facade, обращающихся к соответствующим методам классов из пространства имен interpr.logic.

Классы, относящиеся к пользовательскому интерфейсу интерпретатора, показаны на диаграмме на рис. 12.

Рис. 11.

Окно «Переменные».

Рис. 12.

Классы, связанные с графическим интерфейсом пользователя.

Взаимодействие подсистем интерпретатора. Класс Facade.

Как уже было сказано выше, класс Facade является посредником между двумя основными подсистемами - графическим интерфейсом пользователя и логикой работы интерпретатора. Здесь использован паттерн Facade. Все обращения извне к классам пространства имен interpr.logic производятся через вызов методов класса Facade. Сама же подсистема логики работы интерпретатора не хранит ссылок, как это требует данный паттерн, ни на класс Facade, ни на другие классы, не входящие в нее. Таким образом, класс Facade является как бы мостом между пространством имен interpr.logic и классами, реализующими пользовательский интерфейс.

При запуске интерпретатора в обработчике события Load класса Form1 происходит начальная инициализация приложения. Вначале вызывается статический метод Facade.Create(), которому передается ссылка на элемент управления ConsoleBox, расположенный на главной форме интерпретатора. Тип этого параметра - интерфейс IConsole. Переданная ссылка но объект консоли присваивается свойству InterprEnvironment.CurrentConsole. В методе Facade.Create() создается единственный объект класса Facade, к которому в дальнейшем доступ осуществляется через статическое свойство только для чтения Facade.Instance. Здесь используется паттерн Singleton.

При первом обращении к свойству InterprEnvironment.Instance вызывается конструктор класса InterprEnvironment, В нем создается объект ConsoleNamespace для пространства имен консоли. Затем производится восстановление переменных, сохраненных в файле variables в рабочем каталоге интерпретатора. Если этот файл отсутствует, то он создается (пустой) и восстановление не производится. Данный файл является двоичным. В его начале записывается общее число переменных, затем для каждой из них сохраняется информация о типе (один символ), имя (строка) и значение. Для массива после имени записывается общее число элементов, затем каждый из элементов в виде пары «тип-значение». Восстановление переменных производится в методе ConsoleNamespace.Restore(). Если восстановление не прошло успешно по причине неправильного формата файла variables, то в методе Restore() генерируется исключение NamespaceSerialisationException. Оно перехватывается в конструкторе класса InterprEnvironment, в результате чего изменяется значение соответствующего поля, после этого свойство InterprEnvironment.NotRestored, как и обращающееся к нему свойство Facade.NotRestored, возвращает истину. В случае, если такая ошибка произошла, в обработчике Form1.Form1_Load выдается соответствующее сообщение пользователю.

На следующем шаге инициализации устанавливается обработчик для события Facade.Done (завершение выполнения команды). Затем загружаются пользовательские функции с помощью метода Facade.LoadSubs(), вызывающего метод InterprEnvironment.LoadSubs(). Если при загрузке какой-либо функции произошла ошибка, сообщение выводится на консоль. Наконец, вызывается метод Prompt() (вывести приглашение и ждать ввода команды) элемента управления ConsoleBox, расположенного на главной форме.

Класс Facade имеет целый ряд методов для работы с пользовательскими функциями и переменными среды консоли, которые вызывают соответствующие методы объекта InterprEnvironment.Instance. Среди них: LoadSub(), LoadSubs(), GetSubs(), UnloadSub(), GetVariables(), DeleteVariable(), SaveVariables(). Через эти методы производятся операции во многих обработчиках событий пользовательского интерфейса.

Но, пожалуй, наиболее важным из методов класса Facade является ExecuteCommand() - выполнить команду. Он вызывается в обработчике события GetCommand элемента ConsoleBox на главной форме. В нем в отдельном потоке запускается на выполнение частный метод ThrStart(), в котором введенная с консоли команда сначала «компилируется» методом LineCompiler.CompileCommand(), затем выполняется, по окончании чего генерируется событие Facade.Done(), в обработчике которого консоль переводится в состояние ожидания следующей команды методом ConsoleBox.Prompt(). И «компиляция» и выполнение команды производятся в блоках try, в случае возникновения исключения на консоль выдается соответствующее сообщение об ошибке.

Необходимость выполнять команды в отдельном потоке связана с тем, что только в этом случае можно прервать зациклившуюся или долго работающую пользовательскую функцию без аварийного завершения интерпретатора. Для перезапуска интерпретатора, возможно, с прерыванием работы пользовательской функции, предназначен метод Facade.Restart(). В нем в отдельном потоке запускается метод DoRestart(), в котором выполняются следующие действия. Во-первых, если в данный момент времени выполняется команда, то вызывается статический метод Subroutine.Moment.Break().В нем с помощью метода Interlocked.Exchange() (безопасное при параллельном выполнении присваивание) статическому полю Subroutine.Moment.s_break присваивается значение 1. На каждой итерации цикла в методе Subroutine.Moment.Run(), помимо выполнения очередного оператора функции, проверяется значение этого поля. Если оно равно единице, то генерируется исключение CalcException, то есть выполнение команды завершается с ошибкой времени выполнения. После вызова Subroutine.Moment.Break() в методе DoRestart() следует цикл без тела, который выполняется до тех пор, пока выполнение команды не будет завершено, чего, конечно же, не приходится долго ждать. После того, как выполнение будет прервано, производится повторная инициализация, аналогичная происходящей при запуске интерпретатора.

Для реализации многопоточности используется стандартный класс System.Threading.Thread. Его конструктору передается один параметр типа делегата System.Threading.ThreadStart (процедура без параметров). Метод, на который указывает этот делегат, начинает выполняться в отдельном потоке при вызове метода Start() объекта потока. Когда метод, запущенный в потоке, возвращается, выполнение потока завершается. Повторное использование того же объекта класса Thread невозможно, его нужно создавать заново. При использовании многопоточности следует принимать ряд мер предосторожности для обеспечения безопасного доступа к общим данным. Например, присваивание значений переменным, используемым несколькими потоками, по возможности следует производить с помощью метода Interlocked.Exchange, который гарантирует атомарность операции, то есть то, что ее выполнение не будет прервано до полного завершения для передачи управления другому потоку. Также обращаться к методам и свойствам элементов графического интерфейса пользователя напрямую можно только из того же потока, в котором они были созданы. Если необходимо воздействовать на графический интерфейс пользователя из других потоков, то это следует делать в методе (процедуре без параметров), вызываемом с помощью делегата System.Windows.Forms.MethodInvoker. В языке C# имеются и другие средства синхронизации работы потоков, которые не используются в данном интерпретаторе.

Заключение

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

Приложение. Исходный текст (сокращенно).

Ввиду большого объема исходного кода, приведены лишь наиболее важные его фрагменты.

1. Класс VarBase.

using System;

using System.IO;

namespace interpr.logic.vartypes {

public abstract class VarBase : ICloneable , IComputable {

public bool IsArray() {

return (this is ArrayVar);

}

public bool IsNum() {

return (this is NumVar);

}

public bool IsString() {

return (this is StringVar);

}

public bool IsInt() {

return (this is IntVar);

}

public bool IsReal() {

return (this is RealVar);

}

public bool IsSingle() {

return (this is SingleVar);

}

public virtual VarBase Compute() {

return this.Clone() as VarBase;

}

public abstract System.Object Clone();

public override abstract string ToString();

public abstract void Serialise(BinaryWriter bw);

}

}

2. Класс ArrayVar.

using System.Collections;

using System.IO;

namespace interpr.logic.vartypes {

public class ArrayVar : VarBase {

public virtual IntVar Size {

get { return new IntVar(m_list.Count); }

}

private ArrayList m_list;

public ArrayVar() {

m_list = new ArrayList();

}

public int GetSize() {

return m_list.Count;

}

public void setAt(int index, SingleVar var) {

if (var == null) {

throw new CalcException("Ошибка");

}

if (index < 0)

throw new CalcException("Индекс не может быть отрицательным");

for (int ind = index, s = m_list.Count; ind >= s; ind--)

m_list.Add(null);

m_list[index] = var.Clone();

}

public SingleVar getAt(int index) {

if (index < 0)

throw new CalcException("Индекс не может быть отрицательным");

if (index >= m_list.Count)

throw new CalcException("Выход за пределы массива");

else

return (SingleVar) m_list[index];

}

public SingleVar this[int index] {

get { return getAt(index); }

set { setAt(index, value); }

}

public IntVar IsElementDefined(int index) {

bool result = index>=0;

result = result&&(index<m_list.Count);

result = result&&(m_list[index]!=null);

return new IntVar(result);

}

public override System.Object Clone() {

ArrayVar res = new ArrayVar();

int li = 0;

SingleVar e = null;

while (li < m_list.Count) {

e = (SingleVar) m_list[li++];

if (e != null)

res.m_list.Add(e.Clone());

else

res.m_list.Add(null);

}

return res;

}

public override void Serialise(BinaryWriter bw) {

bw.Write('a');

int size = m_list.Count;

bw.Write(size);

for (int i = 0; i < size; i++) {

if (m_list[i] == null)

bw.Write('n');

else

(m_list[i] as VarBase).Serialise(bw);

}

}

public override System.String ToString() {

System.String res = "[";

int li = 0;

SingleVar e = null;

if (li < m_list.Count) {

e = (SingleVar) m_list[li++];

if (e != null) {

res += e.ToString();

}

else

res += "-";

}

while (li < m_list.Count) {

e = (SingleVar) m_list[li++];

if (e != null) {

res += ", " + e.ToString();

}

else

res += ", -";

}

return res + "]";

}

}

}

3. Класс InterprEnvironment.

using System;

using System.Collections;

using System.IO;

namespace interpr.logic {

public class InterprEnvironment {

private SubroutinesManager m_subsman = null;

private ConsoleNamespace m_console_vars;

private bool m_not_restored = false;

public bool NotRestored {

get { return m_not_restored; }

}

public ConsoleNamespace ConsoleNamespace {

get { return m_console_vars; }

}

public ConsoleNamespace.VariableReport[] GetGlobalVarsList() {

return m_console_vars.GetVariableList();

}

private InterprEnvironment() {

m_current_namespace = new ConsoleNamespace();

m_console_vars = m_current_namespace as ConsoleNamespace;

m_not_restored = false;

try {

m_console_vars.Restore();

} catch {

m_not_restored = true;

m_console_vars = new ConsoleNamespace();

m_current_namespace = m_console_vars;

}

}

public void LoadSubs() {

if (m_current_console == null)

throw new OtherException("Error in Environment.LoadSubs()");

s_instance.m_subsman = SubroutinesManager.GetInstance();

s_instance.m_subsman.ReloadAll();

}

private static InterprEnvironment s_instance = null;

public static InterprEnvironment Instance {

get {

if (s_instance == null)

s_instance = new InterprEnvironment();

return s_instance;

}

}

public static void Reset() {

s_instance = new InterprEnvironment();

}

public void SaveVars() {

m_console_vars.Save();

}

public bool LoadSub(string name) {

return m_subsman.Load(name);

}

private Namespace m_current_namespace = null;

public Namespace CurrentNamespace {

get { return m_current_namespace; }

set { m_current_namespace = value; }

}

private IConsole m_current_console = null;

public IConsole CurrentConsole {

get { return m_current_console; }

set { m_current_console = value; }

}

public Operation GetFunction(string name) {

if (name == "abs")

return Operation.ABS;

...........................

if (name == "size")

return Operation.SIZE;

return new SubName(name);

}

public string[] LoadedSubs {

get { return m_subsman.SubroutineNames; }

}

private class SubroutinesManager {

private ArrayList m_subs = new ArrayList();

private ArrayList m_names = new ArrayList();

private SubroutinesManager() {

DirectoryInfo di =

new DirectoryInfo(Directory.GetCurrentDirectory() + @"\subroutines");

if (!di.Exists) {

di.Create();

}

}

public bool Load(string name) {

FileInfo fi = new FileInfo(Directory.GetCurrentDirectory() + @"\subroutines\" + name);

if (!fi.Exists)

throw new OtherException("Error in SubroutinesManager.Load()");

return LoadFile(fi);

}

private bool LoadFile(FileInfo file) {

try {

StreamReader sr = file.OpenText();

LinkedList ll = new LinkedList();

try {

while (sr.Peek() != -1) {

ll.AddFirst(sr.ReadLine());

}

} finally {

sr.Close();

}

string[] strs = new String[ll.Count];

int i = 0;

while (!ll.IsEmpty()) {

strs[i] = (ll.RemoveLast() as String);

i++;

}

Subroutine sub;

try {

sub = new Subroutine(strs, file.Name);

} catch (LineSyntaxException ex) {

InterprEnvironment.Instance.CurrentConsole.PrintLn("Синтаксическая ошибка в " + ex.Function + "[] at line " + ex.Line + " " + ex.Message);

return false;

} catch (SyntaxErrorException ex) {

InterprEnvironment.Instance.CurrentConsole.PrintLn("Синтаксическая ошибка в " + file.Name + " " + ex.Message);

return false;

}

Set(file.Name, sub);

} catch {

throw new OtherException("Error in Environment.Load()");

}

return true;

}

public Subroutine this[string name] {

get {

int sres = m_names.IndexOf(name);

if (sres < 0)

return null;

else

return m_subs[sres] as Subroutine;

}

}

private void Set(string name, Subroutine sub) {

int sres = m_names.IndexOf(name);

if (sres >= 0) {

m_names.RemoveAt(sres);

m_subs.RemoveAt(sres);

}

m_names.Add(name);

m_subs.Add(sub);

}

private static SubroutinesManager s_inst = null;

public static SubroutinesManager GetInstance() {

if (s_inst == null)

s_inst = new SubroutinesManager();

return s_inst;

}

public string[] SubroutineNames {

get {

int count = m_names.Count;

string[] res = new string[count];

for (int i = 0; i < count; i++) {

res[i] = (m_names[i] as String);

}

for (int i = 0; i < count - 1; i++) {

int k = i;

for (int j = i + 1; j < count; j++)

k = (string.Compare(res[j], res[k]) < 0) ? j : k;

if (i != k) {

string temp = res[i];

res[i] = res[k];

res[k] = temp;

}

}

return res;

}

}

public void ReloadAll() {

m_subs = new ArrayList();

m_names = new ArrayList();

DirectoryInfo di =

new DirectoryInfo(Directory.GetCurrentDirectory() + @"\subroutines");

if (!di.Exists) {

di.Create();

}

foreach (FileInfo file in di.GetFiles()) {

if (Parser.IsID(file.Name)) {

LoadFile(file);

}

}

}

public void Unload(string name) {

int index = m_names.IndexOf(name);

if (index >= 0) {

m_names.RemoveAt(index);

m_subs.RemoveAt(index);

}

}

}

public Subroutine GetSub(string name) {

Subroutine res = m_subsman[name];

if (res == null)

throw new CalcException("Функция " + name + " не существует");

return res;

}

public void UnloadSub(string name) {

m_subsman.Unload(name);

}

}

}

4. Класс Namespace.

using System;

using System.Collections;

using interpr.logic.vartypes;

namespace interpr.logic {

public class NamespaceSerializationException : Exception {

public NamespaceSerializationException() : base() {}

}

public class Namespace {

protected class Pair {

internal string m_str;

internal VarBase m_var;

}

protected ArrayList m_list = new ArrayList();

protected int m_n = 0;

private Namespace m_previous_namespace = null;

public Namespace PreviousNamespace {

get { return m_previous_namespace; }

}

public Namespace(Namespace previous) {

m_previous_namespace = previous;

}

protected Namespace() {}

public VarBase Get(string name) {

if (m_n == 0)

return null;

int i = 0;

Pair p;

do {

p = (m_list[i++] as Pair);

if (p.m_str == name)

return p.m_var;

} while (i < m_n);

return null;

}

public void Assign(VarBase var, string name) {

Pair p;

if (m_n != 0) {

int i = 0;

do {

p = (m_list[i++] as Pair);

if (p.m_str == name) {

p.m_var = var;

return;

}

} while (i < m_n);

}

p = new Pair();

p.m_var = var;

p.m_str = name;

m_list.Add(p);

m_n++;

}

public void AssignToElement(SingleVar var, string name, int index) {

Pair p;

if (m_n != 0) {

int i = 0;

do {

p = (m_list[i++] as Pair);

if (p.m_str == name) {

if (!p.m_var.IsArray())

throw new CalcException("Переменная не является массивом");

(p.m_var as ArrayVar)[index] = var;

return;

}

} while (i < m_n);

}

p = new Pair();

p.m_var = new ArrayVar();

(p.m_var as ArrayVar)[index] = var;

p.m_str = name;

m_list.Add(p);

m_n++;

}

public void Remove(String name) {

if (m_n == 0)

return;

int i = 0;

do {

Pair p = (m_list[i++] as Pair);

if (p.m_str == name) {

m_list.RemoveAt(i - 1);

m_n--;

return;

}

} while (i < m_n);

}

public VarBase this[string name] {

set { Assign(value, name); }

get { return Get(name); }

}

}

}

5. Интерфейс IСomputable.

namespace interpr.logic {

public interface IComputable {

logic.vartypes.VarBase Compute();

}

}

6. Класс Call.

using interpr.logic.vartypes;

namespace interpr.logic {

public class Call : IComputable {

private Operation m_op;

private ArgList m_al = null;

public Call(Operation op) {

m_op = op;

}

public void SetArgList(ArgList al) {

m_al = al;

}

public int ReqCount {

get { return m_op.ReqCount; }

}

public VarBase Compute() {

return m_op.Perform(m_al);

}

}

}

7. Класс ArgList

using interpr.logic.vartypes;

namespace interpr.logic {

public class ArgList {

private bool m_read = false;

private LinkedList m_list = new LinkedList();

private LinkedList.Iterator m_i = null;

public void Add(VarBase var) {

if (m_read)

throw new OtherException("Write to the argument list after reading begin");

m_list.Add(var);

}

public VarBase Get() {

if (!m_read)

throw new OtherException("Try to read from argument list before reset");

if (!m_i.HasPrevious)

throw new OtherException("Try to read from empty argument list");

m_read = true;

IComputable obj = (m_i.Previous() as IComputable);

if (obj == null)

throw new CalcException("Переменная не инициализированна.");

return obj.Compute();

}

public void Reset() {

m_read = true;

m_i = m_list.GetIterator(m_list.Count);

}

public int Count {

get { return m_list.Count; }

}

}

}

8. Класс Expression.

using System;

using interpr.logic.vartypes;

namespace interpr.logic {

public class Expression {

public Expression(String str) {

Parser p = new Parser(str);

Analyse(p);

}

public Expression(Parser p) {

Analyse(p);

}

private class Element {

internal IComputable m_o;

internal Element m_next;

internal Element(IComputable obj, Element next) {

m_o = obj;

m_next = next;

}

}

private Element m_top = null;

private Element m_bottom = null;

private int m_c = 0;

private void AddFront(IComputable obj) {

m_c++;

if (m_c == 1)

m_top = m_bottom = new Element(obj, null);

else {

Element t = new Element(obj, null);

m_bottom.m_next = t;

m_bottom = t;

}

}

private void Analyse(Parser p) {

try {

LinkedList l = new LinkedList();

while (p.MoveNext())

l.Add(p.Current);

OPZ(l);

}

catch (CalcException ex) {

throw ex;

}

catch {

throw new SyntaxErrorException("Синтаксическая ошибка в выражении");

}

}

private void OPZ(LinkedList tokens) {

/* ** Бинарная операция выталкивает из стека в результат

* все операции с большим или равным приоритетом, затем

* записывается в стек сама

* ** Унарная операция записывается в стек

* ** Открывающая скобка записывается в стек

* ** Закрывающая скобка выталкивает в результат все операции

* из стека до открывающей скобки, затем

* скобки уничтожаются и выталкиваются унарные операции

* ** Переменная или константа сразу пишутся в результат, затем

* выталкиваются из стека унарные операции

* ** При вызове функции

* сначала отдельно разбираются все операнды, затем в результат

* дописывается сама функция, как операция

* ** Обращение к элементу массива обрабатывается аналогично

* В конце все оставшиеся в стеке операции выталкиваются в результат

*/

InterprEnvironment env = InterprEnvironment.Instance;

if (tokens.IsEmpty()) return;

LinkedList.Iterator itr = tokens.GetIterator();

LinkedList stk = new LinkedList();

while (itr.HasMore) {

string si = (itr.Step() as System.String);

if (si == "(") {

stk.Add(O_BR);

}

else if (si == ")") {

while (true) {

object o = stk.RemoveLast();

if (o == O_BR) break;

AddFront(new Call(o as Operation));

}

while ((!stk.IsEmpty()) && IsUnary(stk.Last)) {

AddFront(new Call(stk.RemoveLast() as Operation));

}

}

else if (Parser.IsID(si)) {

bool bfun = false;

bool barray = false;

if (itr.HasMore) {

string s = (itr.Step() as System.String);

if (s == "[")

bfun = true;

else if (s == "{")

barray = true;

else

itr.Previous();

}

if (bfun) {

LinkedList l = null;

while (true) {

l = new LinkedList();

int level = 0;

while (true) {

if (!itr.HasMore)

throw new SyntaxErrorException("Синтаксическая ошибка в выражении");

string sj = (itr.Step() as System.String);

if (sj == "[") {

level++;

l.Add(sj);

}

else if (sj == "]") {

if (level == 0)

goto label1;

else {

level--;

l.Add(sj);

}

}

else if (sj == ",") {

if (level > 0)

l.Add(sj);

else

break;

}

else

l.Add(sj);

}

OPZ(l);

}

label1:

if (l != null)

OPZ(l);

Operation sub = env.GetFunction(si);

AddFront(new Call(sub));

while ((stk.Count > 0) && IsUnary(stk.Last)) {

AddFront(new Call((Operation) stk.RemoveLast()));

}

}

else if (barray) {

LinkedList l = new LinkedList();

int level = 0;

while (true) {

if (!itr.HasMore)

throw new SyntaxErrorException("Синтаксическая ошибка в выражении");

String sj = (String) itr.Step();

if (sj == "{") {

level++;

l.Add(sj);

}

else if (sj == "}") {

if (level == 0)

break;

else {

level--;

l.Add(sj);

}

}

else

l.Add(sj);

}

OPZ(l);

VarName v = new VarName(si);

AddFront(v);

AddFront(new Call(Operation.INDEX));

while ((stk.Count > 0) && IsUnary(stk.Last)) {

AddFront(new Call(stk.RemoveLast() as Operation));

}

}

else {

VarName v = new VarName(si);

AddFront(v);

while ((stk.Count > 0) && IsUnary(stk.Last)) {

AddFront(new Call(stk.RemoveLast() as Operation));

}

}

}

else {

Operation op = StrToOperation(si);

if (op == null) {

SingleVar sv = SingleVar.FromString(si);

if (si == null)

throw new SyntaxErrorException("Синтаксическая ошибка в выражении");

AddFront(sv);

while ((stk.Count > 0) && IsUnary(stk.Last)) {

AddFront(new Call(stk.RemoveLast() as Operation));

}

}

else {

//operation

if (op == Operation.ADD) {

itr.Previous();

if (!itr.HasPrevious) {

stk.Add(Operation.UPLUS);

itr.Step();

continue;

}

String strpr = (String) itr.Previous();

itr.Step();

itr.Step();

if ((StrToOperation(strpr) != null) || (strpr == "(") ||

(strpr == "[") || (strpr == "{")) {

stk.Add(Operation.UPLUS);

continue;

}

}

else if (op == Operation.SUB) {

itr.Previous();

if (!itr.HasPrevious) {

stk.Add(Operation.UMINUS);

itr.Step();

continue;

}

String strpr = (String) itr.Previous();

itr.Step();

itr.Step();

if ((StrToOperation(strpr) != null) || (strpr == "(") ||

(strpr == "[") || (strpr == "{")) {

stk.Add(Operation.UMINUS);

continue;

}

}

else if (op == Operation.NOT) {

stk.Add(op);

continue;

}

if (stk.IsEmpty() || (stk.Last == O_BR)) {

stk.Add(op);

}

else {

int pr = Priority(op);

while (true) {

if (stk.IsEmpty())

break;

Object stktop = stk.Last;

if (stktop is Operation) {

int pr1 = Priority(stktop as Operation);

if ((pr <= pr1) && (pr1 < 6)) {

AddFront(new Call(stktop as Operation));

stk.RemoveLast();

}

else

break;

}

else

break;

}

stk.Add(op);

}

}

}

}

while (!stk.IsEmpty()) {

Object o = stk.RemoveLast();

AddFront(new Call(o as Operation));

}

}

public VarBase Calculate() {

if (m_c == 0)

throw new CalcException("Ошибка: пустое выражение.");

Element top1 = null;

Element cur = m_top;

try {

for (; cur != null; cur = cur.m_next) {

if (cur.m_o is Call) {

int rc = (cur.m_o as Call).ReqCount;

ArgList al = new ArgList();

for (int i = 0; i < rc; i++) {

if (top1 == null)

throw new CalcException("Ошибка при вычислении выражения");

al.Add(top1.m_o.Compute());

top1 = top1.m_next;

}

(cur.m_o as Call).SetArgList(al);

top1 = new Element((cur.m_o as Call).Compute(), top1);

}

else {

top1 = new Element(cur.m_o, top1);

}

}

if ((top1 == null) || (top1.m_next != null))

throw new CalcException("Ошибка при вычислении выражения");

return top1.m_o.Compute();

}

catch (CalcException ex) {

throw ex;

}

catch {

throw new CalcException("Ошибка при вычислении выражения");

}

}

private static Operation StrToOperation(String str) {

//не возвращает унарные плюс и минус

if (str == "+")

return Operation.ADD;

else if (str == "-")

return Operation.SUB;

else if (str == "*")

return Operation.MUL;

else if (str == "/")

return Operation.DIV;

else if (str == "~")

return Operation.NOT;

else if (str == "|")

return Operation.OR;

else if (str == "&")

return Operation.AND;

else if (str == "^")

return Operation.XOR;

else if (str == "~=")

return Operation.BE;

else if (str == "=")

return Operation.EQ;

else if (str == "<>")

return Operation.NE;

else if (str == ">=")

return Operation.GE;

else if (str == "<=")

return Operation.LE;

else if (str == ">")

return Operation.GT;

else if (str == "<")

return Operation.LT;

else

return null;

}

private static int Priority(Operation op) {

if ((op == Operation.OR) || (op == Operation.XOR) ||

(op == Operation.BE))

return 1;

else if (op == Operation.AND)

return 2;

else if ((op == Operation.EQ) || (op == Operation.NE) ||

(op == Operation.LE) || (op == Operation.LT) ||

(op == Operation.GE) || (op == Operation.GT))

return 3;

else if ((op == Operation.ADD) || (op == Operation.SUB))

return 4;

else if ((op == Operation.MUL) || (op == Operation.DIV))

return 5;

else

return 6;

}

private static bool IsBinary(Operation op) {

return Priority(op) < 6;

}

private static bool IsUnary(object obj) {

return ((obj == Operation.NOT) || (obj == Operation.UPLUS) ||

(obj == Operation.UMINUS));

}

private class BR_c {}

private static object O_BR = new BR_c();

}

}

9. Класс Operation (сокращенно).

using System;

using interpr.logic.vartypes;

namespace interpr.logic {

public abstract class Operation {

public abstract int ReqCount { get; }

public abstract VarBase Perform(ArgList al);

public static readonly Operation ABS = new ABS_c();

private class ABS_c : Operation {

public override int ReqCount {

get { return 1; }

}

public override VarBase Perform(ArgList al) {

if (al.Count != ReqCount)

throw new OtherException("Invalid argument list");

al.Reset();

VarBase arg1 = al.Get();

if (arg1 is IntVar)

return ((arg1 as IntVar).Val>0) ? (arg1.Clone() as IntVar) : (new IntVar(-((IntVar) arg1).Val));

else if (arg1 is RealVar)

return ((arg1 as RealVar).Val>0) ? (arg1.Clone() as RealVar) : (new RealVar(-((RealVar) arg1).Val));

else

throw new CalcException("Неправильные аргументы функции");

}

}

public static readonly Operation ADD = new ADD_c();

private class ADD_c : Operation {

public override int ReqCount {

get { return 2; }

}

public override VarBase Perform(ArgList al) {

if (al.Count != ReqCount)

throw new OtherException("Invalid argument list");

al.Reset();

VarBase arg1 = al.Get();

VarBase arg2 = al.Get();

if(!(arg1.IsSingle()&&arg2.IsSingle()))

throw new CalcException("Неверные типы операндов");

return (arg1 as SingleVar).add(arg2 as SingleVar);

}

}

public static readonly Operation AND = new AND_c();

private class AND_c : Operation {

public override int ReqCount {

get { return 2; }

}

public override VarBase Perform(ArgList al) {

if (al.Count != ReqCount)

throw new OtherException("Invalid argument list");

al.Reset();

VarBase arg1 = al.Get();

VarBase arg2 = al.Get();

if(!(arg1.IsSingle()&&arg2.IsSingle()))

throw new CalcException("Неверные типы операндов");

return (arg1 as SingleVar).and(arg2 as SingleVar);

}

}

.......................................................................................

}

}

10. Класс Parser.

using System;

using System.Collections;

namespace interpr.logic {

public class Parser : IEnumerable, IEnumerator {

private char[] m_a;

private int m_len;

private int m_cur = 0;

private int m_new_cur = -1;

private bool m_at_begin;

private static readonly string[] s_keywords =

new string[] {

"if",

"else",

"elseif",

"endif",

"while",

"loop",

"return",

"call",

"print",

"println",

"readln",

"clear",

"for",

"next",

"error"

};

private static readonly int s_keywords_length = s_keywords.Length;

private static bool IsLD(char c) {

return ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')) || (c == '0')

|| ((c >= '1') && (c <= '9')) || (c == '_');

}

private static bool IsSp(char c) {

return (c == ' ') || (c == '\t');

}

public static bool IsID(string str) {

int l = str.Length;

if (l == 0)

return false;

if (char.IsDigit(str[0]) || (!IsLD(str[0])))

return false;

int i;

for (i = 1; i < str.Length; i++)

if (!IsLD(str[i]))

return false;

for (i = 0; i < s_keywords_length; i++)

if (str == s_keywords[i])

return false;

return true;

}

public void Reset() {

m_cur = 0;

m_new_cur = -1;

m_at_begin = true;

}

public string GetString() {

return new String(m_a, 0, m_len);

}

public bool HasMore() {

return m_cur < m_len;

}

public Parser(string str) {

char[] a = str.ToCharArray();

int n = a.Length;

int i = 0;

int j = 0;

m_a = new char[n];

while (i < n) {

if (a[i] == '#') {

break;

} else if (a[i] == '\"') {

m_a[j] = '\"';

i++;

j++;

while ((i < n) && (a[i] != '\"')) {

m_a[j] = a[i];

i++;

j++;

}

if (i == n)

throw new SyntaxErrorException("Не закрытая строковая константа");

else {

m_a[j] = '\"';

i++;

j++;

}

} else if (IsSp(a[i])) {

bool flag = false;

if ((i > 0) && (IsLD(a[i - 1]))) {

m_a[j] = ' ';

j++;

flag = true;

}

while ((i < n) && IsSp(a[i]))

i++;

if (((i == n) || (!IsLD(a[i]))) && flag)

j--;

} else {

m_a[j] = a[i];

i++;

j++;

}

}

m_len = j;

Reset();

}

private string GetCurrent() {

int cur = m_cur;

int beg = m_cur;

int end = m_len;

string res = null;

bool flag = true;

if ((m_a[cur] == '.') && ((cur < end - 1) && (!char.IsDigit(m_a[cur + 1]))) || (cur == end - 1)) {

flag = true;

} else if (char.IsDigit(m_a[cur]) || (m_a[cur] == '.')) {

flag = false;

while ((cur < end) && char.IsDigit(m_a[cur]))

cur++;

if (cur == end) {

res = new String(m_a, beg, cur - beg);

} else if ((m_a[cur] == 'e') || (m_a[cur] == 'E')) {

cur++;

if (cur == end) {

cur--;

res = new String(m_a, beg, cur - beg);

} else if ((m_a[cur] == '+') || (m_a[cur] == '-')) {

cur++;

if ((cur == end) || (!char.IsDigit(m_a[cur]))) {

cur -= 2;

res = new String(m_a, beg, cur - beg);

}

while ((cur < end) && char.IsDigit(m_a[cur]))

cur++;


Подобные документы

  • Функции и основные компоненты систем программирования. Средства создания программ. Трансляторы языков программирования. Принципы и фазы работы компилятора, трансформация языка программирования в машинный код. Механизм преобразования интерпретатора.

    презентация [3,3 M], добавлен 07.02.2012

  • Проектирование лексического и синтаксического анализаторов учебного языка. Правила преобразования логических выражений в ПОЛИЗ. Формирование триад, оптимизация их списка. Логическая структура программы. Тестирование модулей транслятора-интерпретатора.

    курсовая работа [1,3 M], добавлен 28.05.2013

  • Исследование возможностей и областей использования языка программирования JavaScript. Сравнительный анализ языков программирования JavaScript и PHP. Разработка интерактивного Web-приложения на примере теста по теме "Программирование на языке Delphi".

    практическая работа [26,0 K], добавлен 04.02.2015

  • Разработка программы-интерпретатора, способной получать на входе текстовый файл (в формате ASCII или ANSI) с текстом программы и на выходе выводить на экран результаты вычислений, определяемых программистом. Выбор лексем, интерфейс и листинг программы.

    курсовая работа [132,0 K], добавлен 12.03.2013

  • Файлы IO.SYS и MSDOS.SYS; командный процессор DOS. Базовая система ввода-вывода, загрузчик, диалог пользователя с DOS, команды. Недостатки языка програмирования с++. Создание и описание программы, позволяющей работать с файлами в среде DOS, ее алгоритм.

    курсовая работа [24,4 K], добавлен 02.12.2009

  • Арифметические команды языка Assembler в архитектуре x86. Организация ветвлений и циклов в программах. Ввод строк с клавиатуры и команды пакетной обработки (строковые команды). Алгоритм вывода на экран в текстовом режиме с использованием средств BIOS.

    контрольная работа [18,0 K], добавлен 05.07.2014

  • Анализ различных командных интерпретаторов. Разработка структуры программы на языке программирования С и ее алгоритма. Требования для работы с ней. Действия, необходимые для её запуска и функционирования. Описание функций translate, sozd, info и f.

    курсовая работа [238,2 K], добавлен 06.12.2014

  • Изучение алгоритма рекурсивного спуска и системы построения грамматики с помощью лексического анализатора Lex. Написание программы интерпретатора языка разметки HTML. Проверка входной последовательности на корректность входа как общая функция программы.

    контрольная работа [226,7 K], добавлен 25.12.2012

  • Сравнительная характеристика, возможности и функции языков программирования JavaScript и PHP. Основные области их использования. Разработка интерактивного Web-приложения с применением JavaScript на примере теста по теме "Программирование на языке Delphi".

    курсовая работа [19,3 K], добавлен 01.07.2014

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

    дипломная работа [1,4 M], добавлен 11.06.2012

Работы в архивах красиво оформлены согласно требованиям ВУЗов и содержат рисунки, диаграммы, формулы и т.д.
PPT, PPTX и PDF-файлы представлены только в архивах.
Рекомендуем скачать работу.