Lex e Yacc. .... Há muita teoria... Até chegar neste ponto...

34
Lex e Yacc

Transcript of Lex e Yacc. .... Há muita teoria... Até chegar neste ponto...

Page 1: Lex e Yacc. .... Há muita teoria... Até chegar neste ponto...

Lex e Yacc

Page 2: Lex e Yacc. .... Há muita teoria... Até chegar neste ponto...

.... Há muita teoria... Até chegar neste ponto...

Page 3: Lex e Yacc. .... Há muita teoria... Até chegar neste ponto...

Definição

Lex e Yacc são ferramentas que ajudam a criar programas em C para analisar e interpretar um arquivos de entrada.

Eles podem ser usados para ajudar a escrever montadores, compiladores e interpretadores, ou qualquer outro programa cuja entrada pertence a uma estrutura bem definida, e que se deseja transformar em outra.

Page 4: Lex e Yacc. .... Há muita teoria... Até chegar neste ponto...

Lex

Toma um conjunto de descrições de possíveis tokens e produz uma rotina em C que irá identificar estes tokens analisador léxico.

Essa rotina lê a entrada e identifica “tokens”. Os “tokens” são definidos a partir de expressões

regulares (especificação léxica).

Page 5: Lex e Yacc. .... Há muita teoria... Até chegar neste ponto...

Yacc

Lê um arquivo que codifica a gramática de uma linguagem e e produz uma rotina em C que irá executar a análise sintática ou parsing.

Essa rotina agrupa os “tokens” em uma seqüência de interesse e invoca rotinas para realizar ações sobre elas ou a respeito delas.

Page 6: Lex e Yacc. .... Há muita teoria... Até chegar neste ponto...

Montadores Um montador recebe como entrada um programa

em linguagem de montagem (que pode ser lido por humanos) e gera como saída um programa em linguagem de máquina (bits: adequado para máquinas).

O funcionamento de um montador pode ser decomposto em três etapas: Análise léxica - LEX Análise sintática e semântica - YACC Geração de Código.

Page 7: Lex e Yacc. .... Há muita teoria... Até chegar neste ponto...

Diagrama de um Montador

Arquivo texto Montador Programa

Executável

usuário

Page 8: Lex e Yacc. .... Há muita teoria... Até chegar neste ponto...

Etapas de um montador

Cada estágio prepara a entrada para o próximo estágio. O usuário disponibiliza um arquivo texto (bytes) O analisador léxico detecta e disponibiliza tokens O parser detecta agrupamentos de tokens segundo os

comandos da linguagem de montagem e gera o código (realiza Ações) associado aos comandos.

Page 9: Lex e Yacc. .... Há muita teoria... Até chegar neste ponto...

Modelo básico de processamento para montadores

AnalisadorSintático(Parser)

input AnalisadorLéxico

Ações

Page 10: Lex e Yacc. .... Há muita teoria... Até chegar neste ponto...

Características Gerais A análise léxica pode ser vista como a primeira fase de um

processo de tradução (compilação). Sua principal tarefa é ler uma seqüência de caracteres de

entrada, geralmente associados a um código-fonte, e produzir como saída uma seqüência de itens léxicos.

Por outro lado, a análise sintática tem por objetivo agrupar os itens léxicos em blocos de comandos válidos.

Os itens léxicos são geralmente denominados tokens e correspondem a palavras-chave, operadores, símbolos especiais, símbolos de pontuação, identificadores (variáveis) e literais (constantes) presentes em uma linguagem.

Page 11: Lex e Yacc. .... Há muita teoria... Até chegar neste ponto...

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 12: Lex e Yacc. .... Há muita teoria... Até chegar neste ponto...

Especif.LEX

Bibliot.UNIX

RotinasC

yylex( ) yyparse( )

lex

gcc

programa

yacc

Especif.YACC

*.l *.y

lex.yy.c y.tab.c *.c

libl.aliby.a

