5.6 – complementos de yacc 5.6.1 – usando yacc com gramáticas ambíguas gramáticas ambíguas...
TRANSCRIPT
5.6 – Complementos de 5.6 – Complementos de YaccYacc
5.6.1 – Usando Yacc com gramáticas 5.6.1 – Usando Yacc com gramáticas ambíguasambíguas
Gramáticas ambíguasGramáticas ambíguas causam causam conflitosconflitos durante a durante a construção de um analisador sintático pelo construção de um analisador sintático pelo YaccYacc
Os Os tipostipos de conflitos são: de conflitos são:
Deslocamento-redução: Deslocamento-redução: o analisador tanto o analisador tanto pode pode deslocardeslocar um átomo para a pilha, como um átomo para a pilha, como pode pode reduzirreduzir o topo da pilha por uma o topo da pilha por uma produçãoprodução
Redução-redução: Redução-redução: o analisador pode usar o analisador pode usar mais mais de uma produçãode uma produção para para reduzirreduzir o topo da pilha o topo da pilha
Há Há regrasregras para a solução de para a solução de ambiguidades ambiguidades
Yacc Yacc gera analisadores mais gera analisadores mais eficientes eficientes para para gramáticas ambíguasgramáticas ambíguas do que para do que para gramáticas gramáticas não ambíguasnão ambíguas
Exemplo 5.34:Exemplo 5.34: Programa para análise da Programa para análise da seguinte seguinte gramática ambígua gramática ambígua para cálculo de para cálculo de expressões:expressões:
E E E + E | E - E | E * E | E / E | ( E ) | - E E + E | E - E | E * E | E / E | ( E ) | - E
| num| num
Com a seguinte Com a seguinte precedência de operadoresprecedência de operadores::
‘‘*’*’ e e ‘/’‘/’ tem precedência sobre tem precedência sobre ‘+’‘+’ e e ‘-’‘-’ Menos-unárioMenos-unário tem precedência sobre tem precedência sobre ‘*’‘*’ e e ‘/’‘/’
O programa deve calcular expressões de valor realO programa deve calcular expressões de valor real
E E E + E | E - E | E * E | E / E | ( E ) | - E + E | E - E | E * E | E / E | ( E ) | - E E
| num| num
A gramática é A gramática é ambíguaambígua pois para a sentença pois para a sentença 5 5 + 8 * 3+ 8 * 3 tem duas árvores sintáticas tem duas árvores sintáticas
E
E + E
5 E * E
8 3
E
E * E
E + E 3
5 8
Programa com regras para Programa com regras para eliminação de eliminação de ambiguidadesambiguidades e e comandos de escritacomandos de escrita para para mostrar as mostrar as reduçõesreduções feitas: feitas:
%{%{
#include#include <stdio.h><stdio.h>
#include#include <ctype.h><ctype.h>
#define #define YYSTYPEYYSTYPE double double
%}%}
%token%token NUMNUM
%left%left '+' '-''+' '-'
%left%left '*' '/''*' '/'
%right%right MENUNMENUN
%%%%
Declarações para solução de ambiguidades
lineline :: expr expr '$''$'
{printf ( "Valor: %g\n", {printf ( "Valor: %g\n", $1$1););
returnreturn 0;} 0;}
;;
exprexpr :: expr '+' exprexpr '+' expr
{{$$$$ = = $1$1 + + $3$3;;
printf ("Regra1: %g = %g + %g\n", printf ("Regra1: %g = %g + %g\n", $$$$, , $1$1, , $3$3);});}
|| expr '-' exprexpr '-' expr
{{$$$$ = = $1$1 - - $3$3;;
printf ("Regra2: %g = %g - %g\n", printf ("Regra2: %g = %g - %g\n", $$$$, , $1$1, , $3$3);});}
|| expr '*' exprexpr '*' expr
{{$$$$ = = $1$1 * * $3$3;;
printf ("Regra3: %g = %g * %g\n", printf ("Regra3: %g = %g * %g\n", $$$$, , $1$1, , $3$3);});}
|| expr '/' exprexpr '/' expr
{{$$$$ = = $1$1 / / $3$3;;
printf ("Regra4: %g = %g / %g\n", printf ("Regra4: %g = %g / %g\n", $$$$, , $1$1, , $3$3);});}
|| '(' expr ')''(' expr ')'
{{$$ $$ = = $2$2; ;
printf ("Regra5: %g = ( %g )\n", printf ("Regra5: %g = ( %g )\n", $$$$, , $2$2);});}
| | '-' expr'-' expr %prec MENUN%prec MENUN
{{$$$$ = - = -$2$2;;
printf ("Regra6: %g = - %g \n", printf ("Regra6: %g = - %g \n", $$$$, , $2$2);});}
|| NUMNUM
{{$$$$ = = $1$1; printf ("Regra7: %g = %g\n", ; printf ("Regra7: %g = %g\n", $$$$, , $1$1);});}
;;
%%%%
Dispositivo para solução de ambiguidades
yylex () {yylex () {
int c;int c;
dodo
c = getchar ();c = getchar ();
while (c == ' ');while (c == ' ');
if (c == '.' || isdigit (c)) {if (c == '.' || isdigit (c)) {
ungetc (c, stdin);ungetc (c, stdin);
scanf ("%lf", &yylval) ;scanf ("%lf", &yylval) ;
return (NUM);return (NUM);
}}
return c;return c;
}}
A seguir, são descritas A seguir, são descritas regras e dispositivosregras e dispositivos de programação do de programação do YaccYacc para solucionar para solucionar ambiguidadesambiguidades
Por Por defaultdefault, o conflito , o conflito redução-reduçãoredução-redução é é resolvido em favor da resolvido em favor da produção que aparece produção que aparece primeiroprimeiro na lista de produções na lista de produções
Por Por defaultdefault, o conflito , o conflito deslocamento-deslocamento-reduçãoredução é resolvido em favor do é resolvido em favor do deslocamentodeslocamento
No exemplo anterior, não fosse pelas No exemplo anterior, não fosse pelas regras regras de precedênciade precedência a serem comentadas logo a a serem comentadas logo a seguir, a forma sentencial:seguir, a forma sentencial:
provocaria o deslocamento do ‘+’ para o topo provocaria o deslocamento do ‘+’ para o topo da pilhada pilha
A soma seria realizada antes da multiplicaçãoA soma seria realizada antes da multiplicação
PilhaPilha EntradaEntrada
expr ‘*’ expr ‘*’ exprexpr
‘‘+’ 3+’ 3
Nas declarações do programa Nas declarações do programa YaccYacc, pode-se atribuir , pode-se atribuir precedênciasprecedências e e associatividadesassociatividades aos terminais da gramática; sejam as aos terminais da gramática; sejam as declarações:declarações:
%left%left '+' '-''+' '-'
%left%left '*' '/''*' '/'
%right%right '~' '~' (menos unário) (menos unário)
'+' e '-' têm mesma precedência'+' e '-' têm mesma precedência '*' e '/' têm mesma precedência'*' e '/' têm mesma precedência A precedência cresce de cima para baixoA precedência cresce de cima para baixo
No programa aparece: No programa aparece: %right%right MENUN MENUN
provocaria o deslocamento do ‘+’ para o topo da pilhaprovocaria o deslocamento do ‘+’ para o topo da pilha
A soma seria realizada antes da multiplicaçãoA soma seria realizada antes da multiplicação
Diferentes
Cada produção em Cada produção em YaccYacc também tem também tem associada a si uma associada a si uma precedênciaprecedência e uma e uma associatividadeassociatividade::
Por default, é a precedência e Por default, é a precedência e associatividade de associatividade de seu terminal mais a seu terminal mais a direitadireita
Exemplo: a precedência e associatividade Exemplo: a precedência e associatividade da produção da produção A A a B c D e F G a B c D e F G será a será a de de ‘e’‘e’
Na decisão (deslocar Na decisão (deslocar ‘a’‘a’) ou (reduzir por ) ou (reduzir por AA) haverá deslocamento se ) haverá deslocamento se ‘a’‘a’ tiver tiver maior precedência que maior precedência que AA, e vice-versa, e vice-versa
Na forma sentencial:Na forma sentencial:
haverá redução, pois a produção haverá redução, pois a produção
expr ‘*’ expr expr ‘*’ expr tem a precedência tem a precedência de de ‘*’‘*’
que é maior que a de que é maior que a de ‘+’‘+’
PilhaPilha EntradaEntrada
expr ‘*’ exprexpr ‘*’ expr ‘‘+’ 3+’ 3
Na declaração Na declaração %left ‘-’%left ‘-’, o operador , o operador ‘-’‘-’ é é associativo à esquerdaassociativo à esquerda; a seguinte forma ; a seguinte forma sentencial causa redução:sentencial causa redução:
A expressão A expressão 5-3-1 = 2-1 = 15-3-1 = 2-1 = 1
Se fosse Se fosse %right ‘-’%right ‘-’, causaria deslocamento, causaria deslocamento
O cálculo de O cálculo de 5-3-15-3-1 seria seria 5-3-1 = 5-2 = 35-3-1 = 5-2 = 3
PilhaPilha EntradaEntrada
expr ‘-’ exprexpr ‘-’ expr ‘‘-’ 3-’ 3
Pode-se também Pode-se também forçar uma produçãoforçar uma produção a ter a ter uma determinada uma determinada precedênciaprecedência
O programa visto apresenta:O programa visto apresenta:
%left%left '+' '-''+' '-'
%left%left '*' '/''*' '/'
%right%right MENUNMENUN
- - - - - - - - - - - - - - - -
expr expr | '-' expr | '-' expr %prec MENUN%prec MENUN
Esta produção é forçada a ter precedência Esta produção é forçada a ter precedência maior que maior que ‘+’‘+’, , ‘-’‘-’, , ‘*’‘*’, , ‘/’‘/’
Exemplo: Exemplo: o programa visto produziu os o programa visto produziu os seguintes resultados experimentais:seguintes resultados experimentais:
1) Entrada: 5-2-2$Regra7: 5 = 5Regra7: 2 = 2Regra2: 3 = 5 - 2Regra7: 2 = 2Regra2: 1 = 3 - 2Valor: 1
2) Trocando %left '+' '-' por %right '+' '-': Entrada: 5-2-2$Regra7: 5 = 5Regra7: 2 = 2Regra7: 2 = 2Regra2: 0 = 2 - 2Regra2: 5 = 5 - 0Valor: 5
Exemplo: Exemplo: o programa visto produziu os o programa visto produziu os seguintes resultados experimentais:seguintes resultados experimentais:
3) Destrocando:
Entrada: 5*-(3+2)$Regra7: 5 = 5Regra7: 3 = 3Regra7: 2 = 2Regra1: 5 = 3 + 2Regra5: 5 = ( 5 )Regra6: -5 = - 5Regra3: -25 = 5 * -5Valor: -25
4) Entrada: -3+8$Regra7: 3 = 3Regra6: -3 = - 3Regra7: 8 = 8Regra1: 5 = -3 + 8Valor: 5
5) Trocando %rightMENUN
%left '+' '-'
%left '*' '/'
Entrada: -3+8$Regra7: 3 = 3Regra7: 8 = 8Regra1: 11 = 3 + 8Regra6: -11 = - 11Valor: -11
5.6.2 – Notificação e tratamento de erros 5.6.2 – Notificação e tratamento de erros no Yaccno Yacc
Em Em YaccYacc, o tratamento de , o tratamento de erroserros pode ser feito pode ser feito usando usando produçõesproduções de errosde erros entre as produções entre as produções da gramáticada gramática
Primeiramente deve-se decidir Primeiramente deve-se decidir quais não-quais não-terminaisterminais da gramática da gramática terão essas produçõesterão essas produções
Esses podem ser Esses podem ser não-terminaisnão-terminais que possuam que possuam átomosátomos em suas produções normais, para que em suas produções normais, para que mensagensmensagens notificando a notificando a faltafalta deles possam ser deles possam ser emitidasemitidas
Ou então outros Ou então outros estratégicosestratégicos geradores de geradores de expressões, comandos, sub-programas, etc.expressões, comandos, sub-programas, etc.
Seja Seja AA um não-terminal um não-terminal escolhidoescolhido; introduz-se, na ; introduz-se, na gramática, produções da forma gramática, produções da forma A A error error
e e são são cadeiascadeias de terminais e ou não-terminais, de terminais e ou não-terminais, vaziasvazias ou não ou não
errorerror é uma palavra é uma palavra reservadareservada do do YaccYacc (um (um token token especial)especial)
Na Na montagemmontagem do analisador, as produções de do analisador, as produções de erroserros são tratadas como são tratadas como produções normaisproduções normais da da gramáticagramática
No entanto, quando o analisador produzido No entanto, quando o analisador produzido encontra um erroencontra um erro, a manipulação dos , a manipulação dos estadosestados e e da da pilhapilha é é diferentediferente do normal do normal
Encontrando um erroEncontrando um erro, , desempilha-sedesempilha-se símbolos e estados, até encontrar um símbolos e estados, até encontrar um estadoestado no topo da pilha, cujo no topo da pilha, cujo conjunto de itensconjunto de itens contenha um item do tipo contenha um item do tipo A A . error . error
Programa
analisador LR
Entrada
0Pilha
Saída
Tabelas LR
erro
Estado com item do tipo A . error
Encontrando um erroEncontrando um erro, , desempilha-sedesempilha-se símbolos e estados, até encontrar um símbolos e estados, até encontrar um estadoestado no topo da pilha, cujo no topo da pilha, cujo conjunto de itensconjunto de itens contenha um item do tipo contenha um item do tipo A A . error . error
Programa
analisador LR
Entrada
0Pilha
Saída
Tabelas LR
erro
Estado com item do tipo A . error
Desloca-seDesloca-se o átomo fictício o átomo fictício error error para o para o topo topo da pilha, como se tivesse visto um da pilha, como se tivesse visto um erroerro na na entradaentrada
Programa
analisador LR
Entrada
0Pilha
Saída
Tabelas LR
erro
Estado com item do tipo A . error
error
Estado com item do tipo A error .
Se Se for for vaziavazia, , reduz-sereduz-se imediatamente para imediatamente para AA e e uma eventual uma eventual ação semânticaação semântica pode ocorrer pode ocorrer (notificação e tratamento de erros (notificação e tratamento de erros programadoprogramado))
Programa
analisador LR
Entrada
0Pilha
Saída
Tabelas LR
erro
Estado com item do tipo A . error
error
Estado com item do tipo A error .
Se Se for for vaziavazia, , reduz-sereduz-se imediatamente para imediatamente para AA e e uma eventual uma eventual ação semânticaação semântica pode ocorrer pode ocorrer (notificação e tratamento de erros (notificação e tratamento de erros programadoprogramado))
Programa
analisador LR
Entrada
0Pilha
Saída
A
Tabelas LR
erro
Se Se não for não for vaziavazia::
Programa
analisador LR
Entrada
0Pilha
Saída
A
Tabelas LR
erro
Se Se não for não for vaziavazia::
o analisador observa os o analisador observa os próximos símbolospróximos símbolos de entrada, até encontrar uma de entrada, até encontrar uma sub-cadeiasub-cadeia redutívelredutível para para
Programa
analisador LR
Entrada
0Pilha
Saída
Tabelas LR
erro
Estado com item do tipo A . error
error
Estado com item do tipo A error .
redutível
para
Essa sub-cadeia é deslocada para a pilha Essa sub-cadeia é deslocada para a pilha provocando a redução para provocando a redução para AA
Programa
analisador LR
Entrada
0Pilha
Saída
Tabelas LR
erro
Estado com item do tipo A . error
error
Estado com item do tipo A error .
redutível
para
Essa sub-cadeia é deslocada para a pilha Essa sub-cadeia é deslocada para a pilha provocando a redução para provocando a redução para AA
Programa
analisador LR
Entrada
0Pilha
Saída
A
Tabelas LR
erro
redutível
para O caso mais comum é o de ser uma sequência de terminais
Também uma eventual Também uma eventual ação semânticaação semântica pode pode ocorrer (notificação e tratamento de erros ocorrer (notificação e tratamento de erros programadoprogramado))
Programa
analisador LR
Entrada
0Pilha
Saída
A
Tabelas LR
erro
redutível
para O caso mais comum é o de ser uma sequência de terminais
O analisador deixa o estado de erro e O analisador deixa o estado de erro e volta ao volta ao normalnormal, através da execução de uma macro: , através da execução de uma macro: yyerrokyyerrok
O exemplo a seguir é O exemplo a seguir é experimentalexperimental e e relativamente relativamente simplessimples::
Mostra os casos de Mostra os casos de e e serem vazios e serem vazios e compostos de um e dois terminaiscompostos de um e dois terminais
Mostra também o uso da macro Mostra também o uso da macro yyerrokyyerrok
A literatura (livros, Internet, etc.) apresenta A literatura (livros, Internet, etc.) apresenta outros dispositivos para recuperação de erros no outros dispositivos para recuperação de erros no YaccYacc
Exemplo:Exemplo: programa para a seguinte programa para a seguinte gramática:gramática:
Função : Cabeçalho DeclaraçõesFunção : Cabeçalho Declarações
Cabeçalho : ID ( ) Cabeçalho : ID ( )
Declarações : { ListDecl }Declarações : { ListDecl }
ListDecl : ListDecl : εε | ListDecl Declaração | ListDecl Declaração
Declaração : Tipo ListElemDecl ;Declaração : Tipo ListElemDecl ;
Tipo : INT | FLOAT | CHAR | BOOLTipo : INT | FLOAT | CHAR | BOOL
ListElemDecl : ElemDecl ListElemDecl : ElemDecl
| ListElemDecl , ElemDecl| ListElemDecl , ElemDecl
ElemDecl : IDElemDecl : ID
Analisador léxico:Analisador léxico:delimdelim [ \t\n\r][ \t\n\r]wsws {delim}+{delim}+letraletra [A-Za-z][A-Za-z]digitodigito [0-9][0-9]idid {letra}({letra}|{digito})*{letra}({letra}|{digito})*%%%%{ws}{ws} { ;}{ ;}boolbool {return BOOL;}{return BOOL;}charchar {return CHAR;}{return CHAR;}floatfloat {return FLOAT;}{return FLOAT;}intint {return INT;}{return INT;}{id}{id} {strcpy (yylval.cadeia, yytext); return ID;}{strcpy (yylval.cadeia, yytext); return ID;}"(""(" {return ABPAR;}{return ABPAR;}")"")" {return FPAR;}{return FPAR;}"{""{" {return ABCHAV;}{return ABCHAV;}"}""}" {return FCHAV;}{return FCHAV;}";"";" {return PVIRG;}{return PVIRG;}",""," {return VIRG;}{return VIRG;}.. {yylval.carac = yytext[0]; return INVAL;}{yylval.carac = yytext[0]; return INVAL;}%%%%
Analisador sintático:Analisador sintático:
%{%{
#include <string.h>#include <string.h>
#include <stdio.h>#include <stdio.h>
#include <stdlib.h>#include <stdlib.h>
void Esperado (char *);void Esperado (char *);
%}%}
%union {%union {
char cadeia[50];char cadeia[50];
char carac;char carac;
}}
%token%token BOOLBOOL
%token%token CHARCHAR
%token%token FLOATFLOAT
%token%token INTINT
%token%token <cadeia><cadeia> IDID
%token%token ABPARABPAR
%token%token FPARFPAR
%token%token ABCHAVABCHAV
%token%token FCHAVFCHAV
%token%token PVIRGPVIRG
%token%token VIRG VIRG
%token%token <carac><carac> INVALINVAL
%%%%
FuncaoFuncao : Cabecalho Declaracoes: Cabecalho Declaracoes;;
Cabecalho Cabecalho : ID ABPAR {printf ("%s \( ", : ID ABPAR {printf ("%s \( ", $1);} FPAR $1);} FPAR {printf (")\n");}{printf (")\n");}
| ID error {printf ("%s ", $1); | ID error {printf ("%s ", $1); Esperado ("(");} Esperado ("(");} FPAR {yyerrok; printf (")\n");}FPAR {yyerrok; printf (")\n");}| ID error {printf ("%s\n", $1); | ID error {printf ("%s\n", $1); Esperado ("( )"); yyerrok;}Esperado ("( )"); yyerrok;}| error {Esperado | error {Esperado
("Identificador");} ("Identificador");} ABPAR FPAR {yyerrok; printf ABPAR FPAR {yyerrok; printf
("() ");}("() ");}| ID ABPAR error {printf ("%s (\n", | ID ABPAR error {printf ("%s (\n",
$1); $1); Esperado (")"); yyerrok;} Esperado (")"); yyerrok;};;
Declaracoes : ABCHAV {printf ("\{\n");} Declaracoes : ABCHAV {printf ("\{\n");} ListDecl ListDecl
FCHAV {printf ("}\n");}FCHAV {printf ("}\n");};;
ListDeclListDecl ::| ListDecl Declaracao| ListDecl Declaracao;;
DeclaracaoDeclaracao : Tipo ListElemDecl : Tipo ListElemDecl PVIRG PVIRG
{printf ("; \n");}{printf ("; \n");}| Tipo ListElemDecl error | Tipo ListElemDecl error
PVIRG PVIRG {Esperado("';' "); {Esperado("';' "); yyerrok;}yyerrok;}
;;
Tipo Tipo : INT : INT {printf ("int ");} {printf ("int ");}| FLOAT {printf ("float ");}| FLOAT {printf ("float ");}| CHAR| CHAR {printf ("char ");} {printf ("char ");}| BOOL| BOOL {printf ("bool ");} {printf ("bool ");};;
ListElemDecl : ElemDeclListElemDecl : ElemDecl| ListElemDecl VIRG {printf (", | ListElemDecl VIRG {printf (",
");} ");} ElemDecl ElemDecl;;
ElemDecl : ID {printf ("%s ", $1);}ElemDecl : ID {printf ("%s ", $1);}| error ID | error ID {Esperado("Identificador"); {Esperado("Identificador");
yyerrok;}yyerrok;}; ;
%%%%#include "lex.yy.c"#include "lex.yy.c"
void Esperado (char *s) {void Esperado (char *s) {printf ("\n***** Esperado: %s \n", s);printf ("\n***** Esperado: %s \n", s);
}}
A seguir alguns testesA seguir alguns testes e seus resultadose seus resultados
1) Programa para teste: (sem erros)1) Programa para teste: (sem erros)
main ( )main ( ){{
int i, j, k, fat;int i, j, k, fat;bool m, n;bool m, n;float x;float x;char a;char a;
}}
Resultado:
main ( ){int i , j , k , fat ;bool m , n ;float x ;char a ;}
2) Programa para teste: 2) Programa para teste:
( )( ){{
int i, j, k, fat;int i, j, k, fat;bool m, n;bool m, n;float x;float x;char a;char a;
}}
Resultado:
syntax error
***** Esperado: Identificador() {int i , j , k , fat ;bool m , n ;float x ;char a ;}
3) Programa para teste: 3) Programa para teste:
abc )abc ){{
int i, j, k, fat;int i, j, k, fat;bool m, n;bool m, n;float x;float x;char a;char a;
}}
Resultado:
syntax errorabc***** Esperado: (){int i , j , k , fat ;bool m , n ;float x ;char a ;}
4) Programa para teste: 4) Programa para teste:
abc (abc ({{
int i, j, k, fat;int i, j, k, fat;bool m, n;bool m, n;float x;float x;char a;char a;
}}
Resultado:
syntax errorabc (
***** Esperado: ){int i , j , k , fat ;bool m , n ;float x ;char a ;}
5) Programa para teste: 5) Programa para teste:
abc abc {{
int i, j, k, fat;int i, j, k, fat;bool m, n;bool m, n;float x;float x;char a;char a;
}}
Resultado:
syntax errorabc
***** Esperado: ( ){int i , j , k , fat ;bool m , n ;float x ;char a ;}
6) Programa para teste: 6) Programa para teste:
abc ( )abc ( ){{
int bool i, j, k, fat;int bool i, j, k, fat;bool m, nbool m, nfloat x;float x;char a;char a;
}}
Resultado:
abc ( ){int syntax error
***** Esperado: Identificador, j , k , fat ;bool m , n syntax error
***** Esperado: ';'char a ;}