Разработка программы-компилятора
Обновлено
113
Содержание
- Введение
- 1. Анализ задания
- 2. Разработка лексического анализатора
- 2.1 Выбор и обоснование структур данных
- 2.2 Разработка автоматных грамматик для распознавания лексем
- 2.3 Разработка автоматов, работающих по правилам грамматики
- 2.3.1 Автомат для распознавания имён
- 2.3.2 Автомат для распознавания 16-ричных констант
- 2.3.3 Автомат для распознавания римских констант
- 2.3.4 Объединённый автомат
- 2.4 Разработка алгоритма и программы лексического анализа
- 2.4.1 Выделение лексем
- 2.4.2 Распознавание лексем
- 2.4.3 Реализация лексического анализатора
- 2.4.4 Тестирование лексического анализатора
- 3. Разработка синтаксического анализатора
- 3.1 Уточнение грамматики языка применительно к варианту задания
- 3.2 Разработка алгоритма синтаксического анализа
- 3.3 Алгоритмы распознающих функций
- 3.3.1 Функция Lex_Progr
- 3.3.2 Функция Lex_Descr_List
- 3.3.3 Функция Lex_Descr
- 3.3.4 Функция Lex_Name_List
- 3.3.5 Функция Lex_Oper_List
- 3.3.6 Функция Lex_Assign
- 3.3.7 Функция Lex_Exp
- 3.3.8 Функция Lex_Simple_Exp
- 3.3.9 Функция Lex_Term
- 3.3.10 Функция Lex_mnozh
- 3.3.12 Функция Lex_Body
- 3.4 Тексты распознающих процедур
- 3.5 Результаты тестирования синтаксического анализатора
- 4. Реализация двухфазного компилятора
- 4.1 Результаты тестирования двухфазного компилятора
- 5. Описание программы
- 5.1 Общие сведения и функциональное назначение
- 5.2 Вызов и загрузка
- 5.3 Входные данные
- 5.4 Выходные данные
- 5.5 Описание логической структуры программы
- 5.5.1 Файлы программы
- 5.5.2 Общее описание работы программы
- Список использованной литературы
Праволинейная | Леволинейная | |
A>aB | A>Ba | |
A>a | A>a |
где a Т; А, В N
Эти грамматики широко используются для построения лексических анализаторов. Грамматику лексических единиц обычно явно не описывают, а строят эквивалентный ей граф распознавания лексических единиц.
Грамматика для идентификаторов:
<имя>><буква><буква>
<буква>> ('a'. 'z')
<цифра>> (`0'. '9')
Грамматика для констант:
<константа>><16-рич. константа>|<римск. константа>
Для 16-ричных констант:
<16-рич. константа>> (`$+','$-`) (<цифра>, `A'. 'F') { (<цифра>,`A'. 'F') }
Для римских констант:
2.3 Разработка автоматов, работающих по правилам грамматики2.3.1 Автомат для распознавания имёнрис.1. Автомат для распознавания имёнСостояния автомата:S - начальное состояние;1 - промежуточное состояние, соответствующее продолжению формирования имени;2 - конечное состояние, соответствующее выделению правильного идентификатора;3 - конечное состояние, соответствующее ошибке при выделении идентификатора.2.3.2 Автомат для распознавания 16-ричных константрис.3. Автомат для распознавания 16-ричных константСостояния автомата:S - начальное состояние;1 - промежуточное состояние, обозначающее, что распознан символ начала константы `$';2 - промежуточное состояние, обозначающее, что распознан знак константы, и продолжение формирования константы;3 - конечное состояние, соответствующее выделению правильной 16-ричной константы;4 - конечное состояние, соответствующее ошибке при выделении 16-ричной константы.2.3.3 Автомат для распознавания римских константРимские константы образуются по следующим правилам:Римская система нумерации состоит из семи знаков: I - 1, V - 5, X - 10, C - 100, D - 500, M - 1000. В данной работе используются только три первых знака, т.е. автомат может распознавать числа от 1 (I) до 39 (XXXIX).Если меньший знак пишется после большего, то его прибавляют к большему числу; если же перед большим - вычитают. Вычитать можно только числа, начинающиеся с 1, в данном случае - 1, т.к не имеет смысла вычитать, например, 5 из 5 (в результате 0) или из 10 (в результате 5).Знаки, эквивалентные числам, начинающимся с 1 (1, 10, 100, 1000), могут использоваться от одного до 3 раз. Знаки, эквивалентные числам, начинающимся с 5 (5, 50, 500) могут использоваться только 1 раз. Таким образом, чтобы образовать число 4, нужно из 5 вычесть 1 (IV), а чтобы образовать число 6, нужно прибавить 1 к 5 (VI).В соответствии с приведёнными правилами, сформируем ряд ограничений для автомата-распознавателя:Символ X может встречаться в начале строки от 1 до 3 раз подряд (см. правило 3).Символ V может встречаться не более 1 раза в начале строки и после 1 или более символов X (см. правило 3).Символ I может встречаться от 1 до 3 раз подряд в начале строки, а также в конце правильной строки, образованной символами X и V (см. ограничения 1 и 2, правило 3).Символ X может встречаться в конце строки 1 раз после символа I, если перед последним находятся только символы X или ничего (иначе будет нарушено правило 2 - неизвестно, к какому символу будет относиться символ I).Символ V может встречаться в конце строки 1 раз после символа I, если перед последним находятся только символы X (аналогично ограничению 4).рис.4. Автомат для распознавания римских константСостояния автомата:S - начальное состояние;Sg - промежуточное состояние, соответствующее распознаванию знака константы.1 - промежуточное состояние, соответствующее распознаванию символа X.2 - промежуточное состояние, соответствующее распознаванию символа V.3 - промежуточное состояние, соответствующее распознаванию символа I.4 - конечное состояние, соответствующее ошибке пр. выделении римской константы.5 - промежуточное состояние, соответствующее распознаванию строки XX.6 - промежуточное состояние, соответствующее распознаванию строки XXX.7 - промежуточное состояние, соответствующее распознаванию символа I после V, XV, XXV или XXXV.8 - промежуточное состояние, соответствующее распознаванию символа X после I, XI, XXI или XXXI.9 - промежуточное состояние, соответствующее распознаванию символа V после I, XI, XXI или XXXI.10 - промежуточное состояние, соответствующее распознаванию символа I после правильной строки, заканчивающейся на I.11 - промежуточное состояние, соответствующее распознаванию символа I после правильной строки, заканчивающейся на II.В конечное состояние автомата, соответствующее распознаванию правильной римской константы, можно перейти из любого состояния, кроме Sg и 4, как только наступит конец лексемы.2.3.4 Объединённый автоматОбъединённый автомат является соединением приведённых выше автоматов при общем начальном состоянии S. Все состояния и входные сигналы останутся теми же.2.4 Разработка алгоритма и программы лексического анализаНепосредственно лексический анализ представляет собой 2 этапа: выделение лексем и их распознавание. На экран выводятся таблицы констант, идентификаторов, терминальных символов и кодов лексем. Все таблицы сохраняются в файлы на диске.После завершения лексического анализа становится возможным выполнить синтаксический анализ.2.4.1 Выделение лексемПроцесс выделения лексем состоит в просмотре входной строки по одному символу и в случае обнаружения символа-разделителя формирование лексемы. Символами разделителями являются как сами разделители (терминальные символы) так и знаки операций. В программе предусмотрены двойные знаки операций (`: =').При чтении очередного символа сначала проверяется, является ли он разделителем. Если это не так, то разделитель считается частью текущей лексемы и продолжается процесс ее формирования. Если это так, то проверяется вариант двойной операции и работа заканчивается. Если это не двойная операция, то происходит запись разделителя, как лексемы.Такая последовательность действий повторяется до окончания входной строки. Процесс выделения лексем реализован в функции Select_Lex, которая возвращает строки, содержащие выделенные лексемы.2.4.2 Распознавание лексемПоследовательно определяется тип каждой лексемы с помощью соответствующих распознавателей. Каждая лексема добавляется в таблицу кодов лексем и в соответствующую типу таблицу (констант, имен, терминальных символов). Если лексема ошибочна (т.е. не принадлежит ни одному из вышеназванных типов), то в таблице кодов лексем ей присваивается тип Е, обозначающий ошибку.Каждая процедура распознавания, кроме распознавателя терминальных символов, построена как конечный автомат. Описание самих автоматов приведено выше. В плане программной реализации каждый такой распознаватель имеет следующие элементы:константа, определяющая начальное состояние (обычно 0);множество состояний, соответствующих удачному распознаванию лексемы;множество состояний, свидетельствующих об ошибке в лексеме;Распознавателем идентификаторов является функция Ident, 16-ричных констант - функция FConst, римских констант - функция Rome. Все они возвращают значение 1, если лексема распознана и - 1 в противном случае. Распознавателем терминальных символов является функция Termin. Она возвращает значение 3, если лексема - ключевое слово, 1 - если разделитель, 2 - если знак операции. Если лексема не является терминальным символом, то функция возвращает значение - 1. Если лексема ошибочна, то она заносится в таблицу кодов лексем с типом E и выдаётся сообщение об ошибке (процедура Err_Lex). Все эти подпрограммы вызываются из процедуры TForm1. N5Click (соответствует выбору пункта меню Анализатор/Лексический). В ней производится обнуление всех таблиц, вызов функции выделения лексем и процедуры WriteLex (см. ниже).Поиск идентификаторов, констант и терминальных символов в соответствующих таблицах производится, соответственно, процедурами Search_Ident, Search_Const и Search_Term, добавление в таблицы - процедурами Add_Ident, Add_Const и Add_Term. Все они вызываются из процедуры WriteLex, входными данными для которой являются результаты распознавания лексем, т.е. типы лексем. Запись в таблицу кодов лексем производится процедурой WriteCode, вывод всех таблиц на экран - процедурой vyvod.Перевод констант в десятичную форму производится процедурой perevod.2.4.3 Реализация лексического анализатораПриведём текст подпрограммы лексического анализатора: // процедура перевода констант в десятичную формуprocedure perevod (SS: string; var Str16: string);var ch3,ch4,ch, i: integer;zn: string;beginch: =0; // для римских константif (SS [2] ='X') or (SS [2] ='V') or (SS [2] ='I') thenbeginzn: =SS [1] ;delete (SS,1,1);while Length (SS) <>0 dobeginif SS [1] ='X' then begin ch: =ch+10; delete (SS,1,1); endelse beginif SS [1] ='V'then begin ch: =ch+5; delete (SS,1,1); endelse beginif ( (SS [1] ='I') and (SS [2] ='I')) or ( (SS [1] ='I') and (SS [2] ='')) then begin ch: =ch+1; delete (SS,1,1); endelse beginif (SS [1] ='I') and (SS [2] ='X') then begin ch: =ch+9; delete (SS,1,2); endelse beginif (SS [1] ='I') and (SS [2] ='V') then begin ch: =ch+4; delete (SS,1,2); end;end; end; end; end; end;str16: =zn+IntToStr (ch);exit;end; // для 16-рич. константIf SS [3] in ['0'. '9']thench3: =StrToInt (SS [3]) *16elseif SS [3] in ['A'. 'F']thenbeginch3: =ord (SS [3]);case ch3 of65: ch3: =10*16;66: ch3: =11*16;67: ch3: =12*16;68: ch3: =13*16;69: ch3: =14*16;70: ch3: =15*16;end;end;If SS [4] in ['0'. '9']thench4: =StrToInt (SS [4])elseif SS [4] in ['A'. 'F']thenbeginch4: =ord (SS [4]);case ch4 of65: ch4: =10;66: ch4: =11;67: ch4: =12;68: ch4: =13;69: ch4: =14;70: ch4: =15;end;end;ch: =ch3+ch4;If (SS [3] ='0') and (SS [4] ='0')then Str16: =IntToStr (ch)else Str16: =SS [2] +IntToStr (ch);end;procedure TForm1. N3Click (Sender: TObject);beginclose;end;function Select_Lex (S: string; {исх. строка} var Rez: string; {лексема}N: integer {текущая позиция}): integer;label 1;begin // функция выбора слов из строкиk: = Length (S);Rez: ='';i: =N; // точка продолжения в строкеwhile (S [i] =' ') and (i<= k) do i: =i+1; // пропуск ' 'while not (S [i] in deleter) and (i<= k) do // накопление лексемыbeginif s [i] ='$' thenbeginRez: =s [i] +s [i+1] ;i: =i+2;endelse begin1: Rez: =Rez+s [i] ;i: =i+1;end;end;if Rez='' thenbeginif (s [i] =': ') thenbeginif (s [i+1] ='=') then // в случае операции из двух символовbeginRez: =s [i] +s [i+1] ;Select_Lex: =i+2;endelsebeginRez: =s [i] ;Select_Lex: =i+1;end;end elsebeginif ( (s [i] ='+') or (s [i] ='-')) and (s [i-1] =' (')then beginRez: =s [i] +s [i+1] ;i: =i+2;goto 1;endelse beginRez: =s [i] ;Select_Lex: =i+1;end; end;end else Select_Lex: =i;end;procedure Add_Const (Curr_term: integer; str_lex: string); // Процедура добавления идентификаторов в деревоbeginif NumConst=1 then // Если корень дерева еще не создан, то создаем его.beginperevod (str_lex,str16);Const_tab [NumConst]. value: =str_lex;Const_tab [NumConst]. nomer: =NumConst;Const_tab [NumConst]. Val10: =str16;Const_tab [NumConst]. Left: =0;Const_tab [NumConst]. Right: =0;Const_tab [NumConst]. Way: ='V';Exit;end;if (CompareStr (Const_tab [Curr_term]. value,str_lex) >0) then // Если значение текущего узла дерева больше добавляемогоif Const_tab [Curr_term]. Left=0 then // если у этого элемента дерева нет левого указателя, тоbeginperevod (str_lex,str16);Const_tab [Curr_term]. Left: =NumConst; // Создание левого элемента.Const_tab [NumConst]. value: =str_lex;Const_tab [NumConst]. nomer: =NumConst;Const_tab [NumConst]. Val10: =str16;Const_tab [NumConst]. Left: =0;Const_tab [NumConst]. Right: =0;Const_tab [NumConst]. Way: =Const_tab [NumConst]. Way+'L';end else beginConst_tab [NumConst]. Way: =Const_tab [NumConst]. Way+'L';Add_Const (Const_tab [Curr_term]. Left,str_lex); // Если левый указатель существует, то вызываем уже функцию для левого указателя.end;if (CompareStr (Const_tab [Curr_term]. value,str_lex) <0) then // если у этого элемента дерева нет правого указателя, тоif Const_tab [Curr_term]. Right=0 thenbeginperevod (str_lex,str16);Const_tab [Curr_term]. Right: =NumConst; // Создаем правый элемент.Const_tab [NumConst]. value: =str_lex;Const_tab [NumConst]. nomer: =NumConst;Const_tab [NumConst]. Val10: =str16;Const_tab [NumConst]. Left: =0;Const_tab [NumConst]. Right: =0;Const_tab [NumConst]. Way: =Const_tab [NumConst]. Way+'R';end else beginConst_tab [NumConst]. Way: =Const_tab [NumConst]. Way+'R';Add_Const (Const_tab [Curr_term]. Right,str_lex); // Если правый указатель существует, то вызываем уже функцию для правого указателя.end;end;procedure Add_Term (Curr_term: integer; str_lex: string); // Процедура добавления идентификаторов в деревоbeginif NumTerm=1 then // Если корень дерева еще не создан, то создаем его.beginTerm_tab [NumTerm]. lex: =str_lex;Term_tab [NumTerm]. nomer: =NumTerm;Term_tab [NumTerm]. Left: =0;Term_tab [NumTerm]. Right: =0;Term_tab [NumTerm]. Way: ='V';Exit;end;if (CompareStr (Term_tab [Curr_term]. lex,str_lex) >0) then // Если значение текущего узла дерева больше добавляемогоif Term_tab [Curr_term]. Left=0 then // если у этого элемента дерева нет левого указателя, тоbeginTerm_tab [Curr_term]. Left: =NumTerm; // Создание левого элемента.Term_tab [NumTerm]. lex: =str_lex;Term_tab [NumTerm]. nomer: =NumTerm;Term_tab [NumTerm]. Left: =0;Term_tab [NumTerm]. Right: =0;Term_tab [NumTerm]. Way: =Term_tab [NumTerm]. Way+'L';end else beginTerm_tab [NumTerm]. Way: =Term_tab [NumTerm]. Way+'L';Add_Term (Term_tab [Curr_term]. Left,str_lex); // Если левый указатель существует, то вызываем уже функцию для левого указателя.end;if (CompareStr (Term_tab [Curr_term]. lex,str_lex) <0) then // если у этого элемента дерева нет правого указателя, тоif Term_tab [Curr_term]. Right=0 thenbeginTerm_tab [Curr_term]. Right: =NumTerm; // Создаем правый элемент.Term_tab [NumTerm]. lex: =str_lex;Term_tab [NumTerm]. nomer: =NumTerm;Term_tab [NumTerm]. Left: =0;Term_tab [NumTerm]. Right: =0;Term_tab [NumTerm]. Way: =Term_tab [NumTerm]. Way+'R';end else beginTerm_tab [NumTerm]. Way: =Term_tab [NumTerm]. Way+'R';Add_Term (Term_tab [Curr_term]. Right,str_lex); // Если правый указатель существует, то вызываем уже функцию для правого указателя.end;end;procedure Add_Ident (str: string); // процедура добавления константыvar i: integer;beginkod: =Length (str) +2;hesh: =0;for i: =1 to Length (str) do hesh: =hesh+ord (str [i]); // вычисление хэшhesh: =round (hesh/kod); // метод деленияwhile (Id_tab [hesh]. lex<>'') and (hesh<maxnum) do // пока ячейка занятаbeginId_tab [hesh]. ssylka: =hesh+1;hesh: =hesh+1;end;Id_tab [hesh]. nomer: =Numid; // запись данныхId_tab [hesh]. lex: =str;end;function Search_Ident (str: string): integer; // функция поиска терминалаvar i: integer;label 1;beginkod: =Length (str) +2;hesh: =0;for i: =1 to Length (str) do hesh: =hesh+ord (str [i]); // вычисление хэшhesh: =round (hesh/kod);1: if str=Id_tab [hesh]. lex then Search_Ident: =Id_tab [hesh]. nomer else // поиск идентификатораbeginif Id_tab [hesh]. ssylka=0 then Search_Ident: =0 elsebeginhesh: =Id_tab [hesh]. ssylka;goto 1;end;end;end;procedure Search_Const (Curr_term: integer; str_lex: string); // Процедура поиска лексем в дереве идентификаторовbeginConstyes: =0; // флаг: найдена ли лексемаif (NumConst<>0) and (str_lex<>'') thenbeginif (CompareStr (Const_tab [Curr_term]. value,str_lex) >0) and (Const_tab [Curr_term]. Left<>0) thenSearch_Const (Const_tab [Curr_term]. Left,str_lex); // рекурсивный "спуск по дереву"if (CompareStr (Const_tab [Curr_term]. value,str_lex) <0) and (Const_tab [Curr_term]. Right<>0) thenSearch_Const (Const_tab [Curr_term]. Right,str_lex);if Const_tab [Curr_term]. value=str_lex then Constyes: =Const_tab [Curr_term]. nomer;end;end;procedure Search_Term (Curr_term: integer; str_lex: string); // Процедура поиска лексем в дереве идентификаторовbeginTermyes: =0; // флаг: найдена ли лексемаif (NumTerm<>0) and (str_lex<>'') thenbeginif (CompareStr (Term_tab [Curr_term]. lex,str_lex) >0) and (Term_tab [Curr_term]. Left<>0) thenSearch_Term (Term_tab [Curr_term]. Left,str_lex); // рекурсивный "спуск по дереву"if (CompareStr (Term_tab [Curr_term]. lex,str_lex) <0) and (Term_tab [Curr_term]. Right<>0) thenSearch_Term (Term_tab [Curr_term]. Right,str_lex);if Term_tab [Curr_term]. lex=str_lex then Termyes: =Term_tab [Curr_term]. nomer;end;end; // функция распознавания 16-рич. константfunction FConst (str: string): integer;varsost: byte;beginsost: =0;if str [1] ='$' then // распознаём символ '$'beginsost: =1;delete (str,1,1);endelse exit;if (str [1] ='+') or (str [1] ='-') then // распознаём знакbeginsost: =2;delete (str,1,1)endelse begin sost: =4; exit; end;if str='' then exit;while length (str) >0 do beginif (str [1] in cifra) or (str [1] in bukva)then sost: =2 // распознаём буквы или цифрыelse begin sost: =4; exit;end;delete (str,1,1);end;sost: =3;if sost=3 then FConst: =1 else FConst: =-1;end;function termin: integer; // распознаватель терминальных символовbegintermin: =-1;for k: =1 to 14 do if Words [k] =Lexem then termin: =3;for k: =1 to 8 do if Razdel [k] =Lexem then termin: =1;for k: =1 to 11 do if Operacii [k] =Lexem then termin: =2;end;function Rome (str: string): integer; // распознаватель римских константvar sost: byte;beginsost: =0;if (str [1] ='-') or (str [1] ='+')then begin sost: =12; delete (str,1,1); end;if str='' then exit;if str [1] ='X'then begin sost: =1; delete (str,1,1) endelse beginif str [1] ='V' then begin sost: =2; delete (str,1,1) endelse beginif str [1] ='I' then begin sost: =3; delete (str,1,1) endelse begin sost: =4; exit; end; end; end;while Length (str) <>0 do begincase sost of1: if str [1] ='X'then begin sost: =5; delete (str,1,1) endelse beginif str [1] ='V' then begin sost: =2; delete (str,1,1) endelse beginif str [1] ='I' then begin sost: =3; delete (str,1,1) endelse begin sost: =4; exit; end; end; end;2: if str [1] ='I'then begin sost: =7; delete (str,1,1) endelse begin sost: =4; exit; end;3: if str [1] ='X'then begin sost: =8; delete (str,1,1) endelse beginif str [1] ='V' then begin sost: =9; delete (str,1,1) endelse beginif str [1] ='I' then begin sost: =10; delete (str,1,1) endelse begin sost: =4; exit; end; end; end;4: exit;5: if str [1] ='X'then begin sost: =6; delete (str,1,1) endelse beginif str [1] ='V' then begin sost: =2; delete (str,1,1) endelse beginif str [1] ='I' then begin sost: =3; delete (str,1,1) endelse begin sost: =4; exit; end; end; end;6: if str [1] ='V'then begin sost: =2; delete (str,1,1) endelse beginif str [1] ='I' then begin sost: =3; delete (str,1,1) endelse begin sost: =4; exit; end; end;7: if str [1] ='I'then begin sost: =10; delete (str,1,1) endelse begin sost: =4; exit; end;8: begin sost: =4; exit; end;9: begin sost: =4; exit; end;10: if str [1] ='I'then begin sost: =11; delete (str,1,1) endelse begin sost: =4; exit; end;11: begin sost: =4; exit; end;end;end;if (sost=4) or (sost=12) then Rome: =-1 else Rome: =1;end; // функция распознавания идентификаторовfunction Ident (str: string): integer;varsost: byte;beginsost: =0; // реализация конечного автоматаif str [1] in ['a'. 'z'] thenbeginsost: =1;delete (str,1,1)endelse exit;while length (str) >0 do beginif str [1] in ['a'. 'z','0'. '9','_']then begin sost: =1; delete (str,1,1); endelse begin sost: =3; exit; end;end;sost: =2;if sost=2 then ident: =1 else ident: =-1;end;procedure WriteCode (nomer: integer; lex: string; typ: char; num: integer); // запись в таблицу кодов лексемbeginCode_Tab [NumLex]. nomer: =nomer;Code_Tab [NumLex]. Lex: =lex;Code_Tab [NumLex]. typ: =typ;Code_Tab [NumLex]. Num: =num;Code_Tab [NumLex]. numstr: =string_counter+1;end;procedure WriteLex (typelex: char); // запись лексем в таблицыbegincase typelex of'C': begin // если лексема-16-рич. константаNumLex: =NumLex+1;Search_Const (1,Lexem);if Constyes=0 then // если лексема не найденаbeginNumConst: =NumConst+1;Add_Const (1,Lexem);Const_tab [NumConst]. Typ: ='16-рич. ';Const_tab [Numconst]. Width: ='2 байта';WriteCode (NumLex,Lexem,'C',NumConst);end else // если лексема найденаbeginWriteCode (NumLex,Lexem,'C',Constyes);end;end;'M': begin // если лексема-римская константаNumLex: =NumLex+1;Search_Const (1,Lexem);if Constyes=0 then // если лексема не найденаbeginNumConst: =NumConst+1;Add_Const (1,Lexem);Const_tab [NumConst]. Typ: ='римск. ';Const_tab [Numconst]. Width: ='2 байта';WriteCode (NumLex,Lexem,'C',NumConst);end else // если лексема найденаbeginWriteCode (NumLex,Lexem,'C',Constyes);end;end;'I': begin // если лексема-идентификаторNumLex: =NumLex+1;y: =Search_Ident ({1,}Lexem);if y=0 then // если лексема не найденаbeginNumId: =NumId+1;WriteCode (NumLex,Lexem,'I',NumId);Add_Ident (Lexem);end else WriteCode (NumLex,Lexem,'I',y); // если лексема найденаend;'K': begin // если лексема-служебное словоNumLex: =NumLex+1;Search_Term (1,Lexem);if Termyes=0 then // если лексема не найденаbeginNumTerm: =NumTerm+1;Add_Term (1,Lexem);Term_tab [Numterm]. razd: =0;Term_tab [Numterm]. oper: =0;Term_tab [Numterm]. slug: =1;WriteCode (NumLex,Lexem,'T',NumTerm);end else WriteCode (NumLex,Lexem,'T',Termyes); // если лексема найденаend;'R': begin // если лексема-разделительNumLex: =NumLex+1;Search_Term (1,Lexem);if Termyes=0 then // если лексема не найденаbeginNumTerm: =NumTerm+1;Add_Term (1,Lexem);Term_tab [NumTerm]. razd: =1;Term_tab [NumTerm]. oper: =0;Term_tab [NumTerm]. slug: =0;WriteCode (NumLex,Lexem,'T',NumTerm)end else WriteCode (NumLex,Lexem,'T',Termyes) // если лексема найденаend;'O': begin // если лексема-знак операцияNumLex: =NumLex+1;Search_Term (1,Lexem);if Termyes=0 then // если лексема не найденаbeginNumTerm: =NumTerm+1;Add_Term (1,Lexem);Term_tab [Numterm]. razd: =0;Term_tab [Numterm]. oper: =1;Term_tab [Numterm]. slug: =0;WriteCode (NumLex,Lexem,'T',NumTerm)end else WriteCode (NumLex,Lexem,'T',Termyes) // есди лексема найденаend;end;end;procedure TForm1. N5Click (Sender: TObject);var i,pip: integer;beginfor k: =1 to numid do // обнуление таблицы идентификаторовbeginid_tab [k]. lex: ='0';id_tab [k]. nomer: =0;id_tab [i]. ssylka: =0;end;for i: =1 to numlex do // обнуление выходной таблицыbeginCode_Tab [i]. Lex: ='';Code_Tab [i]. typ: =#0;Code_Tab [i]. Num: =0;Code_Tab [i]. nomer: =0;end;for i: =0 to numconst do // обнуление таблицы константbeginConst_tab [i]. nomer: =0;Const_tab [i]. value: ='';Const_tab [i]. Typ: ='';Const_tab [i]. Width: ='';Const_tab [i]. Val10: ='';Const_tab [k]. Left: =0;Const_tab [k]. Right: =0;Const_tab [k]. Way: ='';end;for i: =1 to numterm dobeginTerm_tab [i]. nomer: =0;Term_tab [i]. Lex: ='';Term_tab [i]. razd: =0;Term_tab [i]. oper: =0;Term_tab [i]. slug: =0;Term_tab [k]. Left: =0;Term_tab [k]. Right: =0;Term_tab [k]. Way: ='';end; // инициализацияNumLex: =0; NumId: =0; NumConst: =0; NumErr: =0; NumTerm: =0;Error: =false; Found: =false;i: =0; j: =0; k: =0; y: =0;String_counter: =0;Memo2. Lines. Clear;N6. Enabled: =true;while string_counter<=Memo1. Lines. Count do // цикл по строкам файлаbeginn: =1;m: =1;s: =Form1. Memo1. Lines. Strings [string_counter] ;for l: =1 to 2 dowhile m<=Length (s) do // цикл по строкеbeginn: =m;m: =Select_Lex (s,Lexem,n);if (Lexem<>'') and not (Lexem [1] in [#0. #32]) thenbeginif FConst (Lexem) =1 then WriteLex ('C') else // вызов процедуры записиif Termin=3 then WriteLex ('K') elseif Rome (Lexem) =1 then WriteLex ('M') elseif Ident (Lexem) =1 then WriteLex ('I') elseif Termin=1 then WriteLex ('R') elseif Termin=2 then WriteLex ('O')else Err_lex;end;end;string_counter: =string_counter+1;end;vyvod; // вызов процедуры выводаend;procedure TForm1. vyvod; // Вывод результатовvarf: textfile; // выходной файлbeginStringGrid1. RowCount: =NumConst+1; // определение числа строк в таблицахStringGrid2. RowCount: =NumId+1;StringGrid3. RowCount: =NumTerm+1;StringGrid4. RowCount: =NumLex+1;StringGrid1. Cells [0,0]: ='№'; StringGrid1. Cells [1,0]: ='Константа'; StringGrid1. Cells [2,0]: ='Тип';StringGrid1. Cells [3,0]: ='Ширина'; StringGrid1. Cells [4,0]: ='10-тичный формат';StringGrid1. Cells [5,0]: ='L'; StringGrid1. Cells [6,0]: ='R';StringGrid1. Cells [7,0]: ='Путь'; // определение заголовковfor k: =1 to NumConst do // вывод таблицы константbeginStringGrid1. cells [0,k]: = Inttostr (Const_Tab [k]. nomer);StringGrid1. cells [1,k]: = Const_Tab [k]. value;StringGrid1. cells [2,k]: = Const_Tab [k]. Typ;StringGrid1. cells [3,k]: = Const_Tab [k]. Width;StringGrid1. cells [4,k]: = Const_Tab [k]. Val10;StringGrid1. cells [5,k]: = Inttostr (Const_Tab [k]. Left);StringGrid1. cells [6,k]: = Inttostr (Const_Tab [k]. Right);StringGrid1. cells [7,k]: = Const_Tab [k]. Way;end;AssignFile (F,'Const. txt'); // запись в файл таблицы константRewrite (F);for k: =1 to NumConst doWriteln (F, StringGrid1. cells [0,k] +' '+StringGrid1. cells [1,k] +' '+StringGrid1. cells [2,k] +' '+StringGrid1. cells [3,k]);CloseFile (F);StringGrid2. Cells [0,0]: ='№'; StringGrid2. Cells [1,0]: ='Имя'; // определение заголовковk: =0;k1: =0;while k<numid do // вывод таблицы идентификаторовbeginif Id_tab [k1]. lex<>'' thenbeginStringGrid2. cells [0,k+1]: =IntToStr (Id_tab [k1]. nomer);StringGrid2. cells [1,k+1]: =Id_Tab [k1]. lex;k: =k+1;end;k1: =k1+1;end;AssignFile (F,'Ident. txt'); // запись в файл таблицы константRewrite (F);for k: =1 to NumId do Writeln (F, StringGrid2. cells [0,k] +' '+StringGrid2. cells [1,k]);CloseFile (F);StringGrid3. Cells [0,0]: ='№'; StringGrid3. Cells [1,0]: ='Символ'; StringGrid3. Cells [2,0]: ='Раздел. ';StringGrid3. Cells [3,0]: ='Зн. операции'; StringGrid3. Cells [4,0]: ='Ключ. слово';StringGrid3. Cells [5,0]: ='L'; StringGrid3. Cells [6,0]: ='R';StringGrid3. Cells [7,0]: ='Путь'; // определение заголовковfor k: =1 to NumTerm do // вывод таблицы терминальных символовbeginStringGrid3. cells [0,k]: = Inttostr (Term_Tab [k]. nomer);StringGrid3. cells [1,k]: = Term_Tab [k]. lex;StringGrid3. cells [2,k]: = Inttostr (Term_Tab [k]. razd);StringGrid3. cells [3,k]: = Inttostr (Term_Tab [k]. oper);StringGrid3. cells [4,k]: = Inttostr (Term_Tab [k]. slug);StringGrid3. cells [5,k]: = Inttostr (Term_Tab [k]. Left);StringGrid3. cells [6,k]: = Inttostr (Term_Tab [k]. Right);StringGrid3. cells [7,k]: = Term_Tab [k]. Way;end;AssignFile (F,'Term. txt'); // запись в файл таблицы терминальных символовRewrite (F);for k: =1 to NumTerm do Writeln (F, StringGrid3. cells [0,k] +' '+StringGrid3. cells [1,k] +' '+StringGrid3. cells [2,k] +' '+StringGrid3. cells [3,k] +' '+StringGrid3. cells [4,k]);