Implementação de Linguagens de Programação - Compiladores. Price e Toscani (2001, 103p)

August 18, 2017 | Author: api-26417123 | Category: Compiler, Programming Language, Parsing, Computer Program, Formalism (Deductive)
Share Embed Donate


Short Description

Download Implementação de Linguagens de Programação - Compiladores. Price e Toscani (2001, 103p)...

Description

.

=;;.,no

Ana Maria de ~ l e n c ar~! r i c e

In forrnáfica

Doutora em Computer Science pela Universityof Sussex. UK formatica pela PUCIRJ (1976) I Graduada em Engenharia Ouimica pela (1972) I Professora da UFRGS desde 1975. aaando no curso de Ciência da Computaçao. em Cursos de Especialização em Slstemas de Informaçáo e nos programasdemestrado edoutorado do Instituto de Informática

Direlor

Prof. Philippe Olivier Alexandre Navaux

Simão Sirineo Toscani

ViceDiretor

Doutor em Informática pela Universidade Nova de Lisboa. Portugal (1993) 1 Mestre em Informatica pela PUCIRJ (1969) 1 Engenheiro Eletricista pela UFRGS (1967) 1 Professor do 0epariamen:o de lnformatica de PUCiRJ (1969 - 1974) e do Instituto de Informatica da UFRGS (1975 1998) 1 Atualmente e coordenador e professor do Curso de Cikncia da Computação da Universidade de Cruz Alta (UNICRUZ) e professor orientador do Programa de Pós-Graduação em Computaçao da UFRGS

Prof. Otacílio Jose Carollo de Souza

-

Comissão Editorial

Prof. Tiarajú Asrnuz Diverio Prof. Clesio Saraiva dos Santos Prof. Ricardo Augusto da Luz Reis Profa Carla Maria Dal Sasso Freitas Endere o

U F R ~ -S Instituto de Informática Av Bento Gon alves, 9500 Bloco IV Bairro A ronomia Caxa Posial1!064 91501-970 Porto Ale , \ S Fone O0 55 (05y3316 6165 ~ a 00x 55 (091) 3319 7308 e-mall: -.;,y ::; -' :+-c

implementacao de Linguagens 1

1

1

3

Compiladores Série Livros Didáticos a Número 9 Instituto de Informática da UFRGS

ditor Sagra ,& , h

Prefácio da Segunda Edigão Agradecemos à turma da UA'ISC. em especial, à Professora Alessandra Dahmer pelas modificações sugendas. Somos gratos, também, ao Professor Giovani Librelotto, da UNICRUZ, por sua colaboração nessa segunda edição. Ana Price e Simão Toscani Porto Alegre, Julho de 2001

Sumário 1 Traduqão de Linguagens de Programação i 1.1 Evolução das Linguagens de Programação . .......................1 1.2 Tradutores de Linguagens de Programação ...............................................................4 1.3 Estrutura de um Tradutor .......................................................................................... 7 1.3.1 Análise Léxica ....................................................................................................... 7 1.3.2 Análise Sintáiica e Semântica .............................................................................9 1.3.3 Geração de Código Intermediário 11 1.3.4 Otirnização de Código ...............................................................................12 1.3.5 Geração de Código Objeto .................................................................................13 1.3.6 Gerência de Tabelas ................................................. ........................ 13 1.3.7 Atendimento a Erros ....................................................................................... 14 1.4 Geradores de Compiladores ......................................................................... 14 Exercícios .............................................................................................................. 16

2 Análise Léxica ........................................................................

i7 2.1 Gramáticas e Linguagens Regulares ....................................................................... 18 . .................................................................................... 22 2.2 Tokens .................... . 2.3 Especificação .......................................................................................................... 24 2.4 Implementação ....................................................................................................... 25 2.5 Tabela de Símbolos .......................................................................................26 Exercícios ...................................................................................................................... 28

3 Análise Sintática................................................................29 3.1 Revisão de Gramáticas Livres-do-Contexto ............................................................ 30 3.1.1 Definições e exemplos ........................................................................................30 34 3.1.2 Transformações de GLC's 3.2 Análise Descendente (Top-down) .......................................................................38 38 3.2.1 Análise Recursiva com Retrocesso 3.2.2 Análise Recursiva Preditiva ................................................................................. 41 3.2.3 Análise Preditiva Tabular .................................................................................... 45 3.3 Anásile Redutiva (Bottom-up) ..........................................................................53 3.3.1 Analisadores de Precedência de Operadores ........................................................55 3.3.2 Funções de Precedéncia . ........................................................... 66 3.3.3 Analisadores LR .................................. 3.4 Recuperação de Erros ........................................................................................ 74 . . . . . . . . . .. . 75 3.4.1 Recuperação de Erros na Análise LL 3.4.2 Recuperação de Erros na Análise de Precedência de Operadores ......................... 77 ........................... 79 3.4.3 Recuperação de Erros na Análise LR Exercícios . ............................................................................... 80

7 Gerência de Memória ........................................................... 169

4 Tradução Dirigida por Sintaxe ..............................................85

7.1 Estratégias para Alocação de Memória.................................................................. 7.2 Alocaçáo em Memória de Pilha ............................................................................. 169 7 .Acesso 3 à Variáveis Não-locais .............................................................................. 171 174 7.4 Passagem de Parimetros ....................................................................................... 7.5 Alocação Dinâmica de Memória ........................................................................... 182 183 Exercícios ....................................................................................................................185

4.1 Esquemas de Tradução ......................................................................................... 86 4.1. 1 Estratégia depth-first ...................................................................................... 88 4.1.2 Atributos sintetizados e atributos herdados ........................................................ 89 4. 1.3 Gramática de atributos .........................................................................................89 4.1.4 Tipos de Esquemas de Tradução ..........................................................................92 4.2 Grafos de dependências ........................................................................................ 94 4.3 Árvore de Sintaxe ...................................................................................................96 4.4 Implementação de Esquemas S-Atribuídos .............................................................98 4.5 Esquemas de Tradução L-Atribuídos .................................................................. 101 4.6 Implementaçáo de Esquemas L-atribuídos ............................................................. 104 4.7 Projeto de um Tradutor Preditivo ........................................................................ 110 Exercícios .................................................................................................................... 112

8 Geração de Código Objeto ....................................................

5 Geração de Código Intermediário .......................................i I5 5. l Linguagens Intermediárias ..................................................................................... 115 115 5. 1.1 Árvore e Grafo de Sintaxe .............................................................................. 116 5.1.2 Notações Pós-fixada e Pré-fixada 117 5. 1.3 Código de Três-Endereços ................................................................................. 5.2 Ações Seminticas para a Construção de Tabelas de Símbolos ...............................120 5.3 Geração de Código para Comando de Atribuição ................................................. 123 5.3.1 Conversão de Tipos em Expressões Aritméticas ...............................................124 5.3.2 Endereçamento de Elementos de Matrizes ........................................................125 5.4 Expressões Lógicas e Comandos de Controle ...................................................129 5.4.1 Representação Numérica de Expressões Lógicas ...............................................129 5.4.2 Representaçào por Fluxode Controle .............................................................132 .. 5.5 Backpatching ........................................................................................................ 136 137 5.5.1 Backpatching em Expressões Lógicas ............................................................. 5.5.2 Backpatching em Comandos de Controle ......................................................... 138 Exercícios ....................................................................................................................141

6 Otimização de Código ............................................................ 145

146 6.1 Otimização de Código Intermediário ..................................................................... 6.1.1 Representação de Blocos Básicos Através de Grafos .........................................146 6.1.2 Algoritmo para Construir o GAD de um Bloco .................................................147 6.1.3 Algoritmo para Gerar uma Sequência Otimizada de Código ............................... 149 6.2 Otimização de Código para Expressões Aritméticas............................................ 150 6.2.1 Algoritmo para Obter o Número de Acumuladores ............................................152 6.2.2 Geração de Código para Máquina com N Acumuladores ................................... .153 , Exercícios .................................................................................................................... 10" m

8.1 Considerações no Projeto de um Gerador de Código ............................................. 8 . 2 A Máquina Objeio ................................................................................................. 8.3 Gerador de Código Simplificado ........................................................................... 8.3.1 Informação de Próximo-Uso ................................................................. ............. 8.3.2 Descritores de Registradores e de Endereços .................................................... 8.3.3 Algoritmo de Geração de Código ....................................................................... Exercícios ....................................................................................................................

Referências Bibliográficas ........................................

1 Tradução de Linguagens de Programação O meio mais eficaz de comunicaç5o entre pessoas é a litigira$etri (língua ou idioma). N~

programaçáo de computadores, uma lilgitagetii de prograninçõo serve como meio de comunicação entre o indivíduo que deseja resolver um determinado problema e o computador escolhido para ajudá-lo na soluçáo. A linzuagem de programafão deve fazer a ligaçio entre o pensamento humano (muitas vezes. de natureza não estruturada) e a precisão requerida para o processamento pela máquina. O desenvolvimento de um programa torna-se mais fácil se a linguagem de programaçso em uso estiver próxima ao problema a ser resohido. Isto é, se a linguagem incluir construções que refletem a terminologia d o u os elementos usados na descrição do problema. Tal tipo de linguagem de programaçáo é considerada como uma linguagem de alto nível. Os computadores digitais, por sua vez. aceitam e entendem somente sua própria linguagem de máquina (dita de baixo nível). a qual consiste tipicamente de sequências de zeros e uns. Esse tipo de linguagem é bem diferente da linguagem de alto nível usada para descrever um problema numa dada área de aplicação. As linguagens de programação mais utilizadas hoje s3o aquelas classificadas como de alto nível, consideradas mais próximas às linguagens naturais ou

30

domínio da aplicação em

questão (linguagens procedimentais e linguagens de 4' geração). Para que se tomem operacionais, os programas escritos em linguagens de alto nível devem ser traduzidos para lirigitagetn de nniguina. Essa conversão é realizada através de sistemas especializados

-

contpiladores ou inrerpreradores - que aceitam (como entrada) uma representaçáo textual da

e produzem uma representação solução de um problema, expresso em uma li~igicngetttjo~t~e, do mesmo algoritmo expresso em outra linguagem, dita linguageiii objeto.

1.1 Evolução das Linguagens de Programação Cronologicamente, as linguagens de programaçáo podem ser classificadas em cinco gerações: (1') linguagens de máquina. (2') linguagens simbólicas (Assembly), (3') linguagens orientadas

ao usuário, (4') linguagens orientadas à aplicação e (5.) linguagens de conhecimento. As linguagens de 1' e 2' gerações s5o consideradas linguagens de baixo nível; as demais ~ 3 0 classificadas como linguagens de alto nível.

2 . ......_.__

Irnplernenwçào de Linguagens de Prognirnação - Ana M. A. Price e simioS. ~~~~~~i . ............................. ....................... ........................................................... , , ........

_

Os primeiros computadores eram programados em linguagem de máquina, em notação

I - Traduçáo de Linguagens de Progrm3ção .........

............ .

. . .............. ..... ". Os comandos while e de atribuiçáo podem ser definidos (parcialmente) pelas seguintes

I

produções:

I

J

-t





-t

while do



-t



I ...



Figura 1.5 Árvore de derivação

:=



-t

<

-t

I I J

< número >

+

100



I

1.3.3 Gerasão de Código Intermediário Esta fase utiliza a representação interna produzida pelo Analisador Sintático e gera como



saída uma sequência de código. Esse código pode. eventualmente, ser o código objeto fins1 mas, na maioria das vezes, constitui-se num código intermediário, pois a tradução de código fonte para objeto em mais de um passo apresenta algumas vantagens:

-

EXEMPLO 1.3 Árvore de derivação.

Considerando o comando while do exemplo 1.1, o Analisador Sintático produziria a árvore de derivação mostrada na Figura 1.5 (a partir da sequência de tokens liberada pelo Analisador

-

possibilita a otimização de código intermediário, de modo a obter-se o código objeto final mais eficiente; resolve, gradualmente, as dificuldades da passagem de código fonte para código objeto (alto nível para baixo nível), já que o código fonte pode ser visto como um texto

Léxico).

R

condensado que "explode" em inúmeras instmções elementares de baixo nível.

As fases até aqui descritas constituem módulos que executam tarefas analíticas. As

A geração de código intermediário pode estar estruturalmente distribuída nas fases

fases seguintes trabalham para construir o código objeto: geração de código intermediário.

anteriores (andlise siniática e semintica) ou mesmo não existir (tradução direta para código

otimização e geração de código objeto.

objeto), no caso de tradutores bem simples.

12

..........................

I..._........

[mplemeni3q5ode Linguagens de Programiçzo - Ana M. A. Price e Sim20 S. Toscini .............................................................................................................................................................

A grande diferença entre o código intermediário e

O

código objeto final é que o

1 - TraduçBo de Linguagens de Progrnmnçlo .............................................................................................................................................................................

_._

.................... 13

1.3.5 Geração de Código Objeto

intermediário não especifica detalhes tais como quais registradores serão usados, quais Esta fase tem como objetivos: produção de código objeto, reserva de memória para constantes

endereços de memória serão referenciados, etc.

e variáveis, seleção de registradores, etc. É a fase mais difícil, pois requer uma seleção cuidadosa das instnições e dos registradores da máquina alvo a fim de produzir código objeto

EXEMPLO 1.4 Código ititertriediário.

eficiente. Existem tradutores que possuem mais uma fase para realizar a otimização do código Para o comando while apresentado anteriormente, o gerador de código intermediário,

objeto, isto é, otimização do código dependente de máquina.

recebendo a árvore de derivação mostrada na figura 1.5, poderia produzir a seguinte sequência de instnições:

.

EXEMPLO 1.6 Código de ttiáqiti,io.

L0

i f l < 100goto L1 goto L2

L1

TEMP := J

+

1

I := TEMP

A partir do código intermediário otimizado mostrado no exemplo antenor, obter-se-ia o código objeto final abaixo, código este baseado na linguagem simbólica de um microcomputador PC 8086.

goto L0 L2

L0

MOV AX.1

...

CMP AX, 100 JGE

L2

(I

4

a e

(I!

MOV AX. J

Há vários tipos de código intermediário: quádruplas, triplas, notação polonesa pósfixada. etc. A linguagem intermediária do exemplo acima é chamada "código de três

MOV BX, I

endereços". pois cada instrução tem no máximo três operandos.

ADD BX

1.3.4 Otiniização de Código

JMP L0

MOV I, AX L2

...

Esta fase tem por objetivo otimizar o código intermediário em termos de velocidade de execução e espaço de memória.

1.3.6 Gerência de Tabelas

EXEMPLO 1.5 Código orúlikado.

Este módulo não constitui uma fase no sentido das anteriores, mas compreende um conjunto de tabelas e rotinas associadas que são utilizadas por quase todas as fases do tradutor.

Considerando o código intermediário do exemplo anterior, o seguinte código otimizado Algumas das tabelas usadas são fixas para cada linguagem. por exemplo, a tabela de

poderia ser obtido:

palavras reservadas, tabelas de delimitadores, etc. Entretanto, a estrutura que possui impoflincia fundamental é aquela que é montada durante a análise do programa fonte, com goto L0 L2

...

informações sobre:

-

declarações de variáveis;

- declarações dos procedimentos ou subrotinas;

-

parâmetros de subrotinas; etc.

4 4-

i(l

4 4

(1

4

I

Implementaqão de Linguagens de Progr~maçào- Ana M. A. Pnce e s ~S. ~~~~i ~ s ~ _.__..__ ...................... .. ............ ...i~trexigem que a gramática não apresente recursividade à esquerda. Quando a recursão é direta, a eliminação é simples (ver Exemplo 3.4). Quando a

I

repita

/

X - + X I...X,,

E

P tq Xl ,...,X , E N, )

até que o cardinal de N, não aumente. b) Erapa 2: Consrririr co~ljuiitode produções setn prodiL I*

Inicialmente. o cabeçote aponta para o símbolo mais à esquerda da sentença de O

próximo símbolo na fita de entrada;

entrada. Observando as ações produzidas pelo reconhecedor. pode-se notar que as produções

I I1

i

usadas na análise constituem uma derivação mais à esquerda da sentença.

3) se X é um símbolo não-terminal, o analisador consulta a entrada M[X, a] da tabela de análise. Essa entrada poderá conter uma produção da gramática ou ser vazia. Supondo M[X. a] = ( X + UVW), o analisador substitui X (que está no topo da pilha) por WVU (ficando U no topo) e retoma a produção aplicada. Se M[X, a] é vazia, isso corresponde a uma situação de erro; nesse caso, o analisador chama uma rotina de tratamento de erro. O comportamento do analisador pode ser descrito através de uma tabela que mostra. a cada passo. o conteúdo da pilha e o restante da sentença a ser lida, conforme é exemplificado a seguir. EXEMPLO 3.10 Moiti~tienrosde

rcm

a~talisndorrabiilnr predirivo.

Considere a gramática nào-ambígua abaixo que gera expressões lógicas:

I

T

E

-t

EvT

T

+

T&F ( F

F +

- F

( i d

Eliminando-se a recursividade à esquerda das produções que definem E e T, obtémse:

Figura 3.5 Movimentos de um analisador tabular preditivo

O O algoritmo que guia os movimentos de um analisador preditivo n5o-recursivo é

E - + TE' E'-+

vTE'I

apresentado a seguir: E

Algoritmo do Analisudor Preditivo Tabular:

T - 3 FT'

T'+

&FT'IE

Entrada: Uma sentença

S

e a tabela de análise h l para a gramática G.

Resultado: Uma derivação mais à esquerda de A tabela de análise preditiva para essa gram6tica é mostrada a seguir:

s, se s está em L(G), ou uma indicação de

erro, caso contrário.

I

I

I

I.

Método: Inicialmente, o analisador está numa configuração na qual a pilha contém $S (com S no topo), e a fita de entrada contém s$. O programa utiliza a tabela de análise preditiva h1 e comporta-se do seguinte modo: Posiciona o cabeçote sobre o primeiro símbolo de s$; Com a sentença mostrados na Figura 3.5

idvidkid,

o reconhecedor preditivo realiza

OS

movimentos

Seja X o símbolo do topo da pilha e a o símbolo sob o cabeçote.

I

1

....

3) Se X + Y,Y ,...Y, é uma produção e. para algum i, todos Y,,Y,, Y,, derivam E, então FIRST(YJ está em FIRST(X). Se todo Y,íj =1,2 .....k) deriva E , então E está em FIRST(X).

Repete se X é um terminal então se X = a então desempilha X e avança o cabeçote

Algoritrtro para calcular FOLLO W(X):

senão ERRO

Para computar FOLLOW(X), aplicam-se as regras abaixo até que não se possa

senão I* X é um símbolo não-terminal *I se M[X,al = X + Y, Y,

adicionar mais símbolos ao conjunto.

... Y,

1) Se S é o símbolo inicial da gramática c $ é o marcador de fim da sentença, então $

então { desempilha X;

está em FOLLOW(S).

empilha YkY,,... Y, com Y, no topo; imprime a produção X + Y,Y....Y,

2) Se existe producão do tipo A fazem parte de FOLLO\V(X).

1

senão ERRO até que X = $ I* pilha vazia * I O

-+

aXfi. então todos os terminais de FIRST(B)

3) Se existe produção do tipo A + CLY. O U A -t aXfi,sendo que j3 +* E , então todos os terminais que estiverem em FOLLO\i'(A) fazem parte de

FOLLOW(X).

Na implementação de um analisador preditivo tabular, a maior dificuldade está na constmção da iabela de análise. Para constmir essa tabela, é necessário computar duas

EXEMPLO 3.11 De/erttibiação das j ~ n ç õ e sFIRST e FOLLOW.

funções associadas i gramática: as funçóes FIRST e FOLLOW.

Considere novamente a gramática da expressão lógica:

Definição 3.10 FIRST(a). Se a é um3 forma sentencia1 (sequência de símbolos da gramática). então FIRST(a) é conjunto de terminais que iniciam formas sentenciais derivadas a partir de a. Se a

**

E

O

,

então a palavra vazia também faz parte do conjunto.

E +

TE'

E'+

vTE'

T

FT'

-t

IE IE

T'+

& FT'

F +

-,FI id

Definição 3.11 FOLLOW(A). A função FOLLOW é definida para símbolos não-terminais. Sendo A um não--terminal,

FOLLOI\'(A) é o conjunto de terminais a que podem aparecer imediatamente i direita de A

em alguma forma sentencial. Isto é, o conjunto de terminais a, tal que existe uma derivação da forma S ** aAap para a e

Cor~uirlosFIRST:

Convém iniciar pelos não-terminais para os quais a obtenção do conjunto FIRST é trivipl. Isso ocorre para F, que deriva apenas formas sentenciais que iniciam por terminais: FIRST(F) = (

quaisquer.

id )

1,

T' deriva no terminal & e na palavra vazia; logo: FIRST(T') = ( & ,

Cálcrrlo dasfunções FIRST e FOLLOW

E

)

Similarmente, E' deriva no terminal v e na palavra vazia: Algoritnto para calcular FIRST(X):

FIRST(E') = ( v , Para computar FIRST(X) para um símbolo X da gramática, aplicam-se as regras abaix0, até que não se possa adicionar mais terminais ou E ao conjunto em questão. 1) Se a é terminal, então FIRST(a) = ( a

2) Se S

-t E

1.

é uma produ~ão,então adicione

Portanto: FIRST(T) = (

E

a FIRST(X)

E )

Como T deriva apenas em FT',e F não deriva a palavra v a i a , então FIRST(T) = FIRST(F).

id )

1,

3 - Analise Sintafica _._ ................. ..........................................................................................................................................

Irnplernenlaslo de Linguagens de Prograrn;ição- Ana M. A. Price e Simão S. Toscani

50

Para

E +T E '

Para

E'

Para

E' -,E

Para

T + FT'

Para

~'+&FT'tem-se

Tem-se que FOLLOW(E') = FOLLOW(E), pois E' é o ultimo símbolo do lado direito da

Para

T' + E

produção E - + T E ' (regra 3):

Para Para

Como E deriva apenas em E

+ TE? e T não deriva E, tem-se FlRST(E) = FIRST(T): FIRST(E) = (

-. id

)

Corijuritos FOLLOIV: FOLLO\V(E) contém $ pela regra 1: FOLLOW(E) = j $ )

FOLLOW(E') = ( $ ) A parrir da análise da produção E'

4

tem-se

+ V T E' tem-se

FIRST(T E') =

1

-. id )

MIE'. v ] = E + v T E'

tem-se

FOLLOW(E') = I f

M[E'.$] = E'+ e

lem-se

FIRST(F T') = (

I

-. id )

M[T.

] = M[T. id] = T+ F T'

FIRST(&B=l&)

M[T',&]=T'+&FT'

tem-se

FOLLOW(T') = [

M[T.

F+-F

tem-se

F

F -+ id

tem-se

FIRST( id ) = 1 id 1

R

(

F

)

S)

)

]

<

MIE. -, ] = M[E. id] = E-, TE'

FIRST(vT E') = [ v ]

V.

51

. $ se S a ' y a 6 e 6 é ~ o u N T . Figura 3.1 1 Tabela de precedência obtida pelo método intuitivo

A regra 2 (aaX$) diz: um terminal a seguido imediatamente de um não-terminal X

[em precedência menor que os primeiros terminais deriváveis a partir de X (estes terminais aparecem em formas sentenciais precedidos de E ou NT). Estes terminais estarão num haiidle Para o caso de expressões lógicas. a tabela de precedência é obtida de maneira similar. Nesse caso, tem-se dois operadores binários (v e A) e um operador unário prefixado (7). sendo que o operador

A

tem precedência sobre o operador v. O caso dos operadores

unários é considerado a seguir.

fazer "0 < -I" e

"7

A regra 3 (fibfl) diz: todos os últimos terminais que podem ser derivados a partir de

um não-terminal X (terminais que aparecem bem à direita, sucedidos de

E

ou NT) têm

precedência maior que um terminal que segue imediatamente a X. Estes terminais estarão num Iiaridle que será reduzido antes do Iiandle que contém b.

Operadores unários: O operador lógico

que será reduzido antes do handle que contém a.

apresenta maior precedência que o v e o

A.

Para introduzi-lo, basta

> 0 , para qualquer operador 0, quer binário ou unário. Para o "-", a

EXEMPLO 3.17 Eliniitiação da atnbigiiidade de Irrna gramática.

Seja G a seguinte gramática:

complicação adicional é o fato de que ele pode ser tanto binário como unário. Uma solução

E

simples seria o analisador léxico distinguir entre os dois tipos de lokens. por exemplo, representando o operador unirio por "+I".

Nesse caso, a solução seria a mesma do "7". Essa

-t

E+E

I

E*E

I

E**F

I

(E)

I

id

G é de operadores. porém é ambígua. É possível tomar G não-ambígua, transformando as

soluçáo é usada pelo analisador léxico do Fortran, que devolve "-u" se o "-"é precedido de

produções para expressar a precedência e a associatividade dos operadores. Consegue-se isto

outro operador, de abre parênteses, de vírgula ou de símbolo de atribui~no.Outra solução,

introduzindo um símbolo não-terminal, para cada nível de precedência, conforme será visto

não muito elegante. seria proibir o uso de

O-"

unário: por exemplo, ao invés de escrever "-

e", o programador seria obrigado a escrever "(0-e)".

neste exemplo.

Implementaçlo de Linguagens de Progr~maçio- Ana M. A. Price e Simno S. ~~~~~~i .._ .... ....._.._ ....... .............................................................................. .................. -.. ..................................................................

62



+

>

)

* > **

Eliminando a ambigüidade (conforme o exemplo anterior), tem-se a seguinte gramática: E -+ E + T T

-t

T*F

F

-+

P**F

P -+ id -~

I

1 I I

T

F P

(E)

~~

' Na expressáo A**I**J.6 16gico avaliar da direita para a esquerda.

isto 6. calcular primeiro K:=I'*J e depois calcular A**K. porque se fosse usado o sentido esquerda-tdireita (isio 6. calcular B=A**I e depois B**J) o que obteríamos de fato seria A**(18J),e náo 6 isso o que se quer (convenga-se de que (A8*I)**J = A**(IWJ)).

4) Para computar =, examinar os lados direitos de produção procurando por formas apb, onde a e b são terminais, e

p é E ou NT, e fazer a = b. A única ocorrência dessa forma é

na produção P -+ ( E ) ;portanto: ( = )

5) $ tem precedência menor do que todos os "primeiros" terminais derivados a partir do símbolo inicial: $

< ( + * ** ( i d )

64

Irnplernenraçãode Linguagens de Programação - Ana M. A. Price e Simão S. Toscani

6 ) Todos os "Últimos" derivados a partir do símbolo inicial s30 > do que $: ( + *

**

) id]

3) Gerar um grafo dirieido cujos nodos sã0 os grupos anteriormente formados. Para quaisquer a e b, se a > b, construa um arco do gmpo fa para

> $

A matriz de precedência completa é aquela mostrada na Figura 3.1 1

3.3.2 Funções de Precedência

O

grupo gb e. se a < b,

construa um arco do grupo g b para o grupo fa. (Observe que o grafo é biparrido, isto é, não existem ligqões entre dois nodos f ou dois nodos g.) 4) Se o grafo contém ciclos, as funções de precedência não existem. Se não houvcr ciclos. f(a) é igual ao comprimento do caminho mais longo iniciando em fa; g(a) é

Para uma classe grande de gramáticas. a matriz de preccdência pode ser substituída pelas funções de preccdência f e g que mapeiam símbolos terminais para inteiros. As funções de

igual ao comprimento do caminho mais longo iniciando em ga.

precedência permitem uma representação mais eficiente, pois ocupam um espaço 0(3*n). scndo n o númcro de terminais da gramática, enquanto a matriz de preccdência ocupa um espaço O(n*n). Infelizmcntc, nem toda tabcla de precedência pode ser substituída por

Scja a matriz de precedência pua gramática que gera expressões lógicas simplificadris:

funçõcs de preccdência como pode ser visto no algoritmo aprescniado mais adiantc. Sejam a e h símbolos terminais. A dcterminaçáo de f e g é ta1 quc: f(a) < g(b) sempre que a < b [(a) = g(b) sempre que a = b f(a) > g(b) sempre que a > b Na comparaç50 de dois símbolos a e b usa-se a função f para o símbolo da pilha e a funçáo g para o da entrada. Assim, a relaçáo de precedência entre a e b é equivalente à relaçáo numérica entre f(a) e g(b). Como sempre existirá uma relaçáo ou = entre f(a) e g(b), quaisquer que sejam a e b, então as entradas de erro da matriz de precedência não terão representação. Os erros serão detectados quando. em reduções, os hatldles náo forem encontrados na pilha.

Algoritr~iopara ericoritrar as Funções d e Precedêizcia Entrada: matriz de precedência. Saída: funções de precedência, se existirem. I) Criar símbolos fa e ga para cada terminal a e para o

S.

2) Distribuir os símbolos criados em grupos. Se a=b, entáo f a e g b ficam no mesmo grupo. Se a=b e c=b, então fa e fc ficam no mesmo grupo que gb. Se, ainda, c=d, então fa, fc. gb e gd ficam no mesmo grupo. mesmo que a=d 1130ocorra.

Seguindo o algoritmo proposto, obtém-se o grafo da Figura 3.12. As funções f e g resultam os seguintes valores:

66

ImplementaçJo de Linguagens de Programação - Ana M. A. Price e Sim50 S. Toscani

......................................................................................................................................................................................................

3) LALR (Look Ahead LR). de nível intermediário e implementação eficiente, que funciona para a maioria das linguagens de programação. O YACC gera esse tipo de analisador. Nesta seção, será apresentada em detalhe a construç50 de um analisador SLR(1)

Funcionaniento dos A~ialisadoresLR A estruiura genérica de um analisador LR(I) é mostrada na Figura 3.13. A fila de entrada

mostra a sentença (al ... a, ... a, $) a ser analisada, e a pilha armazena símbolos da gramática

(X,) intercalados com estados (E,) do analisador. O símbolo da base da pilha é Figura 3.12. Grafo para obter as funções de precedência.

3.3.3 Analisadores LR(k)

b.estado

inicial do analisador. O analisador é dirigido pela Tabela dc Análise, cuja estrutura é mostrada na Figura 3.14. Fita de entrada

Os analisadores LR O f t to right with Rightmost derivation) são analisadores redutores eficientes que lêem a sentençrr em análise da esquerda para a direita e produzem uma

Pilha

derivação mais à direita ao reverso. considerando k símbolos sob o cabeçote de leitura. Dentre as vantagens identificadas nesses analisadores. destacam-se:

Em

Xr"

Analisador

1) são capazes de reconhecer, praticamente. todas as estruturas sintáticas definidas por gramáticas livres do contexto;

Xl

E0 -

2) O método de reconhecimento LR é mais geral que o de precedência de operadores e que qualquer outro d o tipo empilha-reduz e pode ser implernentado com o mesmo grau de eficiência; 3) analisadores LR são capazes de descobrir erros sintáticos no momento mais cedo.

