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

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

CES-41 COMPILADORES Aulas Práticas

Apresentações semelhantes


Apresentação em tema: "CES-41 COMPILADORES Aulas Práticas"— Transcrição da apresentação:

1 CES-41 COMPILADORES Aulas Práticas - 2017
Capítulo II A Ferramenta Yacc

2 Yacc é um gerador de analisadores sintáticos:
Tem como entrada a gramática livre de contexto da linguagem-fonte do compilador e implementa uma função de nome yyparse, que responde se o programa analisado tem ou não erros sintáticos Yacc (Yet Another Compiler-Compiler) do sistema UNIX também possui diversas versões para o sistema DOS (o Yacc do Mingw é uma delas) O analisador gerado é um programa em Linguagem C

3 Programa 2.1: Saída de dados
Criar na pasta MinGW/bin um arquivo extensão .y (saida.y, por exemplo) com o seguinte programa: %% prod: {printf ("hello friends!\n");} ; yylex () { return 0; } Executar os seguintes comandos: yacc saida.y gcc y.tab.c main.c yyerror.c -o saida -lfl saida Colocar pelo menos uma produção Não pode haver função main Tem de haver função yylex

4 Executar: saida > ppp Abrir o arquivo ppp (No DOS: more ppp)
%% prod: {printf ("hello friends!\n");} ; yylex () { return 0; } Executar: saida > ppp Abrir o arquivo ppp (No DOS: more ppp) Abrir o arquivo main.c (só executa yyparse e retorna) yyparse é o analisador sintático produzido pelo Yacc Abrir o arquivo y.tab.c e localizar yylex, prod e o printf acima

5 Estrutura de um programa em Yacc:
Tal como em Lex, um programa em Yacc é dividido em três partes, a saber: Declarações % % Produções da gramática Rotinas auxiliares

6 Produções da gramática:
É a parte principal de um programa em Yacc O programa deve conter pelo menos uma produção As produções podem vir acompanhadas de ações escritas na Linguagem C, inseridas em qualquer posição de seu lado direito

7 Produções da gramática: Exemplo: Sejam as produções:
Expr  Expr OPAD Termo | Termo Termo  ID | CTE Em Yacc, com ações opcionais: expr : expr OPAD {comandos em C} termo | {comandos em C} termo ; termo : ID {comandos em C} | CTE {comandos em C}

8 Produções da gramática:
Ações podem aparecer no lado direito de uma produção vazia Exemplo: yyy : {comandos em C} | xxx {comandos em C} zzz ; A primeira produção de yyy é vazia

9 Declarações: Nelas estão inclusas: Em C, delimitadas por %{ e %}: Declarações de variáveis, tipos, protótipos, etc. Definições de constantes e macros (define’s) Inclusão de arquivos sem definição de funções Declarações do Yacc (fora de %{ e %}) usadas para definir terminais, não-terminais, precedência de operadores, tipos dos atributos, etc.

10 Exemplo: para as produções anteriores
Declarações: Exemplo: para as produções anteriores expr : expr OPAD {comandos em C} termo | {comandos em C} termo ; termo : ID {comandos em C} | CTE {comandos em C} os átomos são assim declarados: %token OPAD %token ID %token CTE

11 Rotinas auxiliares: São definições de funções em C, referenciadas nas ações das produções da gramática Podem trazer a inclusão de arquivos com extensão .c; por exemplo, o arquivo lex.yy.c, do Flex Não devem conter a função main, pois essa já vem inclusa no ambiente da ferramenta Devem incluir a função yylex; quando usado com Flex, essa função já vem contida no arquivo lex.yy.c

12 Fazer yylex retornar algo diferente de zero
%% prod : {printf ("hello friends!\n");} ; yylex () { return 0; } Fazer yylex retornar algo diferente de zero Colocar um return dentro da ação depois do printf prod : {printf ("hello friends!\n"); return;} return 50; Retomando o programa saida.y

13 O analisador gerado pelo Yacc é bottom-up
%% prod : {printf ("hello friends!\n");} ; yylex () { return 0; } O analisador gerado pelo Yacc é bottom-up Vai detectando lados direitos de produções e reduzindo-os para seus lados esquerdos Tudo acaba bem quando se consegue chegar ao símbolo inicial Explicando os fatos

14 A única produção desta gramática (prod) é vazia
%% prod : {printf ("hello friends!\n");} ; yylex () { return 0; } A única produção desta gramática (prod) é vazia Antes de yyparse pedir um átomo para yylex, ele casa a falta de átomo em suas mãos com o lado direito dessa produção yyparse faz a redução para o lado esquerdo e executa a ação no final da produção Chegou ao símbolo inicial Explicando os fatos

15 Em seguida, chama yylex que lhe retorna zero
%% prod : {printf ("hello friends!\n");} ; yylex () { return 0; } Em seguida, chama yylex que lhe retorna zero Recebendo zero, ele aceita e retorna main então se encerra Explicando os fatos

16 Depois de chegar ao símbolo inicial, yyparse só aceita o átomo zero
%% prod : {printf ("hello friends!\n");} ; yylex () { return 50; } Depois de chegar ao símbolo inicial, yyparse só aceita o átomo zero Se yylex lhe retornar algo diferente de zero, ele rejeitará Com o return dentro da ação, yyparse retorna para main antes de chamar yylex prod : {printf ("hello friends!\n"); return;} Explicando os fatos

17 Programa 2.2: Entrada de dados
Criar um arquivo extensão .y (entra.y, por exemplo) com o seguinte programa: %% ppp: {int i, n; printf ("Digite o numero de repeticoes: "); scanf ("%d", &n); for (i = 1; i <= n; i++) printf ("\nhello friends!"); } ; yylex () {return 0;}

