Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
lab_tlpt_12_7.doc
Скачиваний:
2
Добавлен:
01.03.2025
Размер:
494 Кб
Скачать
☆

Лабораторная работа № 6. Лабораторная работа №3.2. Синтаксический анализатор.

Общая схема разбора. Разбор инструкции присваивания.

В ходе прошлой лабораторной работы был реализован синтаксический разбор секции объявления переменных для синтаксиса исходного языка. Следующий этап - разбор секции кода. Логичнее (и проще всего) представить блок кода как последовательность инструкций, разделенных переносом строки. Метод разобратьПоследовательностьИнструкций() в синтаксическом анализаторе будет обеспечивать необходимый функционал.

разобратьПоследовательностьИнструкций ()

{

разобратьИнструкцию();

пока( LexicalAnalyzer.текущаяЛексема == Lexems.Разделитель )

{

LexicalAnalyzer.разобратьСледующуюЛексему();

разобратьИнструкцию ();

}

}

Метод разобратьИнструкцию() будет реализовывать разбор одной строки исходного кода. На текущем этапе разработки синтаксического анализатора основной целью является разбор инструкции присваивания.

разобратьИнструкцию()

{

если( LexicalAnalyzer.текущаяЛексема == Lexems. Идентификатор )

{

Идентификатор Х = NameTable.найтиПоИмени( LexicalAnalyzer.текущееИмя );

если( !Х. эквивалентно( новый Идентификатор() ) )

разобратьИнструкциюПрисваивания();

иначе

ошибка();

}

}

разобратьИнструкциюПрисваивания()

{

LexicalAnalyzer.разобратьСледующуюЛексему();

если( LexicalAnalyzer.текущаяЛексема == Lexems.Присваивание )

{

LexicalAnalyzer.разобратьСледующуюЛексему();

разобратьВыражение();

}

иначе

ошибка();

}

Метод разобратьВыражение() будет реализован в ходе следующей лабораторной работы. Пока оставим для него заглушку.

tType разобратьВыражение()

{

пока( LexicalAnalyzer.текущаяЛексема != Lexems.Разделитель )

LexicalAnalyzer.разобратьСледующуюЛексему();

вернуть tType.Int;

}

Также необходимо доработать метод компилировать(), используя в нем реализованный функционал.

компилировать()

{

LexicalAnalyzer.инициализировать();

разобратьОбъявлениеПеременных();

проверитьЛексему( Lexems.ПереносСтроки );

если( LexicalAnalyzer.текущаяЛексема == Lexems.Begin )

LexicalAnalyzer.разобратьСледующуюЛексему();

LexicalAnalyzer.разобратьСледующуюЛексему();

LexicalAnalyzer. разобратьПоследовательностьИнструкций();

проверитьЛексему( Lexems.End );

}

Тестирование описанного функционала можно провести, вызывая метод SyntaxAnalyzer.компилировать() для разных (в том числе некорректных) вариантов секции кода.

Примеры кода:

Файл SyntaxAnalyzer.cs в проекте.

Лабораторная работа № 7. Лабораторная работа №3.3. Синтаксический анализатор.

Схема разбора сложных выражений – разбиение на подвыражения и рекурсивный спуск.

На текущем этапе разработки синтаксического анализатора остается реализовать разбор правой части инструкции присваивания – некоторого выражения. Это выражение может быть достаточно сложным, поэтому для простоты будем разбивать его на бинарные операции (то есть, операции с двумя операндами – сложение, вычитание, умножение, деление). Две из перечисленных операций – умножение и деление имеют высший приоритет, поэтому при прочих равных анализатор сначала выполнит их разбор. При встрече с круглыми скобками анализатор должен уметь разбирать их содержимое, как отдельное выражение. Таким образом, мы от сложного выражения поэтапно перейдем к цепочке простых – это и есть так называемый «рекурсивный спуск». Ниже приведен псевдокод трех методов: разобратьСложениеИлиВычитание(), разобратьУмножениеИлиДеление(), разобратьПодвыражение() – для операций с разным приоритетом.

