Sie sind auf Seite 1von 7

Flex Um Tutorial

O que o Flex? Como o Flex funciona? Estrutura do arquivo de descrio Um exemplo bsico Gerando um scanner Um outro exemplo Mais um exemplo Definio de Padres

Aulas Compiladores

O que o Flex?
Flex uma ferramenta para gerao automtica de analisadores lxicos (scanners), isto , programas que reconhecem padres lxicos num texto. O Flex uma evoluo da ferramenta Lex sendo mais rpido (Fast Lex). Lex foi desenvolvido por M. E. Lesk e E. Shmidt (Bell Laboratories - AT&T) enquanto que o Flex um produto da Free Software Foundation, Inc. Como so comumente distribudos em sistemas Unix sua documentao se encontra na forma de manual pages para as entradas lex, flex e flexdoc. Ao invs do programador escrever manualmente um programa que realize a identificao de padres numa entrada, o uso do Flex/Lex permite que sejam apenas especificados os padres desejados e as aes necessrias para process-los. Para que Flex/Lex reconheam padres no texto, tais padres devem ser descritos atravs de expresses regulares.

Como o Flex funciona?


Flex l os arquivos de entrada especificados, ou a entrada padro se nenhum arquivo for especificado, obtendo assim uma descrio do scanner a ser gerado. Este arquivo de entrada o que chamamos arquivo de definio ou arquivo de descrio. A descrio realizada na forma de pares de expresses regulares e cdigo C. Tais pares so denominados regras. As regras definem simultaneamente quais padres devem ser procurados e quais as aes que devem ser executada quando da identificao deste padro, ou seja, para cada padro desejado pode ser associado um conjunto de aes escritas sob a forma de cdigo C. Flex gera como sada um arquivo fonte em linguagem C, cujo nome lex.yy.c, no qual definida a funo yylex () e as variveis global yytext e yyleng. A funo yylex() na verdade o analisador lxico gerado pelo arquivo de definio atravs do Flex. A varivel global yytext contm o texto do padro reconhecido (uma string) no momento enquanto yyleng contm o nmero de caracteres de tal string, podendo ambas serem usadas no trechos de cdigo C que definem as aes associadas a cada padro. A seguir temos uma ilustrao que indica os arquivos e etapas necessrias para produo de um scanner atravs da ferramenta Flex.

O arquivo lex.yy.c pode ser compilado para produzir um executvel ou pode ser combinado com outros arquivo ou ainda modificado para se integrar com outros sistemas.

Quando executado, o programa gerado capaz analisar uma cadeia de caracteres recebida como sua entrada buscando ocorrncias dos padres especificados no arquivo de descrio. Quando um dos padres encontrados a varavel yytext passa a apontar para a string do padro encontrado e o comprimento da string armazenado em yyleng. Aps isto o programa gerado passa a executar as aes especificadas pelo cdigo C associado a cada padro. Se nenhum padro encontrado ento tomada a ao default que copiar o caractere para a sada. A entrada varrida caractere a caractere at seu final, quando a funo yylex retorna zero. Se necessrio a funo yylex pode ser acionada outras vezes mas tal ao s ser efetiva se uma chamada a funo yyrestart(FILE *f) for executada informando um ponteiro vlido para um arquivo de entrada.

Estrutura do arquivo de descrio


Todo arquivo de descrio do Flex possui trs sees separadas por uma linha com apenas os caracteres %% colocados em seu incio, como esquematicamente ilustrado a seguir: DEFINIES %% REGRAS %% CDIGO

Seo DEFINIES
Como esperado a seo DEFINIES possui definies lxicas. possvel no entanto que esta seo permanea vazia, isto , sem defines. Toda definio lxica tem a forma: nome definio

Como nome devemos usar uma palavra, iniciada por letra ou underscore ('_') seguida de uma ou mais letras, dgitos, underscore ou traos ('-'). A definio segue o nome e se inicia no primeiro caractere no branco continuando at o final da linha. Usualmente as definies so conjuntos de caracteres ou expresses regulares contidas entre colchetes. A seo DEFINIES pode ainda conter a declarao e inicializao de variveis globais que podero ser utilizadas nas aes e no cdigo fornecido pelo programador.

Seo REGRAS
A seo REGRAS possui por sua vez as regras do analisador lxico a ser construdo. Esta seo sempre possui regras, pois sem estas o analisador gerado apenas copia sua entrada para a sada. Uma regra tem sempre a forma: padro ao

O padro deve comear na primeira coluna do texto e so definidos como expresses regulares extendidas. A ao deve sempre ser iniciada na mesma linha e usualmente corresponde a um trecho de cdigo C que ser executado toda vez que o padro for reconhecido na entrada. Tanto na seo de DEFINIES como de REGRAS qualquer texto identado ou entre %{ e %} copiado literalmente para a sada (sem os caracteres %{ e %} ). Para o reconhecimento dos caracteres {, } e % estes devem aparecer no identados como padres em separado. Em adio, apenas na seo de DEFINIES, qualquer texto no identado copiado literalmente para a sada. Sob certos aspectos os caracteres %% indicam o incio e o fim da seo REGRAS.

