[ Содержание ] [ Предыдущая ] [ Следующая ]

2. Регулярные выражения в Lex-правилах

    Регулярные выражения определяют лексему. Регулярное выражение может содержать символы латинского и русского алфавитов в верхнем и нижнем регистрах, другие символы (цифры, знаки препинания и т.д.) и символы-операторы.

    Операторы позволяют осуществлять различные действия над выделенной цепочкой символов. Операторы также обозначаются символами.

2.1. Обозначения символов в выражениях

    В выражении можно использовать любой символ. Символ можно указывать в двойных кавычках. В этом случае это всегда просто символ - его специальное значение отменяется. Например:

"abc"
abc

эти последовательности символов идентичны.

. точка означает любой символ, кроме символа новой строки "\n";
\XXX указание символа его восьмеричным кодом (как в Си);
\n символ новой строки;
\t символ табуляции;
\b возврат курсора на один шаг назад;
" " любой символ пробела в выражении, если он не находится внутри квадратных скобок, необходимо заключать в двойные кавычки. Это необходимо, так как пробел и табуляция спользуются lex в качестве разделителя между определе нием и действием в правиле.

2.2. Операторы регулярных выражений

    Операторы обозначаются символами-операторами, к ним относятся:

\   ^   ?   *   +   |   $   /   %
[]   {}   ()   <>

Каждый из этих символов или пар скобок в регулярном выражении играет роль оператора. Если необходимо отменить специальное значение символа, обозначающего оператор, перед ним нужно поставить символ \ или указать его в двойных кавычках. Например:

abc+    - символ "+" - оператор;
abc\+   - символ "+";
abc"+"  - символ "+".

2.3. Оператор выделения классов символов

    Квадратные скобки задают классы символов, которые в них заключены.

[abc]

означает либо символ "a", либо "b", либо символ "c";

    Знак - используется для указания любого символа из лексикографически упорядоченной последовательности:

[A-z]

означает любой латинский символ;

[А-Я]

любая прописная русская буква;

[+-0-9]

все цифры и знаки "+" и "-".

2.4. Повторители

    Когда необходимо указать повторяемость вхождения символа в регулярном выражении, используют операторыповторители * и +.

    Оператор * означает любое (в том числе и 0) число вхождений символа или класса символов. Например:

x*

любое число вхождений символа "x";

abc*

любое число вхождений цепочки "abc";

[A-z]*

любое число вхождений любой латинской буквы;

[A-ZА-Яa-zа-я_0-9]*

любое вхождение русских и латинских букв, знака подчеркивания и цифр.

    Оператор + означает одно и более вхождений. Например:

x+

одно или более вхождений "x";

[0-9]+

одно или более вхождений цифр;

abc+

одно или более вхождений цепочки abc;

[A-z]+

одно или более вхождений любой латинской буквы.

2.5. Операторы выбора

    Операторы

/   |   ?   $   ^

управляют процессом выбора символов.

Оператор /

ab/cd

"ab" учитывается только тогда, когда за ним следует "cd".

Опeратор |

ab|cd

или "ab", или "cd".

Опeратор ?

x?

означает необязательный символ "x".

_?[A-Za-z]*

означает, что перед цепочкой любого количества латинских букв может быть необязательный знак подчеркивания.

-?[0-9]+

выделит любое целое число с необязательным минусом впереди.

Оператор $

x$

означает выбрать символ "x", если он является последним в строке. Стоит перед символом "\n"!

abc$

означает выбрать цепочку "abc", если она завершает строку.

Оператор ^

^x

означает выбрать символ "x", если он является первым символом строки;

^abc

означает выбрать цепочку символов "abc", если она начинает строку.

[^A-Z]*

означает все символы, кроме прописных латинских букв. Когда символ ^ стоит перед выражением или внутри [], он выполняет операцию дополнение. Внутри квадратных скобок символ ^ должен обязательно стоять первым у открывающей скобки.

2.6. Оператор {}

    Оператор {} имеет два различных применения:

x{n,m}

здесь n и m натуральные, m > n. Означает от n до m вхождений x, например, x{2,7} - от 2 до 7 вхождений x.

{имя}

вместо {имя} в данное место выражения будет подставлено определение имени из области определений Lex-программы.

    Пример:

БУКВА           [A-ZА-Яa-zа-я_]
ЦИФРА           [0-9]
ИДЕНТИФИКАТОР   {БУКВА}({БУКВА}|{ЦИФРА})*
%%
{ИДЕНТИФИКАТОР} printf("\n%s",yytext);

    lex построит лексический анализатор, который будет определять и выводить все "слова" из входного файла. Под словом в данном случае подразумевается идентификатор Си-программы. В этом примере {ИДЕНТИФИКАТОР} будет заменен на {БУКВА}({БУКВА}|{ЦИФРА})*, затем на [A-ZА-Яa-zа-я_]([A-ZА- Яa-zа-я_]|[0-9])*.

    yytext - это внешний массив символов программы lex.yy.c, которую строит lex. yytext формируется в процессе чтения входного файла и содержит текст, для которого установлено соответствие какому-либо выражению. Этот массив доступен пользовательским разделам Lex-программы.

    Оператор printf выводит каждый идентификатор на новой строке.

    Правило ".|\n ;" используется для того, чтобы пропустить (не выводить) все цепочки символов, которые не соответствуют регулярному выражению {ИДЕНТИФИКАТОР}.