18 Executar os seguintes comandos:
yacc entra.y gcc y.tab.c yyerror.c main.c -o entra -lfl entra Criar um arquivo entra.dat, colocando nele o número 10 Executar os comandos: entra < entra.dat entra < entra.dat > ppp Abrir o arquivo ppp

19 Esquema de produção de um programa executável usando Yacc, sem auxilio do Flex:

20 Programa 2.3: Reconhecimento de frase
Rodar yacc e gcc para um arquivo recfrase.y com o seguinte programa: %% prod : 'C' 'O' 'M' 'P' ' ' '1' '8' {printf ("Reconheco!\n"); return;} ; yylex () { return getchar (); } O lado direito das produções tem apenas terminais (tokens) Um caractere entre apóstrofos é considerado um token Executar recfrase com: COMP 17 COMP 18 COMP 19 COMP 183

21 Programa 2.3: Reconhecimento de frase
Rodar yacc e gcc para um arquivo recfrase.y com o seguinte programa: %% prod : 'C' 'O' 'M' 'P' ' ' '1' '8' {printf ("Reconheco!\n"); return;} ; yylex () { return getchar (); } Executar com arquivo de dados (recfrase.dat, por exemplo): uma frase de cada vez Executar: recfrase < recfrase.dat > ppp Executar recfrase com: COMP 17 COMP 18 COMP 19 COMP 183

22 Programa 2.4: Gramática S → ε | a S b
%token a %token b %token dolar %token erro %% SS : S dolar {printf ("Fim da analise\n"); return;} ; S : | a S b Experimente tirar o return; sem e com arquivo de dados Tokens são convertidos em defines pelo Yacc yylex () { char x; x = getchar (); while (x == ' ' || x == '\n' || x == '\t' || x == '\r') printf ("Caractere lido: %c\n", x); if (x == 'a') return a; if (x == 'b') return b; if (x == '$') return dolar; return erro; } Rodar para várias cadeias, uma por vez: aabb$ $ aaabbb$ a$ b$ aaabb$ aabbb$ aba$ ba$ Rodar com arquivo de dados contendo: aabb$

23 Programa 2.4: Gramática S → ε | a S b
%token a %token b %token dolar %token erro %% SS : S dolar {printf ("Fim da analise\n"); return;} ; S : | a S b Experimente tirar o return; sem e com arquivo de dados yylex () { char x; x = getchar (); while (x == ' ' || x == '\n' || x == '\t' || x == '\r') printf ("Caractere lido: %c\n", x); if (x == 'a') return a; if (x == 'b') return b; if (x == '$') return dolar; return erro; } Chegando ao símbolo inicial, yyparse sempre chama yylex, esperando zero yylex só retorna quando um caractere é digitado e nunca retorna zero Com fim de arquivo, yylex retorna erro

24 Exercício 2.1: Escrever em Yacc, um analisador sintático para a seguinte gramática geradora da linguagem L abaixo: L = { (a b)n cn (d d)* | n  1 } Gramática: S  a b A c D A  a b A c | ε D  d d D | ε

25 Exercício 2.2: Escrever em Yacc, um analisador sintático para a seguinte gramática geradora da linguagem L abaixo: L = { ai bj | j  i  0 } Gramática: S  A B A  a A b | ε B  b B | ε

26 Exercício 2.3: Escrever em Yacc, um analisador sintático para a seguinte gramática geradora de expressões contendo só pares de parêntesis balanceados e nenhum outro caractere Exemplos: ( ), ( ( ) ), ( ) ( ), ( ) ( ( ) ( ( ) ) ) ( ( ) ) Gramática: S  ( A ) | S ( A ) A  ε | S

27 Programa 2.5: Yacc auxiliado por Lex
Programa em Flex no arquivo expr01.l delim [ \t\n\r] ws {delim}+ digit [0-9] num {digit}+ %% {ws} { ;} {num} {return CTE;} "+" {return OPAD;} "-" {return OPAD;} "*" {return OPMULT;} "/" {return OPMULT;} "(" {return ABPAR;} ")" {return FPAR;} "$" {return DOLAR;} . {return INVAL;} yylex retorna tokens declarados no programa em Yacc

