- •Расчетно-графическая работа
- •Оглавление
- •Введение
- •Проектирование компилятора
- •Общие сведения
- •Грамматика языка
- •Разработка интерфейса
- •Реализация компилятора
- •2.1. Реализация лексического блока
- •2.2. Реализация синтаксического блока
- •2.3. Реализация генератора кода
- •2.4. Реализация р-ичной библиотеки
- •Тестирование и анализ результатов
- •Заключение
- •Список использованной литературы
-
Реализация компилятора
2.1. Реализация лексического блока
Основным назначением ЛБ является разбиение цепочки литер, представляющей программу на исходном языке, в цепочку символов языка, опознание этих цепочек, начальное заполнение таблиц, замена символов кодами. При этом, если в программе были комментарии, то ЛБ их должен удалить.
Таким образом,ЛБ представляет собой программу, в которой:
-
открывается на чтение файл с текстом программы на исходном языке программирования;
-
открывается на запись файл, в который будем заносить версию программы на исходном языке программирования в виде кодов символов;
-
читаем построчно файл с исходным текстом программы;
-
обрабатываем строку:
-
удаляем комментарии;
-
выделяем очередную цепочку литер до ближайшего разделителя, распознаем ее и записываем в файл в виде кода;
-
продолжаем, пока не дойдем до конца считанной строки;
-
пункты 3,4 повторяем до тех пор, пока не дойдем до конца файла.
Для запуска программы используем головную процедуру Button1Click (TObject *Sender), в которой последовательно реализуются все блоки компилятора.
В Лексическом блоке были использованы следующие функции:
-
char *NextToken(char *, char *) – выделяет лексему в строке «str» и возвращает ее в строку «ls» и ее код.
-
voidDoLexicalAnalysis (char *) – получает строку из входного файла и дубликатэтой же строки для отображения ее оригинального вида в окне лексического блока, распознает и удаляет многострочные комментарии, обнаруживает незакрытые комментарии и принудительно их закрывает, распознает служебные слова, идентификаторы, константы и символы-разделители, заносит коды всех символов в файл с расширением .lex и отображает содержимое файла в поле Memo1 формы LexForm.
-
intIsDelimiter(char) - определяет символ-разделитель«c».
-
intRecognizeConstant(char *) - распознает константы в строке, возвращает соответствующий код, а также создает таблицу констант с частичным заполнением полей таблицы.
-
intRecognizeIdentifier(char *) – распознает идентификаторы в строке, возвращает их код и создает таблицу идентификаторов с частичным заполнением полей таблицы.
-
intRecognizeReservedToken(char *) - распознает терминальные символы, заданные грамматикой языка, в строке s и возвращает их код.
-
intRecognizeDelimiter(char *) - распознает символы-разделители в строке s и возвращает соответствующий код.
-
intRecognizeToken(char *) - распознаетлексему.
2.2. Реализация синтаксического блока
При синтаксическом разборе выражений необходимо не только провести проверку синтаксиса, но и более явно указать порядок выполнения операций. При этом в грамматику можно добавлять символы действия, выполняющие не проверку синтаксиса, а какие-то другие действия, например, работа с таблицами, преобразование выражения и т.д.
Как известно, есть 3 способа записи выражений:
-
инфиксная a+b;
-
префиксная +ab;
-
постфиксная ab+.
Префиксная и постфиксная формы известны как, соответственно, прямая и обратная польские записи (по стране ее изобретателя, поляка, Яна Лукасевича).
Это, так называемые бесскобочные формы записи.
Среди множества известных алгоритмов перехода от инфиксной формы записи выражения к обратной польской, рассмотрим следующий алгоритм, состоящий из трех действий:
-
PushSymbol(PS)– если при чтении выражения слева направо встречается идентификатор, печатаем его;
-
PushToStack (PTS) – если при чтении выражения слева направо встречается знак операции, заносим его в стек;
-
PopFromStack(PFS) – если при чтении выражения слева направо встречается конец выражения или подвыражения, извлекаем знак из стека и печатаем его.
В синтаксическом блоке использованы следующие функции:
-
structtbl *FindTblByCode(int)– ищет идентификатор по коду, переданному в качестве параметра, и возвращает структуру, содержащую искомый идентификатор;
-
structtbl *FindLitByCode(int)–ищет константу по коду, переданному в качестве параметра, и возвращает структуру, содержащую искомую константу;
-
intNextSymb(void) – выделяет следующий символ из входного потока данных
-
voidTitleOperator (void) – обрабатывает и проверяет заголовок программы;
-
voidDeclareOperator(void) – обрабатывает и проверяет объявление переменных;
-
voidExeсutionOperator(void) –обрабатывает и проверяет структуру выполняемых операторов и функций;
-
voidBaseOperator(void) – обрабатывает и проверяет установку основания системы счисления;
-
voidReadOperator(inttype) –обрабатывает и проверяетсписок переменных ввода;
-
voidWriteOperator(void) – обрабатывает и проверяет список переменных вывода;
-
voidAssignmentOperator (void) – обрабатывает и проверяет операции присваивания переменных;
-
voidEndOperator (void) – обрабатывает и проверяет окончание программы;
-
voidexpr(void) – разбирает выражение, преобразуя его в обратную польскую запись.
Функции, реализующие эти преобразования:
-
voidlitem(void);
-
voidlitem2(void);
-
voidlfactor(void);
-
void lfactor2(void);
-
void item (void);
-
void item2 (void);
-
void factor2 (void);
-
void arithm (void);
-
void arithm2 (void);
-
voidprim (void).