Вход/Регистрация
Фундаментальные алгоритмы и структуры данных в Delphi
вернуться

Бакнелл Джулиан М.

Шрифт:

Листинг 10.9. Синтаксический анализ <элемента> и вспомогательных компонентов

function TtdRegexEngine.rcParseAtom : integer;

var

MatchType : TtdNFAMatchType;

CharClass : PtdCharSet;

begin

case FPosn^ of

'(' : begin

{обработка открывающей круглой скобки}

inc(FPosn);

{синтаксический анализ всего регулярного выражения, заключенного в круглые скобки}

Result := rcParseExpr;

if (Result = ErrorState) then

Exit;

{если текущий символ не является закрывающей круглой скобкой, имеет место ошибка}

if (FPosn^ <> ')') then begin

FErrorCode := recNoCloseParen;

Result := ErrorState;

Exit;

end;

{обработка закрывающей круглой скобки}

inc(FPosn);

end;

'[':

begin

{обработка открывающей квадратной скобки}

inc(FPosn);

{если первый символ класса - ' ^' то класс является классом с отрицанием, в противном случае это обычный класс}

if (FPosn^ = '^') then begin

inc(FPosn);

MatchType := mtNegClass;

end

else begin

MatchType :=mtClass;

end;

{выделить набор символов класса и выполнить синтаксический анализ класса символов; в результате возврат будет выполнен либо в случае сшибки, либо при обнаружении закрывающей квадратной скобки}

New(CharClass);

CharClass^ := [];

if not rcParseCharClass (CharClass) then begin

Dispose(CharClass);

Result := ErrorState;

Exit;

end;

{обработка закрывающей квадратной скобки}

inc(FPosn);

{добавить новое состояние для класса символов}

Result := rcAddState(MatchType, #0, CharClass, NewFinalState, UnusedState);

end;

'.':

begin

{обработка метасимвола точки}

inc(FPosn);

{добавить новое состояние для лексемы 'любой символ'}

Result := rcAddState(mtAnyChar, #0, nil,

NewFinalState, UnusedState);

end;

else

{в противном случае - выполнить синтаксический анализ отдельного символа}

Result := rcParseChar;

end; {case}

end;

До сих пор мы создавали состояния без каких-либо ссылок состояний друг на друга. Но если вы обратитесь к блок-схеме конечного NFA-автомата для операции п|", то увидите, что, в конце концов, некоторые состояния приходится объединять друг с другом. Необходимо сохранить начальные состояния для каждого подвыражения и нужно создать новое начальное состояние, которое будет связано бесплатными связями с каждым из этих двух состояний. Заключительное состояние первого подвыражения должно быть связано с заключительным состоянием второго подвыражения, которое после этого становится конечным состоянием выражения дизъюнкции.

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

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

В результате выполнения всех этих манипуляций нам пришлось создать два новых состояния (первое является начальным состоянием для дизъюнкции, а второе -конечным состоянием исходного <члена> ). При этом мы проявили достаточную осмотрительность, чтобы виртуальное конечное состояние второго < выражения> было виртуальным конечным состоянием всей операции дизъюнкции. Код реализации этого конечного автомата приведен в листинге 10.10 (обратите внимание, что был создан еще один метод, который определяет связи для состояния после его создания).

Листинг 10.10. Синтаксический анализ операции "|"

function TtdRegexEngine.rcSetState(aState : integer;

aNextStatel: integer;

aNextState2: integer): integer;

var

StateData : PNFAState;

begin

{извлечь запись состояния и изменить информацию о переходе}

StateData := PNFAState(FTable[aState])/ StateData^.sdNextState1 := aNextStatel/ StateData^.sdNextState2 := aNextState2;

Result := aState;

end;

fmiction TtdRegexEngine.rcParseExpr : integer;

  • Читать дальше
  • 1
  • ...
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: