Анализатор конечных автоматов - PullRequest
5 голосов
/ 21 июня 2010

Я хотел бы проанализировать формат файла, разработанный самим собой, с помощью FSM-подобного синтаксического анализатора в C ++ (это проект teach-myself-c++-the-hard-way-by-doing-something-big-and-difficult :)). У меня есть токенизированная строка с символами новой строки, обозначающими конец строки ... См. здесь для примера ввода . Все комментарии будут, а мусор отфильтрован, поэтому у меня есть std :: string как это:

global \n { \n SOURCE_DIRS src \n HEADER_DIRS include \n SOURCES bitwise.c framing.c \n HEADERS ogg/os_types.h ogg/ogg.h \n } \n ...

Синтаксическое объяснение:

  • {} - это области видимости, а заглавные слова означают, что список опций / файлов должен следовать.
  • \ n важны только в списке опций / файлов, обозначая конец списка.

Поэтому я подумал, что FSM будет достаточно простым / расширяемым для моих нужд / знаний. Насколько я могу судить (и хочу, чтобы мой дизайн файлов был таким), мне не нужны параллельные состояния или что-то подобное. Некоторые вопросы проектирования / реализации:

  1. Должен ли я использовать enum или абстрактные class + производные для моих состояний? Первое, вероятно, лучше для небольшого синтаксиса, но может стать уродливым позже, а второе с полной противоположностью. Я склоняюсь к первому, из-за его простоты. enum пример и пример класса . РЕДАКТИРОВАТЬ: как насчет это предложение для goto, я думал, что они были злы в C ++?
  2. При чтении списка мне НЕ нужно игнорировать \n. Мой предпочтительный способ использования string через stringstream, по умолчанию игнорирует \n. Поэтому мне нужен простой способ сказать (то же самое!) stringstream, чтобы не игнорировать символы новой строки при включении определенного состояния.
  3. Достаточно ли будет простых enum состояний для многоуровневого анализа (области в пределах областей действия {...{...}...}) или для этого потребуются хакерские реализации?
  4. Вот проекты состояний, которые я имею в виду:
    • upper: читает глобальные, exe, lib + целевые имена ...
    • normal: внутри области видимости можно читать ИСТОЧНИКИ ..., создавать пользовательские переменные ...
    • list: добавляет элементы в список, пока не встретится новая строка.

Каждая область будет иметь своего рода условные условия (например, win32: global {gcc: CFLAGS = ...}) и должна обрабатываться точно так же, как и везде (даже в состоянии list для каждого элемента) .

Спасибо за любой вклад.

Ответы [ 3 ]

12 голосов
/ 21 июня 2010

Если у вас есть области вложенности, то конечный автомат - , а не - правильный путь, и вы должны посмотреть на синтаксический анализатор грамматики без контекста. LL (1) синтаксический анализатор может быть записан как набор рекурсивных функций, или LALR (1) синтаксический анализатор может быть записан с использованием генератора синтаксических анализаторов, такого как Bison.

Если вы добавите стек в FSM, то попадете на автомат с нажатием .Недетерминированный автомат с нажатием кнопки эквивалентен грамматике без контекста (хотя детерминированный автомат с нажатием строго менее мощный.) Генераторы синтаксического анализатора LALR (1) фактически генерируют детерминированный автомат с понижением частоты внутри себя.Хороший учебник по проектированию компилятора расскажет о точном алгоритме, по которому построенный автомат строится из грамматики.(Таким образом, добавление стека не является «хакерским».) В этой статье Википедии также описывается, как создать автомат с запуском LR (1) из вашей грамматики, но IMO, статья не так яснакак это может быть.

Если ваши области видимости вложены только конечной глубины (т. е. у вас есть уровни upper, normal и list, но у вас нет вложенных list s или вложенных normal s), то вы можете использовать FSM без стека.

3 голосов
/ 21 июня 2010

Есть два этапа анализа потока ввода текста для разбора:

Лексический анализ: Здесь ваш входной поток разбивается на лексические единицы. Он просматривает последовательность символов и генерирует токены (аналогичные слову в устной или письменной речи). Конечные автоматы очень хороши в лексическом анализе, если вы приняли правильное проектное решение о лексической структуре. Исходя из ваших данных выше, индивидуальными лексемами будут такие вещи, как ваши ключевые слова (например, «global»), идентификаторы (например, «bitwise», «SOURCES»), символические tokesn (например, «{" "}", ".", "/" ), числовые значения, escape-значения (например, "\ n") и т. д.

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

Итак, в ответ на ваши вопросы:

Должен ли я использовать перечисление или абстрактный класс + производные для моих состояний?

Я обнаружил, что для небольших токенизаторов подходит матрица значений состояния / перехода, что-то вроде next_state = state_transitions[current_state][current_input_char]. В этом случае next_state и current_state являются некоторыми целочисленными типами (включая, возможно, перечислимый тип). Ошибки ввода обнаруживаются при переходе в недопустимое состояние. Конец токена идентифицируется на основе идентификации состояния действительных конечных состояний без действительного перехода, доступного в другое состояние с учетом следующего входного символа. Если вы беспокоитесь о космосе, вы можете вместо этого использовать вектор карт. Создание классов состояний возможно, но я думаю, что это, вероятно, усложнит вам задачу.

При чтении списка мне НЕ нужно игнорировать \ n.

Вы можете создать токен с именем \ n или более обобщенный escape-токен (идентификатор, которому предшествует обратная косая черта. Если вы говорите об идентификации разрывов строк в источнике, то это просто символы, которые вам нужно создавать переходы для матрицы переходов состояний (однако следует помнить о различиях между переносами строк в Unix и Windows; вы можете создать FSM, работающий на любом из них).

Хватит ли простых перечисляемых состояний для многоуровневого синтаксического анализа (области в пределах областей {... {...} ...}) или для этого потребуются хакерские реализации?

Здесь вам понадобится грамматика или автомат, если вы не можете гарантировать, что вложенность не превысит определенного уровня. Даже тогда это, вероятно, сделает ваш FSM очень сложным.

Вот проекты состояний, которые я имею в виду: ...

См. Мои комментарии по лексическому и грамматическому анализу выше.

1 голос
/ 21 июня 2010

Для анализа я всегда стараюсь использовать что-то, что уже доказало свою эффективность: ANTLR с ANTLRWorks , что очень помогает при разработке и тестировании грамматики.Вы можете сгенерировать код для C / C ++ (и других языков ), но вам нужно построить среду выполнения ANTLR для этих языков.

Конечно, если вы найдете flex или бизон проще в использовании, вы тоже можете их использовать (я знаю, что они генерируют только C и C ++, но я могу ошибаться, поскольку некоторое время не использовал их).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...