X, - símbolo da gramática E, - estado

isto é, já na leitura da sentença em análise.

Figura 3.13 Estrutura dos analisadores LR

A principal desvantagem desses analisadores é a dificuldade de implementação dos

mesmos, sendo necessário utilizar ferramentas automatizadas na construção da tabela de análise. Há, basicamente, três tipos de analisadores LR:

A Tabela de Análise é uma tabela de transição de estados formada por duas partes: a parte AÇÃO contém ações (empilhar, reduzir, aceitar, ou condição de erro) associadas às transições de estados; e a parte TR~SSIÇÃOcontém transições de estados com relação aos

1) SLR (Simple LR), fáceis de implementar, porém aplicáveis a uma classe restrita de

gramáticas; 2) LR Canônicos, mais poderosos, podendo ser aplicados a um grande número de

linguagens livres do contexto; e

símbolos não-terminais.

Irnplernenta~áode Linguagens de Prograrnaçáo -

68

................................................

Ana

M.A. Price e Simáo S. Toscani

................. _ .

-........................................

3 - Anilise Sintática ........................................... ......

sendo

101 = r

69

_

............................................................ ...........................................................

e TRANSIÇÃO[E,,.,.A] = E,. Nesse caso. são desempilhados 2r símbolos,

para depois ser empilhado "A E,". empilha reduz