Page 13: Lex e Yacc. .... Há muita teoria... Até chegar neste ponto...

Análise Léxica

Processo (programa) que classifica partes do arquivo texto de entrada em diversos tipos de tokens: números; comandos; strings; comentários.

Pode ser especificada por meio de expressões regulares, passíveis de representação na forma de autômatos finitos.

Page 14: Lex e Yacc. .... Há muita teoria... Até chegar neste ponto...

Expressões Regulares

Forma compacta de descrever uma sequência de caracteres.

Ex.: ([0-9]*\.)*[0-9]+

Essa expressão permite reconhecer os seguintes números: 100 6.8 45.92

Page 15: Lex e Yacc. .... Há muita teoria... Até chegar neste ponto...
Page 16: Lex e Yacc. .... Há muita teoria... Até chegar neste ponto...

Ações

A função básica de uma rotina léxica é retornar tokens ao parser.

As ações, em uma especificação Lex, consistem em expressões da linguagem C que retornam um token.

Para retornar o token em uma ação, usa-se a expressão return.

[0-9]+ { yylval = atoi(yytext);

return NUMBER;

}

Page 17: Lex e Yacc. .... Há muita teoria... Até chegar neste ponto...

Um Parser

Um analisador léxico gera uma entrada para um parser interpretar.

O parser tenta organizar os tokens de acordo com as regras de uma gramática.

A gramática, para uma linguagem de programação, descreve a estrutura de um programa.

Quando o parser encontra uma seqüência de tokens que corresponde a um comando da linguagem, a ação associada é executada.

Page 18: Lex e Yacc. .... Há muita teoria... Até chegar neste ponto...

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 yylex cada vez que precisa de um token.

A rotina léxica lê a 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 (entre outras).

Page 19: Lex e Yacc. .... Há muita teoria... Até chegar neste ponto...

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 20: Lex e Yacc. .... Há muita teoria... Até chegar neste ponto...

LEX

Page 21: Lex e Yacc. .... Há muita teoria... Até chegar neste ponto...

Lex

É um gerador de programas (módulo) destinados ao processamento léxico de textos.

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 uso em conjunto com módulos

de reconhecimento sintático.

Page 22: Lex e Yacc. .... Há muita teoria... Até chegar neste ponto...

Usando o LEX

Etapas: Escrever um arquivo texto com uma especificação Lex.

Esse arquivo, por convenção, tem o sufixo .l. Executar o lex usando como entrada o arquivo .l. Esse

passo gera um arquivo chamado lex.yy.c. Compilar lex.yy.c com o gcc, juntamente com quaisquer

outros arquivos fonte ou bibliotecas eventualmente necessárias.

Usar o executável gerado para análise léxica.

Page 23: Lex e Yacc. .... Há muita teoria... Até chegar neste ponto...

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

aquelas presentes na biblioteca standard do UNIX, a libl.a.

Page 24: Lex e Yacc. .... Há muita teoria... Até chegar neste ponto...

Estrutura de um texto LEX (.l)

<definições gerais> /* opcional */

“%%”

<regras de tradução>

“%%”

<rotinas C do usuário > /* opcional */

Page 25: Lex e Yacc. .... Há muita teoria... Até chegar neste ponto...

Estrutura de um texto LEX (.l)

A seção de definições inclui: 1. A definição de macros como:

digito [01]+ /* substituir {digito} por [01]+ ao processar as regras */ frac .[0-9]+ /* substituir {frac} por .[0-9]+ ao processar regras */ nl \n /* substituir {nl} por \n ao processar as regras */

2. A inclusão de linhas de comando em C, que devem ser delimitadas por <%{> e <%}>, como:

%{#include <y.tab.h>

extern int yylval;

%}

Page 26: Lex e Yacc. .... Há muita teoria... Até chegar neste ponto...

Estrutura de um texto LEX (.l)

A seção de regras define a funcionalidade do analisador léxico.

