CES41 COMPILADORES Aulas Prticas 2016 Captulo II A

  • Slides: 116
Download presentation
CES-41 COMPILADORES Aulas Práticas - 2016 Capítulo II A Ferramenta Yacc

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

Yacc é um gerador de analisadores sintáticos: n Tem como entrada a gramática livre

Yacc é um gerador de analisadores sintáticos: n 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 n Yacc (Yet Another Compiler-Compiler) do sistema UNIX também possui diversas versões para o sistema DOS (o Yacc do Mingw é uma delas) n O analisador gerado é um programa em Linguagem C

Programa 2. 1: Saída de dados n Criar na pasta Min. GW/bin um arquivo

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

%% prod: {printf ("hello friends!n"); } ; %% yylex () { return 0; }

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

Estrutura de um programa em Yacc: n Tal como em Lex, um programa em

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

Produções da gramática: n É a parte principal de um programa em Yacc n

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

Produções da gramática: n Exemplo: Sejam as produções: Expr OPAD Termo | Termo ID

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

Produções da gramática: n Ações podem aparecer no lado direito de uma produção vazia

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

Declarações: Nelas estão inclusas: n Em C, delimitadas por %{ e %}: - Declarações

Declarações: Nelas estão inclusas: n 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 n Declarações do Yacc (fora de %{ e %}) usadas para definir terminais, não-terminais, precedência de operadores, tipos dos atributos, etc.

Declarações: n Exemplo: para as produções anteriores expr : | ; termo | ;

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

Rotinas auxiliares: n São definições de funções em C, referenciadas nas ações das produções

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

%% prod : {printf ("hello friends!n"); } friends!n"); return; } ; %% yylex ()

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

