Главная страница

МУ_ЛР_ЛиПОАС. Методические указания по выполнению лабораторных работ по дисциплине (модулю) Лингвистическое и программное обеспечение автоматизированных систем


Скачать 2.76 Mb.
НазваниеМетодические указания по выполнению лабораторных работ по дисциплине (модулю) Лингвистическое и программное обеспечение автоматизированных систем
Дата12.04.2023
Размер2.76 Mb.
Формат файлаdoc
Имя файлаМУ_ЛР_ЛиПОАС.doc
ТипМетодические указания
#1057976
страница6 из 32
1   2   3   4   5   6   7   8   9   ...   32

2.2. Разработка синтаксического анализатора


После получения списка лексем необходимо ответить на вопрос: в правильном ли порядке они идут? Из грамматики языка очевидно, что, к примеру, последовательность лексем ID – PLUS – NUMBER является верной, а последовательность ID – ID – MINUS – неверной. Программа-распознаватель должна ответить на вопрос, допустима ли предлагаемая последовательность лексем в рамках грамматики того или иного языка.

Существуют различные методы построения анализаторов. Один из основных – метод нисходящего разбора, при котором диаграмма Вирта фактически является блок-схемой процедур распознавания. Основная программа будет состоять из оператора чтения первой лексемы, за которым следует оператор активации основной цели грамматического разбора. Отдельные процедуры, соответствующие целям грамматического разбора или графам, получаются по следующим правилам.

Правила преобразования графа в программу:

1. Свести систему графов к как можно меньшему числу отдельных графов с помощью соответствующих подстановок.

2. Преобразовать каждый граф в описание процедуры в соответствии с приведенными ниже правилами З-7.

3. Последовательность элементов


S1


S2

Sn


переводится в составной оператор

T(S1); T(S2); ...; T(Sn)

4. Выбор элементов

переводится в выбирающий или условный оператор:


switch (ch)

{

case L1: T(S1);

break;

case L2:

T(S2);

break;

…………

case Ln: T(Sn);

break;

default:

error;

}




if (ch == L1) T(S1);

else

if (ch == L2) T(S2);

else ……………

if (ch == Ln) T(Sn);

else

error;


где Li означает множество начальных символов нетерминального символа Si. Если Li состоит из одного символа a, то, разумеется, вместо ch in Li нужно писать ch == а.

5. Цикл вида


while (ch == L[i]) T(S);


переводится в оператор

где T(S) есть отображение S в соответствии с правилами З-7, a L есть множество начальных символов нетерминального символа S (см. предыдущее правило).

6 Элемент графа, обозначающий другой граф А

переводится в оператор обращения к процедуре А.

7. Элемент графа, обозначающий терминальный символ,


if (ch = x) ReadLex(ch);

else error;

переводится в:
где error - процедура, к которой обращаются при появлении неправильной конструкции; ReadLex(ch) – процедура чтения следующей лексемы в переменную ch.

2.3. Пример построения простого синтаксического анализатора


Реализуем синтаксический анализатор в виде следующего класса:

public partial class TSyntaxAnalyzer

{

private string Ferr; //Сообщение об ошибке

private ushort FerrPos; //Позиция ошибки во входной строке

private Tresult[] Flex; //Входной массив лексем после лексического разбора

private Int32 Count; //Номер текущей лексемы

public ushort ErrorPos { get { return FerrPos; } }

public String Error { get { return Ferr; } }

public TSyntaxAnalyzer(Tresult[] Lexems) //Конструктор

{

Ferr = "";

FerrPos = 0;

Flex = Lexems;

Count = 0;

}
Как видно, при создании объекта класса TSyntaxAnalyzer его конструктору на вход подается массив лексем, сформированный ранее лексическим анализатором.

В методе GetLex в случае, если лексемы в массиве кончились, всегда возвращается лексема FINISH.

private Tresult GetLex()

{

if (Count <= Flex.Length - 1)

{

Count++;

return Flex[Count - 1];

}

else

{

Tresult FinishRes;

FinishRes.lexeme = "FINISH";

FinishRes.name = "";

FinishRes.value = 0;

FinishRes.position = 0;

return FinishRes;

}

}

Самое сложное – процедура PARSE, отвечающая на вопрос соответствия заданной последовательности лексем грамматике языка. Ее алгоритм программируется в точном соответствии с правилом грамматики:

 < слагаемое>[{<операция><слагаемое>}]

Для удобства введены два константных множества Operation и Item.

Алгоритм имеет следующий вид:

public void Parse()

{

string[] Operation = { "PLUS", "MINUS" }, item = { "ID", "NUMBER" };

Tresult Curlex = GetLex();

do

{

if (Array.IndexOf(item, Curlex.lexeme) != -1)

{

Curlex = GetLex();

if (Curlex.lexeme == "FINISH") break;

do

{

if (Array.IndexOf(Operation, Curlex.lexeme) != -1)

{

Curlex = GetLex();

if (Array.IndexOf(item, Curlex.lexeme) == -1)

{

Ferr = "Синтаксическая ошибка. Ожидается слагаемое";

FerrPos = Curlex.position;

break;

}

}

else

{

Ferr = "Синтаксическая ошибка. Ожидается операция";

FerrPos = Curlex.position;

break;

}

Curlex = GetLex();

}

while (Curlex.lexeme != "FINISH");

}

else

{

Ferr = "Синтаксическая ошибка. Неизвестная лексема!";

FerrPos = Curlex.position;

break;

}
}

while (Curlex.lexeme != "FINISH");

}

Все! Легко убедиться, что данный синтаксический анализатор действительно корректно проверяет введенное выражение.
1   2   3   4   5   6   7   8   9   ...   32


написать администратору сайта