Рефераты
 

Разработка программы-компилятора

loseFile (F);

StringGrid4. Cells [0,0]: ='№'; StringGrid4. Cells [1,0]: ='Тип'; StringGrid4. Cells [2,0]: ='№ в таблице'; StringGrid4. Cells [3,0]: ='Лексема'; // определение заголовков

for k: =1 to NumLex do // вывод таблицы кодов лексем

begin

StringGrid4. cells [0,k]: = Inttostr (Code_Tab [k]. nomer);

StringGrid4. cells [1,k]: = Code_Tab [k]. typ;

StringGrid4. cells [2,k]: = Inttostr (Code_Tab [k]. num);

StringGrid4. cells [3,k]: = Code_Tab [k]. lex;

end;

AssignFile (F,'Cod. txt'); // запись в файл выходной таблицы

Rewrite (F);

for k: =1 to NumLex do Writeln (F, StringGrid4. cells [0,k] +' '+StringGrid4. cells [1,k] +' '+StringGrid4. cells [2,k] +' '+StringGrid4. cells [3,k]);

CloseFile (F);

end;

procedure TForm1. Err_Lex; // процедура вывода ошибки в лексеме

begin

Memo2. Lines. Add ('В строке №'+Inttostr (String_counter+1) +' ошибочная лексема '+Lexem);

NumErr: =NumErr+1;

NumLex: =NumLex+1;

Code_Tab [NumLex]. nomer: =NumLex;

Code_Tab [NumLex]. Lex: =Lexem;

Code_Tab [NumLex]. typ: ='E';

Code_Tab [NumLex]. Num: =NumErr;

Exit;

end;

2.4.4 Тестирование лексического анализатора

Текст программы не содержит ошибок
:

program var15;

var n: integer;

begin

n: =$+00;

repeat

n: =n- (-XII);

until n<$-0A;

end.

Результат - таблицы констант, идентификаторов, терминальных символов и кодов лексем (см. рис.5, б) и отсутствие сообщениий об ошибках (см. рис.5, а).

рис.5, а.

рис.5, б

рис.5. Результаты тестирования программы, не содержащей ошибок.

Текст программы содержит ошибочные лексемы var% и $+MN.

program var15;

var% n: integer;

begin

n: =$+MN;

repeat

n: =n- (-XII);

until n<$-0A;

end.

Результат - в таблицу кодов лексем эти лексемы занесены с типом Е, что означает, что они ошибочны (см. Рис.6, а, б), программа выдала также сообщения об ошибках (Рис.6, в).

Рис.6, а

Рис.6, б

Рис.6, в

Рис.6. Результаты тестирования программы, содержащей ошибочные лексемы.

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_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.11 Функция Lex_Repeat_Until

3.3.12 Функция Lex_Body

3.4 Тексты распознающих процедур

function TForm1. Lex_Progr: boolean; // 1. программа

begin

Lex_Progr: =False;

if Code_Tab [i]. Lex='program' then i: =i+1 else // конец блока для PROGRAM

begin

Err_Synt ('Отсутствует служебное слово program, либо в нем ошибка ', i);

Exit;

end;

if Lex_Prog_Name=false then Exit; // начало блока для имени программы

if Code_Tab [i]. Lex='; ' then i: =i+1 else // начало блока для точки с запятой

begin

Err_Synt ('Отсутствует точка с запятой после имени программы', i-1);

Exit;

end;

if Code_Tab [i]. Lex='var' then i: =i+1 else // начало блока для VAR

begin

Err_Synt ('Отсутствует служебное слово var после заголовка программы', i);

Exit;

end;

if Lex_descr_list=false then Exit;

if Code_Tab [i]. Lex='begin' then // начало блока для BEGIN

begin

i: =i+1;

if Code_Tab [i]. Lex='; ' then

begin

Err_Synt ('После begin недопустим символ "; "', i);

Exit;

end;

end else

begin

Err_Synt ('Отсутствует служебное слово begin после описаний переменных', i);

Exit;

end;

if Lex_oper_list=false then Exit;

if Code_Tab [i]. Lex='end' then i: =i+1 else // начало блока для END