2.6. 2.7. Оператор <>. Служебные слова START и BEGIN

    Раздел правил Lex-программы может содержать активные и неактивные правила. Активные правила выполняются всегда. Неактивные выполняются только в тех случаях, когда выполняется некоторое начальное условие.

    Начальные условия Lex-программы помещаются в раздел определений, а неактивные правила помечаются соответствующими условиями. Оператор START позволяет указать список начальных условий Lex-программы, а оператор BEGIN позволяет активировать правила, помеченные начальными условиями.

    Активные правила имеют следующий синтаксис:

РЕГУЛЯРНОЕ_ВЫРАЖЕНИЕ  ДЕЙСТВИЕ

    Неактивные правила имеют следующий синтаксис:

<МЕТКА_УСЛОВИЯ>РЕГ_ВЫРАЖЕНИЕ  ДЕЙСТВИЕ

    ВАЖНО: любое правило должно начинаться с первой позиции строки, пробелы и табуляции недопустимы - они используются как разделители между регулярным выражением и действием в правиле!

    Рассмотрим пример:

%START  COMMENT

КОММ_НАЧАЛО "/*"
КОММ_КОНЕЦ  "*/"

%%
{КОММ_НАЧАЛО} { 
	ECHO;
  BEGIN COMMENT;};

[\t\n]* ;

<COMMENT>[^*]* ECHO;
<COMMENT>[^/] ECHO;
<COMMENT>{КОММ_КОНЕЦ} {
  ECHO;
  printf("0);
  BEGIN 0; };

lex построит лексический анализатор, который выделяет комментарии в Си-программе и записывает их в стандартный файл вывода. Программа начинается с ключевого слова START, которое указано после символа %. Ключевое слово START можно указать и так: Start, или S, или s . За ключевым словом START указана метка начального условия COMMENT.

    Оператор "<COMMENT>x" означает - x, если анализатор находится в начальном условии COMMENT.

    Oператор "BEGIN COMMENT;" переводит анализатор в начальное условие COMMENT (смотрите первое правило раздела правил этой Lex-программы). После этого анализатор уже находится в новом состоянии и теперь разбор входного потока символов будет осуществляется и теми правилами, которые начинаются оператором "<COMMENT>". Например, правило

<COMMENT>[^*]* ECHO;

выполняется только тогда, когда во входном потоке символов будет обнаружено начало комментариев ("/*"). В этом случае анализатор записывает в стандартный файл вывода любое число (в том числе и ноль) символов, отличных от символа "*". Оператор "BEGIN 0;" переводит анализатор в исходное состояние.

    Lex-программа может содержать несколько помеченных начальных условий. Например, если Lex-программа начинается строкой

%START AA BB CC DD

то это означает, что она управляет четырьмя начальными состояниями анализатора. В каждое из этих начальных состояний анализатор можно перевести, используя оператор BEGIN.

    Каждое правило, перед которым указан оператор типа "<МЕТКА>", мы будем называть помеченным правилом. Метка формируется так же, как и метка в Си.

    Количество помеченных правил не ограничивается. Кроме того, разрешается одно правило помечать несколькими метками, например:

<МЕТКА1,МЕТКА2,МЕТКА3>x  ДЕЙСТВИЕ

Запятая - обязательный разделитель списка меток!

    Рассмотрим пример с несколькими начальными условиями:

%START AA BB CC

БУКВА [A-ZА-Яa-zа-я_]
ЦИФРА [0-9]
ИДЕНТИФИКАТОР {БУКВА}({БУКВА}|{ЦИФРА})*

%%
^#  BEGIN AA;
^[ \t]*main  BEGIN BB;
^[ \t]*{ИДЕНТИФИКАТОР}  BEGIN CC;
\t  ;
\n  BEGIN 0;

<AA>define {
  printf("Определение.\n"); }
<AA>include 
  printf("Включение.\n"); }
<AA>ifdef {
  printf("Условная компиляция.\n"); }
<BB>[^\,]*","[^\,]*")"  {
  printf("main с аргументамии.\n"); }
<BB>[^\,]*")"   {
  printf("main без аргументов.\n"); }
<CC>":"/[ \t] {
  printf("Метка.\n"); }

Программа содержит активные и неактивные правила. Все неактивные правила помечены, перед ними указана метка начального условия. Lex-программа управляет тремя начальными условиями, в соответствии с которыми активируются помеченные правила.

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

[ Содержание ] [ Предыдущая ] [ Следующая ]

c 1998-2000 SoloTony (Antonio Solo) mailto:solotony@mail.ru