28 Programa em Yacc no arquivo expr01.y
%{ #include <stdio.h> #include <stdlib.h> %} %token DOLAR %token CTE %token OPAD %token OPMULT %token ABPAR %token FPAR %token INVAL %% Tokens a serem retornados por yylex

29 line : expr DOLAR {printf("Fim da analise\n"); return;} ; expr : expr OPAD term | term term : term OPMULT fat | fat fat : CTE | ABPAR expr FPAR %% #include "lex.yy.c" Tokens aparecem do lado direito das produções yylex está em lex.yy.c

30 Executar os seguintes comandos:
flex expr01.l yacc expr01.y gcc y.tab.c main.c yyerror.c -o expr01 -lfl expr01 (digitar uma expressão correta terminada por ‘$’) (digitar uma expressão incorreta terminada por ‘$’) Usando arquivo de dados de entrada, yylex retorna zero ao ler fim de arquivo, quando criado pelo Flex Então, dispensa-se o return da produção line

31 Esquema de produção de um programa executável usando Yacc, com auxilio do Flex:

32 Programa 2.6: Uso de atributos (calculadora simples)
Programa em Flex no arquivo calc01.l delim [ \t\n\r] ws {delim}+ digit [0-9] num {digit}+ %% {ws} { ;} {num} {yylval = atoi(yytext); return CTE;} "+" {yylval = MAIS; return OPAD;} "-" {yylval = MENOS; return OPAD;} "*" {yylval = VEZES; return OPMULT;} "/" {yylval = DIV; return OPMULT;} "(" {return ABPAR;} ")" {return FPAR;} "$" {return DOLAR;} . {yylval = yytext[0]; return INVAL;} yylval guarda o atributo de um token yylval é declarado pelo Yacc

33 Programa em Yacc no arquivo calc01.y
%{ #include <stdio.h> #include <stdlib.h> #define MAIS 1 #define MENOS 2 #define VEZES 3 #define DIV 4 %} %token DOLAR %token CTE %token OPAD %token OPMULT %token ABPAR %token FPAR %token INVAL %% Atributos para os tokens OPAD e OPMULT Por default, yylval é inteiro

34 line : expr DOLAR { printf("valor: %d\n", $1); } ; expr : expr OPAD term { switch ($2) case MAIS : $$ = $1 + $3; break; case MENOS : $$ = $1 - $3; break; | term Não-terminais também têm atributos Numa produção qualquer: $$ é o atributo do não-terminal do lado esquerdo $1, $2, $3 ... são atributos dos 1o, 2o, 3o ... símbolos do lado direito

35 term : term OPMULT fat { switch ($2) case VEZES: $$ = $1 * $3; break; case DIV: $$ = $1 / $3; break; } | fat ; fat : CTE | ABPAR expr FPAR {$$ = $2;} %% #include "lex.yy.c" Rodar o executável para um arquivo com a expressão 10 * (5 + 3)$ O atributo de um terminal é fornecido por yylex, em yylval Os atributos dos não-terminais devem ser calculados nas ações Por default, a ação tomada no final de uma produção é: $$ = $1;

36 No Yacc, a análise é bottom-up (por deslocamento e redução)
Os átomos são obtidos e deslocados para uma pilha (deslocamento) Quando no topo da pilha se formar o lado-direito de uma produção, tem-se uma ocasião para reduzir O analisador verifica se a redução é válida Isso será estudado no tópico sobre Análise Bottom-Up do capítulo sobre Análise Sintática Em caso positivo, substitui, na pilha, o lado-direito pelo lado-esquerdo da produção (redução) Então, a ação no final da produção é executada

37 Pilha Entrada Operação Ação
Análise e cálculo da expressão 10 * (5 + 3)$ line : expr DOLAR expr : expr OPAD term | term term : term OPMULT fat | fat fat : CTE | ABPAR expr FPAR Pilha Entrada Operação Ação # 10*(5+3)$#

38 Pilha Entrada Operação Ação
Análise e cálculo da expressão 10 * (5 + 3)$ line : expr DOLAR expr : expr OPAD term | term term : term OPMULT fat | fat fat : CTE | ABPAR expr FPAR Pilha Entrada Operação Ação # 10*(5+3)$# d

39 Pilha Entrada Operação Ação
Análise e cálculo da expressão 10 * (5 + 3)$ line : expr DOLAR expr : expr OPAD term | term term : term OPMULT fat | fat fat : CTE | ABPAR expr FPAR Pilha Entrada Operação Ação #C10 *(5+3)$#

40 Pilha Entrada Operação Ação
Análise e cálculo da expressão 10 * (5 + 3)$ line : expr DOLAR expr : expr OPAD term | term term : term OPMULT fat | fat fat : CTE | ABPAR expr FPAR Pilha Entrada Operação Ação #C10 *(5+3)$# r: F → C $$ = $1

41 Pilha Entrada Operação Ação
Análise e cálculo da expressão 10 * (5 + 3)$ line : expr DOLAR expr : expr OPAD term | term term : term OPMULT fat | fat fat : CTE | ABPAR expr FPAR Pilha Entrada Operação Ação #F10 *(5+3)$#

42 Pilha Entrada Operação Ação
Análise e cálculo da expressão 10 * (5 + 3)$ line : expr DOLAR expr : expr OPAD term | term term : term OPMULT fat | fat fat : CTE | ABPAR expr FPAR Pilha Entrada Operação Ação #F10 *(5+3)$# r: T → F $$ = $1

43 Pilha Entrada Operação Ação
Análise e cálculo da expressão 10 * (5 + 3)$ line : expr DOLAR expr : expr OPAD term | term term : term OPMULT fat | fat fat : CTE | ABPAR expr FPAR Pilha Entrada Operação Ação #T10 *(5+3)$#

44 Pilha Entrada Operação Ação
Análise e cálculo da expressão 10 * (5 + 3)$ line : expr DOLAR expr : expr OPAD term | term term : term OPMULT fat | fat fat : CTE | ABPAR expr FPAR Pilha Entrada Operação Ação #T10 *(5+3)$# d d d Por que não reduz segundo E → T ? A resposta virá no estudo de Análise Bottom-Up

45 Pilha Entrada Operação Ação
Análise e cálculo da expressão 10 * (5 + 3)$ line : expr DOLAR expr : expr OPAD term | term term : term OPMULT fat | fat fat : CTE | ABPAR expr FPAR Pilha Entrada Operação Ação #T10*(C5 +3)$#

46 Pilha Entrada Operação Ação
Análise e cálculo da expressão 10 * (5 + 3)$ line : expr DOLAR expr : expr OPAD term | term term : term OPMULT fat | fat fat : CTE | ABPAR expr FPAR Pilha Entrada Operação Ação #T10*(C5 +3)$# r: F → C $$ = $1

47 Pilha Entrada Operação Ação
Análise e cálculo da expressão 10 * (5 + 3)$ line : expr DOLAR expr : expr OPAD term | term term : term OPMULT fat | fat fat : CTE | ABPAR expr FPAR Pilha Entrada Operação Ação #T10*(F5 +3)$#

48 Pilha Entrada Operação Ação
Análise e cálculo da expressão 10 * (5 + 3)$ line : expr DOLAR expr : expr OPAD term | term term : term OPMULT fat | fat fat : CTE | ABPAR expr FPAR Pilha Entrada Operação Ação #T10*(F5 +3)$# r: T → F $$ = $1

49 Pilha Entrada Operação Ação
Análise e cálculo da expressão 10 * (5 + 3)$ line : expr DOLAR expr : expr OPAD term | term term : term OPMULT fat | fat fat : CTE | ABPAR expr FPAR Pilha Entrada Operação Ação #T10*(T5 +3)$#

50 Pilha Entrada Operação Ação
Análise e cálculo da expressão 10 * (5 + 3)$ line : expr DOLAR expr : expr OPAD term | term term : term OPMULT fat | fat fat : CTE | ABPAR expr FPAR Pilha Entrada Operação Ação #T10*(T5 +3)$# r: E → T $$ = $1

51 Pilha Entrada Operação Ação
Análise e cálculo da expressão 10 * (5 + 3)$ line : expr DOLAR expr : expr OPAD term | term term : term OPMULT fat | fat fat : CTE | ABPAR expr FPAR Pilha Entrada Operação Ação #T10*(E5 +3)$#

52 Pilha Entrada Operação Ação
Análise e cálculo da expressão 10 * (5 + 3)$ line : expr DOLAR expr : expr OPAD term | term term : term OPMULT fat | fat fat : CTE | ABPAR expr FPAR Pilha Entrada Operação Ação #T10*(E5 +3)$# d d

53 Pilha Entrada Operação Ação
Análise e cálculo da expressão 10 * (5 + 3)$ line : expr DOLAR expr : expr OPAD term | term term : term OPMULT fat | fat fat : CTE | ABPAR expr FPAR Pilha Entrada Operação Ação #T10*(E5+C3 )$#

54 Pilha Entrada Operação Ação
Análise e cálculo da expressão 10 * (5 + 3)$ line : expr DOLAR expr : expr OPAD term | term term : term OPMULT fat | fat fat : CTE | ABPAR expr FPAR Pilha Entrada Operação Ação #T10*(E5+C3 )$# r: F → C $$ = $1

55 Pilha Entrada Operação Ação
Análise e cálculo da expressão 10 * (5 + 3)$ line : expr DOLAR expr : expr OPAD term | term term : term OPMULT fat | fat fat : CTE | ABPAR expr FPAR Pilha Entrada Operação Ação #T10*(E5+F3 )$#

56 Pilha Entrada Operação Ação
Análise e cálculo da expressão 10 * (5 + 3)$ line : expr DOLAR expr : expr OPAD term | term term : term OPMULT fat | fat fat : CTE | ABPAR expr FPAR Pilha Entrada Operação Ação #T10*(E5+F3 )$# r: T → F $$ = $1

57 Pilha Entrada Operação Ação
Análise e cálculo da expressão 10 * (5 + 3)$ line : expr DOLAR expr : expr OPAD term | term term : term OPMULT fat | fat fat : CTE | ABPAR expr FPAR Pilha Entrada Operação Ação #T10*(E5+T3 )$#

58 Pilha Entrada Operação Ação
Análise e cálculo da expressão 10 * (5 + 3)$ line : expr DOLAR expr : expr OPAD term | term term : term OPMULT fat | fat fat : CTE | ABPAR expr FPAR Pilha Entrada Operação Ação #T10*(E5+T3 )$# r: E → E+T $$ = $1+$3

59 Pilha Entrada Operação Ação
Análise e cálculo da expressão 10 * (5 + 3)$ line : expr DOLAR expr : expr OPAD term | term term : term OPMULT fat | fat fat : CTE | ABPAR expr FPAR Pilha Entrada Operação Ação #T10*(E8 )$#

60 Pilha Entrada Operação Ação
Análise e cálculo da expressão 10 * (5 + 3)$ line : expr DOLAR expr : expr OPAD term | term term : term OPMULT fat | fat fat : CTE | ABPAR expr FPAR Pilha Entrada Operação Ação #T10*(E8 )$# d

61 Pilha Entrada Operação Ação
Análise e cálculo da expressão 10 * (5 + 3)$ line : expr DOLAR expr : expr OPAD term | term term : term OPMULT fat | fat fat : CTE | ABPAR expr FPAR Pilha Entrada Operação Ação #T10*(E8) $#

62 Pilha Entrada Operação Ação
Análise e cálculo da expressão 10 * (5 + 3)$ line : expr DOLAR expr : expr OPAD term | term term : term OPMULT fat | fat fat : CTE | ABPAR expr FPAR Pilha Entrada Operação Ação #T10*(E8) $# r: F → (E) $$ = $2

63 Pilha Entrada Operação Ação
Análise e cálculo da expressão 10 * (5 + 3)$ line : expr DOLAR expr : expr OPAD term | term term : term OPMULT fat | fat fat : CTE | ABPAR expr FPAR Pilha Entrada Operação Ação #T10*F8 $#

64 Pilha Entrada Operação Ação
Análise e cálculo da expressão 10 * (5 + 3)$ line : expr DOLAR expr : expr OPAD term | term term : term OPMULT fat | fat fat : CTE | ABPAR expr FPAR Pilha Entrada Operação Ação #T10*F8 $# r: T → T*F $$ = $1*$3

65 Pilha Entrada Operação Ação
Análise e cálculo da expressão 10 * (5 + 3)$ line : expr DOLAR expr : expr OPAD term | term term : term OPMULT fat | fat fat : CTE | ABPAR expr FPAR Pilha Entrada Operação Ação #T80 $#

66 Pilha Entrada Operação Ação
Análise e cálculo da expressão 10 * (5 + 3)$ line : expr DOLAR expr : expr OPAD term | term term : term OPMULT fat | fat fat : CTE | ABPAR expr FPAR Pilha Entrada Operação Ação #T80 $# r: E → T $$ = $1

67 Pilha Entrada Operação Ação
Análise e cálculo da expressão 10 * (5 + 3)$ line : expr DOLAR expr : expr OPAD term | term term : term OPMULT fat | fat fat : CTE | ABPAR expr FPAR Pilha Entrada Operação Ação #E80 $#

68 Pilha Entrada Operação Ação
Análise e cálculo da expressão 10 * (5 + 3)$ line : expr DOLAR expr : expr OPAD term | term term : term OPMULT fat | fat fat : CTE | ABPAR expr FPAR Pilha Entrada Operação Ação #E80 $# d

69 Pilha Entrada Operação Ação
Análise e cálculo da expressão 10 * (5 + 3)$ line : expr DOLAR expr : expr OPAD term | term term : term OPMULT fat | fat fat : CTE | ABPAR expr FPAR Pilha Entrada Operação Ação #E80$ #

70 Pilha Entrada Operação Ação
Análise e cálculo da expressão 10 * (5 + 3)$ line : expr DOLAR expr : expr OPAD term | term term : term OPMULT fat | fat fat : CTE | ABPAR expr FPAR Pilha Entrada Operação Ação #E80$ # r: L → E$ Imprimir $1

71 Pilha Entrada Operação Ação
Análise e cálculo da expressão 10 * (5 + 3)$ line : expr DOLAR expr : expr OPAD term | term term : term OPMULT fat | fat fat : CTE | ABPAR expr FPAR Pilha Entrada Operação Ação #L # Escrito no vídeo: valor 80

72 Pilha Entrada Operação Ação
Análise e cálculo da expressão 10 * (5 + 3)$ line : expr DOLAR expr : expr OPAD term | term term : term OPMULT fat | fat fat : CTE | ABPAR expr FPAR Pilha Entrada Operação Ação #L # aceitar Escrito no vídeo: valor 80

73 Árvore sintática de 10*(5+3)$ com atributos:

74 Programa 2.7: Alteração no tipo dos atributos
Programa em Flex no arquivo calc02.l: delim [ \t\n] ws {delim}+ digit [0-9] cte {digit}+(\.{digit}*)? %% {ws} { ;} {cte} {yylval = atof(yytext); return CTE;} "+" {return MAIS;} "*" {return VEZES;} "(" {return ABPAR;} ")" {return FPAR;} "$" {return DOLAR;} Para simplificar: Expressões somente com somas e multiplicações

75 Programa em Yacc no arquivo calc02.y
%{ #include <stdio.h> #include <stdlib.h> #define YYSTYPE float %} %token DOLAR %token CTE %token MAIS %token VEZES %token ABPAR %token FPAR %% Alteração no tipo de yylval e dos atributos dos não-terminais

76 line : expr DOLAR { printf("valor: %g\n",$1); return 0;} ; expr : expr MAIS term {$$ = $1 + $3;} | term term : term VEZES fat {$$ = $1 * $3;} | fat fat : CTE | ABPAR expr FPAR {$$ = $2;} %% #include "lex.yy.c" Rodar o executável para um arquivo com uma expressão tal como 10.5 * ( )$

77 Programa 2.8: Atributos de tipos alternativos
Programa em Flex no arquivo calc03.l delim [ \t\n] ws {delim}+ digit [0-9] ctint {digit}+ ctfloat {digit}+\.{digit}* %% Programa com constantes inteiras e reais

78 {ws} { ;} {ctint} {yylval.valint = atoi(yytext); return CTINT;} {ctfloat} {yylval.valfloat = atof(yytext); return CTFLOAT;} "+" {yylval.atr = MAIS; return OPAD;} "-" {yylval.atr = MENOS; return OPAD;} "*" {yylval.atr = VEZES; return OPMULT;} "/" {yylval.atr = DIV; return OPMULT;} "(" {return ABPAR;} ")" {return FPAR;} "$" {return DOLAR;} %% yylval não é mais declarado no programa Flex Deve ser uma union com os campos: valint, valfloat e atr Agora yylval está sendo usado como apresentado no capítulo sobre Flex

79 Programa em Yacc no arquivo calc03.y
%{ #include <stdio.h> #include <stdlib.h> #define MAIS 1 #define MENOS 2 #define VEZES 3 #define DIV 4 %} %union { int valint, atr; float valfloat; } Os campos da union podem ser struct’s ou até outras union’s Declaração da estrutura e dos campos de yylval e de outras variáveis de mesmo tipo, usadas na função yyparse

80 Especificação dos atributos dos tokens e dos não-terminais
%type <valfloat> expr term fat %token DOLAR %token <valint> CTINT %token <valfloat> CTFLOAT %token <atr> OPAD %token <atr> OPMULT %token ABPAR %token FPAR %% Especificação dos atributos dos tokens e dos não-terminais %type: para os não-terminais %token: para os terminais

81 printf("valor: %g\n",$1); } ; expr : expr OPAD term { switch ($2) {
line : expr DOLAR { printf("valor: %g\n",$1); } ; expr : expr OPAD term { switch ($2) { case MAIS : $$ = $1 + $3; break; case MENOS : $$ = $1 - $3; break; | term Aqui, $1 corresponde ao campo valfloat de alguma variável de yyparse Mudança no tipo do valor a ser escrito Aqui: $1, $3 e $$ correspondem ao campo valfloat $2 corresponde ao campo atr

82 term : term OPMULT fat { switch ($2) { case VEZES: $$ = $1 * $3; break; case DIV: $$ = $1 / $3; break; } | fat ; fat : CTINT {$$ = (float)$1;} | CTFLOAT | ABPAR expr FPAR {$$ = $2;} %% #include "lex.yy.c" Fator de conversão Rodar o executável para um arquivo com uma expressão tal como 10.5 * ( )$

83 Programa 2.9: Ações no início e meio das produções
%{ #include <stdio.h> #include <stdlib.h> int v, w, x, y, z; %} %% A : {w = 10; $$ = 5*w;} B {$$ = 1; v = $1; y = $2;} C { x = $3; z = $4; printf ("v = %d; w = %d; x = %d; y = %c; z = %c;", v, w, x, y, z); return 0; } ; B : 'b' C : 'c' Arquivo acaomeio.y Caracteres entre apóstrofos são tokens yylex () { char x; x = getchar (); while (x != 'b' && x != 'c') yylval = x; return x; } O tipo e o atributo são iguais

84 A : {w = 10; $$ = 5*w;} B {$$ = 1; v = $1; y = $2;} C { x = $3; z = $4; printf ("- - -", v, w, x, y, z); return 0; } ; B : 'b' C : 'c' Ação no início ou meio de uma produção: Yacc cria uma produção vazia para um não-terminal fictício A ação fica no final dessa produção vazia Tal não-terminal fica no lugar da ação, na produção original

85 A Produção: Torna-se: A : {w = 10; $$ = 5*w;} B
{$$ = 1; v = $1; y = $2;} C {x = $3; z = $4; printf ("... ", v, w, x, y, z); return 0;} ; $$1 : {w = 10; $$ = 5*w;} ; $$2 : {$$ = 1; v = $1; y = $2;} ; A : $$1 B $$2 C { x = $3; z = $4; printf ("…", v, w, x, y, z); return 0; } ;

86 Nas produções de $$1 e $$2, $$ é o atributo do lado esquerdo
Na produção de $$2, $1 é o atributo de $$1 e $2 é o de B, da produção de A Na produção de A, $3 é o atributo de $$2 e $4 é o de C Cuidado com a numeração dos atributos da produção original $$1 : {w = 10; $$ = 5*w;} ; $$2 : {$$ = 1; v = $1; y = $2;} ; A : $$1 B $$2 C { x = $3; z = $4; printf ("…", v, w, x, y, z); return 0; } ;

87 Para entrada bc: Resultado no vídeo:
$$1 : {w = 10; $$ = 5*w;} ; $$2 : {$$ = 1; v = $1; y = $2;} ; A : $$1 B $$2 C { x = $3; z = $4; printf ("…", v, w, x, y, z); return 0; } ; B : 'b'; C : 'c'; Resultado no vídeo: v = 50; w = 10; x = 1; y = b; z = c;

88 Programa 2.10: Pretty-Printer Dada uma entrada desorganizada do tipo:
{ i = 1; i = i + 1; i = 0; {j = 0;{ j = j + 1; a = b - (x-3) + c; } i = i - 1; } } Obter uma saída organizada do tipo: { i = 1 ; i = i + 1 ; i = 0 ; j = 0 ; j = j + 1 ; a = b - ( x - 3 ) + c ; } i = i - 1 ; É necessário mudar de linha e tabular oportunamente

89 Programa em Flex no arquivo pretty2017.l
delim [ \t\n] ws {delim}+ digito [0-9] letra [A-Za-z] intct {digito}+ id {letra}({letra}|{digito})* %% {ws} { ;} {id} {strcpy (yylval.cadeia, yytext); return ID;} {intct} {yylval.valint = atoi(yytext); return INTCT;} "+" {yylval.atr = MAIS; return ADOP;} "-" {yylval.atr = MENOS; return ADOP;} "(" {return OPPAR;} ")" {return CLPAR;} "{" {return OPBRACE;} "}" {return CLBRACE;} ";" {return SCOLON;} "=" {return ASSIGN;} . {yylval.carac = yytext[0]; return INVAL;}

90 Programa em Yacc no arquivo pretty2017.y
%{ #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAIS 7 #define MENOS 8 int tab = 0; %} %union { char cadeia[50]; int atr, valint; char carac; } tab: no de tabulações a serem dadas por uma função de nome tabular

91 %token <cadeia> ID
%token <valint> INTCT %token <atr> ADOP %token OPPAR %token CLPAR %token OPBRACE %token CLBRACE %token SCOLON %token ASSIGN %token <carac> INVAL %%

92 tabular: dá tantas tabulações quanto for o valor de tab
CompStat : OPBRACE {tabular (); printf ("\{\n"); tab++;} StatList CLBRACE {tab--; tabular (); printf ("}\n");} ; StatList : Statement | StatList Statement Statement : AssignStat | CompStat AssignStat : ID {tabular (); printf ("%s ", $1);} ASSIGN {printf ("= ");} Expression SCOLON {printf(";\n");} tabular: dá tantas tabulações quanto for o valor de tab Depois de todo token imprime seu texto Para alguns tokens, imprime ‘\n’

93 Expression : Term | Expression ADOP { if ($2 == MAIS) printf ("+ "); else printf ("- "); } Term ; Term : ID {printf ("%s ", $1);} | INTCT {printf ("%d ", $1);} | OPPAR {printf("\( ");} Expression CLPAR {printf (") ");} %% #include "lex.yy.c" tabular () { int i; for (i = 1; i <= tab; i++) printf ("\t"); } Rodar o executável para um arquivo contendo o programa desorganizado ilustrativo

94 Outra forma de apresentar a gramática (com abreviaturas):
Comp : ‘{’ $$1 StatL ‘}’ {tab--; tabular (); write("}\n");} ; StatL : Stat | StatL Stat ; Stat : AsStat | Comp ; AsStat : ID $$2 “=” $$3 Expr ‘;’ {write(";\n");} ; Expr : Term | Expr OPAD $$4 Term ; Term : ID {write($1);} | INTCT {write($1);} | ‘(’ $$5 Expr ‘)’ {write (")");} ; $$1: {tabular (); write ("{\n"); tab++;} $$2: {tabular (); write ($1);} $$3: {write ("=");} $$4: {if ($2 == MAIS) write (‘+’); else printf (‘-’);} $$5: {write (‘(’);}

95 Seja a seguinte sentença bem simples:
A análise bottom-up por deslocamento e redução, feita pelo Yacc, simula o caminhamento em pós-ordem, na árvore sintática de uma sentença correta Isso é usado a seguir para ilustrar o resultado das ações do pretty-printer para produzir o efeito desejado Seja a seguinte sentença bem simples: { i = 1 ; j = 2 ; } A seguir, sua árvore sintática

96 AsStat ID(j) $$2 = $$3 Expr ; ID(i) $$2 = $$3 Expr ;   Term
Comp { $$ StatL }  StatL Stat Stat AsStat AsStat ID(j) $$ = $$ Expr ; ID(i) $$ = $$ Expr ;   Term   Term INTCT(2) INTCT(1) Seja a pós-ordem: tab 1 Os elementos dos retângulos formam a pilha { _ _ Reduzir: Ação: { tabular (); write ("{\n"); tab++;} Deslocar vazio Deslocar Tela do vídeo

97 AsStat ID(j) $$2 = $$3 Expr ; ID(i) $$2 = $$3 Expr ;   Term
Seja a pós-ordem: Comp { $$ StatL }  StatL Stat Stat AsStat AsStat ID(j) $$ = $$ Expr ; ID(i) $$ = $$ Expr ;   Term   Term INTCT(2) INTCT(1) tab 1 { _ { i_ Reduzir: Ação: {tabular (); write ($1);} Deslocar vazio Deslocar

98 AsStat ID(j) $$2 = $$3 Expr ; ID(i) $$2 = $$3 Expr ;   Term
Comp { $$ StatL }  StatL Stat Stat AsStat AsStat ID(j) $$ = $$ Expr ; ID(i) $$ = $$ Expr ;   Term   Term INTCT(2) INTCT(1) Seja a pós-ordem: tab 1 { i =_ { i_ Reduzir: Ação: {write (“=");} Deslocar vazio Deslocar

99 AsStat ID(j) $$2 = $$3 Expr ; ID(i) $$2 = $$3 Expr ;   Term
Seja a pós-ordem: Comp { $$ StatL }  StatL Stat Stat AsStat AsStat ID(j) $$ = $$ Expr ; ID(i) $$ = $$ Expr ;   Term   Term INTCT(2) INTCT(1) tab 1 { i =_ { i = 1_ Reduzir: Ação: {$$ = $1);} irrelevante Reduzir: Ação: {write ($1);} Deslocar

100 AsStat ID(j) $$2 = $$3 Expr ; ID(i) $$2 = $$3 Expr ;   Term
Seja a pós-ordem: Comp { $$ StatL }  StatL Stat Stat AsStat AsStat ID(j) $$ = $$ Expr ; ID(i) $$ = $$ Expr ;   Term   Term INTCT(2) INTCT(1) tab 1 { i = 1_ { i = 1 ; _ Reduzir: Ação: {$$ = $1);} irrelevante Reduzir: Ação: {write (“;\n”);} Deslocar

101 AsStat ID(j) $$2 = $$3 Expr ; ID(i) $$2 = $$3 Expr ;   Term
Comp { $$ StatL }  StatL Stat Stat AsStat AsStat ID(j) $$ = $$ Expr ; ID(i) $$ = $$ Expr ;   Term   Term INTCT(2) INTCT(1) Seja a pós-ordem: tab 1 { i = 1 ; j_ { i = 1 ; _ Reduzir: Ação: {tabular(); write ($1);} Deslocar vazio Deslocar

102 AsStat ID(j) $$2 = $$3 Expr ; ID(i) $$2 = $$3 Expr ;   Term
Comp { $$ StatL }  StatL Stat Stat AsStat AsStat ID(j) $$ = $$ Expr ; ID(i) $$ = $$ Expr ;   Term   Term INTCT(2) INTCT(1) Seja a pós-ordem: tab 1 { i = 1 ; j =_ { i = 1 ; j_ Reduzir: Ação: {write (“=”);} Deslocar vazio Deslocar

103 AsStat ID(j) $$2 = $$3 Expr ; ID(i) $$2 = $$3 Expr ;   Term
Seja a pós-ordem: Comp { $$ StatL }  StatL Stat Stat AsStat AsStat ID(j) $$ = $$ Expr ; ID(i) $$ = $$ Expr ;   Term   Term INTCT(2) INTCT(1) tab 1 { i = 1 ; j =_ { i = 1 ; j = 2_ Reduzir: Ação: {write ($1);} Reduzir: Ação: {$$ = $1);} irrelevante Deslocar

104 AsStat ID(j) $$2 = $$3 Expr ; ID(i) $$2 = $$3 Expr ;   Term
Seja a pós-ordem: Comp { $$ StatL }  StatL Stat Stat AsStat AsStat ID(j) $$ = $$ Expr ; ID(i) $$ = $$ Expr ;   Term   Term INTCT(2) INTCT(1) tab 1 { i = 1 ; j = 2_ { i = 1 ; j = 2 ; _ Reduzir: Ação: {write (“;\n”);} Reduzir: Ação: {$$ = $1);} irrelevante Deslocar

105 AsStat ID(j) $$2 = $$3 Expr ; ID(i) $$2 = $$3 Expr ;   Term
Seja a pós-ordem: Comp { $$ StatL }  StatL Stat Stat AsStat AsStat ID(j) $$ = $$ Expr ; ID(i) $$ = $$ Expr ;   Term   Term INTCT(2) INTCT(1) tab 1 { i = 1 ; j = 2 ; _ { i = 1 ; j = 2 ; } _ Reduzir: Ação: {tab--; tabular(); write (“}\n”);} Aceitar Deslocar

106 AsStat ID(j) $$2 = $$3 Expr ; ID(i) $$2 = $$3 Expr ;   Term
Comp { $$ StatL }  StatL Stat Stat AsStat AsStat ID(j) $$ = $$ Expr ; ID(i) $$ = $$ Expr ;   Term   Term INTCT(2) INTCT(1) As ações no pretty-printer produziram os resultados desejados { i = 1 ; j = 2 ; } _ Processamento de um não-terminal: é uma redução para ele Resultado

107 Programa 2.11: Conflitos no Yacc
%token a %token b %token c %token dolar %token erro %% SS : S dolar {printf ("Fim da analise\n"); return;} ; S : X C | A Y ; A : /* vazia */ | A a ; X : /* vazia */ | a X b ; Y : /* vazia */ | b Y c ; C : /* vazia */ | C c ; Arquivo conflito.y com uma gramática geradora da linguagem L = {aibjck | i=j ou j=k} A gramática é ambígua: Sentença aaabbbccc tem mais de uma árvore sintática

108 Executar: yacc conflito.y Resultado:
yylex () { char x; x = getchar (); while (x == ' ' || x == '\n' || x == '\t' || x == '\r') printf ("Caractere lido: %c\n", x); if (x == 'a') return a; if (x == 'b') return b; if (x == 'c') return c; if (x == '$') return dolar; return erro; } Executar: yacc conflito.y Resultado: yacc: 1 shift/reduce conflict, 1 reduce/reduce conflict. Arquivo conflito.y (continuação) O analisador gerado pelo Yacc não consegue tratar certas gramáticas Solução: Método mais geral

109 Executar: yacc –v conflito.y Abrir arquivo y.output
yylex () { char x; x = getchar (); while (x == ' ' || x == '\n' || x == '\t' || x == '\r') printf ("Caractere lido: %c\n", x); if (x == 'a') return a; if (x == 'b') return b; if (x == 'c') return c; if (x == '$') return dolar; return erro; } Executar: yacc –v conflito.y Abrir arquivo y.output Arquivo conflito.y (continuação) O analisador gerado pelo Yacc não consegue tratar certas gramáticas Solução: Método mais geral

110 Arquivo y.output: Contém um relatório da montagem do analisador Conflito shift-reduce: indecisão entre deslocar o átomo para a pilha ou fazer uma redução no topo da pilha Conflito reduce-reduce: indecisão na escolha de uma produção para reduzir no topo da pilha

111 Arquivo y.output - as produções são numeradas:
0 $accept : SS $end 1 SS : S dolar 2 S : X C 3 | A Y 4 A : 5 | A a 6 X : 7 | a X b 8 Y : 9 | b Y c 10 C : 11 | C c Produção arfificial do Yacc 0: shift/reduce conflict (shift 1, reduce 4) on a No estado 0 (zero – início da análise), diante de um ‘a’ na entrada, ele não sabe se o empilha e vai para o estado 1, ou se faz uma redução usando a produção 4 0: reduce/reduce conflict (reduce 4, reduce 6) on dolar No estado 0 (zero – início da análise), diante de um ‘$’ na entrada, ele não sabe se faz uma redução usando a produção 4 ou 6

112 ( ), ( ( ) ), ( ) ( ), ( ) ( ( ) ( ( ) ) ) ( ( ) )
Há gramáticas ambíguas que têm equivalentes não ambíguas Exemplo: gramática S  S S | ( S ) | ε geradora expressões com pares de parêntesis balanceados, tais como: ( ), ( ( ) ), ( ) ( ), ( ) ( ( ) ( ( ) ) ) ( ( ) ) Gramática equivalente: S  ε | S ( S )

113 Programa 2.12: Conflito por ações no início ou meio de produções
%% SS : S '$' {printf ("Fim da analise\n"); return;} ; S : | S '(' S ')' ; yylex () { char x; x = getchar (); while (x == ' ' || x == '\n' || x == '\t' || x == '\r') x = getchar (); printf ("Caractere lido: %c\n", x); if (x == '\(' || x == ')' || x == '$') return x; return '#'; } Programa correto para S  ε | S ( S ) Rodar para: ( ) ( ( ) ( ) ) ( ( ) ) $

114 Inserindo uma ação: %% SS : S '$' {printf ("Fim da analise\n"); return;} ; S : | {printf ("\nyyy");} S '(' S ')' ; yylex () { char x; x = getchar (); while (x == ' ' || x == '\n' || x == '\t' || x == '\r') x = getchar (); printf ("Caractere lido: %c\n", x); if (x == '\(' || x == ')' || x == '$') return x; return '#'; } yacc: 1 reduce/reduce conflict.

115 O conflito é em usar a produção 2 ou 3 para reduzir diante do ‘(’
Arquivo y.output: 0 $accept : SS $end 1 SS : S '$' 2 S : 3 $$1 : 4 S : $$1 S '(' S ')' O conflito é em usar a produção 2 ou 3 para reduzir diante do ‘(’ $$1 é um não-terminal fictício Cada caso tem sua solução particular Aqui, pode-se colocar a ação depois do S

116 Observações finais: Apesar do conflito, o Yacc gera o analisador O problema é que os resultados produzidos podem não ser corretos No projeto da disciplina, as produções do comando condicional irão gerar um conflito shift/reduce O analisador gerado resolverá o conflito de forma a obedecer à regra usual para o caso if-else


Carregar ppt "CES-41 COMPILADORES Aulas Práticas"

Apresentações semelhantes


Anúncios Google