begin

Err_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);

begin

if Error<>true then

begin

Memo1. 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. имя программы

begin

Lex_Prog_Name: =False;

if (Code_Tab [i]. typ<>'I') and (Code_Tab [i]. Lex<>'; ') then

begin

Err_Synt ('Неправильное имя программы. Ошибочное выражение: "'+Code_Tab [i]. Lex+'"', i);

Exit;

end;

if Code_Tab [i]. Lex='; ' then

begin

Err_Synt ('Отсутствует имя программы после program', i);

Exit;

end;

Lex_Prog_Name: =true;

i: =i+1;

end;

function TForm1. Lex_Descr_List: boolean; // 3. список описаний

begin

Lex_descr_list: =false;

Found: =false;

while Code_Tab [i]. typ='I' do

begin

Found: =true;

if Lex_descr=false then Exit;

if Code_Tab [i]. Lex='; ' then i: =i+1 else

begin

Err_Synt ('Отсутствует точка с запятой после описания переменных ', i-1);

Exit;

end;

end;;

if Found=false then

begin

Err_Synt ('Отсутствует идентификатор в описании ', i);

Exit;

end;

Lex_descr_list: =true;

end;

function TForm1. Lex_descr: boolean; // 4. описание

begin

Lex_descr: =false;

if Lex_name_list=true then

begin

if Code_Tab [i]. Lex=': ' then i: =i+1 else

begin

Err_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. список имен

begin

Lex_name_list: =false;

if Code_Tab [i]. typ='I' then i: =i+1 else

begin

Err_Synt ('Ожидается идентификатор ', i);

Exit;

end;

while Code_Tab [i]. Lex=',' do

begin

i: =i+1;

if Code_Tab [i]. Typ='I' then i: =i+1 else

begin

Err_Synt ('Ожидается идентификатор ', i);

Exit;

end;

end;

Lex_name_list: =true;

end;

function TForm1. Lex_type: boolean; // 5. тип

begin

Lex_type: =false;

if (Code_Tab [i]. Lex='integer') then

begin

Lex_type: =true;

i: =i+1

end else

begin

Err_Synt ('Отсутствует тип: integer ', i-1);

Exit;

end;

end;

function TForm1. Lex_oper_list: boolean; // 7. список операторов

begin

Lex_oper_list: =false;

found: =false;

while Lex_oper=true do

begin

Found: =true;

if (Code_Tab [i]. Lex='; ') then i: =i+1 else // Если след. лексема после проверенного оператора ни "; ", ни END, а любая другая лексема.

if Code_Tab [i]. Lex<>'end' then

begin

Err_Synt ('Ожидается точка с запятой после оператора (после лексемы '+Code_Tab [i-1]. Lex+') ', i-1);

Exit;

end;

end;

Lex_oper_list: =true;

if found=false then

begin

Err_Synt ('Не найдены операторы между begin и end', i-1);

Lex_oper_list: =false;

end;

end;

function TForm1. Lex_oper: boolean;

begin

Lex_oper: =false;

if (Lex_assign) or (Lex_repeat_until) then Lex_oper: =true else