tType разобратьСложениеИлиВычитание()

{

tType т;

Lexems оператор;

если( LexicalAnalyzer.текущаяЛексема == Lexems.Плюс

или LexicalAnalyzer.текущаяЛексема == Lexems.Минус )

{

оператор = LexicalAnalyzer.текущаяЛексема;

LexicalAnalyzer.разобратьСледующуюЛексему();

т = разобратьУмножениеИлиДеление();

}

иначе

т = разобратьУмножениеИлиДеление();

если( LexicalAnalyzer.текущаяЛексема == Lexems.Плюс

или LexicalAnalyzer.текущаяЛексема == Lexems.Минус )

{

выполнять

{

оператор = LexicalAnalyzer.текущаяЛексема;

LexicalAnalyzer.разобратьСледующуюЛексему();

т = разобратьУмножениеИлиДеление();

switch( оператор )

{

case Lexems.Плюс:

break;

case Lexems.Минус:

break;

}

}

пока( LexicalAnalyzer.текущаяЛексема == Lexems.Плюс

или LexicalAnalyzer.текущаяЛексема == Lexems.Минус );

}

вернуть т;

}

tType разобратьУмножениеИлиДеление()

{

Lexems оператор;

tType т = разобратьПодвыражение();

если( LexicalAnalyzer.текущаяЛексема == Lexems.Умножить

или LexicalAnalyzer.текущаяЛексема == Lexems.Делить )

{

выполнять

{

оператор = LexicalAnalyzer.текущаяЛексема;

LexicalAnalyzer.разобратьСледующуюЛексему();

т = разобратьПодвыражение();

switch( оператор )

{

case Lexems.Умножить:

break;

case Lexems.Делить:

break;

}

}

пока( LexicalAnalyzer.текущаяЛексема == Lexems.Умножить

или LexicalAnalyzer.текущаяЛексема == Lexems.Делить );

}

вернуть т;

}

tType разобратьПодвыражение()

{

Идентификатор х;

tType т = tType.None;

если( LexicalAnalyzer.текущаяЛексема == Lexems. Идентификатор )

{

х = NameTable.найтиПоИмени( LexicalAnalyzer.текущееИмя );

если( !Х. эквивалентно( новый Идентификатор() ) и х.категория == tCat.Var )

{

LexicalAnalyzer. разобратьСледующуюЛексему ();

вернуть х.тип;

}

иначе

ошибка();

}

иначе если( LexicalAnalyzer.текущаяЛексема == Lexems.Число )

{

LexicalAnalyzer.разобратьСледующуюЛексему();

вернуть tType.Int;

}

иначе если( LexicalAnalyzer.текущаяЛексема == Lexems.ЛеваяСкобка )

{

LexicalAnalyzer.разобратьСледующуюЛексему();

т = разобратьВыражение();

проверитьЛексему( Lexems.ПраваяСкобка );

}

иначе

ошибка();

вернуть т;

}

Частично код этих методов будет доработан в процессе разработки генератора кода. В ходе прошлой лабораторной работы мы сделали заглушку для метода разобратьВыражение(). Теперь же в этом методе мы можем использовать реализованный функционал – просто запустим разбор вызовом метода разобратьСложениеИлиВычитание().

tType разобратьВыражение()

{

вернуть разобратьСложениеИлиВычитание();

}

Тестирование синтаксического анализатора можно проводить в полном объеме - выполняя разбор для кода со сложными выражениями. Также необходимо проверить механизм обнаружения ошибок на этапе синтаксического анализа.

Замечания по коду:

  1. Реализация методов разбора не является полной без проверки типов выражений на совместимость – эту проверку необходимо реализовать самостоятельно.

Примеры кода:

Файл SyntaxAnalyzer.cs в проекте.

ЛАБОРАТОРНАЯ РАБОТА №4.

ФОРМИРОВАНИЕ ПОСТФИКСНОЙ ЗАПИСИ

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]