CES41 COMPILADORES Aulas Prticas 2015 Captulo II A

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

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

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

Yacc é um gerador de analisadores sintáticos: n Têm 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 produção yylex () { Não pode haver função main return 0; 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' '6' {printf ("Reconheco!n"); return; } %% yylex () { return getchar (); } Executar recfrase com: COMP 15 16 17 163 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 15 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 dados %token dolar %token erro %% 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 dados %token dolar %token erro %% 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 os 3 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 yylval fat Os atributos dos não-terminais devem ser calculados nas ações CTE ABPAR expr FPAR {$$ = $2; } %% #include "lex. yy. c" 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ãoterminais

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 %% 10. 5 * (5. 2 + 3. 3)$ #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 %% Deve ser uma union com os Agora yylval está sendo usado campos: como apresentado no capítulo sobre Flex valint, valfloat e atr

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 variáveis de float valfloat; 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 10. 5 * (5 + 3. 3)$

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 %% apóstrofos são A : {w = 10; $$ = 5*w; } B tokens {$$ = 1; v = $1; y = $2; } C { 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 = 1;

Programa 2. 10: Pretty-Printer Dada uma entrada desorganizada do tipo: { i = 1; i + 1; i {j = 0; { = j + 1; - (x-3) + c; } i 1; } } i = = 0; j a = b 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 ; } = i - } É necessário mudar de linha e tabular oportunamente

n Programa em Flex no arquivo pretty 2015. l delim ws digito letra intct

n Programa em Flex no arquivo pretty 2015. l delim ws digito letra intct id %% {ws} {id} {intct} "+" "-" "(" ")" "{" "}" "; " "=". %% [ tn] {delim}+ [0 -9] [A-Za-z] {digito}+ {letra}({letra}|{digito})* { ; } {strcpy (yylval. cadeia, yytext); return ID; } {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; }

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

n Programa em Yacc no arquivo pretty 2015. 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 INTCT ADOP OPPAR CLPAR OPBRACE

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

Comp. Stat : OPBRACE {tabular (); printf ("{n"); tab++; } Stat. List CLBRACE {tab--;

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

Expression Term : | ; : | | Term Expression ADOP { if ($2

Expression Term : | ; : | | Term Expression ADOP { if ($2 == MAIS) printf ("+ "); else printf ("- "); } 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

Outra forma de apresentar a gramática (com abreviaturas): Comp : Stat. L : Stat

Outra forma de apresentar a gramática (com abreviaturas): Comp : Stat. L : Stat As. Stat : Expr Term $$1: $$2: $$3: ‘{’ $$1 Stat. L ‘}’ {tab--; tabular (); write("}n"); } ; Stat | Stat. L Stat ; : As. Stat | Comp ; ID $$2 “=” $$3 Expr ‘; ’ {write("; n"); } ; : Term | Expr OPAD $$4 Term ; : {tabular ID(); {write($1); } INTCT $$4: | {if ($2 =={write($1); } MAIS) write (‘+’); |write ‘(’ $$5 Expr ‘)’ {write ; else printf(")"); } (‘-’); } ("{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

Comp Seja a pós-ordem: { tab 10 $$1 Stat. L } Stat. L Os

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

Comp Seja a pós-ordem: { tab $$1 Stat. L Stat } Stat As. Stat

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

Comp Seja a pós-ordem: { tab $$1 Stat. L Stat } Stat As. Stat

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

Comp Seja a pós-ordem: { tab $$1 Stat. L Stat } Stat As. Stat

Comp Seja a pós-ordem: { tab $$1 Stat. L Stat } Stat As. Stat ID(j) $$2 = $$3 Expr ; ID(i) Term $$2 Reduzir: Ação: Deslocar {write {$$ = $1); } ($1); }irrelevante INTCT(2) 1 = $$3 Expr { ; i= =_1_ Term

Comp Seja a pós-ordem: { tab $$1 Stat. L Stat } Stat As. Stat

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

Comp Seja a pós-ordem: { tab $$1 Stat. L Stat } Stat As. Stat

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

Comp Seja a pós-ordem: { tab $$1 Stat. L Stat } Stat As. Stat

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

Comp Seja a pós-ordem: { tab $$1 Stat. L Stat } Stat As. Stat

Comp Seja a pós-ordem: { tab $$1 Stat. L Stat } Stat As. Stat ID(j) $$2 = $$3 Expr ; ID(i) Term $$2 Reduzir: Ação: Deslocar {write {$$ = $1); } ($1); }irrelevante INTCT(2) 1 = $$3 Expr { ; i=1; j= =_2_ Term

Comp Seja a pós-ordem: { tab $$1 Stat. L Stat } Stat As. Stat

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

Comp Seja a pós-ordem: { tab $$1 Stat. L Stat } Stat As. Stat

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

Comp { As ações no prettyprinter produziram os resultados desejados $$1 Stat. L Stat

Comp { As ações no prettyprinter produziram os resultados desejados $$1 Stat. L Stat } Stat As. Stat ID(j) $$2 = $$3 Expr ; ID(i) Term $$2 Processamento de um não-terminal: é uma redução para ele INTCT(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 (continuação) x = getchar (); while

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

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

yylex () { char x; Arquivo conflito. y (continuação) x = getchar (); while (x == ' ' || x == 'n' || x == 't' || x == 'r') x = getchar (); printf ("Caractere lido: %cn", x); if (x == 'a') return a; O analisador gerado pelo if (x == 'b') return b; Yacc não consegue tratar if (x == 'c') return c; certas gramáticas if (x == '$') return dolar; 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 4) S : X C on a | A Y No estado 0 (zero – início da análise), A : diante de um ‘a’ na entrada, ele não sabe | A a se o empilha e vai para o estado 1, ou se faz X : uma redução usando a produção 4 | a X b Y : 0: reduce/reduce conflict (reduce 4, reduce | b Y c 6) on dolar C : No estado 0 (zero – início da análise), | C c diante de um ‘$’ na entrada, ele não sabe se faz uma redução usando a produção 4

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