Спецификации
Шаблоны специфицируются с помощью нотации, называемой регулярными выражениями. Регулярное выражение задается цепочкой символов со знаками операций или без них. Простейшие регулярные выражения - это цепочки символов без знаков операций. Пример:
apple orange pluto
Эти три регулярные выражения сопоставляются со всеми вхождениями указанных цепочек символов. Если Вы хотите, чтобы порожденный лексический анализатор удалял из входного текста цепочки orange, специфицируйте правило
orange ;
Так как действие справа от шаблона (перед точкой с запятой) не задано, lex не делает ничего, кроме вывода первоначального текста с удалением каждого вхождения данного регулярного выражения, то есть вообще без вхождений цепочки orange.
В отличие от orange, большинство распознаваемых выражений нельзя специфицировать так просто. Например, само выражение может быть слишком длинным. В более общем случае класс распознаваемых выражений оказывается слишком большим; на самом деле, он может быть бесконечным. Благодаря использованию операций можно формировать регулярные выражения, обозначающие любое выражение из определенного класса. Операция +, например, обозначает одно или более вхождений предшествующего выражения, ? обозначает 0 или 1 вхождение предшествующего выражения (что, конечно, эквивалентно необязательности предшествующего выражения), * обозначает 0 или более вхождений предшествующего выражения. (На первый взгляд кажется странным говорить о 0 вхождениях выражения и иметь операцию , чтобы выразить данную мысль, однако часто это весьма полезно. Ниже мы увидим соответствующий пример). Так, m+ - это регулярное выражение, которое сопоставляется с любой цепочкой из символов m, такой, как каждая из следующих:
mmm m mmmmm mm
Далее, 7* - это регулярное выражение, которое сопоставляется с любой цепочкой из нуля или большего числа семерок:
77 77777
777
Цепочка пробелов в третьей строке сопоставляется просто потому, что в ней вообще нет семерок.
Квадратные скобки, [ ], обозначают произвольный символ из цепочки символов, указанной в скобках. Так, [dgka] сопоставляется с одиночными символами d, g, k и a. Отметим, что символы в квадратных скобках не нужно разделять запятыми. Любая запятая в данном случае рассматривается как символ, который должен распознаваться во входном тексте. Диапазоны букв или цифр (в стандартном алфавитном или числовом порядке) обозначаются при помощи дефиса, -. Так, запись [a-z] обозначает произвольную строчную латинскую букву. Приведем пример более интересного регуляр- ного выражения:
[A-Za-z0-9*&#]
Такой шаблон сопоставляется с любой латинской буквой (строчной или прописной), любой цифрой, символами *, & или #. Если входной текст имеет вид
$$$$?? ????!!!*$$ $$$$$$&+====r~~# ((
то лексический анализатор, одно из правил которого содержит приведенный выше шаблон, распознает *, &, r и #, выполняя каждый раз действие, специфицированное в правиле (в примере действие опущено), и выводит остаток текста без изменений.
Иногда проще указать не само множество нужных символов, а его дополнение, поместив сразу за открывающей скобкой [ символ ^.
Чрезвычайно мощным средством является комбинирование операций. Пример - регулярное выражение, обозначающее идентификатор во многих языках программирования:
[a-zA-Z][0-9a-zA-Z]*
Идентификатор в этих языках определяется как буква, за которой следует нуль или больше букв или цифр, и именно это задается в регулярном выражении. Первая пара скобок сопоставляется с произвольной буквой. Вторая, если бы за ней не следовал знак операции *, сопоставлялась с произвольной буквой или цифрой. Но за счет использования операции * регулярное выражение сопоставляется с буквой, за которой следует произвольное число букв или цифр. В частности, были бы распознаны как идентификаторы следующие цепочки символов:
e pay distance pH EngineNo99 R2D2
Отметим, что не будут распознаваться как идентификаторы
not_idenTIFIER 5times $hello
так как not_idenTIFIER содержит подчеркивание, 5times начинается с цифры, но не с буквы, а $hello начинается с символа $. Конечно, в качестве упражнения Вы можете написать спецификации для этих трех примеров.
Очевидно, в тех случаях, когда знаки операций нужно использовать как обычные символы, входящие в шаблон, требуется специальная нотация. Так, в последнем из приведенных примеров звездочка не является частью идентификатора. В lex'е указанную проблему можно решать двумя способами. Символ, заключенный в кавычки, либо символ, перед которым указан знак \, рассматривается буквально, то есть как часть искомого текста. Чтобы приме- нить второй способ для распознавания, скажем, символа *, за которым следует произвольное число цифр, можно использовать шаблон
\*[0-9]*
Чтобы распознать сам символ \, требуется шаблон \\.