b>3. Разработка синтаксического анализатора3.1 Уточнение грамматики языка применительно к варианту задания Синтаксический анализ производится методом рекурсивного спуска. Анализатор, основанный на этом методе, состоит из отдельных процедур для распознавания нетерминальных символов, определённых в грамматике. Каждая такая процедура ищет во входном потоке лексем подстроку, которой может быть поставлен в соответствие нетерминальный символ, распознаваемый с помощью данной процедуры. В процессе своей работы процедура может обратиться к другим подобным процедурам для поиска других нетерминальных символов. Если эта процедура интерпретирует входную подстроку как соответствующий нетерминальный символ, то она заканчивает свою работу, передаёт в вызвавшую её программу или процедуру признак успешного завершения и устанавливает указатель текущей лексемы на первую лексему после распознанной подстроки. Если же процедура не может найти подстроку, которая могла бы быть интерпретирована как требуемый нетерминальный символ, она заканчивается с признаком неудачного завершения и выдает соответствующее диагностическое сообщение. Правила синтаксического анализа относятся к грамматике вида LL (1), т.е. используется левосторонний просмотр и левосторонний вывод, при этом необходимо просматривать не более 1 символа. Множество правил грамматики реализуемого языка, записанных в форме Бэкуса-Наура, имеет следующий вид: 1. <программа>>program<имя программы>; var<список описаний> begin<список операторов>end. 2. <имя программы>>ИМЯ 3. <список описаний>><описание>; {<описание>; } 4. <описание>><список имён>: <тип> 5. <тип>>real 6. <список имён>>ИМЯ{, ИМЯ} 7. <список операторов>><оператор>; {<оператор>; } 8. <оператор>><присваивание> | <цикл> 9. <присваивание>>ИМЯ: =<выражение> 10. <выражение>><простое выражение>{ (=, <, <>, >, >=, <=) <простое выражение>} 11. <простое выражение>><терм>+<терм> 12. <терм>><множитель>*<множитель> 13. <множитель>>ИМЯ | КОНСТАНТА | <простое выражение> 14. <цикл>>repeat<тело цикла>until<выражение> 15. <тело цикла>><оператор>|<составной оператор> 16. <составной оператор>>begin<список операторов>end В грамматике, помимо общепринятых, используются следующие терминальные символы: ИМЯ - идентификатор; КОНСТАНТА - 16-ричная или римская константа. 3.2 Разработка алгоритма синтаксического анализаСинтаксический анализ производится методом рекурсивного спуска. Синтаксический анализатор представляет собой набор функций, каждая из которых должна распознавать отдельный нетерминальный символ грамматики. При этом разработка проходит от общего к частному. Первой строится функция распознавания начального символа грамматики, потом функции, непосредственно вызываемые из нее и так далее.Далее рассматриваются алгоритмы отдельных функций распознавания. Общий метод их построения заключается в следующем: изначально значение функции устанавливается в FALSE. Далее происходит поиск символов входящих в распознаваемый нетерминал. Если правило содержит другой нетерминальный символ, то происходит вызов соответствующей функции. Если же необходимо проверить наличие терминального символа, то функция сама выполняет запрос на чтение следующей лексемы и сравнивает ее с той, которая должна присутствовать в конструкции. Чтение следующей лексемы состоит в выборе следующего элемента из таблицы кодов лексем, т.е. в увеличении номера текущего элемента на 1 (в блок-схеме будет обозначаться как ЧтСл). Если происходит ошибка, то выполнение функции прекращается с вызовом процедуры вывода сообщения об ошибке (в блок-схеме будет обозначаться как Ошибка). Причем при выполнении анализа такое сообщение выдается один раз, иначе следующие сообщения могут иметь недостоверную информацию. Сообщение содержит номер строки и описание обнаруженной ошибки. Если ошибок не обнаружено, то в конце работы функции ее результат становится TRUE.Lex_Progr: <программа>Lex_Progr_Name: <имя программы>Lex_Descr_List: <список описаний>Lex_Descr: <описание>Lex_Name_List: <список имён>Lex_Type: <тип>Lex_Oper_List: <список операторов>Lex_Oper: <оператор>Lex_Assign: <присваивание>Lex_Exp: <выражение>Lex_Simple_Exp: <простое выражение>Lex_Term: <терм>Lex_Mnozh <множитель>Lex_Repeat_Intil: <цикл>Lex_Body <тело цикла>3.3 Алгоритмы распознающих функцийНиже представлены упрощённые блок-схемы функций распознавания. Простые функции, такие, как распознавание оператора или имени программы, не рассматриваем в силу их очевидности.3.3.1 Функция Lex_Progr3.3.2 Функция Lex_Descr_List3.3.3 Функция Lex_Descr3.3.4 Функция Lex_Name_List3.3.5 Функция Lex_Oper_List3.3.6 Функция Lex_Assign3.3.7 Функция Lex_Exp3.3.8 Функция Lex_Simple_Exp3.3.9 Функция Lex_Term3.3.10 Функция Lex_mnozh3.3.11 Функция Lex_Repeat_Until 3.3.12 Функция Lex_Body3.4 Тексты распознающих процедурfunction TForm1. Lex_Progr: boolean; // 1. программаbeginLex_Progr: =False;if Code_Tab [i]. Lex='program' then i: =i+1 else // конец блока для PROGRAMbeginErr_Synt ('Отсутствует служебное слово program, либо в нем ошибка ', i);Exit;end;if Lex_Prog_Name=false then Exit; // начало блока для имени программыif Code_Tab [i]. Lex='; ' then i: =i+1 else // начало блока для точки с запятойbeginErr_Synt ('Отсутствует точка с запятой после имени программы', i-1);Exit;end;if Code_Tab [i]. Lex='var' then i: =i+1 else // начало блока для VARbeginErr_Synt ('Отсутствует служебное слово var после заголовка программы', i);Exit;end;if Lex_descr_list=false then Exit;if Code_Tab [i]. Lex='begin' then // начало блока для BEGINbegini: =i+1;if Code_Tab [i]. Lex='; ' thenbeginErr_Synt ('После begin недопустим символ "; "', i);Exit;end;end elsebeginErr_Synt ('Отсутствует служебное слово begin после описаний переменных', i);Exit;end;if Lex_oper_list=false then Exit;if Code_Tab [i]. Lex='end' then i: =i+1 else // начало блока для ENDbeginErr_Synt ('Отсутствует служебное слово end в конце программы', i);Exit;end; // начало блока для точкиif Code_Tab [i]. Lex='. ' then Lex_Progr: =true else if Code_Tab [i]. Lex<>'' then Err_Synt ('После служебного слова END вместо точки находится "'+Code_Tab [i]. Lex+'"', i) else Err_Synt ('Ожидается точка после служебного слова END в конце программы', i-1);end;procedure TForm1. Err_Synt (text: string; l: integer);beginif Error<>true thenbeginMemo1. Lines [Code_tab [l]. numstr-1]: =Memo1. Lines [Code_tab [l]. numstr-1] +'!!! '+'Error!!! ';Memo2. Lines [0]: =Memo2. Lines [0] +text;end;Error: =true;Exit;end;function TForm1. Lex_Prog_Name: boolean; // 2. имя программыbeginLex_Prog_Name: =False;if (Code_Tab [i]. typ<>'I') and (Code_Tab [i]. Lex<>'; ') thenbeginErr_Synt ('Неправильное имя программы. Ошибочное выражение: "'+Code_Tab [i]. Lex+'"', i);Exit;end;if Code_Tab [i]. Lex='; ' thenbeginErr_Synt ('Отсутствует имя программы после program', i);Exit;end;Lex_Prog_Name: =true;i: =i+1;end;function TForm1. Lex_Descr_List: boolean; // 3. список описанийbeginLex_descr_list: =false;Found: =false;while Code_Tab [i]. typ='I' dobeginFound: =true;if Lex_descr=false then Exit;if Code_Tab [i]. Lex='; ' then i: =i+1 elsebeginErr_Synt ('Отсутствует точка с запятой после описания переменных ', i-1);Exit;end;end;;if Found=false thenbeginErr_Synt ('Отсутствует идентификатор в описании ', i);Exit;end;Lex_descr_list: =true;end;function TForm1. Lex_descr: boolean; // 4. описаниеbeginLex_descr: =false;if Lex_name_list=true thenbeginif Code_Tab [i]. Lex=': ' then i: =i+1 elsebeginErr_Synt ('Отсутствует двоеточие перед типом '+Code_Tab [i]. Lex, i);Exit;end;if Lex_type=true then Lex_descr: =true else Exit;end else Exit;end;function TForm1. Lex_name_list: boolean; // 6. список именbeginLex_name_list: =false;if Code_Tab [i]. typ='I' then i: =i+1 elsebeginErr_Synt ('Ожидается идентификатор ', i);Exit;end;while Code_Tab [i]. Lex=',' dobegini: =i+1;if Code_Tab [i]. Typ='I' then i: =i+1 elsebeginErr_Synt ('Ожидается идентификатор ', i);Exit;end;end;Lex_name_list: =true;end;function TForm1. Lex_type: boolean; // 5. типbeginLex_type: =false;if (Code_Tab [i]. Lex='integer') thenbeginLex_type: =true;i: =i+1end elsebeginErr_Synt ('Отсутствует тип: integer ', i-1);Exit;end;end;function TForm1. Lex_oper_list: boolean; // 7. список операторовbeginLex_oper_list: =false;found: =false;while Lex_oper=true dobeginFound: =true;if (Code_Tab [i]. Lex='; ') then i: =i+1 else // Если след. лексема после проверенного оператора ни "; ", ни END, а любая другая лексема.if Code_Tab [i]. Lex<>'end' thenbeginErr_Synt ('Ожидается точка с запятой после оператора (после лексемы '+Code_Tab [i-1]. Lex+') ', i-1);Exit;end;end;Lex_oper_list: =true;if found=false thenbeginErr_Synt ('Не найдены операторы между begin и end', i-1);Lex_oper_list: =false;end;end;function TForm1. Lex_oper: boolean;beginLex_oper: =false;if (Lex_assign) or (Lex_repeat_until) then Lex_oper: =true elseif (Code_Tab [i]. Lex='; ') and (Code_Tab [i-1]. Lex='; ') then Lex_oper: =true else // проверяется на пустой оператор, т.е. на ";; ".if (Code_Tab [i]. Typ='T') and (Code_Tab [i]. Lex<>'end') and (Code_Tab [i]. Lex<>'begin') and (Code_Tab [i]. Lex<>'; ') then Err_Synt ('Лишняя лексема в программе: '+Code_Tab [i]. Lex, i);end;function TForm1. Lex_assign: boolean; // 10. присваиваниеbeginLex_assign: =false;if Code_Tab [i]. typ='I' thenbeginif Code_Tab [i+1]. Lex=': =' thenbegini: =i+2;if Lex_Exp=true then Lex_assign: =true else Memo2. Lines [1]: =Memo2. Lines [1] +' в операторе присваивания'end else Err_Synt ('Ошибка в операторе присваивания', i)end;end;function TForm1. Lex_Exp: boolean; // 11. выражениеbeginLex_Exp: =false;if Lex_simple_Exp=true thenbeginif ( (Code_Tab [i]. Lex='=') or (Code_Tab [i]. Lex='>') or (Code_Tab [i]. Lex='<')or (Code_Tab [i]. Lex='<>') or (Code_Tab [i]. Lex='<=') or (Code_Tab [i]. Lex='>=')) thenbegini: =i+1;if Lex_simple_Exp=true thenbeginLex_Exp: =true;Exit;end;end;end else Exit;Lex_Exp: =true; // если простое выражение без знакаend;function TForm1. Lex_simple_Exp: boolean; // 12. простое выражениеbeginFound: =false;Lex_simple_Exp: =false;if Lex_term=true thenbeginFound: =true;while ( (Code_Tab [i]. Lex='+') or (Code_Tab [i]. Lex='-')) and (Found=true) dobegini: =i+1;if Lex_term=false thenbeginFound: =False;Err_Synt ('Ожидается константа, идентификатор или выражение ', i-1);Exit;end;end;if (Code_Tab [i]. Lex=') ') and (Scobka=false) then Err_Synt ('Ожидается открывающаяся скобка в множителе', i)end;if Found=true then Lex_simple_Exp: =true;end;function TForm1. Lex_Term: boolean; // 13. термbeginFound: =false;Lex_Term: =false;if Lex_mnozh=true thenbeginFound: =true;while ( (Code_Tab [i]. Lex='*') or (Code_Tab [i]. Lex='/')) and (Found=true) dobegini: =i+1;if Lex_mnozh=false then Found: =False;end;end;if Found=true then Lex_Term: =true;end;function TForm1. Lex_mnozh: boolean; // 14. множительbeginLex_mnozh: =false;if (Code_Tab [i]. typ='I') or (Code_Tab [i]. typ='C') thenbegini: =i+1;Lex_mnozh: =true;Exit;end elsebeginif Code_Tab [i]. Lex=' (' thenbeginScobka: =true;i: =i+1;if Lex_simple_Exp=true thenbeginif Code_Tab [i]. Lex=') ' thenbegini: =i+1;Lex_mnozh: =true;end elsebeginErr_Synt ('Ожидается закрывающая скобка в множителе ', i);Exit;end;end;end else Err_Synt ('Ожидается константа, идентификатор или выражение ', i);end;end;function TForm1. Lex_repeat_until: boolean; // 18. циклbeginLex_repeat_until: =false;if Code_Tab [i]. Lex='repeat' thenbegini: =i+1;if Lex_body=true then begin i: =i+1;if Code_Tab [i]. Lex='until' then begin i: =i+1;
Страницы: 1, 2, 3, 4, 5, 6, 7, 8
|