Заглавная страница Избранные статьи Случайная статья Познавательные статьи Новые добавления Обратная связь FAQ Написать работу КАТЕГОРИИ: ТОП 10 на сайте Приготовление дезинфицирующих растворов различной концентрацииТехника нижней прямой подачи мяча. Франко-прусская война (причины и последствия) Организация работы процедурного кабинета Смысловое и механическое запоминание, их место и роль в усвоении знаний Коммуникативные барьеры и пути их преодоления Обработка изделий медицинского назначения многократного применения Образцы текста публицистического стиля Четыре типа изменения баланса Задачи с ответами для Всероссийской олимпиады по праву
Мы поможем в написании ваших работ! ЗНАЕТЕ ЛИ ВЫ?
Влияние общества на человека
Приготовление дезинфицирующих растворов различной концентрации Практические работы по географии для 6 класса Организация работы процедурного кабинета Изменения в неживой природе осенью Уборка процедурного кабинета Сольфеджио. Все правила по сольфеджио Балочные системы. Определение реакций опор и моментов защемления |
Грамматики с непосредственной составляющейСодержание книги Поиск на нашем сайте Правила таких грамматик имеют вид
Это самый общий вид грамматики. Пример:
Контекстно-зависимые грамматики (КЗ-грамматики) Правила таких грамматик имеют вид
Отличается от предыдущего типа тем, что заменяется только один нетерминал. Т.е. правил вида Пример:
Контекстно-свободные грамматики (КС-грамматики) Правила таких грамматик имеют вид
Левая часть правил в таких грамматиках – всегда один символ
Пример:
Регулярные грамматики Бывают праволинейные – с правилами вида.
Бывают леволинейные – с правилами вида.
Левая часть правил в таких грамматиках – всегда один символ, а в правой части не может быть более одного нетерминала. Пример:
Регулярные выражения Идентификатор в паскале представляет собой букву, за которой следует нуль или несколько букв или цифр. Множество идентификаторов можно определить с помощью следующего регулярного выражения: letter(letter|digit)* Регулярное выражение строится из более простых регулярных выражений с использованием набора правил. Каждое регулярное выражение r обозначает или задает язык L(r). Рекурсивное определение регулярного выражения над алфавитом A: 1) e (пустая строка) представляет собой регулярное выражение, обозначающее { e }, т.е. множество содержащее пустую строку. 2) Если 3) Если r и s – регулярные выражения, обозначающее языки L(r) и L(s), то · (r)|(s) – регулярное выражение, задающее язык · (r)(s) – регулярное выражение, обозначающее · (r)* - регулярное выражение, обозначающее · (r) – регулярное выражение, обозначающее L(r). Язык, задаваемый регулярным выражением, называется регулярным множеством. Излишние скобки в регулярном выражении могут быть устранены, если принять следующие соглашения: · Унарный оператор * имеет высший приоритет и левоассоциативен. · Конкатенация имеет второй по значимости приоритет и левоассоциативна. · | (объединение) имеет низший приоритет и левоассоциативно. При этих соглашениях (a)|((b)*(c) эквивалентно a | b * c.
Алгебраические свойства регулярных выражений
Для удобства записи регулярным выражениям можно давать имена и определять регулярные выражения с использованием этих имен. Например: letter ® A | B | …| Z | a | b |…| z digit ® 0 | 1 | … | 9 id ® letter(letter|digit)* id описывает идентификатор, который может содержать буквы и цифры и должен начинаться с буквы. Такие записи называются регулярными определениями. Конечные автоматы Распознавателем (recognizer) языка называется программа, которая получает на вход строку x и отвечает “да”, если x – предложение языка, или в противном случае “нет”. Для регулярных выражений используется частный случай распознавателя – конечный автомат (КА). Конечные автоматы бывают недетерминированные и детерминированные. Недетерминированным конечным автоматом (НКА, nondeterministic finite automation, NFA) называется пятерка (S, A, m, s0, F) из: 1. Множества состояний S; 2. Множества входных символов A. 3. Функции перехода m, которая отображает пары состояние-символ на множество состояний. 4. 5. Состояния s0, известного как стартовое (начальное). 6. Множества состояний F, известных как допускающие (конечные);
Пример: Автомат распознающий язык м((яу)|(ур*)). Т.е. слова мяу, му, мур, мурр и т.д. S = {0, 1, 2, 3, 4, 5} A = {м, я, у, р} m: (0, м) ® 1 (0, м) ® 2 (1, я) ® 3 (2, e) ® 3 (2, у) ® 4 (3, у) ® 5 (4, р) ® 4 s0 = 0 F = {4, 5}
Для конечного автомата можно построить так называемый граф переходов, вершинами которого являются состояния, а дуги задают функцию перехода. Конечные состояния обозначаются двойным кругом. Для автомата из примера граф переходов будет выглядеть так:
Конечный автомат допускает или принимает (accept) входную строку x (а эта строка является допустимой) тогда и только тогда, когда в графе переходов существует некоторый путь от начального состояния к какому-либо из конечных, такой что метки дуг этого пути соответствуют строке x. Автомат работает следующим образом. Работа начинается в стартовом состоянии. Затем автомат на каждом шаге читает символ и переходит в новое состояние (в зависимости от прочитанного символа и текущего символа). Затем читает следующий символ и опять переходит в новое состояние. И так до тех пор, пока не перейдет в конечное состояние. Недетерминированный конечный автомат может переходить в новое состояние и не читая символ (читая пустой символ e). Такой шаг называется e -переходом. Если встретился символ, для которого в данном состоянии нет дуги, и состояние не конечное, то автомат выдает ошибку (это означает, что строка недопустима, т.е. не принадлежит задаваемому автоматом языку). В данном примере, проверяя строку «муррр», автомат пройдет через следующую последовательность состояний: Детерминированный конечный автомат (ДКА, deterministic finite automation, DFA) – специальный случай недетерминированного конечного автомата, в котором · отсутствуют состояния, имеющие e -переходы · для каждого состояния s и входного символа a существует не более одной дуги, исходящей из s и помеченной как a. Для любого недетерминированного автомата можно построить эквивалентный детерминированный автомат. Существует формальный алгоритм приведения недетерминированного автомата к детерминированному, однако он не будет приведен в данной лекции.
Cвязь между конечными автоматами, регулярными выражениями и регулярными грамматиками Для любого регулярного автомата можно построить регулярную грамматику, порождающую тот же язык и наоборот. Для любого регулярного выражения можно построить конечный автомат. Обратное неверно. Это можно изобразить следующим рисунком
Для предыдущего примера регулярная грамматика будет выглядеть так:
Применение конечных автоматов для создания интерпретаторов Разбирая предложения языка и переходя из состояния в состояние, конечный автомат может выполнять дополнительные действия. Таким образом, с помощью конечных автоматов можно создавать интерпретаторы, которые будут выполнять команды, описанные на некотором языке. Рассмотрим в качестве примера простой калькулятор, который умеет складывать и вычитать целые числа. S = {f, p, m, e} f – чтения первого аргумента p – чтение слагаемого m – чтение вычитаемого e – знак = - окончание вычислений A = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, +, -, =} F = {e} Набор правил опишем графом переходов конечного автомата.
class CCalculator { // Состояние enum State {sFirstArg, sPlus, sMinus, sEqual}; State m_State;
public int Calculate(string a_Script, out string a_ErrorMessage) { // Начальное состояние m_State = State.sFirstArg; // Строки, в которой будут сохраняться прочитанные числа int zResult = 0; string zArg = "";
int i = 0; // Текущая позиция в строке while ((m_State!= State.sEqual) && (i < a_Script.Length)) { switch (m_State) { // Чтение первого аргумента case State.sFirstArg: { // Читаем цифры числа if ((a_Script[i] >= '0') && (a_Script[i] <= '9')) { zArg += a_Script[i]; } // Если встретили + или -, // запоминаем считанное число else if (a_Script[i] == '+') { if (zArg == "") zResult = 0; else zResult = int.Parse(zArg); zArg = ""; m_State = State.sPlus; } else if (a_Script[i] == '-') { if (zArg == "") zResult = 0; else zResult = int.Parse(zArg); zArg = ""; m_State = State.sMinus; } else if (a_Script[i] == '=') { if (zArg!= "") zResult = int.Parse(zArg); zArg = ""; m_State = State.sEqual; } else { a_ErrorMessage = "Ошибка на позиции " + i.ToString() + ": недопустимый символ"; return 0; } break; }
// Чтение слагаемого case State.sPlus: { if ((a_Script[i] >= '0') && (a_Script[i] <= '9')) { zArg += a_Script[i]; } else if (a_Script[i] == '+') { if (zArg!= "") zResult += int.Parse(zArg); zArg = ""; m_State = State.sPlus; } else if (a_Script[i] == '-') { if (zArg!= "") zResult += int.Parse(zArg); zArg = ""; m_State = State.sMinus; } else if (a_Script[i] == '=') { if (zArg!= "") zResult += int.Parse(zArg); zArg = ""; m_State = State.sEqual; } else { a_ErrorMessage = "Ошибка на позиции " + i.ToString() + ": недопустимый символ"; return 0; } break; } // Чтение вычитаемого case State.sMinus: { if ((a_Script[i] >= '0') && (a_Script[i] <= '9')) { zArg += a_Script[i]; } else if (a_Script[i] == '+') { if (zArg!= "") zResult -= int.Parse(zArg); zArg = ""; m_State = State.sPlus; } else if (a_Script[i] == '-') { if (zArg!= "") zResult -= int.Parse(zArg); zArg = ""; m_State = State.sMinus; } else if (a_Script[i] == '=') { if (zArg!= "") zResult -= int.Parse(zArg); zArg = ""; m_State = State.sEqual; } else { a_ErrorMessage = "Ошибка на позиции " + i.ToString() + ": недопустимый символ"; return 0; } break; } } i++; } if (m_State == State.sEqual) { if (i == a_Script.Length) { a_ErrorMessage = ""; return zResult; } else { a_ErrorMessage = "Ошибка на позиции " + i.ToString() + " символы после знака ="; return 0; } } a_ErrorMessage = "Ошибка: Скрипт не закончен"; return 0; } }
Конечные автоматы и ООП Каждый объект находится в одном из состояний (которое определяется его атрибутами) и обладает поведением, которое зависит от его состояния. В общем случае, у объекта может быть очень большое (и даже бесконечное) количество состояний, т.к. оно равно множеству всех допустимых атрибутов. Однако иногда бывает удобно явно выделить состояние объекта в отдельный атрибут (это состояние может соответсвовать и диапазону значений атрибутов) и реализовать в нем конечный автомат, определяющий логику перехода между состояниями. Явное выделение состояний и конечного автомата позволяет более четко описать алгоритм работы объекта. Это, в свою очередь, позволяет избежать ошибок, возникающих, когда какое-то из состояний не учтено, например, попыток использовать объект, который не инициализирован. Также конечный автомат позволяет достаточно легко менять поведение объекта. Если функция перехода из состояние в состояние описана вне программы (в файле или базе данных), то поведение программы можно менять, не меняя ее текст. Конечный автомат удобно использовать для описания логики пользовательского интерфейса. Нажимая кнопки и выполняя другие действия, пользователь переводит интерфейс из состояния в состояние. В зависимости от текущего состояния интерфейсные элементы (кнопки, поля ввода и др.) включаются и выключаются. Включение и выключение интерфейсных элементов удобно вынести в отдельный метод формы – так называемый активатор (enabler). Это более удобно и надежно, чем раскидывать включение и выключение кнопок в разные обработчики событий. Благодаря явному выделению автомата можно отследить все возможные действия пользователя (которые могут происходить в разной последовательности) и обеспечить корректную реакцию на них. Конечные автоматы используются в разных областях, когда нужно формально описать некоторое поведение: в компьютерных играх для описания поведения персонажей, в драйверах различных устройств, в прикладных системах (при обработе заказов клиентов, в системах документооборота и т.д.).
[1] Сборка (assembly) – это программная единица в C# - exe или dll-файл. При подключении dll-сборки к проекту в.NET можно использовать то, что не объявлено как internal.
|
|||||||||||||||||||||
|
Последнее изменение этой страницы: 2021-12-15; просмотров: 95; Нарушение авторского права страницы; Мы поможем в написании вашей работы! infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 216.73.216.198 (0.006 с.) |