Разработка процессора p-ичной арифметики с функциями MINUS, ROUND, MIN, страница 2

<arithm>–><item>+{G2}<item2>|<item>-{G2}<item2>|<item>

<item2>–><item>{G3}+{G2}<item2>|<item>{G3}-{G2}<item2>|<item>{G3]

<item>–><factor>*{G2}<factor2>|<factor>/{G2}<factor2>|<factor>

<factor2>–><factor>{G3}*{G2}<factor2>|<factor>{G3}/{G2}<factor2>|<factor>{G3}

<factor>–>-{G2}<factor>{G3}|NOT{G2}<factor>{G3}|<prim>

<prim>->(<выражение>)|

Minus{G2}(<выражение>,<выражение>){G3}|

Round{G2}(<выражение>){G3}|

Min{G2}(<выражение>,<выражение>){G3}|

<идентификатор>{G1}|

<константа>{G1}

<константа> -> <целое>|<дробное>

<целое> -> <цифра>|<цифра><последовательность цифр>

<последовательность цифр> -> <цифра>|<цифра><последовательность цифр>

<дробное> -> <целое>.<дробное>|

<дробное> -> <цифра>|<цифра><последовательность цифр>

<основание системы счисления> -> 2|3|4|5|6|7|8|9|10|11|12|13|14|15|16

<конец> –> End

           В данной грамматике были использованы следующие символы действия:

G1 – если при чтении выражения слева направо встретился операнд (идентификатор или константа), печатаем его.

G2 – если при чтении выражения слева направо встретился знак операции, заносим его в стек.

G3 – если при чтении выражения слева направо встретился конец выражения или подвыражения, извлекаем знак из стека и печатаем его.

1.3 Разработка интерфейса компилятора

В C++ Builder создан новый проект, основанный на пустой форме (Form 1). Свойству Caption TForm1 присвоено значение "Процессор p-ичной арифметики".

На форме размещен компонент TMemo, его свойству Align присвоено значение alClient, свойству ScrollBars - значение ssVertical, а свойству Lines - пустой массив строк.

Для того чтобы можно было открывать и сохранять файлы на форме размещены два диалога со страницы Dialogs: TOpenDialog и TSaveDialog.

На главную форму приложения размещен компонент TMainMenu со страницы Standard и созданы следующие меню: "Файл" (с пунктами "Создать", "Открыть...", "Сохранить", "Сохранить как...", '"-","Выход"), "Редактирование" (с пунктами "Вырезать" "Копировать", "Вставить") и "?" с пунктом "О программе".

Использована возможность быстрого доступа к функциям меню:

Создать – F1;

Открыть – F2;

Сохранить – F3;

Вырезать – Ctrl+X;

Копировать – Ctrl+C;

Вставить – Ctrl+V;

О программе – Ctrl+A;

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

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

Для вывода информации о проекте была создана форма AboutBox (рис. 1.2).

Была создана форма (Form 3) c двумя компонентами TMemo,  для вывода результатов работы лексического блока (Memo 1) и синтаксического блока (Memo 2). Вид этой формы представлен на рис. 1.3.

Рис. 1.1. Вид главной формы приложения

Рис. 1.2. Форма для вывода информации о проекте

Рис. 1.3. Форма для выводов результатов лексического и синтаксического блока

2. Реализация компилятора

2.1 Реализация лексического блока.

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

Используемые  функции:

char NextLex(char*,char*) – выделяет определенную лексему из строки и возвращает ее код.

IdRecogn (char*) – создает таблицу идентификаторов с частичным заполнением полей таблицы, распознает идентификаторы в строке и возвращает их код.

LitRecogn (char *) – создает таблицу констант с частичным заполнением полей таблицы, распознает константы в строке и возвращает их код.

TermRecogn(char *) – распознает служебные  слова, определенные грамматикой языка, в строке и возвращает их код.

 DlmRecogn (char*) – распознает символы-разделители в строке и возвращает их код.

LexRecogn (char*) – распознает лексему.

void LexBl(char *) – заносит коды всех символов в файл с расширением .lex, получает строку из входного файла, а также удаляет многострочные и однострочные комментарии, распознает служебные слова, идентификаторы, константы и  символы разделители.

DlmDeterminat(char ) – определяет символы-разделители в строке.

2. 2 Реализация синтаксического блока

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

Используемые  функции:

int NextSymb(void) – выделяет следующий символ из входного потока;

void SinBl(void) – проверяет структуру программы.

void ErrMess(char*) – выдает ошибку.

void SerrPrt(int,char *) – выдает сообщение об ошибке синтаксического блока.

void WarrMess(int,char *) – выводит на экран предупреждение

void CheckType(int t) – заполняет поле type таблицы идентификаторов передаваемым типом t.

void Ttl (void) – проверяет заголовок программы, выдает сообщение об ошибке в случае отсутствия заголовка.

void ONOp (void) – проверяет на наличие начала программы.

void DclOp(void) – проверяет операторы объявления переменных.

void ListInt (void) – проверяет список объявленных переменных типа INTEGER, и выводит сообщение о многократности объявления.

void ListReal(void) – проверяет список объявленных переменных типа REAL, и выводит сообщение о многократности объявления.

void List(void) – проверяет список переменных, выдает ошибку если  переменная не объявлена.

void ExeOp(void)  – проверяет на выполняемые операторы.

void End (void) – проверяет на конец программы.

struct tbl*FndIdCode(int ) – по коду находит идентификатор в таблице.

struct lit*FindLitCode(int ) – по коду находит константу в таблице.

void Expr(void) – преобразовывает выражение в обратную польскую запись. Для реализации данной функции использовались следующие вспомогательные подфункции: void litem(void), void litem2(void), void lfactor(void), void lfactor2(void), void arithm(void), void arithm2(void), void prim(void), void factor(void), void item(void), void item2(void), void Sub(void), void factor(void), void factor2(void).

2.3 Реализация генератора кода

Генератор кода переводит последовательности кодов, полученных в результате работы синтаксического блока, в код на языке С++. Генератор кода запускается только в случае отсутствия лексических и синтаксических ошибок, в противном случае выдается предупреждение о невозможности начать генерацию кода. На выходе записывается файл, содержащей код на языке С++. После выполнения генерации кода запускается компилятор С++, для 32-х разрядных процессоров, «собирающий» всю программу.

Реализация р-ичного блока в библиотечном файле plib.h.