A primeira coisa a se fazer em uma especificação léxica e saber quais os tokens que deverão ser reconhecidos pelo analisador.

Como neste exemplo vão ser precisos números, operadores e parênteses, já é possível ter uma idéia de quais tokens serão precisos:

Antes de especificar de fato so tokens, é preciso notar que a especificação léxica é dividida em duas partes: Definições Regulares e Definição dos Tokens.

Os tokens são definidos na segunda parte. Nas definições regulares são definidas expressões auxiliáres, para serem utilizadas na definição dos tokens.

Definições Regulares

Pare este exemplo será feira apenas a seguinte definição:

D : [0-9]

Esta definição diz que D (digito) é qualquer letra entre 0 e 9.

Tokens

Os tokens para este exemplo são definidos da seguinte forma:

"+"
"-"
"*"
"/"
"("
")"
NUMERO : {D}+
 : [\s\t\n\r]*

Primeiro são definidos os operadores. Uma grupo de caracteres entre aspas define um tokens cuja representação é a de string entre aspas.

Em seguida é definido NUMERO. Para este token é fornecida uma expressão regular para representá-lo. Nesta expressão é utilizada a definição regular anteriormente definida. Um NUMERO é um D (digito) repetido uma ou mais vezes. Para utilizar uma definição deve-se colocá-la entre { e }.

Por fim é descrita uma expressão sem um token associado. Isto indica ao analisador que ele deve ignorar esta expressão sempre que encontrá-la. Neste caso devem ser ignorados espaço em branco (\s), tabulação (\t) e quebra de linha (\n e \r).

Expressões Regulares

Esta tabela ilustra as possíbilidades de expressões regulares. Quaisquer combinações entre estes padrões é possível. Espaços em branco são ignorados (exceto entre " e ").

a reconhece a
ab reconhece a seguido de b
a|b reconhece a ou b
[abc] recohece a, b ou c
[^abc] reconhece qualquer caractere, exceto a, b e c
[a-z] reconhece a, b, c, ... ou z
a* reconhece zero ou mais a's
a+ reconhece um ou mais a's
a? reconhece um a ou nenhum a.
(a|b)* reconhece qualquer número de a's ou b's
. reconhece qualquer caractere, exceto quebra de linha
\123 reconhace o caractere ASCII 123 (decimal)

Os operadores posfixos (*, + e ?) tem prioridade máxima. Em seguida está a concatenação e por fim a união ( | ). Parenteses podem ser utulisador para agrupar símbolos e driblar prioridades.

Caracteres especiais

Os caracteres " \ | * + ? ( ) [ ] { } . ^ - possuem significado especial. Para utilizá-los como caracteres normais deve-se precedê-los por \, ou colocá-los entre " e ". Qualquer sequancia de caractateres entre " e " é tratada como caracteres ordinários.

\+ reconhece +
"+*" reconhece + seguido de *
"a""b" reconhece a, seguido de ", seguido de b
\" reconhece "

Existem ainda os caracteres não imprimíveis, representados por sequancias de escape

\n Line Feed
\r Carriage Return
\s Espaço
\t Tabulação
\b Backspace
\e Esc
\XXX O caractere ASCII XXX (XXX é um número decimal)

Outras Formas de especificar tokens

Pode-se definir ainda um tokens como sendo um caso particular de um outro token. Por exemplo:

ID : [a-z A-Z][a-z A-Z 0-9]* //letra seguida de zero ou mais letras ou dígito

BEGIN = ID : "begin"
END   = ID : "end"
WHILE = ID : "while"

Assim define-se que BEGIN, END e WHILE são casos especiais de ID. Sempre que o analisador encontrar um ID ele procura na lista de casos especiais para ver se este ID não é um BEGIN ou um WHILE.