Cada regra compreende uma seqüência válida de caracteres (descrita utilizando literais e expressões regulares) e as ações semânticas associadas a ela.

As regras têm a seguinte estrutura:<EspRegular> “{“ <AçãoC> “}”

Page 27: Lex e Yacc. .... Há muita teoria... Até chegar neste ponto...

Estrutura de um texto LEX (.l)

Lex armazena temporariamente a subseqüência de caracteres identificada na variável yytext do tipo <char *>.

Podemos, então, usar a função sscanf() da biblioteca de C para convertê-la em outros tipos de dados.

A variável reservada pelo Lex para armazenar o resultado da conversão é yylval.

A seção de rotinas do usuário é opcional; é usada para incluir rotinas em C eventualmente necessárias e desenvolvidas pelos usuários.

Page 28: Lex e Yacc. .... Há muita teoria... Até chegar neste ponto...

Estrutura de um texto LEX (.l)

Quando uma seqüência de caracteres de entrada casa com duas ou mais regras, Lex adota uma das seguintes estratégias para resolver ambigüidades: escolher a regra que consegue casar a maior

seqüência de caracteres possível; quando há mais de uma regra que case com a maior

seqüência de caracteres, escolher aquela que aparece primeiro na seção de regras.

Page 29: Lex e Yacc. .... Há muita teoria... Até chegar neste ponto...

Um exemplo simples

%%zippy printf(“Eu reconheci zippy”);%%

Este texto lex especifica um filtro para substituir as ocorrências de “zippy” por “Eu reconheci zippy”.

Isso porque, todo o texto que não se “encaixe” em nenhum pattern é simplesmente copiado para a saída.

Neste exemplo, tanto as definições gerais, como as “rotinas C auxiliares” são inexistentes.

Page 30: Lex e Yacc. .... Há muita teoria... Até chegar neste ponto...

Utilização cat > sample.l %%zippy printf(“Eu reconheci zippy”);%% lex sample.l lslex.yy.c sample.l gcc -o sample lex.yy.c -ll lslex.yy.c sample sample.l

Page 31: Lex e Yacc. .... Há muita teoria... Até chegar neste ponto...

cat > testzippy

harry

zippy and zip cat test | ./sampleEu reconheci zippy

harry

Eu reconheci zippy and zip

Page 32: Lex e Yacc. .... Há muita teoria... Até chegar neste ponto...

Exemplo 2 cat sample2.l %%zip printf(“ZIP”);zippy printf(“Eu reconheci zippy”);zippy$ printf(“Achei zippy no final da linha”);%% lex sample2.l gcc -o sample2 lex.yy.c -ll cat test | ./sample2Achei zippy na final da linhaharryEu reconheci zippy and ZIP

Page 33: Lex e Yacc. .... Há muita teoria... Até chegar neste ponto...

Exemplo 3 cat > sample3.l %%[A-Z]+[ \t\n] printf(“%s”, yytext);. ;%% lex sample3.l gcc -o caps lex.yy.c -ll cat > test.caps Xview é uma API executando sob o X Window que suporta o {pula linha}OPEN LOOK GUI. ./caps < test.capsAPI XOPEN LOOK

Page 34: Lex e Yacc. .... Há muita teoria... Até chegar neste ponto...

Trabalho 1 (enviar para [email protected])

Faça um arquivo .l que detecte: O mnemônico “add” e retorne o token ADD. Números inteiros em decimal e retorne o token NUMBER e, na

variável yylval, o valor do número. Números inteiros em hexadecimal (começam com 0x) e retorne o

token NUMBER e, na variável yylval, o valor do número. Labels e retorne o token LABEL e em yytext a string com o label

(sem o “:”). A especificação de um registrador ($1, por exemplo) e retorne o

token REGISTER e, na variável yylval, o número do registrador Os caracteres: “,” (COMMA), “(” (OPEN_PARENTHESIS), “)”

(CLOSE_PARENTHESIS) O fim de uma linha e retorne END_OF_LINE