Подразделы

Другие разделы

Дата и время

28/03/2024 22:30:58

Авторизация

Имя:
Пароль:
Зарегистрироваться
Восстановить пароль
 

printРегулярные выражения

printГенератор лексических анализаторов FLEX

Вместо устаревшего FLEX рекомендуется использовать RE/flex с улучшенной поддержкой RE.
FLEX используется чаще всего для создания лексического блока транслятора, но может быть использован отдельно для обработки текста. По описанию генерируется автомат (при использовании ключей --fast или --full), анализирующий входной текст за `O(n)`, где `n` – длина текста. Описание выглядит так:
определения, опции и вставляемый код
%%
правила
%%
дополнительные подпрограммы
По описанию будет сгенерирована функция int yylex(), набор таблиц и вспомогательных подпрограмм. На вход этой функции поступает некоторый текст, из которого с помощью RE выделяются лексемы (атомарные единицы входного языка).
В первом разделе можно дать имена RE, и затем использовать их для упрощения или повышения наглядности RE. Например:
IDENT [a-z][a-z0-9]*
DIGITS [0-9]+
%%
{IDENT} printf("Идентификатор");
{DIGITS} printf("Целое число");
{DIGITS}"."{DIGITS} printf("Вещественное число");
С помощью команды %option можно указать настройки для генерируемого кода. На практике чаще всего применяются следующие опции:
  • case-insensitive – игнорировать регистр;
  • yylineno – сохранять номер текущей строки в глобальной переменной yylineno;
  • noyywrap – не вызывать по окончании сканирования функцию yywrap();
  • nodefault – не создавать правило по умолчанию – вывод символа, который не подходит ни одному из правил;
  • main – генерировать функцию main по умолчанию: int main(){yylex();}
FLEX позволяет разбить автомат для обработки текста на несколько более простых подавтоматов и выполнять переходы между ними при необходимости. По умолчанию применяется автомат INITIAL и все правила описываются для него. С помощью команды %x можно добавить новые подавтоматы. Перед правилами подавтоматов необходимо писать в угловых скобках имена подавтоматов. Одно правило может применяться для нескольких подавтоматов или всех, если написать <*>.
Кроме того в первом разделе можно написать код в %{ %} и %top{ }, вставляемый в начало генерируемого кода. Обычно таким образом подключаются заголовочные файлы, объявляются функции, определяются типы данных и глобальные переменные.
Каждое правило состоит из RE и действия, разделенных как минимум одним пробельным символом (поэтому пробелы должны быть экранированы с помощью \, "" или []). Как метасимволы интерпретируются символы ", / и <.
Из возможных правил применяется то правило, RE которого выделяет наиболее длинную последовательность символов входного текста. Если таких правил несколько, то применяется первое из них. Если очередной символ не соответствует никакому правилу, то применяется правило по умолчанию – вывод этого символа.
Символы в RE, записанные в "", интерпретируются как обычные символы (кроме " и \).
Правило с RE вида `x`/`y` указывает, что после `x` должно следовать `y`, при этом `y` остается в буфере ввода – упрощенный вариант (?= ).
Правило с RE вида <<EOF>> срабатывает при обнаружении конца файла.
Можно вставлять комментарии в RE с помощью (?# ).
Для изменения опций для части RE применяется (?: ). Например, (?i: ) – игнорировать регистр, (?-i: ) – учитывать регистр букв, (?s: ) – . включает \n.
Действие – это последовательность операторов на C или C++ до конца строки. Многострочная последовательность операторов записывается в { }. Специальным вариантом действия является |, которое означает использование действия из следующего правила. В действии можно получить обработанную RE последовательность символов как глобальный массив yytext, а его длину как yyleng. Для некоторых действий есть специальные макросы и функции:
  • ECHO – печать yytext;
  • BEGIN – переключение на подавтомат с указанным далее именем;
  • YYSTATE – номер текущего подавтомата;
  • REJECT – применить следующее подходящее правило;
  • yymore() – текущий yytext сохраняется и к нему будет добавлена последовательность символов, распознанная следующим правилом;
  • yyless(`n`) – оставить первые `n` символов в yytext, остальные вернуть во входной поток и они снова будут распознаваться правилами;
  • unput(`c`) – вернуть символ `c` во входной поток;
  • input() – считать очередной символ из входного потока;
  • yyterminate() – завершить работу автомата и сбросить его в начальное состояние;
  • yy_push_state(`s`)/yy_pop_state()/yy_top_state() – работа со стеком переходов между подавтоматами, используются вместо BEGIN;
  • yy_create_buffer/yy_switch_to_buffer/yypush_buffer_state/yypop_buffer_state/yy_delete_buffer/… – переключение между несколькими входными файлами.
В последнем разделе можно написать любые подпрограммы на языке на C или C++, которые будут добавлены к сгенерированной программе.
Для ввода информации из строки применяется функции yy_scan_string(`"str"`) и yy_scan_bytes(`"str"`,`"len"`). Для ввода из файла нужно открыть файл с помощью fopen и переключиться на него:
FILE *f=fopen(name,"r");
yyrestart(f);
Упражнения
Решите с использованием FLEX следующие задачи: 1446, 1525, 883, 461, 580, 817, 1209, 1109
Пример решения задачи 1446:
%option noyywrap main
%%
[aeiouy]+ putchar(yytext[yyleng-1]);
%%
loading