if (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. присваивание

begin

Lex_assign: =false;

if Code_Tab [i]. typ='I' then

begin

if Code_Tab [i+1]. Lex=': =' then

begin

i: =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. выражение

begin

Lex_Exp: =false;

if Lex_simple_Exp=true then

begin

if ( (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='>=')) then

begin

i: =i+1;

if Lex_simple_Exp=true then

begin

Lex_Exp: =true;

Exit;

end;

end;

end else Exit;

Lex_Exp: =true; // если простое выражение без знака

end;

function TForm1. Lex_simple_Exp: boolean; // 12. простое выражение

begin

Found: =false;

Lex_simple_Exp: =false;

if Lex_term=true then

begin

Found: =true;

while ( (Code_Tab [i]. Lex='+') or (Code_Tab [i]. Lex='-')) and (Found=true) do

begin

i: =i+1;

if Lex_term=false then

begin

Found: =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. терм

begin

Found: =false;

Lex_Term: =false;

if Lex_mnozh=true then

begin

Found: =true;

while ( (Code_Tab [i]. Lex='*') or (Code_Tab [i]. Lex='/')) and (Found=true) do

begin

i: =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. множитель

begin

Lex_mnozh: =false;

if (Code_Tab [i]. typ='I') or (Code_Tab [i]. typ='C') then

begin

i: =i+1;

Lex_mnozh: =true;

Exit;

end else

begin

if Code_Tab [i]. Lex=' (' then

begin

Scobka: =true;

i: =i+1;

if Lex_simple_Exp=true then

begin

if Code_Tab [i]. Lex=') ' then

begin

i: =i+1;

Lex_mnozh: =true;

end else

begin

Err_Synt ('Ожидается закрывающая скобка в множителе ', i);

Exit;

end;

end;

end else Err_Synt ('Ожидается константа, идентификатор или выражение ', i);

end;

end;

function TForm1. Lex_repeat_until: boolean; // 18. цикл

begin

Lex_repeat_until: =false;

if Code_Tab [i]. Lex='repeat' then

begin

i: =i+1;

if Lex_body=true then begin i: =i+1;

if Code_Tab [i]. Lex='until' then begin i: =i+1;

if Lex_Exp=true then Lex_repeat_until: =true

else Err_Synt ('Ожидается выражение после служебного слова until', i); end

else Err_Synt ('Ожидается служебное слово until', i);

end;

end;

end;

function TForm1. Lex_body: boolean; // 20. тело цикла

begin

Lex_body: =false;

if Lex_oper=true then

begin

Lex_body: =true;

Exit;

end else

if Code_Tab [i]. Lex='begin' then

begin

i: =i+1;

if Code_Tab [i]. Lex='; ' then

begin

Err_Synt ('После begin недопустим символ "; "', i);

Exit;

end;

if Lex_oper_list=true then

begin

if (Code_Tab [i]. Lex='end') and (Code_Tab [i+1]. Lex<>'; ') then

begin

Lex_body: =true;

i: =i+1;

end else Err_Synt ('Ожидается служебное слово end после блока операторов', i-1)

end;

end;

end;

3.5 Результаты тестирования синтаксического анализатора

Тестирование выполнялось на результатах работы лексического анализатора, который работает безошибочно и был протестирован ранее.

Ошибка

Текст программы

Сообщения от анализатора

В объявлении имени программы

prom var15;

. .

program var15.

Отсутствует служебное слово program или в нём ошибка

В описании

program var15;

n: integer;

. .

program var15;

var,: integer;

. .

program var15;

var n: integer

. .

var n integer

. .

var n:;

Отсутствует служебное слово var после заголовка программы

Отсутствует идентификатор в описании

Отсутствует точка с запятой после описания переменных

Отсутствует двоеточие перед типом integer

Отсутствует тип: integer

В begin. end

. .

begin;

. .

var n: integer;

n: =$+00;

. .

until n<$-0A;

После begin недопустим символ точка с запятой

Отсутствует служебное слово begin после описания переменных

Отсутствует служебное слово end в конце программы

В имени программы

...

program $+00;.

Неправильное имя программы. Ошибочное выражение: "$+00"

В операторе присваивания

...

n: $+00;

Ошибка в операторе присваивания

В выражении

...

n: =- (-XII);...

Ожидается константа, идентификатор или выражение

В цикле

...

repeat

n: =n- (-XII);

n<$-0A;.

Ожидается служебное слово until

В теле программы

...

n: =$+00.

Ожидается точка с запятой после оператора (после лексемы $+00)

4. Реализация двухфазного компилятора

Главные процедуры лексического и синтаксического анализатора - это, соответственно, процедуры N5. Click и N6. Click главной формы программы. Из них вызываются остальные подпрограммы

Текст исходная программа выводится в окне в верхнем левом углу формы. Если лексический анализ текста (процедура N5. Click) выявил ошибку, то она выводится в окне сообщёний об ошибках и анализ прекращается.

Лексический анализатор выводит на форму таблицы констант, идентификаторов, терминальных символов и кодов лексем в областях вывода StringGrid1, StringGrid2, StringGrid3 и StringGrid4.

После синтаксического анализа переданной таблицы кодов лексем в окне сообщений об ошибках синтаксического анализатора содержатся сообщения от распознающих процедур разного уровня, затронутых обнаруженной ошибкой (см п.3.5)

Ошибок при двухфазном анализе не выявлено, если область вывода лексических ошибок пуста, а для синтаксических - содержит текст "Ошибок нет".

Внешний вид окна программы представлен на рис.7.

4.1 Результаты тестирования двухфазного компилятора

полностью совпадают с результатами тестирования лексического и синтаксического анализатора по отдельности, проведённых последовательно.

рис.7. Внешний вид окна программы

5. Описание программы

5.1 Общие сведения и функциональное назначение

Данная программа предназначена для лексического и синтаксического анализа небольших (<1 МБ) текстов программ на заданном диалекте подмножества языка Pascal.

Программа написана на языке Delphi в среде разработки Delphi 7.

Программа предназначена для выявления наличия лексических и синтаксических ошибок во входном тексте программы.

5.2 Вызов и загрузка

Запуск файла lex1. exe.

5.3 Входные данные

Исходный текст программы, в текстовом файле `вар14. txt' или в окне ввода исходного текста.

5.4 Выходные данные

Сообщение о первой ошибке, выявленной лексическим анализом, а при отсутствии таковых - вывод сообщения о первой обнаруженной синтаксической ошибке, при отсутствии ошибок - соответствующее сообщение.

5.5 Описание логической структуры программы

5.5.1 Файлы программы

Программа состоит из файлов
:

lex. pas

lex. ~dfm

5.5.2 Общее описание работы программы

Основная форма программы
- в файле lex. dfm, алгоритм её работы - в файле lex. pas.

Список строк исходного текста программы загружается в массив SA. Процедура Select_lex выполняет выделение из текста лексем. Таблицы констант, идентификаторов, терминальных символов и кодов лексем хранятся в массивах Const_Tab, Id_Tab, Term_Tab и Code_Tab. Распознавателем идентификаторов является функция Ident, 16-ричных констант - функция Const16, логических констант - функция Boolconst. Распознавателем терминальных символов является функция Termin. Если лексема ошибочна, то она заносится в таблицу кодов лексем с типом E и выдаётся сообщение об ошибке (процедура Err_Lex). Все эти подпрограммы вызываются из процедуры TForm1. N5Click (соответствует выбору пункта меню Анализатор/Лексический). В ней производится обнуление всех таблиц, вызов функции выделения лексем и процедуры WriteLex (см. ниже).

Поиск идентификаторов, констант и терминальных символов в соответствующих таблицах производится, соответственно, процедурами Search_Ident, Search_Const и Search_Term, добавление в таблицы - процедурами Add_Ident, Add_Const и Add_Term. Все они вызываются из процедуры WriteLex, входными данными для которой являются результаты распознавания лексем, т.е. типы лексем. Запись в таблицу кодов лексем производится процедурой WriteCode, вывод всех таблиц на экран - процедурой vyvod.

Перевод констант в десятичную форму производится процедурой perevod.

Процедура начала синтаксического анализа N6. Click вызывает процедуру Syntax, которая, в свою очередь, вызывает процедуру Lex_Progr, далее реализуется синтаксический анализ методом рекурсивного спуска.

Текст программы лексическому анализатору передаётся из поля в верхнем правом углу главного окна при выборе пункта меню "Анализ/Лексический", куда он может вводиться с клавиатуры или загружать из файла "вар14. txt" (он обязательно должен находиться в каталоге с программой) при создании формы. Полученный список лексем передаётся синтаксическому анализатору, а найденные им ошибки - в поле в левой части окна.

Список использованной литературы

1. Методические указания к лабораторным работам по СПО.

2. Курс лекций по дисциплине "Системное программное обеспечение".

3. А.Ю. Молчанов "Системное программное обеспечение", СПб, 2003 г.

4. Ю.Г. Карпов "Теория автоматов", СПб, 2002 г.

5. В.В. Фаронов“Delphi. Программирование на языке высокого уровня", Питер, 2004 г.

Приложение: текст программы

unit lex;

interface

uses

Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

Dialogs, Menus, StdCtrls, Grids;

type

TVyh = Record // Тип таблицы кодов лексем

nomer: integer; // Номер

typ: char; // Тип лексемы

Num: integer; // Номер в таблице

Lex: String; // Лексема

numstr: integer; // Номер строки

end;

TTerm = Record // тип таблицы терминальных символов

nomer: integer; // номер

Lex: String; // Лексема

razd: byte; // Разделитель?

oper: byte; // Операция?

slug: byte; // Служебное слово?

Left: integer; // Левая ветвь дерева.

Right: integer; // Правая ветвь дерева.

Way: string;

end;

TConst = Record // Тип таблицы констант

nomer: integer; // Номер

value: string; // Само значение лексемы.

Typ: string; // Тип лексемы

Width: string; // Ширина константы

Val10: string; // 10-тичный формат константы

Left: integer; // Левая ветвь дерева.

Right: integer; // Правая ветвь дерева.

Way: string;

end;

TId = Record // таблица имен

nomer: integer; // номер лексемы

lex: string; // лексема

ssylka: integer; // ссылка на элемент цепочки

end;

TForm1 = class (TForm)

MainMenu1: TMainMenu;

N1: TMenuItem;

N2: TMenuItem;

N3: TMenuItem;

N4: TMenuItem;

N5: TMenuItem;

OpenDialog1: TOpenDialog;

Memo1: TMemo;

N6: TMenuItem;

StringGrid1: TStringGrid;

Label1: TLabel;

StringGrid2: TStringGrid;

Label2: TLabel;

StringGrid3: TStringGrid;

StringGrid4: TStringGrid;

Label3: TLabel;

Label4: TLabel;

Memo2: TMemo;

Label5: TLabel;

procedure N2Click (Sender: TObject);

procedure N3Click (Sender: TObject);

procedure N5Click (Sender: TObject);

procedure vyvod;

procedure Err_lex;

procedure Syntax;

procedure Err_Synt (text: string; l: integer);

function Lex_Progr: boolean;

function Lex_Prog_Name: boolean;

function Lex_Descr_List: boolean;

function Lex_descr: boolean;

function Lex_name_list: boolean;

function Lex_type: boolean;

function Lex_oper_list: boolean;

function Lex_oper: boolean;

function Lex_assign: boolean;

function Lex_Exp: boolean;

function Lex_simple_Exp: boolean;

function Lex_Term: boolean;

function Lex_mnozh: boolean;

function Lex_repeat_until: boolean;

function Lex_body: boolean;

procedure N6Click (Sender: TObject);

private

{ Private declarations }

public

{ Public declarations }

end;

const

MaxNum=100; // Максимальное число лексем

deleter= ['. ',' ',' (',') ','{','}',',','<','>','"','? ','! ','*','&','^', {'%','$',}' [','] ',': ','; ','=','-','+','/', '\',''''] ; // разделители лексем

words: Array [1. .14] of string [7] = ('program','var','then','begin','for','to','do','if','end','repeat','until','real','integer', 'else'); // Массив служебных слов

razdel: Array [1. .8] of char= (',','; ',': ',' (',') ',' [','] ','. '); // массив разделителей

operacii: Array [1. .11] of string [2] = (': =','>=','<=','<>','+','-','/','*','>','<','='); // массив операций

cifra= ['0'. '9'] ; // цифры

bukva= ['A'. 'F'] ;

var

Form1: TForm1;

FA,FName: textfile;

SA: array [1. .100] of string;

SS,Name,Constant: string;

Dlina: integer;

Code_tab: array [1. MaxNum] of TVyh; // Таблица кодов лексем

Term_tab: array [1. MaxNum] of TTerm; // Таблица терминальныз символов

Id_tab: array [1. MaxNum] of TId; // Таблица идентификаторов

Const_tab: array [1. .50] of TConst; // Таблица констант

Lexem,s,typel: string; // Лексема, Текст ошибки, Строка программы, Тип лексемы

i,j,k,l,m,n,y,String_counter,constyes,termyes,hesh, // счетчики циклов и строк

NumLex,{Число лексем}NumId,{Число идентификаторов}NumTerm,{Число терминальных символов}NumConst,{Число различных констант}

NumErr{Число ошибочных лексем}: integer;

Error,Found,Flag,Scobka: boolean; // Флаги

str16: string;

k1,kod: integer;

implementation

uses lex2;

{$R *. dfm}

procedure TForm1. N2Click (Sender: TObject);

var i: integer;

begin

OpenDialog1. Filter: ='*. txt';

if opendialog1. Execute and fileExists (openDialog1. FileName)

then

begin

Assignfile (FA, OpenDialog1. FileName);

Reset (FA);

Memo1. Lines. clear;

i: =1;

while not EOF (FA) do

begin

readln (Fa,SA [i]);

Memo1. Lines. Add (SA [i]);

i: =i+1;

end;

Closefile (FA);

end;

end;

// процедура перевода констант в десятичную форму

procedure perevod (SS: string; var Str16: string);

var ch3,ch4,ch, i: integer;

zn: string;

begin

ch: =0; // для римских констант

if (SS [2] ='X') or (SS [2] ='V') or (SS [2] ='I') then

begin

zn: =SS [1] ;

delete (SS,1,1);

while Length (SS) <>0 do

begin

if SS [1] ='X' then begin ch: =ch+10; delete (SS,1,1); end

else begin

if SS [1] ='V'then begin ch: =ch+5; delete (SS,1,1); end

else begin

if ( (SS [1] ='I') and (SS [2] ='I')) or ( (SS [1] ='I') and (SS [2] ='')) then begin ch: =ch+1; delete (SS,1,1); end

else begin

if (SS [1] ='I') and (SS [2] ='X') then begin ch: =ch+9; delete (SS,1,2); end

else begin

if (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']

then

ch3: =StrToInt (SS [3]) *16

else

if SS [3] in ['A'. 'F']

then

begin

ch3: =ord (SS [3]);

case ch3 of

65: 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']

then

ch4: =StrToInt (SS [4])

else

if SS [4] in ['A'. 'F']

then

begin

ch4: =ord (SS [4]);

case ch4 of

65: 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);

begin

close;

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 // накопление лексемы

begin

if s [i] ='$' then

begin

Rez: =s [i] +s [i+1] ;

i: =i+2;

end

else begin

1: Rez: =Rez+s [i] ;

i: =i+1;

end;

end;

if Rez='' then

begin

if (s [i] =': ') then

begin

if (s [i+1] ='=') then // в случае операции из двух символов

begin

Rez: =s [i] +s [i+1] ;

Select_Lex: =i+2;

end

else

begin

Rez: =s [i] ;

Select_Lex: =i+1;

end;

end else

begin

if ( (s [i] ='+') or (s [i] ='-')) and (s [i-1] =' (')

then begin

Rez: =s [i] +s [i+1] ;

i: =i+2;

goto 1;

end

else begin

Rez: =s [i] ;

Select_Lex: =i+1;

end; end;

end else Select_Lex: =i;

end;

procedure Add_Const (Curr_term: integer; str_lex: string); // Процедура добавления идентификаторов в дерево

begin

if NumConst=1 then // Если корень дерева еще не создан, то создаем его.

begin

perevod (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 // если у этого элемента дерева нет левого указателя, то

begin

perevod (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 begin

Const_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 then

begin

perevod (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 begin

Const_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); // Процедура добавления идентификаторов в дерево

begin

if NumTerm=1 then // Если корень дерева еще не создан, то создаем его.

begin

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: ='V';

Exit;

end;

if (CompareStr (Term_tab [Curr_term]. lex,str_lex) >0) then // Если значение текущего узла дерева больше добавляемого

if Term_tab [Curr_term]. Left=0 then // если у этого элемента дерева нет левого указателя, то

begin

Term_tab [Curr_term]. Left: =NumTerm; // Создание левого элемента.

Term_tab [NumTerm]. lex: =str_lex;

Страницы: 1, 2, 3


© 2010 BANKS OF РЕФЕРАТ