lex e yacc compiladores giovani rubert librelotto [email protected] adaptação: claudio cesar...

78
Lex e Yacc Compiladores Compiladores Giovani Rubert Librelotto giovanir@ inf .ufrgs.br Adaptação: Claudio Cesar de Sá claudio @ joinville . udesc .br

Upload: luiza-almada-ferretti

Post on 07-Apr-2016

219 views

Category:

Documents


0 download

TRANSCRIPT

Page 2: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

LEX

Page 21: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

YACC

Page 40: Lex e Yacc Compiladores Giovani Rubert Librelotto giovanir@inf.ufrgs.br Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

<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

<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

<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

<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

<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

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

<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

<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

<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

<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

<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

<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

<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

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

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

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

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

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

Falta o exemplo da calculadora.Está no texto em inglês, no arquivo em PDF e no primeirolink do site!