Seo CDIGO
A ltima seo, CDIGO, contm todo o cdigo C definido e fornecido pelo programador. Nesta seo usualmente temos declarada uma funo main(), que define o incio do programa que pode efetuar uma chamada a funo yylex() (o scanner gerado por Flex). Outras funes, utilizadas nas aes definidas pelas regras, podem ser

colocadas aqui. Esta seo tambm pode permanecer vazia, ou seja, sem cdigo definido pelo programador. Recomenda-se ainda a declarao de uma funo yywrap() como abaixo: int yywrap() { return 1; }

Um exemplo bsico
Um arquivo de descrio simples poderia ser como descrito a seguir: /* separe a primeira definicao por um tab */ int numeroDeLinhas=0, numeroDeCaracteres=0; %% \n

{ /* incrementa numero de linhas */ ++numeroDeLinhas; /* incrementa numero de caracteres */ ++numeroDeCaracteres; } { /* incrementa numero de caracteres */ ++numeroDeCaracteres; }

%% /* recomendavel declarar sempre funcao yywrap() */ int yywrap (); /* programa principal */ main() { yylex(); /* scanner gerado por Flex */ printf("Numero de Linhas = %d\n", numeroDeLinhas); printf("Numero de Caracteres = %d\n",numeroDeCaracteres); } int yywrap() { return 1; } Este scanner conta o nmero de caracteres e o nmero de linhas da entrada fornecida, produzindo como sada apenas duas mensagens informando o valor dos contadores de caracteres e linhas. Neste exemplo a seo DEFINIES contm apenas a declarao de duas variveis globais numeroDeLinhas e numeroDeCaracteres, ambas acessveis para a funo yylex() que ser construda pelo Flex e para main() declarado na seo CDIGO. Na seo REGRAS temos a declarao de duas regras: Uma para o caractere "\n" que incrementa tanto o nmero de linhas como o nmero de caracteres lidos. outra para os demais caracteres, indicada pelo caractere "." que incrementa o nmero de caracteres lidos. Note que o caractere "." tem o comportamente de uma clusula default de uma diretiva switch da linguagem C.

Gerando um scanner
Para gerarmos um analisador lxico (scanner) devemos seguir os passos seguintes num ambiente Unix: 1. Executar o Flex para o arquivo de definio (supondo que seu nome seja lex01.l): $ flex lex01.l

Isto produzir um arquivo fonte em linguagem C que equivale ao scanner desejado. O arquivo C produzido tem sempre o nome lex.yy.c. 2. Compilar o cdigo C gerado pelo Flex: $ cc lex.yy.c -o lex01 O parmetro -o lex01 indica o nome do arquivo executvel desejado. Sua omisso faz que o executvel seja produzido com o nome default a.out. 3. Executar o scanner gerado: $ ./lex01 Ao executarmos o programa este fica aguardando uma entrada manual. Podemos assim digitar qualquer texto em uma ou mais linhas. O scanner no produz qualquer sada intermediria, isto , no produz qualquer espcie de mensagem enquanto esta recebendo sua entrada. Podemos finalizar a entrada teclando Ctrl+D o que produz uma mensagem indicando o numero de linhas e caracteres fornecidos.

Um outro exemplo
Observemos o arquivo de definio a seguir: int subs=0; %% username { printf("%s", getlogin()); ++subs; }

%% int yywrap(); main() { yylex(); if (subs>0) printf("%d substituicoes realizadas.\n",subs); } int yywrap() { return 1; } Nele temos a definio de uma varivel global subs que ser destinada a contabilizar a quantidade de substituies realizadas pelo scanner (seo DEFINIES). Na seo REGRAS temos a declarao de uma nica regra, a qual reconhece a palavra username, cujas ocorrncias sero contabilizadas e substitudas pelo nome do usurio obtido atravs da chamada de uma funo da API do Unix. Como no existem outras regras nem mesmo uma para "." (todas as demais ocorrncias), ento toda a entrada que no corresponder a palavra username ser transcrita verbatim para sada, isto , exatamente como figurou na entrada. Na seo CDIGO temos a declarao de uma funo main() que aciona o scanner gerado por Flex e indica ao finao o nmero de substituies realizadas indicado ao final da execuo do programa. Temos portanto um scanner capaz de substituir uma determinada ocorrncia por outra, convertendo uma certa entrada para outra sada especificada. Isto poderia ser til na substituo de sequncias de caracteres por outros caracteres correspondendo a programas que realizam a filtragem da entrada. Supondo que o arquivo de definio seja denominado lex02.l podemos gerar o scanner repetindo os passos indicados anteriormente (vide Gerando um scanner): $ flex lex02.l $ cc lex.yy.c -o lex02