%% prod : {printf ("hello friends!n"); } ; %% yylex () { Explicando os

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

%% prod : {printf ("hello friends!n"); } ; %% yylex () { Explicando os

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

%% prod : {printf ("hello friends!n"); } ; %% yylex () { Explicando os

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

%% prod : {printf ("hello friends!n"); } friends!n"); return; } ; %% yylex ()

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

Programa 2. 2: Entrada de dados n Criar um arquivo extensão. y (entra. y,

Programa 2. 2: Entrada de dados n 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; }

n Executar os seguintes comandos: yacc entra. y gcc y. tab. c yyerror. c

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

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

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

Programa 2. 3: Reconhecimento de frase n Rodar yacc e gcc para um arquivo

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

Programa 2. 3: Reconhecimento de frase n Rodar yacc e gcc para um arquivo

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

Programa 2. 4: Gramática S → ε | a S b %token a Experimente

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

Programa 2. 4: Gramática S → ε | a S b %token a Experimente

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

Exercício 2. 1: Escrever em Yacc, um analisador sintático para a seguinte gramática geradora

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 ab. Ac. D A ab. Ac | ε D dd. D |ε

Exercício 2. 2: Escrever em Yacc, um analisador sintático para a seguinte gramática geradora

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

Exercício 2. 3: Escrever em Yacc, um analisador sintático para a seguinte gramática geradora

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

Programa 2. 5: Yacc auxiliado por Lex n Programa em Flex no arquivo expr

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

n Programa em Yacc no arquivo expr 01. y %{ #include %} %token %token

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

line : expr DOLAR {printf("Fim da analisen"); return; } ; expr : expr OPAD

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

n Executar os seguintes comandos: flex expr 01. l yacc expr 01. y gcc

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

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

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

Programa 2. 6: Uso de atributos (calculadora simples) n Programa em Flex no arquivo

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

n Programa em Yacc no arquivo calc 01. y %{ #include #define %} %token

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

line : ; expr : { expr DOLAR { printf("valor: %dn", $1); } expr

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

term : { fat } | ; : | ; term OPMULT fat Rodar

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

n No Yacc, a análise é bottom-up (por deslocamento e redução) n Os átomos

n No Yacc, a análise é bottom-up (por deslocamento e redução) n Os átomos são obtidos e deslocados para uma pilha (deslocamento) n Quando no topo da pilha se formar o lado-direito de uma produção, tem-se uma ocasião para reduzir n 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 n Em caso positivo, substitui, na pilha, o lado-direito pelo lado-esquerdo da produção (redução) n Então, a ação no final da produção é executada

n Análise e cálculo da expressão 10 * (5 + 3)$ line : expr

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

n Análise e cálculo da expressão 10 * (5 + 3)$ line : expr

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

n Análise e cálculo da expressão 10 * (5 + 3)$ line : expr

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

n Análise e cálculo da expressão 10 * (5 + 3)$ line : expr

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

n Análise e cálculo da expressão 10 * (5 + 3)$ line : expr

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

n Análise e cálculo da expressão 10 * (5 + 3)$ line : expr

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

n Análise e cálculo da expressão 10 * (5 + 3)$ line : expr

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

n Análise e cálculo da expressão 10 * (5 + 3)$ line : expr

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

n Análise e cálculo da expressão 10 * (5 + 3)$ line : expr

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

n Análise e cálculo da expressão 10 * (5 + 3)$ line : expr

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

n Análise e cálculo da expressão 10 * (5 + 3)$ line : expr

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

n Análise e cálculo da expressão 10 * (5 + 3)$ line : expr

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

n Análise e cálculo da expressão 10 * (5 + 3)$ line : expr

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

n Análise e cálculo da expressão 10 * (5 + 3)$ line : expr

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

n Análise e cálculo da expressão 10 * (5 + 3)$ line : expr

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

n Análise e cálculo da expressão 10 * (5 + 3)$ line : expr

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

n Análise e cálculo da expressão 10 * (5 + 3)$ line : expr

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

n Análise e cálculo da expressão 10 * (5 + 3)$ line : expr

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

n Análise e cálculo da expressão 10 * (5 + 3)$ line : expr

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

n Análise e cálculo da expressão 10 * (5 + 3)$ line : expr

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

n Análise e cálculo da expressão 10 * (5 + 3)$ line : expr

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

n Análise e cálculo da expressão 10 * (5 + 3)$ line : expr

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

n Análise e cálculo da expressão 10 * (5 + 3)$ line : expr

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

n Análise e cálculo da expressão 10 * (5 + 3)$ line : expr

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

n Análise e cálculo da expressão 10 * (5 + 3)$ line : expr

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

n Análise e cálculo da expressão 10 * (5 + 3)$ line : expr

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

n Análise e cálculo da expressão 10 * (5 + 3)$ line : expr

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

n Análise e cálculo da expressão 10 * (5 + 3)$ line : expr

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

n Análise e cálculo da expressão 10 * (5 + 3)$ line : expr

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

n Análise e cálculo da expressão 10 * (5 + 3)$ line : expr

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

n Análise e cálculo da expressão 10 * (5 + 3)$ line : expr

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

n Análise e cálculo da expressão 10 * (5 + 3)$ line : expr

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

n Análise e cálculo da expressão 10 * (5 + 3)$ line : expr

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

n Análise e cálculo da expressão 10 * (5 + 3)$ line : expr

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

n Análise e cálculo da expressão 10 * (5 + 3)$ line : expr

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

n Análise e cálculo da expressão 10 * (5 + 3)$ line : expr

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

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

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

Programa 2. 7: Alteração no tipo dos atributos n Programa em Flex no arquivo

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

n Programa em Yacc no arquivo calc 02. y %{ #include #define %} %token

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

line : expr DOLAR { printf("valor: %gn", $1); return 0; } ; expr :

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

Programa 2. 8: Atributos de tipos alternativos n Programa em Flex no arquivo calc

Programa 2. 8: Atributos de tipos alternativos n Programa em Flex no arquivo calc 03. l delim ws digit ctint ctfloat %% [ tn] {delim}+ [0 -9] {digit}+. {digit}* Programa com constantes inteiras e reais

{ws} {ctint} { ; } {yylval. valint = atoi(yytext); return CTINT; } {ctfloat} {yylval.

{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 Agora yylval está sendo usado Deve ser uma union como apresentado no capítulo os campos: sobre Flex

n Programa em Yacc no arquivo calc 03. y %{ #include <stdio. h> #include

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

%type %token %token %% <valfloat> <valint> <valfloat> <atr> expr term DOLAR CTINT CTFLOAT OPAD

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

line : ; expr : { Aqui, $1 corresponde ao campo valfloat de alguma

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

term : { term OPMULT fat switch ($2) { case VEZES: $$ = $1

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

Programa 2. 9: Ações no início e meio das produções Arquivo %{ acaomeio. y

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

A : ; B : ; C : ; {w = 10; $$ =

A : ; B : ; C : ; {w = 10; $$ = 5*w; } B {$$ = 1; v = $1; y = $2; } C { x = $3; z = $4; printf ("- - -", v, w, x, y, z); return 0; } 'b' Ação no início ou meio de uma produção: 'c' Yacc cria uma produção vazia para um nãoterminal 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

n Nas produções de $$1 e $$2, $$ é o atributo do lado esquerdo

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

Para entrada bc: $$1 $$2 A : : : B C ; : :

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

Programa 2. 10: Pretty-Printer Dada uma entrada desorganizada do tipo: { i : =

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

n Programa em Flex no arquivo pretty 2016. l delim ws digito letra ctint

n Programa em Flex no arquivo pretty 2016. l delim ws digito letra ctint id %% {ws} {id} {ctint} "+" "-" "(" ")" "{" "}" "; " ": =". %% [ tn] {delim}+ [0 -9] [A-Za-z] {digito}+ {letra}({letra}|{digito})* { ; } {strcpy (yylval. cadeia, yytext); return ID; } {yylval. valint = atoi(yytext); return CTINT; } {yylval. atr = MAIS; return OPAD; } {yylval. atr = MENOS; return OPAD; } {return ABPAR; } {return FPAR; } {return ABCHAVE; } {return FCHAVE; } {return PVIRG; } {return ATRIB; } {yylval. carac = yytext[0]; return INVAL; }

n Programa em Yacc no arquivo pretty 2016. y %{ #include <stdio. h> #include

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

%token %token %token %% <cadeia> <valint> <atr> <carac> ID CTINT OPAD ABPAR FPAR ABCHAVE

%token %token %token %% <cadeia> <valint> <atr> <carac> ID CTINT OPAD ABPAR FPAR ABCHAVE FCHAVE PVIRG ATRIB INVAL

Cmd. Composto : ABCHAVE {tabular (); printf ("{n"); tab++; } List. Cmds FCHAVE {tab--;

Cmd. Composto : ABCHAVE {tabular (); printf ("{n"); tab++; } List. Cmds FCHAVE {tab--; tabular (); printf ("}n"); } ; List. Cmds : Comando | List. Cmds Comando ; Comando : Cmd. Atrib | Cmd. Composto ; Cmd. Atrib : tabular: dá tantas tabulações quanto for o valor de tab Depois de todo token imprime seu texto ID {tabular (); printf ("%s ", $1); } ATRIB {printf (": = "); } Expressao PVIRG {printf("; n"); } ; Para alguns tokens, imprime ‘n’

Expressao Termo : | ; : | | Termo Expressao OPAD { if ($2

Expressao Termo : | ; : | | Termo Expressao OPAD { if ($2 == MAIS) printf ("+ "); else printf ("- "); } Termo ID {printf ("%s ", $1); } CTINT {printf ("%d ", $1); } ABPAR {printf("( "); } Expressao FPAR {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

Outra forma de apresentar a gramática (com abreviaturas): CComp : LCmds : Cmd :

Outra forma de apresentar a gramática (com abreviaturas): CComp : LCmds : Cmd : CAtrib : Expr Term $$1: $$2: $$3: ‘{’ $$1 LCmds ‘}’ {tab--; tabular (); write("}n"); } ; Cmd | LCmds Cmd ; CAtrib | CComp ; ID $$2 “=” $$3 Expr ‘; ’ {write("; n"); } ; : Term | Expr OPAD $$4 Term ; : ID {write($1); } | CTINT {write($1); } |{tabular ‘(’ ‘)’ {if {write (")"); } ; ($2 == MAIS) write (‘+’); (); $$5 Expr$$4: else printf (‘-’); } write ("{n"); tab++; } {tabular (); write ($1); } $$5: {write (‘(’); } {write (": ="); }

n A análise bottom-up por deslocamento e redução, feita pelo Yacc, simula o caminhamento

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

CComp Seja a pós-ordem: { tab $$1 LCmds Cmd 10 } Os elementos Cmd

CComp Seja a pós-ordem: { tab $$1 LCmds Cmd 10 } Os elementos Cmd dos retângulos formam a pilha CAtrib ID(j) $$2 : = $$3 Expr ; ID(i) Term $$2 : = Reduzir: Ação: Deslocar vazio write ("{n"); { tabular (); CTINT(2) tab++; } $$3 Expr { _ ; _ Term Tela do vídeo

CComp Seja a pós-ordem: { tab $$1 LCmds Cmd } Cmd CAtrib ID(j) $$2

CComp Seja a pós-ordem: { tab $$1 LCmds Cmd } Cmd CAtrib ID(j) $$2 : = $$3 Expr ; ID(i) Term $$2 : = Reduzir: Ação: Deslocar vazio {tabular (); write ($1); } CTINT(2) 1 $$3 Expr { _ Term ; i_

CComp Seja a pós-ordem: { tab $$1 LCmds Cmd } Cmd CAtrib ID(j) $$2

CComp Seja a pós-ordem: { tab $$1 LCmds Cmd } Cmd CAtrib ID(j) $$2 : = $$3 Expr ; ID(i) Term $$2 Reduzir: Ação: Deslocar vazio {write (“: ="); } CTINT(2) 1 : = $$3 Expr { ; ii_: =_ Term

CComp Seja a pós-ordem: { tab $$1 LCmds Cmd } Cmd CAtrib ID(j) $$2

CComp Seja a pós-ordem: { tab $$1 LCmds Cmd } Cmd CAtrib ID(j) $$2 : = $$3 Expr ; ID(i) Term $$2 Reduzir: Ação: Deslocar {write {$$ = $1); } ($1); }irrelevante CTINT(2) 1 : = $$3 Expr { ; i : =_1_ Term

CComp Seja a pós-ordem: { tab $$1 LCmds Cmd } Cmd CAtrib ID(j) $$2

CComp Seja a pós-ordem: { tab $$1 LCmds Cmd } Cmd CAtrib ID(j) $$2 : = $$3 Expr ; ID(i) Term $$2 : = $$3 Expr { CTINT(2) ; i : = 1 1_; _ Reduzir: Ação: Deslocar {write {$$ = $1); } (“; n”); } irrelevante 1 Term

CComp Seja a pós-ordem: { tab $$1 LCmds Cmd } Cmd CAtrib ID(j) $$2

CComp Seja a pós-ordem: { tab $$1 LCmds Cmd } Cmd CAtrib ID(j) $$2 : = $$3 Expr ; ID(i) Term $$2 : = $$3 Expr { _ Reduzir: Ação: Deslocar vazio {tabular(); write ($1); } CTINT(2) 1 Term ; i : = 1 ; j_

CComp Seja a pós-ordem: { tab $$1 LCmds Cmd } Cmd CAtrib ID(j) $$2

CComp Seja a pós-ordem: { tab $$1 LCmds Cmd } Cmd CAtrib ID(j) $$2 : = $$3 Expr ; ID(i) Term $$2 Reduzir: Ação: Deslocar vazio {write (“: =”); } CTINT(2) 1 : = $$3 Expr { ; i : = 1 ; jj_: =_ Term

CComp Seja a pós-ordem: { tab $$1 LCmds Cmd } Cmd CAtrib ID(j) $$2

CComp Seja a pós-ordem: { tab $$1 LCmds Cmd } Cmd CAtrib ID(j) $$2 : = $$3 Expr ; ID(i) Term $$2 Reduzir: Ação: Deslocar {write {$$ = $1); } ($1); }irrelevante CTINT(2) 1 : = $$3 Expr { ; i : = 1 ; j : =_2_ Term

CComp Seja a pós-ordem: { tab $$1 LCmds Cmd } Cmd CAtrib ID(j) $$2

CComp Seja a pós-ordem: { tab $$1 LCmds Cmd } Cmd CAtrib ID(j) $$2 : = $$3 Expr ; ID(i) Term $$2 Reduzir: Ação: Deslocar {write {$$ = $1); } (“; n”); } irrelevante CTINT(2) 1 : = $$3 Expr { ; i : = 1 ; j : = 2 2_; Term _

CComp Seja a pós-ordem: { tab $$1 LCmds Cmd } Cmd CAtrib ID(j) $$2

CComp Seja a pós-ordem: { tab $$1 LCmds Cmd } Cmd CAtrib ID(j) $$2 : = $$3 Expr ; ID(i) Term $$2 : = $$3 Reduzir: Ação: Aceitar Deslocar {tab--; tabular(); write (“}n”); } CTINT(2) 01 Expr { ; i : = 1 ; j : = 2 ; Term } _ _

CComp { As ações no prettyprinter produziram os resultados desejados $$1 LCmds Cmd }

CComp { As ações no prettyprinter produziram os resultados desejados $$1 LCmds Cmd } Cmd CAtrib ID(j) $$2 : = $$3 Expr ; ID(i) Term $$2 Processamento de um não-terminal: é uma redução para ele CTINT(2) : = $$3 Expr { ; i : = 1 ; j : = 2 ; Term } _ Resultado

Programa 2. 11: Conflitos no Yacc %token a %token b %token c %token dolar

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

yylex () { char x; Arquivo conflito. y x = getchar (); (continuação) while

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

yylex () { char x; Arquivo conflito. y x = getchar (); (continuação) while

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

Arquivo y. output: n Contém um relatório da montagem do analisador n Conflito shift-reduce:

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

Arquivo y. output - as produções são numeradas: 0 1 2 3 4 5

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

n n Há gramáticas ambíguas que têm equivalentes não ambíguas Exemplo: gramática S S

n n 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: ( ), ( ( ) ), ( ) ( ( ) ) n Gramática equivalente: S ε | S ( S )

Programa 2. 12: Conflito por ações no início ou meio de produções %% SS

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

Inserindo uma ação: %% SS : S '$' {printf ("Fim da analisen"); return; }

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

Arquivo y. output: 0 1 2 3 4 $accept : SS $end SS :

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

Observações finais: n Apesar do conflito, o Yacc gera o analisador n O problema

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