Лексический анализ

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

<токен> ::= <шаблон>
number ::= /[0-9]+(\.[0-9]*)?([eE][+-]?[0-9]+)?/
operator ::= /[+*/^-]/
id ::= /[a-z_][a-z_0-9]*/
lparen ::= /\(/
rparen ::= /\)/
comma ::= /,/

Упражнение 1. Постройте ДКА лексического анализа для токена id.

Упражнение 2. Постройте ДКА лексического анализа для токена number.

В результате построения ДКА для всех токенов и объединения их общим начальным состоянием, получим следующий ДКА:

Таблица переходов ДКА
состояние символ новое состояние
0 [a-z_] 7
0 ( 8
0 ) 9
0 , 10
0 [+*/^-] 6
0 [0-9] 1
1 [0-9] 1
1 . 2
1 [eE] 3
2 [0-9] 2
2 [eE] 3
3 [+-] 4
3 [0-9] 5
4 [0-9] 5
5 [0-9] 5
7 [a-z_0-9] 7
Принимающие состояния ДКА
состояние токен
1 number
2 number
5 number
6 operator
7 id
8 lparen
9 rparen
10 comma

Упражнениe 3. Реализуйте аналогичный лексический анализатор на любимом языке программирования. Пробельные символы используются как разделитель – между любыми двумя лексемами может быть произвольное число пробельных символов, но они не могут встречаться внутри лексем. Т.е. 1234 + соответствует лексемам 1234, +; в то же время 12 34 должно интерпретироваться как две лексемы 12 и 34.

Обработку пробелов можно реализовать ad-hoc, как специальный случай в начальном состоянии, либо добавить шаблон / +/, но не создавать для него токены.

Пример реализации этого лексического анализатора на языке Haskell доступен по адресу https://github.com/lierdakil/compilers-course3/blob/master/Lexer.lhs или в читаемой форме здесь

Пример реализации на языке C++:
https://github.com/lierdakil/compilers-course3/blob/cpp/lexer.h
https://github.com/lierdakil/compilers-course3/blob/cpp/lexer.cpp

Упражнение 4. Добавьте обработку лексических ошибок в Ваш анализатор. При обнаружении лексической ошибки анализатор должен прекращать разбор и выводить сообщение типа “обнаружен неожиданный символ x при разборе шаблона y”.

Примеры ввода/вывода лексического анализатора

Ввод Вывод
667.22 (Number, 6.6722e2)
22.18E+10 (Number, 2.218e11)
37e-99 (Number, 3.7e-98)
40. (Number, 40.0)
362e+80 (Number, 3.62e82)
2.010 (Number, 2.010)
35E+35 (Number, 3.5e36)
53.353e-13 (Number, 5.3353e-12)
9 (Number, 9.0)
9.e0 (Number, 9.0)
+ (Operator, ‘+’)
* (Operator, ’*’)
/ (Operator, ‘/’)
^ (Operator, ‘^’)
- (Operator, ‘-’)
( (LParen)
) (RParen)
, (Comma)
hm (Identifier, “hm”)
ocn4wx (Identifier, “ocn4wx”)
o (Identifier, “o”)
qkg (Identifier, “qkg”)
j8w26h (Identifier, “j8w26h”)
lsuec51v (Identifier, “lsuec51v”)
gipgb4 (Identifier, “gipgb4”)
giocqic (Identifier, “giocqic”)
qic (Identifier, “qic”)
qe2315 (Identifier, “qe2315”)
123efg (Number, 1.23e2); (Identifier, “efg”)
1+2*3,var (Number, 1.0); (Operator, ‘+’); (Number, 2.0); (Operator, *); (Number, 3); (Comma); (Identifier, “var”)
123e1 (Number, 1.23e3)
123 e1 (Number, 1.23e2); (Identifier, “e1”)
123e+ (Number, 1.23e2); (Identifier, “e”); (Operator, “+”)