Possuindo um arquivo teste o qual desejamos efetuar a substituio de username pelo nome do usurio corrente poderamos escrever: $ more teste | ./lex02.l Ou $ ./lex02 < teste A sada do programa poderia igualmente ser redirecionada para um arquivo de nome resultado: $ ./lex02 < teste > resultado

Mais um exemplo
Agora veremos um exemplo onde utilizamos expresses regulares para a definio de padres que devero ser reconhecidos pelo analisador lxico: DIGIT ID WHITESPACE %% {DIGIT}+ { printf("Inteiro: %s\n", yytext); } [0-9] [a-z][a-z0-9]* [\t\n\r]

{DIGIT}+"."{DIGIT}* { printf("Real: %s\n", yytext); } {ID}+ { printf("Identificador: %s\n", yytext); } /* Elimina espaos em branco */ { /* Caractere nao reconhecido printf("Caractere nao reconhecido: %s\n", yytext); }

{WHITESPACE}+ .

%% int yywrap(); main() { yylex(); } int yywrap() { return 1; } Neste arquivo de definio temos a declarao de definies lxicas ou invs de variveis C: DIGIT ID WHITESPACE [0-9] [a-z][a-z0-9]* [\t\n\r]

Foram criadas trs definies lxicas: DIGIT: que corresponde ao conjunto de caracteres de '0' at '9' que sero aceitos como dgitos. ID: que corresponde a sequncias iniciadas por letras, seguidas de zero ou mais letras ou dgitos. WHITESPACE: que corresponde aos caracteres de tabulao, nova linha e retorno de carro. Tais definies lxicas so usadas na seo REGRAS atravs de referncias {nome}.

Imaginando que o arquivo de definio seja denominado lex03.l podemos gerar o scanner repetindo os passos indicados anteriormente (vide Gerando um scanner): $ flex lex03.l $ cc lex.yy.c -o lex03 Sua execuo exibe uma mensagem indicando se a entrada reconhecida como um valor inteiro, um valor real ou um identificador sendo que os demais caracteres so indicados como no reconhecidos.

Definio de Padres
Os padres de entrada utilizados nas sees DEFINIES e REGRAS so escritos atravs de uma notao ampliada das expresses regulares que so, da maior para menor precedncia: caractere c. caractere exceto nova linha ('\n'). [abc] um caractere da classe de caracteres, no caso um 'a' ou 'b' ou 'c'. caractere da classe de caracteres, no caso um 'a' ou 'b' ou qualquer caractere entre 'j' e [abj-oZ] 'o' ou 'Z'. [^A-Z] um caractere que no esteja na classe das maisculas de 'A' a 'Z'. [^A-D\t] um caractere que no esteja na classe das maisculas de 'A' a 'T' ou tabulao '\t'. e* zero ou mais e, onde e uma expresso regular. e+ um ou mais e, onde e uma expresso regular. e? zero ou um e (um e opcional) onde e uma expresso regular. r{2,5} dois at cinco e, onde e uma expresso regular. r{2,} dois at mais e, onde e uma expresso regular. r{4} exatamente quatro e, onde e uma expresso regular. {name} uma ocorrncia da definio name. "[xy]\"oi" literal [xy]"oi. \x caractere especial se x um a, b, f, n, r, t ou v. \0 caractere nul (cdigo ASCII zero). \123 caractere cujo cdigo octal 123. \x2a caractere cujo cdigo hexadecimal 2a. (r) expresso regular r sendo que os parntesis so usados para modificar precedncia. rs concatenao das expresses regulares r e s. r | s expresso regular r ou s. expresso regular r apenas se seguido por uma expresso regular s. A expresso s no faz parte do r/s texto reconhecido, sendo denominada trailing context. ^r expresso regular r apenas no incio de uma nova linha (equivale a <\n>r). r$ expresso regular r apenas no final de uma nova linha (equivale a r/\n). <s>r expresso regular r apenas se precedida pela expresso s. <s1,s2>r expresso regular r apenas se precedida pela expresso s1 ou s2. <*>r expresso regular r em qualquer condio de incio. <<EOF>> um end-of-file (fim de arquivo).
c .

Consideraes Adicionais
Note que a noo de uma nova linha ("new line") exatamente o que o compilador C utilizado para compilar os arquivos gerados pelo Flex interpreta como um '\n', ou seja, pode ser significativamente diferente entre sistemas particulares. Sistemas DOS ou Windows entendem uma nova linha como a sequncia '\r\n' indicando que o caractere '\r' deve ser implicitamente filtrado da entrada ou explicitamente indicado pelas definies e regras. Por exemplo: Num sistema Unix r/\n ou r$ indicam a expresso r no final de uma linha Num sistema DOS a expresso equivalente seria r/\r\n. Dentro de classes de caracteres (conjunto de caracteres delimintados por colchetes) todos os operadores de expresses regulares perdem seu sentido exceto o caractere de escape '\', o caractere trao '-' e apenas no

incio da definio da classe o caractere de negao '^'. Prof. Peter Jandl Jr.

Das könnte Ihnen auch gefallen