A apresentação está carregando. Por favor, espere

A apresentação está carregando. Por favor, espere

CES-41 COMPILADORES Aulas Práticas - 2012 Capítulo I A Ferramenta Flex.

Apresentações semelhantes


Apresentação em tema: "CES-41 COMPILADORES Aulas Práticas - 2012 Capítulo I A Ferramenta Flex."— Transcrição da apresentação:

1 CES-41 COMPILADORES Aulas Práticas Capítulo I A Ferramenta Flex

2 Flex é um gerador de analisadores léxicos: Tem como entrada expressões regulares e implementa um autômato finito reconhecedor e classificador dos átomos dos programas a serem compilados Tem como entrada expressões regulares e implementa um autômato finito reconhecedor e classificador dos átomos dos programas a serem compilados Flex é uma versão, para o sistema DOS, do mais conhecido gerador de analisadores léxicos: o Lex do sistema Unix Flex é uma versão, para o sistema DOS, do mais conhecido gerador de analisadores léxicos: o Lex do sistema Unix O analisador gerado é um programa escrito em C O analisador gerado é um programa escrito em C Flex, Yacc, compilador Gcc e outros softwares estão reunidos numa pasta denominada MingW, a ser usada nas aulas práticas de CES-41 Flex, Yacc, compilador Gcc e outros softwares estão reunidos numa pasta denominada MingW, a ser usada nas aulas práticas de CES-41

3 Programa 1.1: Saída de dados Num editor de texto (Bloco de Notas, Borland C++, ou outros), criar o seguinte arquivo extensão.l (saida.l, por exemplo): Num editor de texto (Bloco de Notas, Borland C++, ou outros), criar o seguinte arquivo extensão.l (saida.l, por exemplo):%% main () { printf ("hello friends!"); } Guardar esse arquivo no diretório Guardar esse arquivo no diretório e:\alunos\ces-41\mingw\bin

4 No prompt do DOS, entrar no diretório No prompt do DOS, entrar no diretório e:\alunos\ces-41\mingw\bin Executar os seguintes comandos: Executar os seguintes comandos: flex saida.l gcc lex.yy.c -lfl a Executar: a > ttt Executar: a > ttt Abrir o arquivo ttt (No DOS: more ttt ) Abrir o arquivo ttt (No DOS: more ttt )

5 Por curiosidade, abrir o arquivo lex.yy.c e procurar no final a função main que aparece no arquivo saida.l Por curiosidade, abrir o arquivo lex.yy.c e procurar no final a função main que aparece no arquivo saida.l Flex gera uma função fundamental chamada yylex, mas não é chamada pela main neste programa Flex gera uma função fundamental chamada yylex, mas não é chamada pela main neste programa

6 Programa 1.2: Entrada de dados Criar em e:\alunos\ces-41\mingw\bin o arquivo entra.l com o seguinte programa: Criar em e:\alunos\ces-41\mingw\bin o arquivo entra.l com o seguinte programa:%% main () { int i, n; printf ("Digite o numero de repeticoes: "); scanf ("%d", &n); for (i = 1; i <= n; i++) printf ("\nhello friends!"); }

7 Executar os seguintes comandos: Executar os seguintes comandos: flex entra.l gcc lex.yy.c -lfl a Criar um arquivo entra.dat, colocando nele o número 10 Criar um arquivo entra.dat, colocando nele o número 10 Executar os comandos: Executar os comandos: a < entra.dat a ttt Abrir o arquivo ttt (No DOS: more ttt ) Abrir o arquivo ttt (No DOS: more ttt )

8 Procurar novamente a função main no arquivo lex.yy.c Procurar novamente a função main no arquivo lex.yy.c Novamente main não chama yylex Novamente main não chama yylex

9 Esquema de produção de um programa executável usando Flex:

10 Programa 1.3: Reconhecimento de while Criar um arquivo (while.l) com o seguinte programa: Criar um arquivo (while.l) com o seguinte programa:%{ #define WHILE1 %}% while{return WHILE;} % main () { int i; while (i = yylex ()) printf ("\nstring: %6s; tipo: %d; \n", yytext, i); } Agora main chama yylex yytext é uma variável string, global, do arquivo lex.yy.c Criar um arquivo de dados (while.dat) com o seguinte conteúdo: fabio 111 while else whil whiles if BHwhile22 Executar: flex while.l gcc lex.yy.c –lfl a < while.dat

11 %{ #define WHILE1 %}% while{return WHILE;} % main () { int i; while (i = yylex ()) printf ("\nstring: %6s; tipo: %d; \n", yytext, i); }Resultados: a < while.dat fabio 111 string: while; tipo: 1; else whil else whil string: while; tipo: 1; s if BH string: while; tipo: 1; 22 Arquivo de dados: fabio 111 while else whil whiles if BHwhile22 Funcionamento do yylex: yylex lê caractere por caractere da entrada e o coloca em yytex Quando não reconhece uma seqüência guardada em yytex, ele escreve seu conteúdo e a esvazia Escreve tudo o que não é reconhecido, inclusive espaços em branco

12 %{ #define WHILE1 %}% while{return WHILE;} % main () { int i; while (i = yylex ()) printf ("\nstring: %6s; tipo: %d; \n", yytext, i); }Resultados: a < while.dat fabio 111 string: while; tipo: 1; else whil else whil string: while; tipo: 1; s if BH string: while; tipo: 1; 22 Arquivo de dados: fabio 111 while else whil whiles if BHwhile22 Funcionamento do yylex: Continua percorrendo a entrada, tentando reconhecer algo Neste programa, só while é reconhecido Ao reconhecer algo, executa a ação em frente {return WHILE;}

13 %{ #define WHILE1 %}% while{return WHILE;} % main () { int i; while (i = yylex ()) printf ("\nstring: %6s; tipo: %d; \n", yytext, i); }Resultados: a < while.dat fabio 111 string: while; tipo: 1; else whil else whil string: while; tipo: 1; s if BH string: while; tipo: 1; 22 Arquivo de dados: fabio 111 while else whil whiles if BHwhile22 Funcionamento do yylex: Retorna zero ao encontrar fim de arquivo Tenta reconhecer a maior string possível Sempre esvazia yytext no início de sua execução

14 Estrutura de um programa em Flex: Um programa em Flex é dividido em três partes: Um programa em Flex é dividido em três partes: Declarações Declarações % % Regras de tradução Regras de tradução % % Rotinas auxiliares Rotinas auxiliares As strings % são os separadores dessas partes As strings % são os separadores dessas partes Seu uso é obrigatório, mesmo que o programa não tenha alguma(s) dessa(s) parte(s) Seu uso é obrigatório, mesmo que o programa não tenha alguma(s) dessa(s) parte(s)

15 Regras de tradução: Constituem-se na parte principal de um programa em Flex Constituem-se na parte principal de um programa em Flex São comandos da forma: São comandos da forma: p1 {ação1} p1 {ação1} p2 {ação2} p2 {ação2} pn {açãon} pn {açãon} Cada pi é uma expressão regular e cada açãoi é um fragmento de programa em C Cada pi é uma expressão regular e cada açãoi é um fragmento de programa em C Caso um conjunto máximo de caracteres da entrada se enquadre em uma expressão regular pi, a açãoi é executada Caso um conjunto máximo de caracteres da entrada se enquadre em uma expressão regular pi, a açãoi é executada

16 Declarações: Nelas estão inclusas: Declarações de variáveis, tipos e diretivas de pré- processamento (defines, includes, etc), tudo escrito em C, delimitado por %{ e %} Declarações de variáveis, tipos e diretivas de pré- processamento (defines, includes, etc), tudo escrito em C, delimitado por %{ e %} Definições regulares componentes das expressões regulares que aparecem nas regras de tradução Definições regulares componentes das expressões regulares que aparecem nas regras de tradução Essas definições ficam fora dos %{ e %} Essas definições ficam fora dos %{ e %} Os arquivos incluídos devem conter somente declarações Os arquivos incluídos devem conter somente declarações

17 Rotinas auxiliares: São as definições das funções em C, referenciadas nas ações das regras de tradução São as definições das funções em C, referenciadas nas ações das regras de tradução Podem trazer inclusão de arquivos com extensão.c Podem trazer inclusão de arquivos com extensão.c A função main pode aí aparecer A função main pode aí aparecer

18 Programa 1.4: Reconhecimento de várias palavras Criar um arquivo com o seguinte programa: %{ #define WHILE1 #define IF2 #define IF113 #define FOR4 #define ELSE5 %}% while{return WHILE;} if{return IF;} if11{return IF11;} for{return FOR;} else{return ELSE;} % main () { int i; while (i = yylex ()) printf ("\nstring: %6s; tipo: %d; \n", yytext, i); } Arquivo de dados: fabio 111 while else wh whi whil whiles then if for BHifelse22 if1 if11 Resultados: a < reserv.dat fabio 111 string: while; tipo: 1; string: else; tipo: 5; wh whi whil string: while; tipo: 1; s then string: if; tipo: 2; string: for; tipo: 4; BH string: if; tipo: 2; string: else; tipo: 5; 22 string: if; tipo: 2; 1 string: if11; tipo: 3; Executar

19 Programa 1.4: Reconhecimento de várias palavras %{ #define WHILE1 #define IF2 #define IF113 #define FOR4 #define ELSE5 %}% while{return WHILE;} if{return IF;} if11{return IF11;} for{return FOR;} else{return ELSE;} % main () { int i; while (i = yylex ()) printf ("\nstring: %6s; tipo: %d; \n", yytext, i); } Arquivo de dados: if if1 if11 if12 Resultados: a < reserv.dat string: if; tipo: 2; 1 string: if11; tipo: 3; string: if; tipo: 2; 12 Para if1 e if12, yylex lê 1{branco} e 12 Como if1{branco} e if12 não são reconhecidos, ele devolve 1{branco} e 12 para o buffer de entrada Reconhece o if e retorna

20 Programa 1.5: Tratamento de espaços em branco %{ #define WHILE1 #define IF2 #define IF113 #define FOR4 #define ELSE5 %}% [ \t\n\r]+{printf ("\n");} while{return WHILE;} if{return IF;} if11{return IF11;} for{return FOR;} else{return ELSE;} % main () { int i; while (i = yylex ()) printf ("\nstring: %6s; tipo: %d; \n", yytext, i); } Arquivo de dados: fabio 111 while else wh whi whil whiles then if for BHifelse22 if1 if11 Expressão regular reconhecedora de espaço de um ou mais brancos, tabulações, new-lines ou carriage- returns [abc] significa: um caractere que pode ser a, b ou c [abc]+ significa: um ou mais caracteres a, b ou c [abc]* significa: zero ou mais caracteres a, b ou c

21 Resultados:fabio111 string: while; tipo: 1; string: else; tipo: 5; whwhiwhil string: while; tipo: 1; sthen string: if; tipo: 2; string: for; tipo: 4; BH string: if; tipo: 2; string: else; tipo: 5; 22 string: if; tipo: 2; 1 string: if11; tipo: 3; Reconhecimento da regra [ \t\n\r]+{printf ("\n");} Imprime new-line e não retorna Esvazia yytex ao iniciar novo processo de reconhecimento Arquivo de dados: fabio 111 while else wh whi whil whiles then if for BHifelse22 if1 if11

22 Programa 1.6: Identificadores, números e operadores %{ #define DOLAR 0 #defineLT1 #defineLE2 #defineEQ3 #defineNE4 #defineGT5 #defineGE6 #defineIF7 #define THEN 8 #define ELSE 9 #defineID10 #defineNUM11 %} delim[ \t\n\r] ws{delim}+ digito[0-9] letra[A-Za-z] num{digito}+ id{letra}({letra}|{digito})* % Definições regulares O conteúdo do que está entre os colchetes [ e ] representa um só caractere Entre as chaves { e } coloca-se o nome de uma definição regular Entre os parêntesis ( e ) coloca-se uma sub- expressão regular

23 {ws}{ ;} if{return IF;} then{return THEN;} else{return ELSE;} {id}{return ID;} {num}{return NUM;} "<"{return LT;} "<="{return LE;} "="{return EQ;} "<>"{return NE;} ">"{return GT;} ">="{return GE;} "$"{return DOLAR;} % main () { int i; while (i = yylex ()) printf ("\nstring: %6s; tipo: %d;", yytext, i); } É preciso usar chaves: {id}, {num} e {ws} A função main é igual à dos programas anteriores, exceto por um \n Por que?

24 {ws}{ ;} if{return IF;} then{return THEN;} else{return ELSE;} {id}{return ID;} {num}{return NUM;} "<"{return LT;} "<="{return LE;} "="{return EQ;} "<>"{return NE;} ">"{return GT;} ">="{return GE;} "$"{return DOLAR;} % main () { int i; while (i = yylex ()) printf ("\nstring: %6s; tipo: %d;", yytext, i); } Executar com o seguinte arquivo de entrada: then if xxx 123 = > = else $ Resultados: string: then; tipo: 8; string: if; tipo: 7; string: xxx; tipo: 10; string: 123; tipo: 11; string: <; tipo: 1; string: <>; tipo: 4; string: <=; tipo: 2; string: >=; tipo: 6; string: >; tipo: 5; string: =; tipo: 3; string: else; tipo: 9; Por curiosidade, colocar a regra do {id} antes da regra do if Caso uma string seja reconhecida por 2 regras, a regra escolhida é a que aparece primeiro na lista de regras

25 {ws}{ ;} if{return IF;} then{return THEN;} else{return ELSE;} {id}{return ID;} {num}{return NUM;} "<"{return LT;} "<="{return LE;} "="{return EQ;} "<>"{return NE;} ">"{return GT;} ">="{return GE;} "$"{return DOLAR;} % main () { int i; while (i = yylex ()) printf ("\nstring: %6s; tipo: %d;", yytext, i); } then if xxx 123 = > = else $ Resultados: string: then; tipo: 8; string: if; tipo: 7; string: xxx; tipo: 10; string: 123; tipo: 11; string: <; tipo: 1; string: <>; tipo: 4; string: <=; tipo: 2; string: >=; tipo: 6; string: >; tipo: 5; string: =; tipo: 3; string: else; tipo: 9; Este é um exemplo de formação de átomos de uma mini-linguagem yylex retorna o tipo do átomo

26 Programa 1.7: Autômato %{ #defineACEITA1 #define OUTRA 2 %} delim[ \t\n\r] ws{delim}+ aceita0*1(0*10*1)*0* string[^ \t\n\r]+ % {ws}{ ;} {aceita} {return ACEITA;} {string}{return OUTRA;} % main () { int i; while (i = yylex ()) switch (i) { case ACEITA: printf ("%-20s: Aceita\n", yytext); break; case OUTRA: printf ("%-20s: Rejeitada\n", yytext); break;}} Reconhecimento de strings de 0s e 1s contendo um número ímpar de 1s Executar com o seguinte arquivo de entrada: [^abc] : um caractere diferente de a, b e c

27 Exercício 1.1: Escrever um programa em Flex reconhecedor de strings sobre o alfabeto {0, 1} que possuam pelo menos dois dígitos 0s seguidos Exercício 1.1: Escrever um programa em Flex reconhecedor de strings sobre o alfabeto {0, 1} que possuam pelo menos dois dígitos 0s seguidos Exercício 1.2: Escrever um programa em Flex reconhecedor de strings sobre o alfabeto {0, 1, 2}, nas quais cada dígito 2 é imediatamente seguido por dois 0s e cada dígito 1 é imediatamente seguido por um dígito 0 ou pelo par de dígitos 20 Exercício 1.2: Escrever um programa em Flex reconhecedor de strings sobre o alfabeto {0, 1, 2}, nas quais cada dígito 2 é imediatamente seguido por dois 0s e cada dígito 1 é imediatamente seguido por um dígito 0 ou pelo par de dígitos 20 Exercício 1.3: Escrever um programa em Flex reconhecedor de strings sobre o alfabeto {0, 1}, nas quais o número de dígitos 0 é par ou o número de dígitos 1 é ímpar Exercício 1.3: Escrever um programa em Flex reconhecedor de strings sobre o alfabeto {0, 1}, nas quais o número de dígitos 0 é par ou o número de dígitos 1 é ímpar

28 Exercício 1.4: Escrever um programa em Flex reconhecedor de strings sobre o alfabeto {0, 1}, nas quais a string 101 não é uma sub-string Exercício 1.4: Escrever um programa em Flex reconhecedor de strings sobre o alfabeto {0, 1}, nas quais a string 101 não é uma sub-string Exercício 1.5: Escrever um programa em Flex reconhecedor de strings sobre o alfabeto {0, 1}, nas quais o número de dígitos 0 é par e o número de dígitos 1 é ímpar Exercício 1.5: Escrever um programa em Flex reconhecedor de strings sobre o alfabeto {0, 1}, nas quais o número de dígitos 0 é par e o número de dígitos 1 é ímpar

29 Programa 1.8: Atributos para os átomos além do tipo Sejam os seguintes defines para tipos de átomos: %{ #define ELSE 1 #define IF 2 #defineWHILE 3 #defineID4 #defineCTINT5 #defineOPREL6 %} O tipo dos átomos ELSE, IF e WHILE já os define completamente Os átomos de tipos ID, CTINT e OPREL necessitam de mais informações para ficarem completamente definidos: ID: sua string CTINT: seu valor numérico OPREL: qual o operador relacional Solução: atributos para os átomos

30 %{ #include #include #define ELSE 1 #define IF 2 #defineWHILE 3 #defineID4 #defineCTINT5 #defineOPREL6 #define LT 1 #define LE 2 #defineGT3 #defineGE4 #defineEQ5 #defineNE6 union { char string[50]; int atr, valor; char carac; } yylval; %} yylval: variável global com vários campos: Um campo para cada tipo de átomo Atributos: ID: string CTINT: valor numérico OPREL: operador Defines para os atributos dos átomos de tipo OPREL

31 delim[ \t\n\r] ws{delim}+ digito[0-9] letra[A-Za-z] ctint{digito}+ id{letra}({letra}|{digito})* % {ws}{ ;} else{return ELSE;} if{return IF;} while{return WHILE;} {id}{strcpy (yylval.string, yytext); return ID;} {ctint}{yylval.valor = atoi(yytext); return CTINT;} "<"{yylval.atr = LT; return OPREL;} "<="{yylval.atr = LE; return OPREL;} ">"{yylval.atr = GT; return OPREL;} ">="{yylval.atr = GE; return OPREL;} "=="{yylval.atr = EQ; return OPREL;} "!="{yylval.atr = NE; return OPREL;} % Alguns átomos formados por yylex são compostos pelo valor retornado e pelo valor de algum campo de yylval

32 main () { int i; printf ("\n texto | tipo | atributo \n"); printf (" \n"); while (i = yylex ()) { printf ("%10s|%10d|", yytext, i); switch (i) { case ID: printf ("%10s", yylval.string); break; case CTINT: printf ("%10d", yylval.valor); break; case OPREL: printf ("%10d", yylval.atr); break; } printf ("\n"); }} Executar com o seguinte arquivo de entrada: while if else xxx 123 >= == != Acrescentar pelo meio da entrada: (&%

33 Programa 1.9: Tratamento de caracteres estranhos Acrescentar a seguinte regra no final das regras de tradução: Acrescentar a seguinte regra no final das regras de tradução:.{yylval.carac = yytext[0]; return INVAL;} Acrescentar no meio dos defines a declaração: Acrescentar no meio dos defines a declaração: #define INVAL 7 Acrescentar na função main ( ): Acrescentar na função main ( ): case INVAL: printf ("%10c", yylval.carac); break; O ponto. é um meta-símbolo que significa qualquer caractere, exceto o new-line Alterações no Programa 1.8

34 Exercício 1.6: Acrescentar ao programa anterior regras para reconhecimento de constantes reais, caracteres e strings Constante real: um ou mais dígitos seguidos de um ponto decimal, seguido de zero ou mais dígitos Constante real: um ou mais dígitos seguidos de um ponto decimal, seguido de zero ou mais dígitos A constante pode ainda estar na notação exponencial: A constante pode ainda estar na notação exponencial: Acrescenta-se opcionalmente o seguinte: a letra E maiúscula ou minúscula, seguida opcionalmente de + ou -, seguidos de um ou mais dígitos Acrescenta-se opcionalmente o seguinte: a letra E maiúscula ou minúscula, seguida opcionalmente de + ou -, seguidos de um ou mais dígitos Exemplos: E19 7.5e-45 Exemplos: E19 7.5e-45

35 Exercício 1.6: Acrescentar ao programa anterior regras para reconhecimento de constantes reais, caracteres e strings Caractere: qualquer caractere entre apóstrofos; cuidado com os caracteres iniciados pela barra \; cuidado quando o caractere for o apóstrofo Caractere: qualquer caractere entre apóstrofos; cuidado com os caracteres iniciados pela barra \; cuidado quando o caractere for o apóstrofo Exemplos: w \n \ Exemplos: w \n \ Strings: conjunto de caracteres entre aspas; mesmos cuidados; cuidado quando o caractere for aspas Strings: conjunto de caracteres entre aspas; mesmos cuidados; cuidado quando o caractere for aspas Exemplo: w\n123\g\ Exemplo: w\n123\g\ Executar o programa com o seguinte arquivo: while if else xxx E e11 19.E+27 ';' '\'' '\n' 's' "ab \\ \" \n'z" '"' "'"

36 Dicas: Definir novos tipos de átomos: Definir novos tipos de átomos: Constante real, constante caractere e constante string Constante real, constante caractere e constante string Novo campo para yylval: Novo campo para yylval: union { char string[50]; int atr, valor; float valreal; char carac; } yylval; Caractere e string podem usar o campo string do yylval Caractere e string podem usar o campo string do yylval

37 Criar definições regulares para constante real, constante caractere e constante string Criar definições regulares para constante real, constante caractere e constante string Constante caractere: Constante caractere: carac1\\.|[^\\'] ctcarac'{carac1}' Constante string: Constante string: carac2\\.|[^\\\"] string\"{carac2}*\" Criar novas regras de tradução para constante real, ctcarac e string Criar novas regras de tradução para constante real, ctcarac e string Aumentar o switch da função main Aumentar o switch da função main Qualquer caractere precedido pela \ ou qualquer caractere que não seja \ ou apóstrofo isolados Qualquer caractere precedido pela \ ou qualquer caractere que não seja \ ou aspas isolados Solução: no arquivo RealCharString.l Página do Professor

38 Exercício 1.7: Acrescentar ao programa anterior regras para reconhecimento e descarte de comentários Comentários: tudo entre /* e */; Comentários: tudo entre /* e */; Não é para criar um átomo do tipo comentário Não é para criar um átomo do tipo comentário Eles devem ser lidos e descartados, antes do retorno da função yylex Eles devem ser lidos e descartados, antes do retorno da função yylex

39 Exercício 1.7: Acrescentar ao programa anterior regras para reconhecimento e descarte de comentários Acrescentar uma linha com o protótipo Acrescentar uma linha com o protótipo void comentario (void); entre os delimitadores %{ e %} Acrescentar a seguinte regra de tradução: Acrescentar a seguinte regra de tradução: "/*"{comentario ();} Acrescentar e programar a seguinte rotina auxiliar: Acrescentar e programar a seguinte rotina auxiliar: void comentario () { }

40 Idéia: usar o seguinte autômato depois de detectado o par /*: Executar o programa com o seguinte arquivo: while if /* else xxx */ 123 /* E-12 */1.5e11/* 19.E+27*/ ';' '\'' '\n' 's' "ab \\ \" \n'z"


Carregar ppt "CES-41 COMPILADORES Aulas Práticas - 2012 Capítulo I A Ferramenta Flex."

Apresentações semelhantes


Anúncios Google