- •Расчетно-графическая работа
- •Оглавление
- •Введение
- •Проектирование компилятора
- •Общие сведения
- •Грамматика языка
- •Разработка интерфейса
- •Реализация компилятора
- •2.1. Реализация лексического блока
- •2.2. Реализация синтаксического блока
- •2.3. Реализация генератора кода
- •2.4. Реализация р-ичной библиотеки
- •Тестирование
- •Заключение
- •Список использованной литературы
-
Реализация компилятора
2.1. Реализация лексического блока
Основным назначением ЛБ является разбиение цепочки литер, представляющей программу на исходном языке, в цепочку символов языка, опознание этих цепочек, начальное заполнение таблиц, замена символов кодами. При этом, если в программе были комментарии, то ЛБ их должен удалить.
Т.о. ЛБ представляет собой программу, в которой:
-
открывается на чтение файл с текстом программы на исходном языке программирования;
-
открывается на запись файл, в который будем заносить версию программы на исходном языке программирования в виде кодов символов;
-
читаем построчно файл с исходным текстом программы;
-
обрабатываем строку:
-
удаляем комментарии;
-
выделяем очередную цепочку литер до ближайшего разделителя, распознаем ее и записываем в файл в виде кода;
-
все это продолжаем, пока не дойдем до конца считанной строки;
-
пункты 3,4 повторяем до тех пор, пока не дойдем до конца файла.
Для запуска программы используем головную процедуру Button1Click (TObject *Sender), в которой последовательно реализуются все блоки компилятора.
В Лексическом блоке были использованы следующие функции:
-
char *NextLex(char *, char *) – выделяет лексему в строке str и возвращает ее в строку ls и ее код.
-
void Lex (char *) - получает строку из входного файла, распознает и удаляет многострочные комментарии, обнаруживает незакрытые комментарии и принудительно их закрывает, распознает служебные слова, идентификаторы, константы и символы - разделители, заносит коды всех символов в файл с расширением .lex и отображает содержимое файла в поле Memo1 формы Form2.
-
int IsDlm(char) - определяет символ-разделитель c.
-
int LitRecogn(char *) - распознает константы в строке, возвращает соответствующий код, а также создает таблицу констант с частичным заполнением полей таблицы.
-
int IdRecogn(char *) – распознает идентификаторы в строке , возвращает их код и создает таблицу идентификаторов с частичным заполнением полей таблицы.
-
int TermRecogn(char *) - распознает терминальные символы, заданные грамматикой языка, в строке s и возвращает их код.
-
int DlmRecogn(char *) - распознает символы-разделители в строке s и возвращает соответствующий код.
-
int LexRecogn(char *) - распознает лексему.
2.2. Реализация синтаксического блока
При синтаксическом разборе выражений необходимо не только провести проверку синтаксиса, но и более явно указать порядок выполнения операций. При этом в грамматику можно добавлять символы действия, выполняющие не проверку синтаксиса, а какие-то другие действия, например, работа с таблицами, преобразование выражения и т.д.
Как известно, есть 3 способа записи выражений:
-
инфиксная a+b
-
префиксная +ab
-
постфиксная ab+
Префиксная и постфиксная формы известны как, соответственно, прямая и обратная польские записи (по стране ее изобретателя, поляка, Яна Лукасевича).
Это, так называемые бесскобочные формы записи.
Среди множества известных алгоритмов перехода от инфиксной формы записи выражения к обратной польской, рассмотрим следующий, состоящий из трех действий:
-
G1 – если при чтении выражения слева направо встречается идентификатор, печатаем его;
-
G2 – если при чтении выражения слева направо встречается знак операции, заносим его в стек;
-
G3 – если при чтении выражения слева направо встречается конец выражения или подвыражения, извлекаем знак из стека и печатаем его.
В синтаксическом блоке использованы следующие функции:
-
struct tbl *FndId(int);- ищет идентификатор по коду, переданному в качестве параметра, и возвращает структуру, содержащую искомый идентификатор.
-
struct tbl *FndLit(int);-ищет константу по коду, переданному в качестве параметра, и возвращает структуру, содержащую искомую константу.
-
int NextSymb(void) – выделяет следующий символ из входного потока данных.
-
void DclOp(void) – проверяет оператор объявления
-
void ExeOp(void) – проверяет структуру выполняемых операторов
-
void List(int type) – проверяет список ввода
-
void ListVar(void) – проверяет список вывода
-
void Expr(void) – разбирает выражение, преобразуя его в обратную польскую запись.
Функции, реализующие эти преобразования:
-
void litem2(void);
-
void litem(void);
-
void lfactor(void);
-
void lfactor2(void);
-
void arithm(void);
-
void item2(void);
-
void item(void);
-
void factor2(void);
-
void prim(void);