1 / 20

YACC

YACC. Introdução. YACC significa – Yet Another Compiler Compiler O programa YACC recebe um texto com a descrição de uma gramática e ações associadas. A gramática em questão é uma série de regras de formação de strings.

otis
Download Presentation

YACC

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. YACC

  2. Introdução • YACC significa – Yet Another Compiler Compiler • O programa YACC recebe um texto com a descrição de uma gramática e ações associadas. • A gramática em questão é uma série de regras de formação de strings. • As regras descrevem como formar strings válidas (produções) a partir do alfabeto da linguagem (tokens).

  3. Introdução • A cada possível produção da gramática está associada uma ação. • As ações são escritas em C e indicam o que é que se deve fazer cada vez que se reconhece uma produção. • O YACC transforma esta descrição da gramática e ações associadas em um parser programa capaz de analisar uma sequência de tokens de entrada, detectar produções e agir sobre elas.

  4. Usando Yacc • São 4 os passos para se criar um parser: • Escrever uma especificação de uma gramática no formato do yacc. O arquivo terá a extensão .y • Escrever uma especificação de um analisador léxico que pode produzir tokens; extensão .l • Executar o yacc sobre a especificação .y e o lex sobre a especificação .l • Compilar e linkar os códigos fontes do parser, do analisador léxico e suas rotinas auxiliares.

  5. A saída do yacc, y.tab.c, contém a rotina yyparse que chama a rotina yylex para obter tokens. • Como o Lex, o Yacc não gera programas completos. • A yyparse deve ser chamada a partir de uma rotina main. • Um programa completo também requer uma rotina de erro chamada yyerror. • Ambas, main e yyerror, podem ser supridas pelo programador, por meio da biblioteca liby.a, que pode ser linkada com a opção -ly, na compilação.

  6. Escrevendo uma Especificação Yacc • Uma especificação yacc descreve uma gramática livre do contexto que pode ser usada para gerar um parser. • Ela possui elementos membros de 4 classes: • Tokens, que é o conjunto de símbolos terminais; • Elementos sintáticos, que são símbolos não terminais. • Regras de produção, que definem símbolos não terminais em termos de seqüência de terminais e não terminais; • Uma regrastart, que reduz todos os elementos da gramática para uma regra.

  7. Símbolos • A cada regra está associado um símbolo não terminal (lado esquerdo). • As definições (lado direito) consistem de zero ou mais símbolos terminais (tokens ou caracteres literais) ou não terminais. • Tokens são símbolos terminais reconhecidos pelo analisador léxico, e só aparecem no lado direito das regras. • A cada regra pode ser associada uma ação em C. Estas ações ficam entre chaves ( { } ).

  8. Símbolos (continuação) • Os nomes de símbolos podem ter qualquer tamanho, consistindo de letras, ponto, sublinhado e números (exceto na primeira posição). • Caracteres maiúsculos e minúsculos são distintos. • Os nomes de não terminais são usualmente especificados em minúsculos. • Tokens, em maiúsculos.

  9. Formato da especificação • Uma especificação mínima em yacc consiste de uma seção de regras, precedida de uma seção de declaração de tokens reconhecidos pela gramática. • O formato é similar ao formato do Lex. declarações %% regras de produção %% rotinas em C do usuário

  10. Yacc: Declarações • Códigos em C entre %{ %} (como no Lex) • Definição de tokens: %token T1 T2 T3 ... TN • Definição de regras auxiliares para solução de ambigüidades: • Exemplos: • %left MAIS MENOS • %left VEZES DIVIDIDO • %left MENOS_UNARIO

  11. Yacc: Regras de Produção • As regras de produção tem a forma: /* uma gramática definida assim: */ <lado esquerdo> := <alt1>|<alt2>|...|<altN> /* transforma-se na seguinte especificação yacc */ <lado esquerdo>: <alt1> {/*ação 1*/} | <alt2> {/*ação 2*/} ... | <alt3> {/*ação N*/} ;

  12. Yacc: Regras de Produção • Cada símbolo (terminal ou não) tem associado a ele uma pseudo variável; • O símbolo do lado esquerdo tem associada a ele a pseudo variável $$; • Cada símbolo i da direita tem associada a ele a variável $i; • $i contém o valor do token (retornado por yylex()) se o símbolo i for terminal, caso contrário contém o valor do $$ do não terminal; • Ações podem ser executadas sobre estas variáveis.

  13. Yacc: Rotinas em C do Usuário • São funções em C que são copiadas para o parser gerado. • São semelhantes às subrotinas auxiliares do Lex. • Se o Lex não for usado para especificação do analisador léxico, a função yylex() deve ser implementada como uma rotina em C do usuário.

  14. Exemplo (cat parser.y) %{ #include <stdio.h> #include <stdlib.h> %} %start calc %token END_OF_LINE ADD SUB OPEN_PARENTHESIS CLOSE_PARENTHESIS NUMBER %left ADD SUB %% calc : expr END_OF_LINE { printf("r: %d\n", $1); exit(0); } ; expr : expr ADD expr { $$ = $1 + $3; } | expr SUB expr { $$ = $1 - $3; } | OPEN_PARENTHESIS expr CLOSE_PARENTHESIS { $$ = $2; } | NUMBER ; %% /* código do usuário */

  15. Exemplo (restante de cat parser.y) int yyerror (char *mens) { fprintf(stderr, "%s\n", mens); return (1); } int main (int argc, char **argv) { return (yyparse()); }

  16. Exemplo (cat analisador_lexico.l) %{ #include <stdio.h> #include "y.tab.h" extern int yylval; %} %% add return (ADD); sub return (SUB); [0-9]+ {yylval = atoi(yytext); return NUMBER;}; 0x[0-9a-fA-F]+ {sscanf(yytext, "%x", &yylval); return NUMBER;}; \( return (OPEN_PARENTHESIS); \) return (CLOSE_PARENTHESIS); \n return (END_OF_LINE); . ; %%

  17. Compilando o Exemplo • yacc -d parser.y • lex analisador_lexico.l • gcc -o calc lex.yy.c y.tab.c -ll

  18. Exemplo2 (cat parser2.y) %{ #include <stdio.h> #include <stdlib.h> %} %union { float float_val; } %start calc %token END_OF_LINE ADD SUB OPEN_PARENTHESIS CLOSE_PARENTHESIS %token <float_val> NUMBER %type <float_val> expr %left ADD SUB %% calc : expr END_OF_LINE { printf("r: %f\n", $1); exit(0); } ; expr : expr ADD expr ...

  19. Exemplo2 (cat analisador_lexico2.l) %{ #include <stdio.h> #include "y.tab.h" //extern int yylval; int int_val; %} %% add return (ADD); sub return (SUB); [0-9]+ {yylval.float_val = atoi(yytext); return NUMBER;}; 0x[0-9a-fA-F]+ {sscanf(yytext, "%x", &int_val); yylval.float_val = int_val; return NUMBER;}; \( return (OPEN_PARENTHESIS); \) return (CLOSE_PARENTHESIS); \n return (END_OF_LINE); . ; %%

  20. Trabalho 2 (enviar para sp1@lcad.inf.ufes.br) • Faça uma calculadora de ponto flutuante usando o lex e o yacc que: • Realize as operações de +, -, * e / sobre expressões; • Compute as funções seno, cosseno e raiz quadrada sobre expressões.

More Related