estados

EXE,MPLO 3.20 Alovi~neiitosde uni a~ialisadorSLR(1). Considerando a gramática abaixo. que gera expressões lógicas, a Figura 3.15 mostra a tabela

erro

de análise SLR(1) e os passos do analisador para reconhecer a sentença id&idvid.

Figura 3.14 Estmtura da Tabela de Análise

O analisador funciona basicamente conio segue. Seja E, o estado do topo da pilha e ai

1) E + E v T

4)T-F

2)E-T

5) F + ( E )

3) T -+ T & F

6) F

+

id

o rokeii sob o caheçote de leitura. O analisador consulta a tabela AÇÃo[L,. a,]. que pode assumir um dos \.alares: a) empilha E,: causa o empilhamento de "a, E,"; b) reduz n (onde n é o número da produç50 A-+D):causa o desempilhamento de 2r simbolos. onde r = I 0 1. e o empilhamento de "AE," onde Ey resulta da consulia 3 tabela de TRANSIÇÃO[E,,,.,. A];~ C)

ace11a:O analisador reconhece a sentença como válida;

d) erro: o analisador pára a execução, identificando um erro sintático

O funcionamento do analisador pode ser entendido, considerando as transfomaçõcs que ocorrem na pilha e na fita de entrada para cada ação. No texto que segue, consideram-se as configurações da pilha e da fita representadas por pares da forma (, ). A configuração inicial de um analisador LR é:

Considerando que a configuração atual é como segue: (

,

Pilha

O id 5

Entrada id & id V id $ & id v id $

OF3

& id v id $

OT2 OT2&7 OT2&7id5

& id v id $ id v id $ v id $

o

TRkh;SIÇÃO[ O F ]

)

tem-se que a configuraçáo resultante após cada ação é:

OT2&7FIO AÇÃOIE,, a,] = reduz A

+P :

( < & X I E I X z E2...Xm.,&.,AE,>,

< a , a , +... ~ a,%>)

osições o esi~doque estQno topo da pillia logo após a operaçáo de redufào; após a trimsi~ã~. p ao topo irio conter Em-r A Ey.

"tti-rk

Açãonransição e5: empilha id 5 r6: reduz F-tid

I

vid $

r4: reduz T+F TRANSIÇÁO[ OT] e7: empilha &: 7 e5: empilha id 5 r6: reduz F-tid

( TRASSIÇÃO[

1 r3: reduz

7F]

OT2

vid $

T-tT&F TRANSICÃO[ OT 1 r2: reduz E+T

OE I OE I v 6

vid $ id $

e6: empilha v 6 e5: empilha id 5

TRANSIÇÃO[ O E ]

70

Implementa~áode Linguagens de Progr~mnção- Ana M. A. Pric- e simão S.~~~~~i

....

...........................

(continuação) Pilha OEIv6id5

... .....,,...,.._
View more...

Comments

Copyright ©2017 KUPDF Inc.
SUPPORT KUPDF