Листинг 3. Лексический анализатор на языке Flex
{
printf("\nNot enough arguments. Please specify filename.\n"); return -1;
}
if((yyin = fopen(argv[1], "r")) == NULL)
{
printf("\nCannot open file %s.\n", argv[1]); return -1;
}
ch = 1; yylineno = 1; yylex(); fclose(yyin); return 0;
}
В современных версиях Flex рекомендуется отключать использование yywrap с помощью опции noyywrap, если в программе на языке Flex есть своя функция main, в которой и определяется, какой файл и когда сканировать.
Использование опции yylineno позволяет вести нумерацию строк входного файла и в случае ошибки сообщать пользователю номер строки, в которой эта ошибка произошла. Flex определяет переменную yylineno и автоматически увеличивает её значение на 1, когда встречается символ '\n'. При этом Flex не инициализирует эту переменную. Поэтому в функции main перед вызовом функции лексического анализа yylex переменной yylineno присваивается 1.
Flex, по умолчанию, присваивает переменной yyin указатель на стандартный поток ввода. Если предполагается сканировать текст из файла, то нужно присвоить переменной yyin результат вызова функции fopen до вызова yylex:
yyin = fopen(argv[1], "r");
В функции main в приведённом примере открывается файл, имя которого было указано пользователем при вызове лексического анализатора.
Входной текстовый файл prog содержит следующую программный код: for(abc1:=.;abc1<11.0E+1;abc1:=abc1>.1)do abc1:=abc1=34E5;
Для компиляции и запуска программы используются следующие команды:
flex example.l
gcc lex.yy.c -o scanner –lfl
./scanner prog
Результат работы программы:
KEYWORD (1, 1): for DELIMITER (1, 4): ( IDENTIFIER (1, 5): abc1 OPERATION (1, 9): :=
Unknown character (1, 11): . DELIMITER (1, 12): ;
16
IDENTIFIER (1, 13): abc1 OPERATION (1, 17): < NUMBER (1, 18): 11.0E+1 DELIMITER (1, 25): ; IDENTIFIER (1, 26): abc1 OPERATION (1, 30): := IDENTIFIER (1, 32): abc1 OPERATION (1, 36): > NUMBER (1, 37): .1 DELIMITER (1, 39): ) KEYWORD (1, 40): do IDENTIFIER (1, 43): abc1 OPERATION (1, 47): := IDENTIFIER (1, 49): abc1 OPERATION (1, 53): = NUMBER (1, 54): 34E5 DELIMITER (1, 58): ;
Символ «.» определяется лексическим анализатором как неизвестный, потому что до него и/или после него отсутствуют цифры. А значит это не вещественное с плавающей точкой, а просто «.». Такой символ не входит во множество терминальных символов языка, для которого создается лексический анализатор.
17
Задание на лабораторную работу
Для выполнения лабораторной работы необходимо:
1)написать программу, которая выполняет лексический анализ входного текста в соответствии с заданием и порождает таблицу лексем с указанием их типов. Программа должна выдавать сообщения о наличии во входном тексте ошибок, которые могут быть обнаружены на этапе лексического анализа;
2)в качестве вспомогательного средства для генерации кода лексического анализатора
использовать Flex.
Варианты заданий
1.Входной язык содержит арифметические выражения, разделённые символом ; (точка с запятой). Арифметические выражения состоят из идентификаторов, десятичных чисел с плавающей точкой (в обычной и экспоненциальной форме), знака присваивания (:=), знаков операций +, –, *, / и круглых скобок.
2.Входной язык содержит логические выражения, разделённые символом ; (точка с запятой). Логические выражения состоят из идентификаторов, констант 0 и 1, знака присваивания (:=), операций or, xor, and, not и круглых скобок.
3.Входной язык содержит операторы условия if … then … else и if … then, разделённые символом ; (точка с запятой). Операторы условия содержат идентификаторы, знаки сравнения <, >, =, шестнадцатеричные числа, знак присваивания (:=). Шестнадцатеричными числами считать последовательность цифр и символов a, b, c, d, e, f, начинающуюся с цифры
(например, 89, 45ac, 0abc).
4.Входной язык содержит операторы цикла for (…; …; …) do …, разделённые символом ; (точка
сзапятой). Операторы цикла содержат идентификаторы, знаки сравнения <, >, =, строковые константы (последовательность символов в двойных кавычках), знак присваивания (:=).
5.Входной язык содержит операторы цикла while (…) … done, разделённые символом ; (точка
сзапятой). Операторы цикла содержат идентификаторы, знаки сравнения <, >, =, десятичные числа с плавающей точкой (в обычной и экспоненциальной форме), знак присваивания (:=).
6.Входной язык содержит операторы цикла do … while (…), разделённые символом ; (точка с запятой). Операторы цикла содержат идентификаторы, знаки сравнения <, >, =, римские числа, знак присваивания (:=). Римскими считать числа, записанные большими буквами X, V и I.
7.Входной язык содержит арифметические выражения, разделённые символом ; (точка с запятой). Арифметические выражения состоят из идентификаторов, римских чисел, знака присваивания (:=), знаков операций +, –, *, / и круглых скобок. Римскими считать числа, записанные большими буквами X, V и I.
8.Входной язык содержит логические выражения, разделённые символом ; (точка с запятой). Логические выражения состоят из идентификаторов, констант true и false, знака присваивания (:=), операций or, xor, and, not и круглых скобок.
9.Входной язык содержит операторы условия if … then … else и if … then, разделённые символом ; (точка с запятой). Операторы условия содержат идентификаторы, знаки сравнения <, >, =, десятичные числа с плавающей точкой (в обычной и экспоненциальной форме), знак присваивания (:=).
18
10.Входной язык содержит операторы цикла for (…; …; …) do …, разделённые символом ; (точка
сзапятой). Операторы цикла содержат идентификаторы, знаки сравнения <, >, =, шестнадцатеричные числа, знак присваивания (:=). Шестнадцатеричными числами считать последовательность цифр и символов a, b, c, d, e, f, начинающуюся с цифры (например, 89,
45ac, 0abc).
11.Входной язык содержит операторы цикла while (…) … done, разделённые символом ; (точка
сзапятой). Операторы условия содержат идентификаторы, знаки сравнения <, >, =, строковые константы (последовательность символов в двойных кавычках), знак присваивания (:=).
12.Входной язык содержит операторы цикла do … while (…), разделённые символом ; (точка с запятой). Операторы цикла содержат идентификаторы, знаки сравнения <=, =>, =, десятичные числа с плавающей точкой (в обычной и экспоненциальной форме), знак присваивания (:=).
13.Входной язык содержит арифметические выражения, разделённые символом ; (точка с запятой). Арифметические выражения состоят из идентификаторов, шестнадцатеричных чисел, знака присваивания (:=), знаков операций +, –, *, / и круглых скобок. Шестнадцатеричными числами считать последовательность цифр и символов a, b, c, d, e, f, начинающуюся с цифры (например, 89, 45ac, 0abc).
14.Входной язык содержит логические выражения, разделённые символом ; (точка с запятой). Логические выражения состоят из идентификаторов, символьных констант 'T' и 'F', знака присваивания (:=), операций or, xor, and, not и круглых скобок.
15.Входной язык содержит операторы условия if … then … else и if … then, разделённые символом ; (точка с запятой). Операторы условия содержат идентификаторы, знаки сравнения <, >, =, римские числа, знак присваивания (:=). Римскими считать числа, записанные большими буквами X, V и I.
16.Входной язык содержит операторы цикла for (…; …; …) do …, разделённые символом ; (точка
сзапятой). Операторы цикла содержат идентификаторы, знаки сравнения <, >, =, десятичные числа с плавающей точкой (в обычной и экспоненциальной форме), знак присваивания (:=).
17.Входной язык содержит операторы цикла do … while (…), разделённые символом ; (точка с запятой). Операторы условия содержат идентификаторы, знаки сравнения <=, =>, =, строковые константы (последовательность символов в двойных кавычках), знак присваивания (:=).
18.Входной язык содержит операторы цикла while (…) … done, разделённые символом ; (точка
сзапятой). Операторы цикла содержат идентификаторы, знаки сравнения <, >, =, римские числа, знак присваивания (:=). Римскими считать числа, записанные большими буквами X, V и I.
19.Входной язык содержит арифметические выражения, разделённые символом ; (точка с запятой). Арифметические выражения состоят из идентификаторов, символьных констант (один символ в одинарных кавычках), знака присваивания (:=), знаков операций +, –, *, / и круглых скобок.
20.Входной язык содержит логические выражения, разделённые символом ; (точка с запятой). Логические выражения состоят из идентификаторов, шестнадцатеричных чисел, знака присваивания (:=), операций or, xor, and, not и круглых скобок. Шестнадцатеричными числами считать последовательность цифр и символов a, b, c, d, e, f, начинающуюся с цифры
(например, 89, 45ac, 0abc).
19
21.Входной язык содержит операторы цикла for (…; …; …) do …, разделённые символом ; (точка
сзапятой). Операторы цикла содержат идентификаторы, знаки сравнения <, >, =, римские числа, знак присваивания (:=). Римскими считать числа, записанные большими буквами X, V и I.
22.Входной язык содержит операторы цикла do … while (…), разделённые символом ; (точка с запятой). Операторы цикла содержат идентификаторы, знаки сравнения <=, =>, =, шестнадцатеричные числа, знак присваивания (:=). Шестнадцатеричными числами считать последовательность цифр и символов a, b, c, d, e, f, начинающуюся с цифры (например, 89,
45ac, 0abc).
23.Входной язык содержит операторы условия if … then … else и if … then, разделённые символом ; (точка с запятой). Операторы условия содержат идентификаторы, знаки сравнения <, >, =, строковые константы (последовательность символов в двойных кавычках), знак присваивания (:=).
24.Входной язык содержит операторы цикла while (…) … done, разделённые символом ; (точка
сзапятой). Операторы цикла содержат идентификаторы, знаки сравнения <, >, =, шестнадцатеричные числа, знак присваивания (:=). Шестнадцатеричными числами считать последовательность цифр и символов a, b, c, d, e, f, начинающуюся с цифры (например, 89,
45ac, 0abc).
Контрольные вопросы
1.Какую роль выполняет лексический анализ в процессе компиляции?
2.Как связаны лексический и синтаксический анализ?
3.Какие проблемы необходимо решить при построении лексического анализатора на основе конечного автомата?
4.Чем отличаются таблица лексем и таблица идентификаторов? В какую из этих таблиц лексический анализатор не должен помещать ключевые слова, разделители и знаки операций?
Список литературы
1.Молчанов А.Ю. Системное программное обеспечение: Учебник для вузов. 3-е изд. – СПб.:
Питер, 2010. – 400 с.
2.Cooper K.D., Torczon L. Engineering a Compiler, 2nd ed. – Elsevier, Inc., 2012. – 825 p.
3.Fast Lexical Analyzer. Режим доступа: http://flex.sourceforge.net/.
4.Levine J.R. Flex & bison. – O’Reilly Media, Inc., 2009. – 274 p.
20