![Page 1: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/1.jpg)
Lex e Yacc
CompiladoresCompiladoresGiovani Rubert Librelotto
[email protected]ção: Claudio Cesar de Sá
![Page 2: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/2.jpg)
Roteiro .... Há muita teoria... Até chegar neste
ponto...
![Page 3: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/3.jpg)
Definição
Lex e Yacc são ferramentas que ajudam a criar rotinas C para analisar e interpretar um arquivo de entrada, na construção de um compilador
Eles podem ser usados para ajudar a escrever compiladores e interpretadores, ou qualquer outro programa cuja entrada pertence a uma estrutura bem definida, e que deseja transformar em outra.
![Page 4: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/4.jpg)
Lex
Lê um arquivo contendo expressões regulares para “pattern matching” e gera rotinas C que executam a análise léxica.
Essa rotina lê a entrada e identifica “tokens”. Os “tokens” são definidos a partir de expressões
regulares (gramática regular, etc).
![Page 5: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/5.jpg)
Yacc
Lê um arquivo que codifica a gramática de uma linguagem e gera uma rotina de “parsing”.
Essa rotina agrupa os “tokens” em uma seqüência significativa (de interesse), e invocar rotinas para agir (realizar ações) sobre elas.
![Page 6: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/6.jpg)
Compiladores
Um compilador pega a descrição de um programa e converte para um conjunto de instruções que pode ser executadas por um computador.
A execução de um compilador tem 3 estágios: Análise léxica - LEX Análise sintática e semântica - YACC Geração de Código.
![Page 7: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/7.jpg)
Diagrama de um Compilador
Text File CompilerProgama
Executável
usuário
![Page 8: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/8.jpg)
Etapas de um compilador
Cada estágio prepara a entrada para o próximo estágio;
Desse modo, o sistema operacional provém um arquivo em bytes, a análise léxica provém um agrupamento de tokens, o parser provém um agrupamento de tokens em instruções dentro da linguagem, e as ações provém interpretação para os valores dos tokens.
![Page 9: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/9.jpg)
Modelo básico de processamento para compiladores
AnalisadorSintático(Parser)
input AnalisadorLéxico
Ações
![Page 10: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/10.jpg)
Características Gerais
Lex gera código C para análise léxica. Yacc gera código C para um parser. Ambas especificações são menores que um programa e
mais fáceis de ler e entender. Por definição, o sufixo de um arquivo Lex é .l e de um
arquivo Yacc é .y Lex cria uma rotina chamada yylex em um arquivo lex.yy.c Yacc cria uma rotina chamada yyparse em um arquivo
chamado y.tab.c
![Page 11: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/11.jpg)
Especif.LEX
Bibliot.UNIX
RotinasCyylex( ) yyparse( )
lex
cc
program
yacc
Especif.YACC
*.l *.y
lex.yy.c y.tab.c *.c
libl.aliby.a
![Page 12: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/12.jpg)
Exemplo de Análise Léxica
Um programa que classifica uma entrada em diversos tipos de tokens: números; comandos; strings; comentários.
Programa em C (pags. 5 e 6) Especificação Lex (pag 7)
![Page 13: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/13.jpg)
Expressões Regulares
Elas provém flexibilidade em muitas situações. Ex.:
([0-9]*\.)*[0-9]+
Essa expressão permite reconhecer os seguintes números: 100 6.8 45.92
![Page 14: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/14.jpg)
Modelo de um autômato finito
01
2
3
[0 - 9]
[0 - 9]
[0 - 9]
. (ponto decimal)
. (ponto decimal)[0 - 9]
![Page 15: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/15.jpg)
Ações
A função básica de uma rotina léxica é retornar tokens ao parser.
As ações, em uma especificação Lex, consiste em expressões da linguagem C que retornam o token.
Para retornar o token em uma ação, usa-se a expressão return. [0-9]+ { yylval = atoi(yytext);
return NUMBER}
![Page 16: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/16.jpg)
Um Parser
Um analisador léxico gera uma entrada para um parser interpretar.
O parser organiza os tokens de acordo com as regras de uma gramática.
A gramática, para uma linguagem de programação, descreve a estrutura de entrada de um programa.
Quando o parser tem uma seqüência de tokens, que corresponde a uma regra, a ação associada é executada.
![Page 17: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/17.jpg)
Sumário de Rotinas Léxicas e Sintáticas A rotina main invoca (chama) yyparse para avaliar
se a entrada é válida. yyparse invoca a rotina invoca a rotina yylex cada
vez que precisa de um token. A rotina léxica lê da entrada, e a cada token
encontrado, retorna o número do token para o parser. A rotina léxica pode também passar o valor do token
usando a variável externa yylval.
![Page 18: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/18.jpg)
Fluxo de controle em rotinas léxicas e sintáticas
main
yyparse( )
yylex( )yylval
input
Entradaavaliada
Valor da ação do processo
Requererpróximo token
Retornar o tokenou 0 se EOF
Valor passadodo token
Ler charsda entrada
Retorna 0 se entrada é valida1 se não
![Page 19: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/19.jpg)
Os Mecanismos de Lex e Yacc
A partir de agora, o objetivo é ajudar a entender como esses programas funcionam.
E o que os programas geram. Veremos alguns programas simples. Será o básico do Lex e do Yacc.
![Page 20: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/20.jpg)
LEX
![Page 21: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/21.jpg)
1.1 Genericamente
É um gerador de programas (módulos) destinados a processamento léxico de testos.
O módulo gerado pode funcionar como: Filtro para processamento léxico; “Pattern Matching” (expressões regulares); Reconhecedor de linguagens regulares simples; Pré-processador simples; Analisador léxico para ligação de módulos de
reconhecimento sintático.
![Page 22: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/22.jpg)
Usando o LEX
São três (quatro) etapas: Escrever uma especificação Lex que contém
seqüências de caracteres em uma entrada. Esse arquivo, por convenção, tem o sufixo .l.
Executar a especificação Lex. Esse passo gera um arquivo chamado lex.yy.c.
Compilar lex.yy.c e qualquer arquivo fonte.
![Page 23: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/23.jpg)
lex.yy.c não contém um programa completo. Ele contém uma rotina léxica chamada yylex. Você pode integrar o analisador léxico com um
parser gerado no Yacc. Um programa léxico também assume a existência
de outras rotinas de suporte. Você pode fornecer essas rotinas, ou usar as
bibliotecas standart do UNIX, a libl.a.
![Page 24: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/24.jpg)
1.2 Funcionamento
Com base num texto “lex”, é gerado um módulo C que contém um reconhecedor baseado em autômatos determinísticos.
Este vai permitir encontrar patterns num texto de entrada e sobre eles executar uma ação semântica correspondente.
O módulo C é automaticamente escrito em um arquivo “lex.yy.c” que inclui numa função “yylex()”, a qual executa o algoritmo que se apresenta:
![Page 25: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/25.jpg)
FUNCAO yylex( ) : intREPETIR | yytext <- “ ”| c <- input( )| ENQUANTO (c cabe numa ExpRegular)| | yytext <- concatenar (yytext, c)| | c <- input( )|| executar a acãoC correspondente a ExpRegularATE chegar ao fim do inputyywrap( )
![Page 26: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/26.jpg)
Escrevendo uma especificação Lex A principal seção de uma especificação léxica
contém um conjunto de regras. A especificação mínima segue o formato:
%%rules
%% indica o início da seção de regras. Cada regra consiste em uma expressão regular.
![Page 27: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/27.jpg)
1.3 Estrutura de um texto LEX
<definições gerais>“%%”<regras de tradução>“%%”<rotinas C auxiliares>
Cada regra vai ter a seguinte estrutura:<EspRegular> “{“ <AçãoC> “}”
![Page 28: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/28.jpg)
1.4 Um exemplo simples
%%zippy printf(“Eu reconheci zippy”)%%
Este texto lex especifica um filtro para substituir as ocorrências de “zippy” por “Eu reconheci ...”.
Todo o texto que não se “encaixe” em nenhum pattern é simplesmente copiada pra saída.
Neste exemplo, tanto as definições gerais, como as “rotinas C auxiliares” são inexistentes.
![Page 29: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/29.jpg)
1.5 Utilização
cat sample.l %%zippy printf(“Eu reconheci zippy”)%% lex sample.l lslex.yy.c sample.l cc -o sample lex.yy.c -ll lslex.yy.c sample* sample.l
![Page 30: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/30.jpg)
cat testzippyharryzippy and zip cat test | sampleEu reconheci zippyharryEu reconheci zippy and zip
![Page 31: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/31.jpg)
Exemplo 2
%%zip printf(“ZIP”);zippy printf(“Eu reconheci zippy”);zippy$ printf(“Achei zippy na final da linha”); Depois de refazer todas as etapas anteriores:Achei zippy na final da linhaharryEu reconheci zippy and ZIP
![Page 32: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/32.jpg)
Exemplo 3
%%[A-Z]+ [ \t\n] printf(“%s”, yytext);. ; cat test.capsXview é uma API executando sob o X Window que suporta o
OPEN LOOK GUI. caps < test.capsAPI XOPEN LOOK
![Page 33: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/33.jpg)
Usando a especificação completa
<definições gerais>“%%”<regras de tradução>“%%”<rotinas C auxiliares>
![Page 34: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/34.jpg)
Exemplo 4 - cutter.l
%%int field_count = 1;extern int field_cut;
\t ++field_count;\n {ECHO; field_count = 1;
}[^\t\n]+ {if(field_count ==
field_cut) ;else printf(“%s”,
yytext); }
%%int field_cut;
main(argc, argv)int argc;char *argv[ ];{
if (argc > 1)field_cut = atoi(argv[1]);elsefield_cut = 1;yylex( );
}
![Page 35: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/35.jpg)
lex cutter.l cc -o cutter lex.yy.c
-ll cat test.cutsabc def ghi jklmno pqr stuwxy z
cutter 3 < test.cutsabc def jklmno pqr wxy z cutter < test.cutsdef ghi jklpqr stuz
![Page 36: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/36.jpg)
1.5.1 Opções do comando LEX
-r ações em Fortran (RATFOR)
-t o arquivo lex.yy.c é enviado para saída padrão
-v fornece estatísticas do autômato gerado
![Page 37: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/37.jpg)
1.6 Funcionamento como pré-processador Para desenvolver um pré-processador, pode-
se usar o módulo gerado através da função correspondente ao seguinte algoritmo:
enquanto não fim inputyytext <- getSimbolo()efetuar ação correspondente ao tipo de símbolo encontrado
![Page 38: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/38.jpg)
1.7 Funcionamento como Analisador Léxico Para funcionar como uma analisador léxico de um
compilador a ser invocado por um Parser, cada vez que um símbolo é reconhecido, guarda-se o seu valor (numa variável global) e retorna inteiro; para tal, as regras terão o seguinte aspecto:
ExpReg { yylval <-- [guardar o valor do símbolo];
return(código); }
![Page 39: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/39.jpg)
YACC
![Page 40: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/40.jpg)
Introdução YACC é um comando UNIX. Seu significado é – Yet Another Compiler
Compiler O YACC recebe um texto com a descrição
de uma gramática com ações semânticas, isto é, ações em C que indicam o que é que se deve fazer cada vez que reconheceu uma produção.
![Page 41: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/41.jpg)
Ele gera um reconhecedor sintático do tipo SLR(1) correspondente.
YACC é, portanto, um gerador de programas. O texto de entrada pode incluir procedimentos
e/ou funções auxiliares. O texto do reconhecedor gerado (código C) pode
ser unido a outros módulos e transportado para outros ambientes.
![Page 42: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/42.jpg)
Usando Yacc
São 4 passos para criar um parser: Escrever uma especificação de uma gramática. O
arquivo terá a extensão .y. Escrever um analisador léxico que pode produzir
tokens, o yylex. Executar yacc na especificação para gerar o código
do parser, o y.tab.c. Compilar e linkar os códigos fontes para o parser e
o analisador léxico e rotinas auxiliares.
![Page 43: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/43.jpg)
A saída y.tab.c contém uma rotina yyparse que chama a rotina léxica yylex, para cada novo token.
Como Lex, Yacc não gera programas completos. yyparse deve ser chamado de uma rotina main. Um programa completo também requer uma rotina
de erro chamada yyerror chamada pelo yyparse. Ambas, main e yyerror, podem ser supridas pelo
programador, através da biblioteca liby.a, que pode ser linkada com a opção -ly, na compilação.
![Page 44: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/44.jpg)
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 tem 4 classe de elementos: Tokens, que é o conjunto de símbolos terminais; Elementos sintáticos, que são os 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 regra start, que reduz todos os elementos da
gramática para uma regra simples.
![Page 45: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/45.jpg)
Foco de uma especificação Yacc
É um conjunto de regras de produções da forma:símbolo: definição{ação};
Dois pontos (:) separam o lado esquerdo do lado direito da regra, e o ponto-e-vírgula (;) finaliza a regra.
Por convenção, a definição segue 2 “tabs” após os dois pontos.
![Page 46: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/46.jpg)
Símbolos
Cada regra em uma gramática é chamada por um símbolo, um não terminal.
A definição consiste de zero ou mais terminais (tokens ou caracteres literais) e outros não terminais.
Tokens são símbolos terminais reconhecidos pelo analisador léxico, e só aparecem no lado direito da regra.
Cada definição pode ter uma ação em C associada a ela. Essa ação está entre chaves ( { } ).
![Page 47: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/47.jpg)
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 em minúsculos. Tokens, em maiúsculos. Uma especificação mínima Yacc consiste de uma
seção de regras precedidas por uma declaração dos tokens usados na gramática.
![Page 48: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/48.jpg)
Formato da especificação
O formato é similar ao formato do Lex.declarações%%regras da gramática%%programas C
![Page 49: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/49.jpg)
Exemplo 1 - print_int.y
%token INTEGER%%lines : /* empty */
| lines line{ printf(“= %d\n”, $2); };
line : INTEGER ‘\n’{ $$ = $1; };
%%#include “ lex.yy.c”
![Page 50: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/50.jpg)
print_int
Especificação para gerar um programa que imprime qualquer número recebido como entrada.
Na seção declaração, declaramos o token INTEGER. Este símbolo é usado para a comunicação entre o analisador léxico e o parser.
Na seção da gramática, especificamos lines e line. A regra lines é definida para 0 ou mais linhas de entrada.
A primeira alternativa é vazia. A segunda alternativa é recursiva.
![Page 51: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/51.jpg)
print_int.y - Ações das regras
Yacc provém pseudo-variáveis, que facilitam a as ações de pegar o valor de um símbolo e setar o valor retornado por uma ação.
O $ tem significado especial para o Yacc. O valor de cada elemento pode ser obtido usando a
notação posicional: $1 para o 1º token, $2 para o 2º, e assim por diante.
O valor retornado pela ação é setado pela tarefa para $$.
![Page 52: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/52.jpg)
print_int.y - Ações das regras
line : INTEGER ‘\n’{ $$ = $1; }
Essa ação, “$1” retorna o token INTEGER. Há 2 elementos na definição, mas o ‘\n’ não retorna.
| lines line{ printf(“= %d\n”, $2); }
Nessa ação, “$2” refere-se ao valor de line.
![Page 53: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/53.jpg)
print_int.l - Analisador léxico
%%[0-9]+ {
sscanf(yytext, “%d”, &yylval);return(INTEGER);}
\n return(‘\n’);[-+=]return yytext[0];quit return 0;. ;
![Page 54: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/54.jpg)
print_int.y - #include
A terceira parte deste exemplo de especificação Yacc contém a instrução #include.
Ela inclui o código para analisador léxico. Para testar a especificação:
lex print_int.lyacc print_int.ycc -o print_int y.tab.c -ly -ll
![Page 55: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/55.jpg)
print_int - Execução
$> print_int3=315= 156= 6zippysintax error
![Page 56: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/56.jpg)
1.1 Gramática do YACCtextoYacc -> <definições> “%%”
<produções> “%%” <codigoCaux>
<definições> -> <def>*
<produções> -> <produção>+
![Page 57: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/57.jpg)
1.1.1 Zona de Definições
Em <definições> são definidos os seguintes elementos referentes a gramática: Axioma da gramática; Conjunto dos terminais (T) e respectivo tipo de
valor, caso exista; Tipo de valor associados a cada não terminal
(NT), caso exista;
![Page 58: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/58.jpg)
Ainda em <definições>, encontram-se elementos referentes a resolução automática de conflitos e ambigüidades: Indicação de propriedades de operadores; Indicação de associatividade de operadores (à
esquerda, direita ou não associatividade).
![Page 59: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/59.jpg)
1.1.1.1 Código C global
<def> -> <defAxioma>| <defTipodeValor> | “%{“ <códigoCglobal> “%}”
| <defTerminais>| <defAssociatividade>| <defTipodeValorT_NT>
<defAxioma> --> “%start” <unionDef>
![Page 60: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/60.jpg)
<defTiposdeValor> -> “%union” <unionDef>
Definição de tipos de valores para T e NT. Esta definição será usada internamente para
a declaração de uma stack valor. <unionDef> é uma declaração de uma
union C; <unionDef> vai definir um conjunto de
identificadores de tipos que poderão ser usados em <tipo>.
![Page 61: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/61.jpg)
<defTerminais> -> “%token” <tipo> <T>*
Define os terminais da gramática podendo ainda associar-lhes um tipo de valor.
Essa definição pode ser feita em várias linhas.
![Page 62: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/62.jpg)
<tipo> ->| “<“ ID “>”
Tipo é opcional. Quando usado, ID é um identificador que
deve figurar na <unionDef> da <defTipos_T_NT>
![Page 63: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/63.jpg)
<defAssociatividade> -> “%left” <tipo> <T_NT>* | “%rigth” <tipo> <T_NT>* | “%noaccoc” <tipo> <T_NT>*
Indica se um operador é associativo ou não. Esta informação é usada para tratamento de
conflitos. Nota-se, portanto, que podem ser tratadas gramáticas ambíguas.
A cada símbolo S fica associada uma propriedade de acordo com a ordem que ela aparece: Os S declarados na mesma linha tem igual prioridade. Os S declarados na linha i tem prioridade maior que os
da linha i-1.
![Page 64: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/64.jpg)
<defTiposdeValorT_NT> -> “%type” <tipo> <NT>*
Permite associar um tipo de valor a um terminal ou não terminal.
![Page 65: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/65.jpg)
1.1.2 Produções
<produção> -> <NT> “:” <rhss>
Produção da gramática segundo a estrutura sintática habitual.
<NT> = não terminal rhs = rigth hand side – lado direito da produção
![Page 66: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/66.jpg)
<rhss> -> <rhs>| <rhs> “|” <rhss>
Lado direito possivelmente múltiplo, e nesse caso, separa-se por “|”
![Page 67: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/67.jpg)
<rhs> -> <simb>*| <simb>* <prec>
Lado esquerdo é uma seqüência de símbolos podendo opcionalmente incluir <prec> para alternar propriedades de operadores.
![Page 68: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/68.jpg)
<simb> -> <T>| <NT>| <simbSemântico>
T = símbolo terminal NT = símbolo não terminal simbSemantico = Símbolo semântico, para
colocar ações no parser.
![Page 69: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/69.jpg)
<T> -> ID_token| “ ’ ” char “ ‘ “
T – símbolo terminal é um identificador declarado como token ou caracter entre aspas.
![Page 70: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/70.jpg)
<NT> -> ID
O identificador ID deve figurar, em pelo menos, um lado esquerdo de uma produção.
![Page 71: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/71.jpg)
<simbSemantico> -> “{“ <codigoCcom$> “}”
<codigoCcom$> -> código C com possibilidade de usar $$, $1, ...;
$$ permite a associação de um valor ao lado esquerdo da produção ($$ = .. – atributo sintetizado)
$i permite a utilização de um valor de um símbolo do rhs (i – na ordem do símbolo)
Esse símbolo pode ser T, NT ou simbSemantico.
![Page 72: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/72.jpg)
<prec> -> “%prec” <T>
Permite associar a prioridade de um símbolo terminal T a uma produção.
![Page 73: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/73.jpg)
1.1.3 Código C
<codigoCaux> -> “%%” <funcoes_C>| /* vazio*/
<funcoes_C> -> código C puro; Não esquecer a definição
da função de análise léxica yylex()
Ex: #include “lex.yy.c”
![Page 74: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/74.jpg)
Exemplo: Calculadora
![Page 75: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/75.jpg)
Operações da Calculadora
Soma: 3 + 9
Subtração: 36.4 - 95
![Page 76: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/76.jpg)
Análise
Léxica: 36.7 + 43.2 REAL PLUS REAL
Sintática: rexpr <-- REAL | rexpr ‘+’ rexpr
{$$ = $1 + $3;} line <-- ‘\n’ | rexpr ‘\n’
![Page 77: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/77.jpg)
Expressões regulares para tokens
Para números inteiros: [0-9]+
Para números reais: [0-9]*\”.”[0-9]+
Para números reais com expoentes: ([0-9]*\”.”[0-9]+) | ([0-9]*\”.”[0-9]+ [eE] [+-]? [0-9]+)
![Page 78: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br](https://reader036.vdocuments.pub/reader036/viewer/2022062522/570638581a28abb8238fc393/html5/thumbnails/78.jpg)
Falta o exemplo da calculadora.Está no texto em inglês, no arquivo em PDF e no primeirolink do site!