Anda di halaman 1dari 105

Compiladores

Ricardo Lus de Freitas

ndice
1
1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 1.10 1.11 1.12

Conceitos Formais.............................................................................................. 1
Introduo....................................................................................................................................1 Conceitos Bsicos........................................................................................................................1 Gramtica ....................................................................................................................................4 Conceitos Auxiliares....................................................................................................................6 Forma Normal de Backus (BNF).................................................................................................7 Tipos de Gramtica......................................................................................................................8 Hierarquia de Chomsky ...............................................................................................................9 rvores de Derivao para GLC ...............................................................................................13 Relaes teis ...........................................................................................................................18 Gramtica Reduzida ..................................................................................................................19 Conceitos ...................................................................................................................................20 Autmatos .................................................................................................................................23

2
2.1 2.2

Especificao de uma Linguagem Simplificada de Programao.................. 29


Descrio BNF da Linguagem Simplificada .............................................................................30 Fundamentos da Programao em LPD.....................................................................................34 2.2.1 A Linguagem LPD.............................................................................................................34 2.2.2 Estrutura de um Programa em LPD...................................................................................34 2.2.3 Palavras Reservadas ..........................................................................................................35 2.2.4 Identificadores Definidos pelo Usurio .............................................................................35 2.2.5 Declaraes VAR ..............................................................................................................35 2.2.6 Introduo aos Tipos de Dados..........................................................................................36 2.2.7 Comando de Atribuio.....................................................................................................37 2.2.8 Procedimentos e Funes em LPD ....................................................................................37 2.2.9 Chamadas a Procedimentos e Funes ..............................................................................38 2.2.10 Declarao Global X Local ...........................................................................................39 2.2.11 Operaes ......................................................................................................................40 2.2.12 Decises e "Loop" .........................................................................................................43

3
3.1 3.2 3.3 3.4 3.5 3.6 3.7

Estrutura Geral dos Compiladores ................................................................. 46


Funcionamento Bsico de um Compilador................................................................................46 Analisador Lxico .....................................................................................................................46 Analisador Sinttico ..................................................................................................................47 Analisador Semntico................................................................................................................48 Gerao de Cdigo ....................................................................................................................49 Otimizao Global e Local ........................................................................................................49 Um Exemplo do Funcionamento de um Compilador ................................................................50

4
4.1 4.2 4.3 4.4 4.5

Analisador Lxico ............................................................................................ 52


Temas da Anlise Lxica...........................................................................................................52 Tokens, Padres, Lexemas.........................................................................................................53 Atributos para os Tokens ...........................................................................................................54 Erros Lxicos.............................................................................................................................55 Anlise Lxica no CSD .............................................................................................................56

5
5.1 5.2 5.3 5.4 5.5

Tabela de Smbolos .......................................................................................... 62


Entradas na Tabela de Smbolos................................................................................................62 Tabela de Smbolos como rvore Invertida ..........................................................................63 Visibilidade dos Smbolos ....................................................................................................64 A Tabela de Smbolos Organizada como um Vetor ..................................................................65 Tabela de Smbolos no CSD......................................................................................................66

Anlise Sinttica .............................................................................................. 67

6.1 6.2 6.3 6.4 6.5 6.6

O Papel do Analisador Sinttico................................................................................................67 Anlise Sinttica Ascendente ....................................................................................................68 Anlise Sinttica Descendente...................................................................................................69 Tratamento dos Erros de Sintaxe ...............................................................................................70 Estratgia de Recuperao de Erros ..........................................................................................73 Anlise Sinttica no CSD ..........................................................................................................74

7
7.1 7.2 7.3

Analisador Semntico ...................................................................................... 82


Gramtica com Atributos...........................................................................................................82 Tabela de Smbolos ...................................................................................................................82 Erros Semnticos no CSD .........................................................................................................83

8
8.1 8.2 8.3 8.4 8.5 8.6 8.7

Mquina Virtual e Gerao de Cdigo ........................................................... 85


Caractersticas Gerais da MVD .................................................................................................85 Avaliao de Expresses ...........................................................................................................86 Comandos de Atribuio ...........................................................................................................89 Comandos Condicionais e Iterativos .........................................................................................90 Comandos de Entrada e de Sada...............................................................................................94 Sub-Programas ..........................................................................................................................95 Procedimentos sem Parmetros .................................................................................................97

Bibliografia..................................................................................................... 102

Ricardo Lus de Freitas

Notas de Aula - Compiladores 1

1 Conceitos Formais
1.1 Introduo
Como resultado de pesquisas em mais de 40 anos, as linguagens de programao tm avanado constantemente, o que tem gerado boas perspectivas aos programadores. Seja com as tcnicas tais como a programao estruturada, orientada a objetos, ou mesmo com a utilizao de ferramentas CASE (Computer-Aided Software Engineering). Nestes anos, a grande dificuldade concentra na polarizao entre padronizar ou no as linguagens de programao. A no padronizao permite a incorporao de novas tendncias, tais como as linguagens paralelas. Ambientes de programao (Ex. Turbo Pascal) acrescentam um grande nmero de novas junes, fazendo com isso que cada verso fornea novas possibilidades aos programadores. Porm, isso torna o cdigo cada vez mais dependente da plataforma onde ele executado. O propsito bsico das linguagens de programao gerar instrues para o computador executar o processamento propriamente dito. Existe a necessidade de facilitar a comunicao entre o homem e a mquina visto que os computadores operam num nvel atmico) em linguagem de mquina (dgitos binrios, registradores, posies de memria, endereo etc.), enquanto as pessoas preferem expressar-se usando linguagens naturais, mais prximas da nossa. Atravs das linguagens de programao, consegue-se : Facilidades para se escrever programas; Diminuio do problema de diferenas entre mquina; Facilidade de depurao e manuteno de programas; Melhoria da interface homem/mquina; Reduo no custo e tempo necessrio para o desenvolvimento de programas; Aumento da compatibilidade e modularidade

Para diminuir as diferenas entre a linguagem de mquina e a linguagem natural que surgiu a linguagem de programao.

1.2 Conceitos Bsicos


1) Alfabeto ou vocabulrio. Conjunto finito no vazio de smbolos. Ex. {a, b} {1, 2, 3} {while, for, do} N={0, 1, 2, 3, 4, 5, 6, 7, 8, 9} V={1, +, ), a} 2) Smbolos (tomos, letras) Elementos do alfabeto. 1, 7, 2 so smbolos de N a, + so smbolos de V

Ricardo Lus de Freitas

Notas de Aula - Compiladores 2

3) Cadeias (palavras, sentenas) Qualquer concatenao finita de smbolos de um alfabeto. Cadeia de N = 1234 Cadeia de V = +1 Exerccio V1 = {a, b} Escreva 3 cadeias diferentes para V1 contendo 3 smbolos cada uma. Cadeia 1 = Cadeia 2 = Cadeia 3 =

Cadeia vazia ( a cadeia que contm elementos) = (ou ) 4) Fechamento de um alfabeto Seja V um vocabulrio (ou alfabeto), ento o fechamento V* o conjunto das cadeias de qualquer comprimento sobre o vocbulo V. Chama-se V+ o fechamento positivo de V, definida por : V+ = V* - {} Exerccio Seja V = {0, 1} V* = 5) Concatenao de cadeias Seja s = a1 a2 ... an t = b1 b2 ... bn (ai, bi V) A concatenao st = a1a2 ... an b1b2 ... bn; Para qualquer s em V*, tem-se s = s = s (elemento neutro); Associatividade s1 (s2s3) = (s1 s2) s3; Comutatividade s1 s2 s2 s1. V+ =

Dada uma cadeia no vazia s = a1 a2 ... an (ai, V), o inteiro n o seu comprimento e ser denotado por |s|. O comprimento || = zero, assim para s e t em V*, |st| = |s| + |t|; Dados s em V* e a em V, denotamos |s|a o nmero de ocorrncias de smbolo a em s. Outra vez se s e t forem cadeias em V* , temos |st|a = |s|a + |t|a

Ricardo Lus de Freitas

Notas de Aula - Compiladores 3

Exerccio Seja {a,b,c} |aaa| = |aabbb|c = || = 6) Produto de dois alfabetos V1 = {a,b} V2 = {1, 2, 3} V1 x V2 = {a1, a2, a3, b1, b2, b3} V1 x V2 V2 x V1 7) Exponenciao de alfabetos

|aab|b = |ccc| = |cccd|c =

V0 = ; V1 = V ; Vn = V n - 1 V ; V* = V0 V1 V2 V3 ... Vn ... Exerccios. a) V = {0,1} V3 = V2 .V = V1 . V.V = V0.V.V.V V0 = V1 = b) V = {x, y, z} V2 = 9) Linguagem Uma linguagem sobre V (ou simplesmente linguagem) um subconjunto de V* Ex. Seja V = {a, b}. As quinze palavras mais curtas de V* so : {, a, b, aa, ab, ba, bb, aaa, bbb, aab, bba, aba, bab, abb, baa} L = {s V* / 0 |s| 3} L = {s V* / s=anb, n 0} = {b, ab, aab, aaab, ... } Exerccio Seja V = {+} , z = + Escreva as cadeias abaixo indicando o tamanho de cada uma delas z= zz = z2 = z5 = z0 = Escrever V* e V+ V2 = V3 =

Ricardo Lus de Freitas

Notas de Aula - Compiladores 4

1.3 Gramtica
Dispositivo de gerao de sentenas que formam as linguagens. Uma gramtica G = (Vn , Vt , P, S), onde : Vn : Alfabeto finito conhecido como vocabulrio no terminal que usado pela gramtica para definir construes auxiliares ou intermedirias na formao de sentenas. Ex. bloco de comandos Os smbolos de Vn so usados como nomes para categorias sintticas (verbo - Lngua Portuguesa). Representao usual : Elementos de Vn em letras maisculas. Vt : Alfabeto terminal, que so os smbolos dos quais as sentenas da linguagem so constitudas. Os smbolos de Vt so aqueles que aparecem em programas (letras, dgitos, palavras reservadas etc.). Representao usual : Elementos de Vt em letras minsculas (incio, fim etc.). V t Vn = V Vt Vn = vazio ()

Cadeias mistas { Vt Vn }* ou V* e so representadas por letras gregas. P : o conjunto finito de regras de produo, que so todas as leis de formao utilizadas pela gramtica para definir a linguagem. Cada produo P tem a forma , onde uma cadeia contendo no mnimo um no terminal ( V* Vn V* ) e uma cadeia contendo terminais e/ou no terminais ( V*). A interpretao de que pode ser substitudo por sempre que ocorrer. S : o elemento de Vn que d incio ao processo de gerao de sentenas, S o smbolo inicial da gramtica. Exerccio P : AB B1A B0 a) V = b) V* = c) 1110 L(G) ? Supondo a linguagem L(G) = {s/s {a, b, c}* e s = am b cn ,m 0, n 1} i) a b L(G) ? ii) a b b c L(G) ? iii) Qual a menor cadeia ?

Ricardo Lus de Freitas

Notas de Aula - Compiladores 5

Supondo a gramtica G = (Vn , Vt , P, Sentena) Vn = {SENTENA, SN, SV, ARTIGO, VERBO, SUBSTANTIVO, COMPLEMENTO} Vt = {aluno, o, estudou, compiladores}

P : SENTENA SN SV SN ARTIGO SUBSTANTIVO SV VERBO COMPLEMENTO COMPLEMENTO ARTIGO SUBSTANTIVO | SUBSTANTIVO ARTIGO o SUBSTANTIVO aluno | compiladores VERBO estudou Derivar : o aluno estudou compiladores

Ricardo Lus de Freitas

Notas de Aula - Compiladores 6

1.4 Conceitos Auxiliares


1) Smbolo inicial sentena da linguagem 2) Uma cadeia gera diretamente ( ) uma cadeia see () P e apenas uma produo aplicada, substituindo por , segundo a gramtica G.
G

aplicao de sucessivas regras

3) Supondo que 1 , 2 ... n so cadeias de V* e 1 2 , 2 3 , ... ,n-1 n , ento diz-se que 1


* G G G G

n se podemos obter n de 1 pela aplicao de um nmero finito de

derivaes pertencente a P. Este processo denomina-se derivao pela aplicao zero ou mais derivaes diretas. 4) Uma derivao no trivial corresponde a uma aplicao de no mnimo uma derivao direta e denotada por + . 5) Se estiver clara qual a gramtica envolvida, os smbolos podem ser substitudos por ,
* G

* G

+ G

, respectivamente.
*

6) Uma cadeia {Vn Vt }* uma forma sentencial see S

Obs : S o smbolo inicial da gramtica e pela definio tambm uma forma sentencial. 7) Uma forma sentencial uma sentena de G see V*t , ou seja, uma sentena uma forma sentencial particular onde todos os seus elementos so terminais. 8) A linguagem gerada por G, denotada por L(G), o conjunto de todas as possveis sentenas por ela gerada atravs de derivaes a partir do smbolo inicial S. L(G) = { w/w V* e S
*

w}

9) Duas gramticas G1 e G2 so equivalentes see L(G1) = L(G2), ou seja, see suas linguagens so iguais. Ex. Quais as linguagens geradas para as seguintes gramticas: G1= ({S}, {a,b}, P, S) P: S aSb S ab S S S ab (menor cadeia) aSb aabb aSb aaSbb aaabbb

G2 = ({S}, {a,b}, P, S) P: S aAb A ab||S S S S aAb aAb aAb ab (menor cadeia) aabb aSb aaAbb aaabbb

Ricardo Lus de Freitas

Notas de Aula - Compiladores 7

L(G1) = L(G2) = {w/w {a,b}* e w = anbn,n>0}. Portanto G1 e G2 so equivalentes.

1.5 Forma Normal de Backus (BNF)


Outra maneira de representar as regras de produo . 1) substitudo por ::= w s w ::= s 2) Os ns no terminais so palavras entre < >. A notao BNF usada para definir gramticas com as caractersticas de que o lado esquerdo de cada regra composta por um nico smbolo no terminal. Ex. G ({S, M, N}, {x,y}, P, S) P: Sx SM M MN Ny M xy BNF G = ({<S>, <M>, <N>}, {x,y}, P, <S>) <S> ::= x | <M> <M> ::= <M> <N> | xy <N> ::= y

Os smbolos <, >, ::= no fazem parte da linguagem L(G) = ?

Exerccio Escreva a gramtica para a seguinte linguagem. L(G) = {w/w {00, 11}* e w = (0011)n , n 0}

Ricardo Lus de Freitas

Notas de Aula - Compiladores 8

1.6 Tipos de Gramtica


1) Gramtica do tipo 0 (Irrestritas) So aquelas s quais nenhuma limitao imposta, exceto a existncia de pelo menos 1 smbolo no terminal do lado esquerdo das regras. Todo o universo das linguagens gerado por gramticas deste tipo. As produes so do tipo onde V* Vn V* e V* V = {Vn Vt} 2) Gramtica do tipo 1 (Sensveis ao Contexto) Se nas regras de produo for imposta a restrio de nenhuma substituio aplicado se causar a reduo no tamanho da cadeia gerada, cria-se a classe de gramticas sensveis ao contexto. As produes so do tipo onde V* Vn V* e V+ e || || Exemplo : aAbcD abcDbcD tipo 1 Abc abDbc tipo 1 AC A no tipo 1

3) Gramtica do tipo 2 (Livres de Contexto) Apresentam uma restrio adicional de que as regras de produo tem apenas 1 elemento no terminal do lado esquerdo ou seja : , Vn e V+ Exemplo : G = ({A,B,C}, {a,b,c}, P, A) L(G) = {a, b, c}

P:

A BC | a Bb Cc

4) Gramtica do tipo 3 (Regulares) Possui a restrio de que as produes substituem um no terminal por uma cadeia de um terminal seguido (direita) (ou precedido (esquerda)), ou no, por um nico no terminal. Produes do tipo : A B ; A ou A B ; A Exemplo : G = (Vn , Vt , P, S) P: S aS S bA Ac L(G) = { w/w {a, b, c}* e w = an bc, n 0 }

Ricardo Lus de Freitas

Notas de Aula - Compiladores 9

1.7 Hierarquia de Chomsky


Toda gramtica regular livre de contexto, toda livre de contexto sensvel ao contexto e toda sensvel ao contexto irrestrita. Tipo 0 Tipo1 Tipo2 Tipo3

Ricardo Lus de Freitas

Notas de Aula - Compiladores 10

Lista de Exerccios n 1 1) Representar a gramtica do exemplo de um sub-conjunto da lngua Portuguesa em BNF. 2) Escreva duas gramticas equivalentes cuja linguagem seja : L(G) = {w/w {a, b}* e w = am bn , m 0 n 1} 3) Escreva uma gramtica para cada uma das linguagens abaixo : a) L(G1 ) = {w/w {a, b, c}* e w = a bn c, n 0} b) L(G2 ) = {w/w {0, 1}* e w = 0m 1n, m n 1} 4) Seja a gramtica abaixo : <S> o smbolo inicial <S> ::= <B> <B> ::= <C> | <C> + <D> <C> ::= <D> | <C> * <D> | *<D> <D> ::= x | (<S>) | - <D> a) Definir Vt e Vn b) Gere 10 sentenas para esta gramtica. 5) P S aSBC | aBC CB BC aB ab bB bb bC bc cC cc Qual a L(G) ?

G = ({S,B,C},{a,b,c},P,S)

Ricardo Lus de Freitas

Notas de Aula - Compiladores 11

Lista de Exerccios n 2 1) Indique qual o tipo das seguintes gramticas : a) G = ({M,N,O,P}, {x,y,z,w}, P, O) P OP P zzz O PNMx O zw Nz Mz b) G = ({M,N,O,P}, {x,,z,w}, P, O) P OzP PO O PNMx OzO zW NM z d) G = ({M,N,O,P}, {x,y,z,w}, P, O) O Mx | Nw Nz My

P:

P:

c) G = ({M,N,O,P}, {x,y,z,w}, P, O) P OP | y0 O PNMx | x OyO zwxyO NM zM

P:

P:

2) Construa as gramticas para as seguintes linguagens a) L(G1) = {0n1m , m,n 0} b) L(G2) = {(xyz)p , p 1} c) L(G3) = {(011)n 0p , p 1, n p} 3) Determinar o tipo da gramtica e gerar 3 sentenas para G = ({A,B,S}, {a,b,c}, P, S) P: S Aa Ac A Ba B abc

4) Seja A = {0,1} , x = 01 e y = 110 Escrever as cadeias xy, yx, xyx, x2, (xy)3 , (xx)2 5) Descrever as linguagens geradas pelas gramticas abaixo e classific-las segundo a hierarquia de Chomsky. Defina tambm Vt , Vn . S o smbolo inicial. a) P: SA A A0 A 1A A0 10 S S0 S A1 A 0A0 A1 b) P: S 1S S 1A A 0A A0

c) P:

Ricardo Lus de Freitas

Notas de Aula - Compiladores 12

6) Mostre a linguagem gerada pelas produes da GLC abaixo e construa uma GR equivalente. G = ({A, B, S}, {a, b}, P, S) S AB A aA A aBB B Bb Bb

P:

Ricardo Lus de Freitas

Notas de Aula - Compiladores 13

1.8 rvores de Derivao para GLC


Seja a gramtica abaixo : G = ({E}, {a, b, +, *, (, ) }, P, E) P : E E * E | E + E | (E) | a | b A sentena (a+b)*a pode ser obtida por vrias derivaes distintas, por exemplo : 1) E 2) E E*E E*E (E) * E E*a (E + E) * E (E) * a (a + E) * E (a + b) * E (a + b) * a

(E+E) * a

(E + b) * a

(a + b) * a rvore 2

rvore 1 E E ( E ) E + E a b * E a

A mesma que 1

No existe na rvore de derivao a ordem em que foram feitas as substituies: 1 e 2 apresentam a mesma rvore. Definio : Dada uma GLC G = (Vn , Vt , P, S), uma rvore dita rvore de derivao para G se: a) Todo n tem um rtulo, que um smbolo de V = {Vn Vt } b) O rtulo da raiz o smbolo inicial c) Todo n no folha tem como rtulo um smbolo Vn d) Se um n rotulado A e seus ns descendentes imediatos da esquerda para a direita, rotulados A1 , A2 , A3 ... Ak, ento A A1A2A3 ... Ak deve ser uma produo de P. e) A construo da rvore termina quando todas as folhas forem smbolos Vt Exerccio : Construir a rvore de derivao para a sentena ((a*b)+(a*a)) e para a+b*a, usando a gramtica G acima definida.

Ricardo Lus de Freitas

Notas de Aula - Compiladores 14

Definio : Dada uma gramtica G = (Vn , Vt , P, S) ela dita ambgua see existir uma cadeia x L(G) para a qual podem ser construdas duas rvores de derivao diferentes. Seja a cadeia a+b*a 1) E E*E E E E + E a 2) E E+E E E a + E E * E b a b E+E*E a+E*E a+b*E a+b*a * E a E+E*E a+E*E a+b*E a+b*a

Tem-se portanto diferentes rvores para a mesma sentena. Isso decorre da ambiguidade da gramtica. A gramtica ambgua porque no tem precedncia de operadores.

Gramtica acima convertida para no ambgua (foi inserida a precedncia na derivao dos operadores (* e +)). P: EE*T|T TT+F|F F a | b | (E)

Mesmo com G no ambgua, tem-se mais de uma derivao para a mesma sentena, embora com a mesma rvore de derivao. Isto se deve ao fato de poder substituir qualquer no terminal em qualquer ordem. possvel escolher um determinado no terminal ou mais a esquerda ou mais a direita. Derivao esquerda : se por um passo no qual o no terminal mais a esquerda
e d

Ricardo Lus de Freitas

Notas de Aula - Compiladores 15

substitudo, escrevemos Derivao direita.

. De maneira anloga podemos escrever

, para a

Derivaes direita e esquerda so chamadas cannicas. Exerccio : Faa as derivaes esquerda e direita usando a gramtica anterior para obter a seguinte sentena ((a+b)+b)

Ricardo Lus de Freitas

Notas de Aula - Compiladores 16

Exerccio : Dada G = ({S}, {a, b}, P, S) P : S aS | aSb | a a) L(G) ? b) rvores de derivao para a, aaab, aabb, abb c) G ambgua ? Em caso afirmativo encontre G , tal que L(G) = L(G) e Gno seja ambgua

Ricardo Lus de Freitas

Notas de Aula - Compiladores 17

Definio : Toda sentena de uma gramtica G tem pelo menos uma derivao esquerda e pelo menos uma direita. Para formas sentenciais, isto no necessariamente verdadeiro. Ex. (E + b) * E Definio : Uma gramtica G no ambgua see toda sentena de G tem uma nica derivao direita e uma nica esquerda. Ex. a + b * a Exerccios Resolvidos: 1) Dizer se so ambguas as gramticas, bem como qual a linguagem gerada. a) S aSaS | S aSaS aa S aSaS aaSaSaS aaaa S aSaS aaSaSaS aaaSaSaSaS aaaaaa L(G) = {w/w {a}* e w = (aa)n , n 0} S a S a S a S S a S S a b) S aSa | S aSa aa S aSa aaSaa aaaa S aSa aaSaa aaaSaaa aaaaaa L(G) = {w/w {a}* e w = (aa)n , n 0} S a S a S a S a a S a NO AMBGUA S

AMBGUA

Ricardo Lus de Freitas

Notas de Aula - Compiladores 18

2) Seja a rv7e de derivao para a gramtica G = (Vn , Vt , P, S) S A S c b S b b B A B S

b c b a) Qual a cadeia representada pela rvore ? b) Vn = ? Vt = ? c) bcbbcbb L(G) ? d) Quais produes (regra de derivaes) pertencem a P ? e) escreva uma derivao cannica para a rvore f) No item e quais as sentenas e formas sentenciais ? a) cbbbbcb b) Vn = {S,A,B} Vt = {c,b} c) S AB BSB bSB bcbB bcbbA bcbbSS bcbbcbS bcbbcbb

d) S AB | cb | b A SS | BS B b | bA e) S AB SSB bSB bbB bbb

f) formas sentenciais {AB,SSB,bSB,bbB,bbb} / sentena {bbb}

1.9 Relaes teis


Dada uma gramtica G, estamos interessados no conjunto de todos os smbolos x que podem aparecer no incio da cadeia derivvel de um no terminal A, ou seja, no conjunto {x / A x } Supondo que a gramtica G no contm produes da forma B e considerando a relao p (primeiro smbolo sobre V) definido por : Ap x see A x Em outras palavras, a relao p indica todos os smbolos que aparecem no incio de alguma cadeia derivvel diretamente de A. (vrias derivaes) fcil ver que o conjunto desejado dado por {x / Ap+ x}
+

Ricardo Lus de Freitas

Notas de Aula - Compiladores 19

S AB Sa/b Ac Bd p = {A,a,b} p+ = {A,a,b,c}

P: p p E T F a b ( ) + * p+

EE+T/T TT*F/F F a / b / (E)

E V

T V V

F V

a V

b V

( V

p+ E T F a b ( ) + *

E V

T V V

F V V

a V V V

b V V V

( V V V

1.10 Gramtica Reduzida


Restries 1) Uma produo da forma A A intil e sua eliminao no altera a linguagem gerada pela gramtica. Imporemos que a gramtica no deve permitir derivaes da forma: A
+

Ricardo Lus de Freitas

Notas de Aula - Compiladores 20

2) Todo smbolo da gramtica deve ser til, isto , deve aparecer em alguma forma sentencial e se for no terminal deve ser possvel derivar dele uma cadeia terminal. 2.1) S 2.2) X
*

X para algum e X terminal ou no w para algum w Vt* X no terminal

3) A gramtica no deve conter produes da forma A

1.11 Conceitos
EXPRESSES REGULARES Definio : a) Um smbolo terminal qualquer uma expresso regular; b) Se x e y so expresses regulares, a sua concatenao xy uma expresso regular; c) Se x e y so expresses regulares, a sua unio x + y uma expresso regular; d) O smbolo uma expresso regular. e) Se x uma expresso regular, (x) influencia na ordem de avaliao da expresso. Ex. ri = r . r . r . r ...(i vezes) uma expresso regular. x* = {, x, xx, xxx, ...} (01)* = {, 01, 0101, 010101, ...} abc*d = {abd, abcd, abccd, ...} (a + b)* = {, a, b, ab, aa, bb, aab, ...} L(G) = {0n1, n 0} = {1, 01, 001, 0001, ...} = 0*1 L(G) = {0n1, n 1} = {01, 001, 0001, ...} = 00*1 = 0+1 (0 + 1)* 00 (0 + 1)* = {00, 100, 000, 1000, ...} 1) (1 + 10)* = {, 1, 10, 110, 1010, ...} Cadeia vazia ou no contendo 0s e 1s, com o nmero de 1s maior ou igual ao nmero de 0s. 2) (0* 1* 2*) = {, 0, 1, 2, 01, 02, 12, 00, 11, 22, 012, ...} Cadeia vazia ou no contendo 0s, 1s e 2s, em qualquer quantidade respeitando essa ordem. 3) (0+ 1+ 2+) = {012, 0112, 0012, 0122, 001122, ...} Cadeia contendo 0s, 1s e 2s, sendo que contm pelo menos um elemento de qualquer um, em qualquer quantidade, respeitando essa ordem. RECURSIVIDADE DE PRODUO Definio : N N| logo N *| onde : e (Vn Vt)* N Vn Ex. S aS | b

Ricardo Lus de Freitas

Notas de Aula - Compiladores 21

FATORAO N | = (|) Ex. E T | +T | -T | E + T | E - T E + T | E - T = {+T|-T}* T | +T | -T = (|+|-)T = [+|-]T => [+|-]T{+T|-T}* Cadeia Opcional []: indica que opcional (pode ocorrer ou no). OCORRNCIAS ADJACENTES {, , ...} {||}*

GRAFO SINTTICO Expresses regulares N ( No terminal) T (terminal) 1 | 2 | n Grafo N T 1 2 n [] n {||}* * n abnc, n 1 a b c

Ricardo Lus de Freitas

Notas de Aula - Compiladores 22

Desenvolvimento de um subconjunto do Pascal e seu grafo sinttico <programa> ::= programa <identificador> ; <bloco> . programa identificador ; bloco .

<bloco> ::= [<etapa de declar. de var.>] [<etapa de declar. de subrotinas>] <comandos> comandos etapa de declar. de var etapa de declar. de subrotinas

<etapa de declar. de var.> ::= var <declarao de vars> ; { <declararao de vars> ; } var declarao de vars ;

<declarao de variveis> ::= <lista de identificadores> : <tipo> Lista de identificadores : tipo

<lista de identificadores> ::= <identificador> {, <identificador>} Identificador , <tipo> ::= inteiro / booleano inteiro boleano <comandos> ::= incio <comando> {; comando} fim incio comando ; fim

Ricardo Lus de Freitas

Notas de Aula - Compiladores 23

1.12 Autmatos
Um autmato uma mquina que possui um dispositivo de leitura e vrios estados, sendo que seu estado pode variar de acordo com o que for lido pelo dispositivo de leitura. Existem diversas formas de representar os autmatos, porm trs formas se destacam e sero usadas. a) Diagrama de estado b) Tabelas de transio c) Regras de transio Diagrama de estado Estado inicial : a partir de onde se iniciam os reconhecimentos da cadeia.

Estado : qualquer estado que faa parte do autmato (exceto o inicial e final). Estado final : qualquer sentena da linguagem de aceitao representada pelo autmato leva a um destes estados aps seu reconhecimento. transio : arco que representa a mudana de um estado para outro dentro do autmato. Exemplo : 1 Exerccio : 1) w = anbm , n 1 , m 1} 1 a 2 a b 3 b a b b 2

L(G) = {w/w {a,b}* e e=anbm , n 0, m 1}

2) (a b)m m 1 a b a

Ricardo Lus de Freitas

Notas de Aula - Compiladores 24

Tabela de Transio (do exerccio 2) Estado Anterior 1 1 2 2 3 3 Regra de Transio g(1,a) = 2 g(2,a) = 2 g(2,b) = 3 g(3,b) = 3 Tabela de Transio (do exerccio 3) Estado Anterior 1 1 2 2 3 3 Regra de Transio g(1,a) = 2 g(2,b) = 3 g(3,a) = 2 Fazer para o exerccio 1. Exerccio Resolvido Para o autmato a seguir : a b a a) Monte a tabela de transio correspondente. b) Monte as regras de transio correspondente. b c c Smbolo de Entrada a b a b a b Estado Posterior 2 erro erro 3 2 erro Smbolo de Entrada a b a b a b Estado Posterior 2 erro 2 3 erro 3

Ricardo Lus de Freitas

Notas de Aula - Compiladores 25

c) Escreva 5 sentenas. d) aabaaac aceita pelo autmato ? a) Tabela de Transio Estado Anterior A A A B B B C C C Regra de Transio g(A,a) = A g(A,b) = B g(B,a) = A g(B,b) = B g(B,c) = C g(C,c) = C c) bc, bbc, abc, aabbc, abaabc d) No porque sempre depois de um a, necessariamente precisa ter um b. A verificao (reconhecimento) de cadeias utilizando autmatos consiste em partir de um estado inicial, ler smbolos sequenciais, efetuando uma transio para cada smbolo lido. Dizemos que uma cadeia de n smbolos K= K1K2K3 ... Kn , N 0 aceito, ou reconhecido, por um autmato finito (AF) quando partindo-se do estado inicial desse AF, forem lidos todos os smbolos de K e efetuadas as correspondentes transies de modo que ao se ler Kn o AF para no estado final. Exerccios Resolvidos 1) Dado S0 0 1 S1 1 b S0 a S1 b Smbolo de Entrada a b c a b c a b c Estado Posterior A B erro A B C erro erro C

0 a) L(G) ? Cadeia no vazia terminado com 1 b) 00111 aceito ? Sim 00110 aceito ? No

a Cadeias com bs e as e qq ordem com n de as par , b, baa, babba, babaaba

Ricardo Lus de Freitas

Notas de Aula - Compiladores 26

Definio Formal AF uma quintupla ordenada = (S,so,F,A,g), onde: S: conjunto de estados de um autmato so: estado inicial, so S F: conjunto de estados finais, F c S. A: alfabeto de entrada g: SxAS: aplicao da transio Definir formalmente o autmato:

S0

S1

AF = ({S0,S1},S0,{S1},{0,1},g) S : S0,S1 So : S0 F : S1 A : 0,1 g : g(S0,0) = S0 g(S0,1) = S1 g(S1,1) = S1

Ricardo Lus de Freitas

Notas de Aula - Compiladores 27

EXERCCIOS 1) Usando a seguinte gramtica responda :` G=({E, V, N, O, T, D, L}, {0, 1, 2, 3, ...9, a, b, c, ...z, +, -, /, *, div, mod}, P, E) P: E V / N / VOE / NOE V L / LT N D / DN T L / D / LT / DT D 0 / 1 / 2 / ... / 9 L a / b / c / ... / z O + / - / / / * / div / mod

a) G ambgua ? b) Mostre a cadeia de derivao para a cadeia a + 1 div 4 c) Mostre as derivaes esquerda e direita para a cadeia do item b d) A cadeia 0 a mod b aceita ? e) No caso de G ser ambgua verifique, se possvel apresentar uma gramtica G1 equivalente a G que no seja ambgua 2) Para a rvore de derivao a seguir responda : S a c A S B e S a B d A b

a B A d b

a) Qual a sentena representada na rvore ? b) Quais smbolos so Vn e Vt ? c) Quais produes pertencem a P ? d) A cadeia adbacb L(G) ? e) Escreva uma direo cannica para a rvore 3) Para as regras de produo obtidas na questo 2, elabore a matriz que represente os conjuntos p , p+ , p* 4) Usando a gramtica da questo 1, elabore os grafos (diagramas) sintticos para cada elemento no terminal

Ricardo Lus de Freitas

Notas de Aula - Compiladores 28

5) Construir AF que reconhea as sentenas da linguagem L = {a bn c, n 0} e represente-o formalmente 6) Seja o AF = ({q0, q1, q2, q3}, q0, {q0}, {0,1}, g) g: g(qo,0) = q2 g(qo,1) = q1 g(q1,0) = q3 g(q1,1) = q0 g(q2,0) = q0 g(q2,1) = q3 g(q3,0) = q1 g(q3,1) = q2 a) Elabore o diagrama correspondente. b) Elabore a tabela de transio. c) Quais so as cadeias aceitas ?

Ricardo Lus de Freitas

Notas de Aula - Compiladores 29

2 Especificao de uma Linguagem Simplificada de Programao


Como j visto, consideramos linguagem uma determinada coleo de cadeias de smbolos de comprimentos finito. Estas cadeias so chamadas sentenas da linguagem e so formadas pela justaposio de elementos individuais, que so smbolos, tomos ou tokens da linguagem. Podemos representar uma linguagem de trs formas: Enumerao de todas as cadeias e smbolos possveis que formam as sentenas; Regras de formao das cadeias reunidas em um conjunto de regras chamado gramtica; Reconhecedor que atua atravs de regras de aceitao de cadeias . A forma efetivamente utilizada a ltima citada. As cadeias so reconhecidas como smbolos substituveis, denominados no-terminais, e smbolos no substituveis, denominados terminais. Antes de se implementar uma linguagem deve-se procurar defini-la da maneira mais precisa possvel. Em primeiro lugar devem ser especificadas todas as seqncias de smbolos que constituiro programas vlidos para uma linguagem. Somente estas seqncias sero aceitas pelo compilador. Assim, tem-se especificada a sintaxe da linguagem. A segunda fase consiste na definio do significado associado a cada construo da linguagem, que compem sua semntica. As regras que determinam a semntica de uma linguagem so muito mais difceis de serem determinadas se comparadas as regras sintticas. Devido a dificuldade de se definir regras semnticas, uma vez que no encontrado um padro que especifique as semnticas de linguagens, a construo de compiladores corretos bastante dificultada. Cada linguagem tem uma particularidade, o que exige um grau de significao diferenciado, interferindo diretamente na semntica da linguagem. Os principais objetivos a serem considerados no projeto de compiladores so: Produzir um cdigo objeto eficiente; Produzir cdigos objetos pequenos; Minimizar o tempo necessrio para compilar programas; Manter o compilador to pequeno quanto possvel; Produzir um compilador com boa capacidade de diagnstico e recuperao de erros; Produzir um compilador confivel. Como fcil perceber os objetivos acima muitas vezes so conflitantes. Por exemplo, um compilador ser mais lento e maior se o objetivo principal for um cdigo mais eficiente, e vice-versa. Dessa forma, torna-se necessrio definir qual dos objetivos o principal e balizar o desenvolvimento do compilador nesse objetivo, porm sem perder de vista os restantes. Outra deciso que deve ser tomada quanto ao nmero de passagens que sero executadas pelo compilador. considerada uma passagem cada vez que o compilador percorre o texto fonte. Do ponto de vista de simplicidade, os compiladores de uma nica passagem so atraentes. No entanto, nem todas as linguagens permitem uma compilao deste tipo. Como compilador de uma passagem entende-se aqueles que necessitam percorrer o texto do cdigo fonte apenas uma nica vez para obter a compilao. J os de vrias passagens necessitam percorrer o texto vrias vezes, sendo feita parcela da compilao a

Ricardo Lus de Freitas

Notas de Aula - Compiladores 30

cada passagem. Como exemplo tem-se que na primeira passagem seria feita a anlise lxica, na segunda a sinttica e assim por diante. Embora existam diferentes notaes para se especificar uma linguagem, a Forma Normal de Backus (BNF), tem se destacado devido a sua grande facilidade de compreenso. A BNF uma metalinguagem, ou seja, uma linguagem usada para especificar outras linguagens. A formalizao da sintaxe da linguagem feita atravs da especificao das regras de produo, ou regras de substituio, onde cada smbolo da metalinguagem associada uma ou mais cadeias de smbolos, indicando as diversas possibilidades de substituio.

2.1 Descrio BNF da Linguagem Simplificada


A linguagem que ser definida representa uma linguagem de programao estruturada semelhante linguagem de programao estruturada PASCAL. Esta linguagem receber o nome de LPD (Linguagem de Programao Didtica). O compilador a ser desenvolvido receber o nome de CSD (Compilador Simplificado Didtico). Os smbolos no terminais de nossa linguagem sero mnemnicos colocados entre parnteses angulares < e >, sendo os smbolos terminais colocados em negrito. Descrio BNF da Linguagem Simplificada <programa>::= programa <identificador> ; <bloco> . <bloco>::= [<etapa de declarao de variveis>] [<etapa de declarao de sub-rotinas>] <comandos> DECLARAES <etapa de declarao de variveis>::= var <declarao de variveis> ; {<declarao de variveis>;} <declarao de variveis>::= <identificador> {, <identificador>} : <tipo> <tipo> ::= (inteiro | booleano) <etapa de declarao de sub-rotinas> ::= (<declarao de procedimento>;| <declarao de funo>;) {<declarao de procedimento>;| <declarao de funo>;} <declarao de procedimento> ::= procedimento <identificador>; <bloco> <declarao de funo> ::= funcao <identificador>: <tipo>; <bloco>

Ricardo Lus de Freitas

Notas de Aula - Compiladores 31

COMANDOS <comandos>::= inicio <comando>{;<comando>}[;] fim <comando>::= (<atribuio_chprocedimento>| <comando condicional> | <comando enquanto> | <comando leitura> | <comando escrita> | <comandos>) <atribuio_chprocedimento>::= (<comando atribuicao>| <chamada de procedimento>) <comando atribuicao>::= <identificador> := <expresso> <chamada de procedimento>::= <identificador> <comando condicional>::= se <expresso> entao <comando> [senao <comando>] <comando enquanto> ::= enquanto <expresso> faca <comando> <comando leitura> ::= leia ( <identificador> ) <comando escrita> ::= escreva ( <identificador> ) EXPRESSES <expresso>::= <expresso simples> [<operador relacional><expresso simples>] <operador relacional>::= (<> | = | < | <= | > | >=) <expresso simples> ::= [ + | - ] <termo> {( + | - | ou) <termo> } <termo>::= <fator> {(* | div | e) <fator>} <fator> ::= (<varivel> | <nmero> | <chamada de funo> | (<expresso>) | verdadeiro | falso nao <fator>) <varivel> ::= <identificador> <chamada de funo> ::= <identificador >

Ricardo Lus de Freitas

Notas de Aula - Compiladores 32

NMEROS E IDENTIFICADORES <identificador> ::= <letra> {<letra> | <dgito> | _ } <nmero> ::= <dgito> {<dgito>} <dgito> ::= (0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9) <letra> ::= (a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z| A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z) COMENTRIOS Uma vez que os comentrios servem apenas como documentao do cdigo fonte, ao realizar a compilao deste cdigo faz-se necessrio eliminar todo o contedo entre seus delimitadores. delimitadores : { }

Ricardo Lus de Freitas

Notas de Aula - Compiladores 33

Exerccios 1) Criar o diagrama sinttico para a linguagem definida. 2) Represente a rvore de derivao para o seguinte programa programa test; var v: inteiro; i,max, juro,: inteiro; incio enquanto v <> -1 faca incio {leia o valor inicial} leia(v); {leia a taxa de juros } leia(juro); { Leia o periodo }; leia(max); valor:= 1; i:= 1; enquanto i <= max { (1+juro) elevado a n } faca incio valor:= valor*(1+juro); i:= i+1 fim; escreva(valor) fim fim.

Ricardo Lus de Freitas

Notas de Aula - Compiladores 34

2.2 Fundamentos da Programao em LPD


2.2.1 A Linguagem LPD Por ser bem prxima da linguagem PASCAL, a linguagem LPD possui muitas de suas caractersticas: um a linguagem altamente estruturada. Necessidades rigorosas na definio de variveis e procedimentos. Voc deve definir todas as variveis, procedimentos, e funes, antes de us-las. Funes e procedimentos. Estas so estruturas auto-delimitadas, nas quais voc pode organizar cada uma das diferentes sees do seu programa. Variveis locais e globais. Voc pode declarar e usar variveis locais em qualquer procedimento ou funo. Os valores de dados de variveis locais permanecem privados para as rotinas que os usem. Voc pode tambm declarar variveis globais que podem ser usadas em qualquer parte do programa. Decises SE estruturadas. Elas permitem que voc construa complexas tomadas de decises. "Loop" estruturado. LPD fornece "loop" estruturado, no qual voc pode especificar a condio sob a qual o "loop" dever continuar (ENQUANTO). 2.2.2 Estrutura de um Programa em LPD Agora vamos examinar a estrutura de um programa em LPD, focalizando os elementos individuais dessa estrutura, especificamente as declaraes VAR, e de sub-rotinas (PROCEDIMENTO e FUNCAO), e a seo principal do programa. Um programa em LPD consiste de diversos elementos estruturais, incluindo os seguintes: Um cabealho PROGRAMA, que fornece o nome do prprio programa. Este cabealho deve ser includo em todos os programas, at nos mais triviais. O comando VAR que declara todas as variveis globais usadas no programa. Esta declarao opcional. Procedimentos e funes, que contm as instrues para tarefas definidas individualmente no programa. Uma seo principal do programa, que controla as aes do mesmo atravs das chamadas a procedimentos e funes includas no programa, ou atravs de comandos executveis. Um esboo de um programa em LPD visto a seguir: programa NomePrograma; var {declarao de variaveis} {declarao de rotinas} incio {programa principal} {comandos da seo principal} fim. {programa principal} As declaraes VAR, de procedimentos e funes so opcionais; as nicas partes necessrias so o cabealho e a seo principal do programa. Consequentemente, a forma mais simples de um programa em LPD tem um cabealho e um

Ricardo Lus de Freitas

Notas de Aula - Compiladores 35

bloco de comandos limitados por INCIO/FIM contendo um ou mais comandos executveis. programa NomePrograma; incio Comando; Comando; Comando; fim. 2.2.3 Palavras Reservadas As palavras que identificam as partes de um programa - por PROGRAMA, VAR, PROCEDIMENTO, FUNCAO, INCIO, FIM - so palavras reservadas. Todas palavras reservadas possuem significados fixos linguagem, que no podem ser alterados. LPD possui as palavras reservadas tabela abaixo.
E SENAO INTEGER LEIA ESCREVA INCIO FIM NAO ENTAO BOOLEANO FALSO OU VERDADEIRO DIV FUNCAO PROCEDIMENTO VAR

exemplo, chamadas dentro da listadas na

FACA SE PROGRAMA ENQUANTO

2.2.4 Identificadores Definidos pelo Usurio Os identificadores na linguagem LPD podem ter comprimento de at 30 caracteres, onde todos os 30 so significativos. Os identificadores devem comear com uma letra do alfabeto, seguida de qualquer nmero de dgitos ou letras. O caractere sublinhado _, tambm legal dentro de um identificador. 2.2.5 Declaraes VAR Variveis so identificadores que representam valores de dados num programa. LPD necessita que todas as variveis sejam declaradas antes de serem usadas (a falha na declarao de uma varivel resulta em um erro em tempo de compilao). Voc pode criar tantas variveis quanto forem necessrias para satisfazer a necessidade de dados dentro de um determinado programa, dentro do limite de memria disponvel. Tipos simples de variveis so projetados para armazenar um nico valor por vez; quando voc atribui um novo valor a uma varivel, o valor armazenado previamente ser perdido. Existe ainda a estrutura vetor, que representa uma lista de valores sob um nico nome. Na seo VAR, voc especifica explicitamente o tipo de cada varivel que voc cria. Aqui est o formato geral da seo VAR: . . var NomedaVarivel1 : Tipo1; NomedaVarivel2 : Tipo2; . .

Ricardo Lus de Freitas

Notas de Aula - Compiladores 36

Alternativamente, voc poder usar o formato a seguir para declarar vrias variveis do mesmo tipo: . . var NomedaVarivel1, NomedaVarivel2, NomedaVarivel3 : Tipo; . . Por exemplo, a seo a seguir declara uma varivel do tipo inteiro e trs variveis do tipo booleano. . var Codigo_Erro : inteiro; Sair, ExisteLista, Troca_Dados : booleano; . 2.2.6 Introduo aos Tipos de Dados Os programas em LPD podem trabalhar com dados expressos como valores literais (tal como o nmero 6), ou como valores representados simbolicamente por identificadores (variveis). Sem considerar como o valor est expresso, voc deve tomar cuidado para distinguir os tipos de dados que LPD reconhece. O uso de dados de modo no apropriado resulta em erros em tempo de compilao. LPD possui dois tipos de dados padro: Tipo numrico inteiro. Tipo booleano. Tipo Inteiro LPD oferece o tipo numrico inteiro INTEGER. Este tipo fornece uma ampla faixa de valores de nmeros inteiros, que vai de -32768 at +32767. Um inteiro no possui valor decimal, e sempre perfeitamente preciso dentro de sua faixa. Valores Booleanos Um valor booleano pode ser tanto VERDADEIRO (verdadeiro), como FALSO (falso). (Os valores booleanos so assim chamados em homenagem ao matemtico ingls do sculo dezenove George Boole. Usaremos algumas vezes o termo alternativo valor lgico.) LPD fornece um conjunto de operaes lgicas e relacionais, que produzem expresses que resultam em valores VERDADEIRO ou FALSO. Veremos estas operaes mais tarde. O identificador padro BOOLEANO define uma varivel desse tipo, como neste exemplo:

Ricardo Lus de Freitas

Notas de Aula - Compiladores 37

. . var Achei : Booleano; . . Os valores lgicos constantes VERDADEIRO e FALSO so identificadores padro na linguagem LPD, e tem significado fixo para esta. 2.2.7 Comando de Atribuio Uma vez que voc tenha declarado uma varivel de qualquer tipo, poder utilizar um comando de atribuio para armazenar um valor na mesma. A sintaxe do comando de atribuio a seguinte: NomedaVarivel := Expresso; Para executar este comando, o CSD avalia a expresso localizada no lado direito do sinal de atribuio e armazena o valor resultante na varivel esquerda. O nome da varivel aparece sempre sozinho, no lado esquerdo do sinal de atribuio. A expresso localizada do lado direito pode ser simples ou complexa. Considere estes exemplos: . . var Achei : booleano; Numero, Linha, Coluna, Local_Erro : inteiro; . . Achei := VERDADEIRO; Numero := 5; Local_Erro := Coluna * (Linha + 160); . . O primeiro exemplo atribui o valor booleano VERDADEIRO varivel Achei, o segundo atribui o nmero 5 varivel Numero, o terceiro atribui o resultado de uma expresso aritmtica varivel Local_Erro. 2.2.8 Procedimentos e Funes em LPD Como j vimos, LPD suporta dois tipos de blocos estruturados : procedimentos e funes. Ns nos referimos a estes blocos genericamente como subprogramas, sub-rotinas, ou simplesmente rotinas. A estrutura de um procedimento semelhante a de uma funo (na LPD). A diferena principal que a funo explicitamente definida para retornar um valor de um tipo especificado.

tambm

Ricardo Lus de Freitas

Notas de Aula - Compiladores 38

Uma chamada a um procedimento ou funo representada num programa em LPD por uma referncia ao nome da prpria rotina. Entretanto o contexto de uma chamada depende da rotina ser procedimento ou funo: A chamada de um procedimento independente como um comando completo e resulta na execuo do procedimento. A chamada de uma funo sempre parte de um comando maior. O nome da funo representa o valor que a funo definitivamente retorna. Em outras palavras, o nome de uma funo sempre um operando em um comando, nunca o prprio comando. Aqui est o formato geral de um procedimento em LPD: procedimento NomedaProcedimento; var {declarao de variveis locais} incio {corpo do procedimento} fim; Nesta representao da sintaxe, NomedaProcedimento o identificador que voc cria como nome do procedimento. A declarao VAR dentro do bloco do procedimento define as variveis locais para a rotina. O formato geral de uma funo similar, mas tem duas diferenas importantes: funcao NomedaFuno: TipodoResultado; var {declarao de variveis locais} incio {corpo da funo} NomedaFuno := ValordeRetorno; fim; NomedaFuno o nome de identificao da funo. Observe que o cabealho da funo define o tipo da funo - ou seja, o tipo do valor que a funo retorna - com o identificador TipodoResultado. Igualmente, dentro de toda funo dever existir um comando de atribuio que identifique o valor exato que a funo retornar. Esse comando possui a seguinte forma: NomedaFuno := ValordeRetorno; 2.2.9 Chamadas a Procedimentos e Funes Um comando de chamada a uma rotina direciona o CSD para execut-la. Uma chamada tem a forma mostrada abaixo: NomedaRotina NomedaRotina faz referncia rotina definida dentro do programa. Por exemplo, considere a chamada a seguir da procedimento Soma definida anteriormente:

Ricardo Lus de Freitas

Notas de Aula - Compiladores 39

. . var X, Y: inteiro; . . Soma; . . Em contraste, a chamada a uma funo no independente como um comando, mas ao invs disso, aparece como parte de um comando maior. Geralmente uma funo est relacionada a uma seqncia de operaes que conduzem a um nico valor calculado. Por exemplo, considere a funo Exp a seguir: funcao Exp: inteiro; var Contador, Resultado, Base, Expoente : inteiro; incio leia(Base); leia(Expoente); Contador := 1; Resultado := 1; enquanto Contador <= Expoente faca incio Resultado := Resultado * Base; Contador := Contador + 1; fim; Exp := Resultado; fim; A funo est definida para retornar um valor do tipo INTEGER. O comando de atribuio no fim da funo especifica que Resultado o valor de retorno. Auxiliar := Exp (3,4) * 5; A varivel que recebe o valor retornado pela funo, bem como o resto da expresso, deve ser do mesmo tipo da funo. No exemplo acima, Auxiliar deve ser do tipo INTEGER. 2.2.10 Declarao Global X Local Ns j vimos que os procedimentos e funes podem ter sua prpria seo VAR. A localizao de um comando de declarao determina o escopo dos identificadores correspondentes: Declaraes em nvel de programa (localizadas imediatamente abaixo do cabealho PROGRAMA), definem identificadores globais, ou seja, variveis que podem ser usadas em qualquer ponto do programa.

Ricardo Lus de Freitas

Notas de Aula - Compiladores 40

Declaraes em nvel de procedimentos e funes definem identificadores locais, ou seja, variveis que s podem ser usadas dentro de uma rotina em particular, sendo removidas da memria quando a execuo da rotina se completa. Alm disso, um procedimento ou funo pode ter suas prprias definies de procedimentos ou funes aninhadas. Uma rotina que esteja localizada inteiramente dentro do bloco de definio de outra rotina, est aninhada dentro desta mesma rotina e local para a rotina que a contm. Por exemplo, considere a rotina hipottica a seguir: procedimento MaisExterna; var {declarao de variveis para MaisExterna}; procedimento Dentro1; {Dentro1 e local para MaisExterna} var {declarao de variveis para Dentro1}; incio {comandos de Dentro1} fim; procedimento Dentro2; {Dentro2 tambm e local para MaisExterna} var {declarao de variveis para Dentro2}; funcao Dentro3 : Booleano; {Dentro3 e local para Dentro2} var {declarao de variveis para Dentro3}; incio {comandos de Dentro3} fim; incio {comandos de Dentro2} fim; incio {comandos de MaisExterna} fim; Neste exemplo, o procedimento MaisExterna possui dois procedimentos locais: Dentro1 e Dentro2. Estes dois procedimentos s esto disponveis para MaisExterna. Alm disso, o procedimento Dentro2 possui sua prpria funo local: Dentro3. Dentro3 s est disponvel para Dentro2. Os procedimentos e funes locais esto sempre localizados acima do bloco INCIO/FIM da rotina que as contm. 2.2.11 Operaes A linguagem LPD oferece duas categorias de operaes, cada qual designada para ser executada sobre um tipo de operando especfico. Estas categorias so as seguintes:

Ricardo Lus de Freitas

Notas de Aula - Compiladores 41

Operaes numricas, que trabalham com tipos inteiros. Operaes relacionais e lgicas, que resultam em valores booleanos. Agora veremos cada uma destas categorias de operaes. Operaes Numricas As quatro operaes numricas so smbolos a seguir: * div + Multiplicao Diviso Adio Subtrao representados na linguagem LPD pelos

Estas so chamadas operaes binrias, por necessitarem sempre de dois operandos numricos. Em contraste, o sinal de menos tambm pode ser utilizado para expressar um nmero negativo; a negao uma operao unria. O operando DIV fornece o quociente inteiro da diviso de dois nmeros; qualquer resto ser simplesmente descartado. Por exemplo, considere a expresso a seguir: a div b Se a varivel a possuir o valor 42, neste exemplo, e b o valor 8, o resultado da expresso ser 5. O resto da diviso, que 2, ser descartado. Em qualquer expresso que contenha mais de uma operao, o CSD normalmente seguir a ordem de precedncia na avaliao de cada operao. Aqui est a ordem, da mais alta para a mais baixa precedncia: 1. Negao 2. Mutiplicao, Diviso 3. Soma, Subtrao Onde existir mais de uma operao com o mesmo nvel de precedncia, as operaes com mesmo nvel sero executadas da esquerda para direita. Por exemplo, considere o fragmento de programa, no qual todos os operandos so do tipo INTEGER: a := 5; b := 4; c := 3; d := 2; x := a * b + c div d; Para atribuir um valor a x, o CSD ir avaliar primeiramente as expresses do lado direito do sinal de atribuio, nesta ordem: a multiplicao, a diviso e, finalmente a adio. A varivel x receber, assim, o valor 21. Se voc desejar que o CSD avalie uma expresso numa ordem diferente do modo padro, poder fornecer parnteses dentro da expresso. O CSD executa operaes dentro de parnteses antes de outras operaes. Por exemplo, considere como a adio de parnteses afeta o resultado da expresso anterior:

Ricardo Lus de Freitas

Notas de Aula - Compiladores 42

x := a * (b + c) div d; Neste caso, a adio realizada primeiramente, depois a multiplicao e, por ltimo, a diviso. Se as variveis tiverem os mesmos valores que antes, o novo resultado ser 17. Os parnteses podem estar aninhados dentro de uma expresso, ou seja, um conjunto de parnteses pode aparecer completamente dentro de outro conjunto de parnteses. O CSD executa a operao localizada dentro dos parnteses mais internos primeiramente, e depois vai executando as operaes contidas nos parnteses mais externos. Por exemplo, no comando a seguir, a adio executada primeiramente, depois a diviso e finalmente, a multiplicao, dando um resultado igual a 15: x := a * ((b + c) div d); Numa expresso aninhada, cada "abre parnteses" deve ser correspondido por um respectivo "fecha parnteses", ou ocorrer um erro em tempo de compilao. Operaes Relacionais Uma operao relacional compara dois itens de dados e fornece um valor booleano como resultado da comparao. Aqui esto os seis operadores relacionais e os seus significados: = Igual < Menor que > Maior que <= Menor ou igual a >= Maior ou igual a <> Diferente de Voc pode usar estas operaes com dois valores do mesmo tipo. Por exemplo, digamos que a varivel inteira Escolha contenha o valor 7. A primeira das expresses a seguir fornece um valor falso, e a segunda um valor verdadeiro: Escolha <= 5 Escolha > 4 Operaes Lgicas A linguagem LPD possui trs operaes lgicas. Duas das quais - E, e OU - so operaes binrias, usadas para combinar pares de valores lgicos em expresses lgicas compostas. A terceira, NAO, uma operao unria que modifica um nico operando lgico para o seu valor oposto. Fornecendo dois valores ou expresses lgicas, representadas por Expresso1 e Expresso2, podemos descrever as trs operaes lgicas a seguir: Expresso1 E Expresso2 verdadeiro somente se ambas, Expresso1 e Expresso2, forem verdadeiras. Se uma for falsa ou se ambas forem falsas, a operao E tambm ser falsa.

Ricardo Lus de Freitas

Notas de Aula - Compiladores 43

Expresso1 OU Expresso2 verdadeiro se tanto Expresso1 como Expresso2 forem verdadeiras. A operao OU s resulta em valores falsos se ambas, Expresso1 e Expresso2, forem falsas. NO Expresso1 avalia verdadeiro se Expresso1 for falsa; de modo contrrio, a operao NAO resultar em falso, se Expresso1 for verdadeira. Os operadores lgicos (E, OU, e NAO), tm uma ordem de precedncia mais alta que os operadores relacionais (=, <>, <, >, <=, >=). Os parnteses so, portanto, necessrios para forar o CSD a avaliar as expresses relacionais antes de avaliar a expresso E. 2.2.12 Decises e "Loop" Para controlar eventos complexos, um programa iterativo em LPD deve ser capaz de tomar decises, escolher entre os cursos de aes disponveis, e executar aes repetidamente. Todas estas atividades necessitam de avaliaes bem sucedidas de condies lgicas, com o objetivo de decidir uma direo especfica na execuo atual ou de determinar a durao de uma seqncia de repetio em particular. A linguagem LPD fornece uma estrutura de controle para executar decises, e outra para executar "loop"; essas estruturas so o nosso prximo assunto. 2.2.12.1 Estrutura de deciso SE Uma estrutura de deciso SE seleciona um entre dois comandos (ou grupo de comandos), para execuo. A estrutura consiste de uma clausula SE (se), em companhia de uma clusula ENTAO (ento) e uma SENAO (seno): se Condio entao {comando ou grupo de comandos que sero executados se a condio for VERDADEIRO} senao {comando ou grupo de comandos que sero executados se a condio for FALSO}; Durante uma execuo, o CSD comea por avaliar a condio da clusula SE. Esta condio deve resultar num valor do tipo booleano, embora possa tomar uma variedade de formas, ela pode ser uma expresso de qualquer combinao de operadores lgicos e relacionais, ou simplesmente uma varivel do tipo BOOLEANO. Se a condio for VERDADEIRO, o comando ou comandos localizados entre o ENTAO e o SENAO so executados e a execuo pula a clusula SENAO. Alternativamente, se a expresso for FALSO, a execuo desviada diretamente para o comando, ou comandos, localizados aps a clusula SENAO. As clusulas ENTAO e SENAO podem ser seguidas tanto de um comando simples como de um comando composto. Um comando composto deve estar entre os marcadores INCIO e FIM. A estrutura do comando SE usando comandos compostos a seguinte: se Condio entao incio {comandos da clusula ENTAO} fim senao incio {comandos de clusula SENAO}

Ricardo Lus de Freitas

Notas de Aula - Compiladores 44

fim; No cometa o erro de omitir os marcadores INCIO/FIM nos comandos compostos de uma estrutura SE. Alm disso, no coloque o ponto e virgula entre o FIM e o SENAO numa estrutura SE. O CSD interpretar esta marcao incorreta como o fim do comando SE sendo que a clusula SENAO, a seguir, resultar num erro em tempo de compilao.Tendo em vista que a clusula SENAO opcional, a forma mais simples da estrutura SE a seguinte: se Condio entao {comando ou comandos que sero executados se a condio for VERDADEIRO}; Neste caso o programa executa o comando ou comandos aps a clusula ENTAO somente se a condio for verdadeira. Se ela for falsa, o comando SE no ter nenhuma ao. As estruturas SE podem estar aninhadas. Em outras palavras, toda uma estrutura de deciso, com as clusulas SE, ENTAO, e SENAO, pode aparecer dentro de uma clusula ENTAO ou SENAO de uma outra estrutura. O aninhamento de estruturas SE pode resultar em seqncias de decises complexas e poderosas. Como exemplo, considere o fragmento de programa a seguir: . . se N < 2 entao G := G + N senao incio H := G; P (N - 1, H); G := H; P (N - 2, G); fim; . . Neste exemplo, a deciso ser baseada no valor de N. Se N for menor que 2, o programa soma N ao valor de G e armazena em G. Se o valor de N for maior ou igual a 2, o programa executa o comando composto localizado aps a clusula SENAO. 2.2.12.2 A Estrutura do "Loop" ENQUANTO Aqui est a sintaxe do "loop" ENQUANTO: enquanto Condio faca Comando; Se o bloco do "loop" possuir um comando composto, a forma geral a seguinte: enquanto Condio faca incio {comandos que sero executados uma vez a cada iterao do "loop"} fim;

Ricardo Lus de Freitas

Notas de Aula - Compiladores 45

A condio uma expresso que o CSD pode avaliar como VERDADEIRO ou FALSO. O CSD avalia a expresso antes de cada iterao do "loop". A repetio continua enquanto a condio for VERDADEIRO. Em algum ponto, a ao dentro do "loop" comuta a condio para FALSO, antes de uma nova iterao a expresso ser avaliada novamente; como ela resultar em FALSO, o "loop" no ser executado. Como exemplo, considere o fragmento de programa a seguir: . . Contador := 0; enquanto Contador <= 11 faca incio escreva (Contador); Contador := Contador + 1; fim; A condio que controla este "loop" em particular o progresso da varivel Contador dentro do prprio "loop". Antes de cada iterao, o programa testa o valor de Contador para ver se menor que 11. Enquanto a condio for VERDADEIRO, o programa executar o "loop". Neste exemplo, o "loop" ser executado at que a instruo que incrementa a varivel Contador armazene na mesma um valor maior que 11. O programa ir, ento, avaliar a condio, obter o valor FALSO, e pular o "loop" passando a executar a instruo seguinte ao FIM. Podemos descrever a ao desse "loop" do seguinte modo: enquanto {enquanto} (contador for menor que 11) faca incio {escreva o valor do contador na tela, e incremente o seu valor de 1} fim;

Ricardo Lus de Freitas

Notas de Aula - Compiladores 46

3 Estrutura Geral dos Compiladores


Programa fonte
Analisador lxico

Analisador sinttico Analisador semntico Gerador de cdigo intermedirio Otimizador de cdigo

Gerenciador da tabela de smbolos

Tratador de erros

Gerador de cdigo

Programa alvo

3.1 Funcionamento Bsico de um Compilador


Este tpico ser dedicado uma breve explicao de cada mdulo da estrutura do compilador. Note-se que esta estrutura apenas uma representao didtica do funcionamento do compilador. Isto pode dar uma impresso de simplicidade e que o compilador seja esttico. Na verdade todos os mdulos esto em constante atuao de forma quase simultnea. Iniciaremos com o primeiro mdulo (anlise lxica) e seguiremos na ordem em que a figura indica para os demais mdulos.

3.2 Analisador Lxico


A anlise lxica a primeira das trs fases que compe a anlise do texto-fonte (source). Um analisador lxico, cumpre uma srie de tarefas, no somente relacionadas a anlise lxica, de grande importncia dentro do compilador. A principal funo deste analisador a de fragmentar o programa fonte de entrada em trechos elementares completos e com identidade prpria. Estes componentes bsicos so chamados tokens.

Ricardo Lus de Freitas

Notas de Aula - Compiladores 47

Ler caractere entrada Analisador lxico Empilha caractere de volta

passar tokens e seus atributos Analisador Sinttico

Conexo do Analisador Lxico com o Analisador Sinttico

Do ponto de vista da implementao do compilador, o analisador lxico atua como uma interface entre o texto fonte e o analisador sinttico, convertendo a sequncia de caracteres que constituem o programa na sequncia de tomos que o analisador sinttico consumir. Os tomos constituem-se em smbolos terminais da gramtica. O analisador lxico do compilador tem como funo varrer o programa fonte da esquerda para a direita, agrupando os smbolos de cada item lxico e determinando a sua classe. A seguir relacionamos algumas funes internas do analisador lxico. Extrao e classificao de tomos. Eliminao de delimitadores e comentrios. Identificao de palavras reservadas. Recuperao de erros
Analisador lxico Analisador sinttico

Programa fonte

Tabela de smbolos

Interao entre o analisador lxico, o analisador sinttico e a tabela de smbolos.

3.3 Analisador Sinttico


o segundo grande bloco componente dos compiladores. A principal funo deste mdulo a de promover a anlise da sequncia com que os tomos componentes do texto fonte se apresentam, a partir da qual se efetua a sntese da rvore sinttica, com base na linguagem fonte. O analisador sinttico ir processar a sequncia de tomos, proveniente do texto fonte, extrados pelo analisador lxico. A partir dessa sequncia o analisador sinttico efetua a verificao da ordem de apresentao na sequncia, de acordo com a gramtica na qual se baseia o reconhecedor. A anlise sinttica cuida exclusivamente da forma das sentenas da linguagem, e procura, com base na gramtica, levantar a estrutura das mesmas.

Ricardo Lus de Freitas

Notas de Aula - Compiladores 48

Programa Fonte

token
Analisador lxico Analisador sinttico

rvore
Resto da interface de vanguarda

representao intermediria

Obter prximo Token


Tabela de smbolos

gramatical

Interao do analisador sinttico com demais mdulos Para a representao de notao da gramtica de uma linguagem, uma forma que vem ganhando muitos adeptos devido a legibilidade de seu aspecto grfico so os diagramas sintticos j descritos anteriormente. Esses diagramas caracterizam-se por dois pontos diferentes: o ponto de partida e o de chegada. Os dois pontos so ligados entre si por um grafo orientado, cujos ndos representam pontos onde eventualmente podem ser feitas escolhas, e cujas arestas representam caminhos de percurso. Cada ramo pode incluir um terminal ou no terminal da gramtica. Identificao de sentenas. Deteco de erros de sintaxe. Recuperao de erros. Montagem da rvore abstrata da sentena. Comando de ativao do analisador lxico. Ativao de rotinas de anlise semntica. Ativao de rotinas de sntese do cdigo objeto.

3.4 Analisador Semntico


O principal objetivo do analisador semntico o de captar o significado das aes a serem tomadas no texto fonte. Ele compe a terceira etapa de anlise do compilador e refere-se a traduo do programa fonte para o programa objeto. Em geral a gerao de cdigo vem acompanhada de atividades da anlise semntica. Denominamos semntica de uma sentena o significado por ela assumido dentro do texto analisado, enquanto semntica da linguagem a interpretao que se pode atribuir ao conjunto de todas as sentenas. A fase da anlise semntica, porm, de difcil formalizao, exigindo notaes complexas. Devido a esse fato, na maioria das linguagens de programao adota-se especificaes mais simplificadas, com bases informais, atravs de linguagens naturais. A partir dessas informaes, podemos afirmar que a principal funo da anlise semntica criar, a partir do texto fonte, uma interpretao deste texto, expressa em alguma notao adequada que , geralmente, uma linguagem intermediria do compilador. Esta operao realizada com base nas informaes existentes nas tabelas construdas pelos outros analisadores, tabelas de palavras reservadas, mapas e sadas dos demais analisadores. Deve ser observada a fundamental importncia de uma anlise semntica bem realizada,

Ricardo Lus de Freitas

Notas de Aula - Compiladores 49

visto que toda a sntese estar embasada na interpretao gerada por este analisador. Entre as aes semnticas encontramos tipicamente as seguintes: Manter informaes sobre o escopo dos identificadores. Representar tipos de dados

3.5 Gerao de Cdigo


A gerao de cdigos a fase final da compilao. Uma gerao de cdigos tima sempre difcil, sendo importante destacar as dificuldades decorrentes das especificidades de cada mquina. A importncia do estudo deve-se ao fato de que um algoritmo de gerao de cdigos bem elaborado pode facilmente produzir cdigos que sero executados at duas vezes mais rpido do que os cdigos produzidos por um algoritmo pouco analisado. Devese destacar que a natureza exata do cdigo objeto altamente dependente da mquina e do sistema operacional. PROGRAMAS OBJETO Em geral, a entrada para uma rotina de gerao de cdigo um programa em linguagem intermediria. A sada do gerador de cdigo o programa-objeto. Esta sada pode apresentar-se numa variedade de formas de cdigo: linguagem de mquina absoluto, linguagem de mquina relocvel, linguagem montadora (assembly), ou ento outra linguagem qualquer de programao. Para o caso de sada em cdigo de linguagem de mquina absoluto, esta colocada em uma posio fixa na memria e executada imediatamente, podendo ser compilada e executada em poucos segundos. Como exemplo, pode-se citar os compiladores usados para fins didticos (student-jobs). A produo de cdigos em linguagem de mquina relocvel (mdulo objeto), permite que sub-programas sejam compilados separadamente. Um conjunto de mdulos objeto relocveis podem ser reunidos e carregados por um montador (linker). O fato de ser possvel compilar sub-rotinas separadamente e chamar outros programas compilados previamente a partir de um mdulo objeto, permite uma grande flexibilidade. Muitos compiladores comerciais produzem mdulos objeto relocveis. A produo de um cdigo em linguagem montadora como sada torna o processo de gerao de cdigos mais fcil. possvel gerar instrues simblicas e utilizar as facilidades do montador para auxiliar a gerao de cdigos. O custo adicional o passo em linguagem montada, depois da gerao de cdigo. Porm, como para a produo do cdigo em linguagem montada o compilador no duplicar o trabalho do montador, esta escolha outra alternativa razovel, especialmente para uma mquina com pouca memria disponvel, onde um compilador precise utilizar diversos passos. A produo de uma linguagem de alto nvel simplifica ainda mais a gerao de cdigos. Este tipo de implementao atua como pr-processador, e transfere os problemas de gerao do cdigo de mquina para um outro compilador.

3.6 Otimizao Global e Local


As tcnicas de otimizao de cdigo so geralmente aplicadas depois da anlise sinttica, usualmente antes e durante a gerao de cdigo. Essas tcnicas consistem em detectar padres no programa e substitu-los por construes equivalentes, porm mais

Ricardo Lus de Freitas

Notas de Aula - Compiladores 50

eficientes. Estes padres podem ser locais ou globais, e a estratgia de substituio pode ser dependente ou independente da mquina. Segundo Aho, o programa-fonte como entrada para um compilador uma especificao de uma ao. O programa-objeto, a sada do compilador, considerado como sendo outra especificao da mesma ao. Para cada programa-fonte, existem infinitos programas-objeto que implementam a mesma ao, ou seja, produzem a mesma sada para uma mesma entrada. Alguns desses programas-objeto podem ser melhores do que outros com relao a critrios tais como tamanho ou velocidade. O termo otimizao de cdigo refere-se s tcnicas que um compilador pode empregar em uma tentativa para produzir um programa-objeto melhorado, para um dado programa-fonte. A qualidade de um programaobjeto pode ser medida por seu tamanho ou tempo de execuo. Para programas grandes, o tempo de execuo particularmente importante. Para computadores de pequeno porte, o tamanho do cdigo objeto pode ser to importante quanto o tempo. Deve-se observar com cuidado o termo otimizao, devido dificuldade de se obter um compilador que produza o melhor programa-objeto possvel, para qualquer programa-fonte, a um custo razovel. Assim, um termo mais exato para otimizao de cdigo seria melhoria de cdigo (code improvement).

3.7 Um Exemplo do Funcionamento de um Compilador


Como exemplo do funcionamento de um compilador vamos analisar um simples clculo do permetro de um tringulo. A primeira etapa consiste na anlise do problema pelo programador. Se o problema o calculo de uma frmula matemtica, deve ser feito uma abstrao matemtica desta situao que a seguinte: Permetro = Lado 1 + Lado 2 + Lado 3 O prximo passo seria converter os elementos da frmula em variveis associadas aos mesmos. Para Lado 1 chamaremos b, para Lado 2 chamaremos c, para Lado 3 chamaremos d e finalmente para Permetro chamaremos a. Em linguagem computacional (alto nvel) a frmula de permetro representada pela seguinte equao: a=b+c+d O primeiro passo do compilador ser ento ler e identificar os smbolos, separando cada elemento. O analisador acessa a tabela de smbolos e palavras reservadas, montando assim uma relao entre os elementos e tokens da linguagem. Os tokens para este caso so: a,=,b,+,c,+,d,fim_de_linha. O caracter fim_de_linha desprezado, assim como todos os espaos em branco que no interessam compilao. A etapa seguinte ser a anlise sinttica que verificar se as variveis a, b, c, d so reconhecidas. Para isso o analisador sinttico consulta a tabela interna de smbolos ou declaraes explcitas, criada pelo analisador sinttico. Deve-se observar que os analisadores esto continuamente em contato entre si, sendo mutuamente ativados. O passo seguinte a verificao das operaes =e +, que devem ser reconhecidas como pertencentes gramtica da linguagem. Na etapa seguinte de investigao, necessrio identificar o que deve ser construdo. Neste exemplo deve-se abstrair o sentido da operao que deseja-se efetuar. Trata-se de uma anlise semntica muito simples. O analisador semntico constri uma linguagem intermediria que dever realizar a operao desejada e ser entendida pela mquina. Neste caso, o significado (semntica) que representa a equao do permetro a soma do Lado 1 com o Lado 2, o

Ricardo Lus de Freitas

Notas de Aula - Compiladores 51

resultado desta soma somado com o Lado 3. Em uma linguagem intermediria isso seria representado da seguinte forma: T1=b+c T2=T1+d A=T2 Com esta etapa realizada o compilador passa para a fase de sntese, que produzir a linguagem assembly (cdigo produzido pela linguagem de montagem (assembler) ), e, dependendo do compilador, efetuar duas otimizaes, global e local. Na primeira fase da sntese o compilador ir buscar uma forma de otimizar, se possvel, as sentenas obtidas pela anlise semntica. Esta fase chamada otimizao global. Podemos notar que a sentena acima no foi otimizada. Uma possvel otimizao seria a eliminao das duas ltimas sentenas em favor de uma que substitusse as duas como pode ser visto abaixo: T1=b+c A=T1+d O passo seguinte seria a produo de linguagem assembly para o texto acima. Caso a linguagem a ser produzida fosse para a arquitetura RISC_LIE, o cdigo que seria produzido a partir do texto no otimizado seria: Ldxw Add Stxw Ldxw Add Stxw Idwx Stxw b c t1 t1 d t2 t2 a

Ldxw: carrega palavra (correspondendo a load) Stxw: armazena palavra (correspondendo a store) O compilador poderia ento, numa ltima etapa de sntese, efetuar uma otimizao local, na linguagem assembly gerada. O resultado desta otimizao seria: Ldxw Add Add Stxw b c d a

A linguagem assembly gerada um mneumnico de cdigo binrio, que entendido pela C. P. U. da mquina. Como as C. P. U. so dispositivos eletrnicos que operam sob forma de tenses eltricas em dois nveis (0 se no h tenso e 1 se h tenso), a linguagem assembly corresponderia a uma sequncia de 0 e 1. Se o tamanho da palavra fosse 32 bits, teramos a seguinte sentena correspondente em linguagem de mquina instruo Ldxw b : 0101 1000 0001 0000 0000 0010 1101 1001

Ricardo Lus de Freitas

Notas de Aula - Compiladores 52

4 Analisador Lxico
O analisador lxico a primeira fase de um compilador. Sua tarefa principal a de ler os caracteres de entrada e produzir uma sequncia de tokens que o analisador sinttico utiliza. Essa interao, sumarizada esquematicamente na Figura 4.1, comumente implementada fazendo-se com que o analisador lxico seja uma sub-rotina ou uma co-rotina do analisador sinttico. Ao receber do analisador sinttico um comando obter o prximo token, o analisador lxico l os caracteres de entrada at que possa identificar o prximo token.
Token Analisador Lxico Obter prximo token Analisador Sinttico

Programa Fonte

Tabela de smbolos Figura 4.1: Interao do analisador lxico com o analisador sinttico.

Como o analisador lxico a parte do compilador que l o texto-fonte, tambm pode realizar algumas tarefas secundrias ao nvel da interface com o usurio. Uma delas a de remover do programa-fonte os comentrios e os espaos em branco, os ltimos sob a forma de espaos, tabulaes e caracteres de avano de linha. Uma outra a de correlacionar as mensagens de erro do compilador com o programa-fonte. Por exemplo, o analisador lxico pode controlar o nmero de caracteres examinados, de tal forma que um nmero de linha possa ser relacionado a uma mensagem de erro. Em alguns compiladores, o analisador lxico fica com a responsabilidade de fazer uma cpia do programa-fonte com as mensagens de erro associadas ao mesmo. Se a linguagem-fonte suporta algumas funes sob a forma de macros pr-processadas, as mesmas tambm podem ser implementadas na medida em que a anlise lxica v se desenvolvendo. Algumas vezes, os analisadores lxicos so divididos em duas fases em cascata, a primeira chamada de varredura(scanning) e a segunda de anlise lxica. O scanner responsvel por realizar tarefas simples, enquanto o analisador lxico propriamente dito realiza as tarefas mais complexas. Por exemplo, um compilador Fortran poderia usar um scanner para eliminar os espaos da entrada.

4.1 Temas da Anlise Lxica


Existem vrias razes para se dividir a fase de anlise da compilao em anlise lxica e anlise sinttica. 1. Um projeto mais simples talvez seja a considerao mais importante. A separao das anlises lxica e sinttica frequentemente nos permite simplificar uma ou outra dessas fases. Por exemplo, um analisador sinttico que incorpore as convenes para comentrios e espaos em branco significativamente mais complexo do que um que assuma que os mesmos j tenham sido removidos pelo analisador lxico. Se estivermos

Ricardo Lus de Freitas

Notas de Aula - Compiladores 53

projetando uma nova linguagem, separar as convenes lxicas das sintticas pode levar a um projeto global de linguagem mais claro. 2. A eficincia do compilador melhorada. Um analisador lxico separado nos permite construir um processador especializado e potencialmente mais eficiente para a tarefa. Uma grande quantidade de tempo gasta lendo-se o programa-fonte e particionando-o em tokens. Tcnicas de buferizao especializadas para a leitura de caracteres e o processamento de tokens podem acelerar significativamente o desempenho de um compilador. 3. A portabilidade do compilador realada. As peculiaridades do alfabeto de entrada e outras anomalias especficas de dispositivos podem ser restringidas ao analisador lxico. A representao de smbolos especiais ou no-padro, tais como ^ em Pascal, pode ser isolada no analisador lxico.

4.2 Tokens, Padres, Lexemas


Quando se fala sobre a anlise lxica, usamos os termos token, padro e lexemacom significados especficos. Exemplos de seus usos so mostrados na Figura 4.2. Em geral, existe um conjunto de cadeias de entrada para as quais o mesmo token produzido como sada. Esse conjunto de cadeias descrito por uma regra chamada de um padro associado ao token de entrada. O padro dito reconhecer cada cadeia do conjunto. Um lexema um conjunto de caracteres no programa-fonte que reconhecido pelo padro de algum token. Por exemplo, no enunciado Pascal Const pi = 3.1416; A subcadeia pi um lexema para o token como smbolos terminais na gramtica para a linguagem-fonte, usando nomes em negrito para represent-los. Os lexemas reconhecidos pelo padro do token representa cadeias de caracteres no programa-fonte, e podem receber um tratamento conjunto, como instncias de uma mesma unidade lxica (por exemplo, instncias de identificadores, nmeros etc. ). Na maioria das linguagens de programao, as seguintes construes so tratadas como tokens: palavras-chave, operadores, identificadores, constantes, literais, cadeias e smbolos de pontuao, como parnteses, vrgulas e ponto-e-vrgulas. No exemplo acima, quando a sequncia de caracteres pi aparece no programa-fonte, um token representando um identificador repassado ao analisador sinttico. O repasse de um token frequentemente implementado transmitindo-se um inteiro associado ao token. justamente esse inteiro que designado por id na Figura 4.2. Um padro uma regra que descreve o conjunto de lexemas que podem representar um token particular nos programas-fonte. O padro para o token const na Figura 4.2 exatamente a cadeia singela const, que soletra a palavra-chave. O padro para o token relacional o conjunto de todos os seis operadores relacionais de Pascal. Certas convenes de linguagem aumentam a dificuldade da anlise lxica. Linguagens como Fortran requerem certas construes em posies fixas na linha de entrada. Dessa forma, o alinhamento de um lexema pode ser importante na determinao da correo de um programa-fonte. A tendncia no projeto moderno de linguagens de programao est na direo de entradas em formato livre, permitindo que as construes sejam colocadas em qualquer local da linha de entrada, e, por conseguinte, esse aspecto da anlise lxica vem se tornando menos importante. O tratamento dos espaos varia grandemente de linguagem para linguagem. Em algumas linguagens, os espaos no so significativos, exceto quando dentro de literais do tipo cadeia de caracteres. Podem ser adicionados vontade a fim de melhorar a legibilidade

Ricardo Lus de Freitas

Notas de Aula - Compiladores 54

de um programa. As convenes relacionadas aos espaos podem complicar grandemente a tarefa de identificao dos tokens. Um exemplo popular que ilustra a dificuldade potencial em se reconhecer tokens o enunciado DO de Fortran. No comando DO 5 I = 1.25 No podemos afirmar que DO seja parte do identificador DO5I, e no um identificador em si, at que tenhamos examinado o ponto decimal. Por outro lado, no enunciado DO 5 I = 1,25 Temos sete tokens: a palavra-chave DO, o rtulo de enunciado 5, o identificador I, o operador =, a constante 1, a vrgula e a constante 25. Aqui no podemos estar certos, at que tenhamos examinado a vrgula, de que DO seja uma palavra-chave. Para aliviar esta incerteza, Fortran 77 permite que uma vrgula opcional seja colocada entre o rtulo e o ndice do enunciado DO ( no exemplo, a varivel I). O uso dessa vrgula encorajado porque a mesma ajuda a tornar o enunciado DO mais claro e legvel. Em muitas linguagens, certas cadeias so reservadas, isto , seus significados so prdefinidos e no podem ser modificados pelo usurio. Se uma palavra-chave no for reservada, o analisador lxico precisar distinguir uma palavra-chave de um identificador definido pelo usurio. Em PL/I, as palavras-chave no so reservadas; consequentemente, as regras para essa distino so um tanto complicadas, como o seguinte enunciado PL/I ilustra: SE ENTAO ENTAO ENTAO = SENAO; SENAO SENAO = ENTAO;

TOKEN Const Se Relacional id num literal

LEXEMAS EXEMPLO const se < , <= , = , <> , > , > = pi , contador , D2 3 . 1416 , 0 , 6 . 02E23 contedo da memria

DESCRIO INFORMAL DO PADRO const se < ou < = ou = ou <> ou > = ou > letra seguida por letras e/ou dgitos qualquer constante numrica quaisquer caracteres entre aspas, exceto aspa

Figura 4.2 Exemplo de tokens.

4.3 Atributos para os Tokens


Quando um lexema for reconhecido por mais de um padro, o analisador lxico precisar providenciar informaes adicionais para as fases subsequentes do compilador a respeito do lexema particular que foi reconhecido. Por exemplo, o padro num reconhece as duas cadeias O e 1, mas essencial para o gerador de cdigo ser informado sobre que cadeia foi efetivamente reconhecida, ou seja, no basta reconhecer num, tem que informar que ele vale 0 ou vale 1.

Ricardo Lus de Freitas

Notas de Aula - Compiladores 55

O analisador lxico coleta informaes a respeito dos tokens em seus atributos associados. Os tokens influenciam decises na anlise gramatical; os atributos influenciam a traduo dos tokens. Do ponto de vista prtico, o token possui usualmente somente um nico atributo - um apontador para a entrada da tabela de smbolos na qual as informaes sobre os mesmos so mantidas; o apontador se torna o atributo do token. Para fins de diagnstico, podemos estar interessados tanto no lexema de um identificador quanto no nmero da linha na qual o mesmo foi primeiramente examinado. Esses dois itens de informao podem, ambos, ser armazenados na entrada da tabela de smbolos para o identificador. Exemplo: Os tokens e os valores de atributos associados ao enunciado Fortran E = M * C ** 2 So escritos abaixo como uma sequncia de pares: <id, apontador para a entrada da tabela de smbolos para E > <operador_de_atribuio,> <id, apontador para a entrada da tabela de smbolos para M> <operador_de_multiplicao,> <id, apontador a para a entrada da tabela de smbolos para C> <operador_de_exponenciao,> <num, valor inteiro 2> Note-se que em certos pares no existe a necessidade de um valor de atributo; o primeiro componente suficiente para identificar o lexema. Nesse pequeno exemplo, ao token num foi associado um atributo de valor inteiro. O compilador pode armazenar a cadeia de caracteres que forma o nmero numa tabela de smbolos e deixar o atributo do token num ser o apontador para a entrada da tabela.

4.4 Erros Lxicos


Poucos erros so distinguveis somente no nvel lxico, uma vez que um analisador lxico possui uma viso muito local do programa-fonte. Se cadeia fi for encontrada pela primeira vez num programa C, no contexto Fi ( a == f (x) ) ... Um analisador lxico no poder dizer se Fi a palavra-chave se incorretamente grafada ou um identificador de funo no declarada. Como Fi um identificador vlido, o analisador lxico precisa retornar o token identificador e deixar alguma fase posterior do compilador tratar o eventual erro. Mas, suponhamos que acontea uma situao na qual o analisador lxico seja incapaz de prosseguir, porque nenhum dos padres reconhea um prefixo na entrada remanescente. Talvez a estratgia mais simples de recuperao seja a da modalidade

Ricardo Lus de Freitas

Notas de Aula - Compiladores 56

pnico. Removemos sucessivos caracteres da entrada remanescente at que o analisador lxico possa encontrar um token bem-formado. Essa tcnica de recuperao pode ocasionalmente confundir o analisador sinttico, mas num ambiente de computao interativo pode ser razoavelmente adequada. Outras possveis aes de recuperao de erros so: 1. 2. 3. 4. remover um caractere estranho inserir um caractere ausente. substituir um caractere incorreto por um correto transpor dois caracteres adjacentes.

Transformaes de erros como essas podem ser experimentadas numa tentativa de se consertar a entrada. A mais simples de tais estratgias a de verificar se um prefixo da entrada remanescente pode ser transformado num lexema vlido atravs de uma nica transformao. Essa estratgia assume que a maioria dos erros lxicos seja resultante de um nico erro de transformao, uma suposio usualmente confirmada na prtica, embora nem sempre. Uma forma de se encontrar erros num programa computar o nmero mnimo de transformaes de erros requeridas para tornar um programa errado num que seja sintaticamente bem-formado. Dizemos que um programa errado possui K erros se a menor sequncia de transformaes de erros que ir mape-lo em algum programa vlido possui comprimento K. A correo de erros de distncia mnima uma conveniente ferramenta terica de longo alcance, mas que no geralmente usada por ser custosa demais de implementar. Entretanto, uns poucos compiladores experimentais tm usado o critrio da distncia mnima para realizar correes localizadas. Outra forma que pode ser adotada registrar como erro cada entrada que no se enquadra dentro dos padres definidos para a linguagem.

4.5 Anlise Lxica no CSD


Como foi dito anteriormente, a principal funo do analisador lxico ler os caracteres de entrada e produzir uma lista de token neste processo so removidos do programa fonte os comentrios e os espaos em branco que o analisador sinttico utilizar. Cada token representa um smbolo vlido na linguagem LPD. No CSD os token so representados internamente por uma estrutura formada por dois campos: Lexema : contm a seqncia de caracteres letras, nmeros, etc. que formam o token; Smbolo : este um campo do tipo numrico que contm uma representao interna para o token. Para aumentar a eficincia do sistema, toda a manipulao da estrutura do token ser feita utilizando-se este campo. O CSD possui a seguinte tabela de smbolo:

Ricardo Lus de Freitas

Notas de Aula - Compiladores 57

TOKEN
programa incio fim procedimento funcao se entao senao enquanto faca := escreva leia var inteiro booleano identificador nmero . ; , ( ) > >= = < <= <> + * div e ou nao :

Lexema

sprograma sincio sfim sprocedimento sfuncao sse sentao ssenao senquanto sfaca satribuio sescreva sleia svar sinteiro Sbooleano Sidentificador Snmero Sponto sponto_vrgula Svrgula sabre_parnteses sfecha_parnteses Smaior Smaiorig Sig Smenor Smenorig Sdif Smais Smenos Smult Sdiv Se Sou Snao Sdoispontos

Smbolo

Por exemplo, na anlise lxica da sentena abaixo se contador > 10 { exemplo de comentrio } entao escreva (contador) senao escreva (x); gerada a seguinte lista de tokens:

Ricardo Lus de Freitas

Notas de Aula - Compiladores 58

Lexema
se contador > 10 entao escreva ( contador ) senao escreva ( x ) ;

Smbolo
sse sidentificador smaior snmero sentao sescreva sabre_parnteses sidentificador sfecha_parnteses ssenao sescreva sabre_parnteses sidentificador sfecha_parnteses sponto_vrgula

Os comentrios na linguagem CSD so feitos atravs do uso dos caracteres { para abrir um comentrio e } para fechar o comentrio , este caracteres assim como a seqncia de caracteres entre eles, no so considerados tokens pelo Analisador Lxico. Estrutura da Lista de Tokens A lista de Tokens uma estrutura de fila First in First out , formada por uma lista encadeada onde cada n possui o formato apresentado na figura abaixo.

Lexema

Smbolo N da lista de tokens.

Os Algoritmos do Analisador Lxico no CSD Uma vez defina a estrutura de dados do analisador lxico, possvel descrever seu algoritmo bsico. No nvel mais alto de abstrao, o funcionamento do analisador lxico pode ser definido pelo algoritmo:

Ricardo Lus de Freitas

Notas de Aula - Compiladores 59

Algoritmo Analisador Lxico (Nvel 0) Inicio Abre arquivo fonte Enquanto no acabou o arquivo fonte Faa { Trata Comentrio e Consome espaos Pega Token Coloca Token na Lista de Tokens } Fecha arquivo fonte Fim

Na tentativa de aproximar o algoritmo acima de um cdigo executvel, so feitos refinamentos sucessivos do mesmo. Durante este processo, surgem novos procedimentos, que so refinados na medida do necessrio.

Algoritmo Analisador Lxico (Nvel 1) Def. token: TipoToken Inicio Abre arquivo fonte Ler(caracter) Enquanto no acabou o arquivo fonte Faa {Enquanto ((caracter = {)ou (caracter = espao)) e (no acabou o arquivo fonte) Faa { Se caracter = { Ento {Enquanto (caracter } ) e (no acabou o arquivo fonte) Faa Ler(caracter) Ler(caracter)} Enquanto (caracter = espao) e (no acabou o arquivo fonte) Faa Ler(caracter) } se caracter <> fim de arquivo ento {Pega Token Insere Lista} } Fecha arquivo fonte Fim.

Ricardo Lus de Freitas

Notas de Aula - Compiladores 60

Algoritmo Pega Token Inicio Se caracter digito Ento Trata Digito Seno Se caracter letra Ento Trata Identificador e Palavra Reservada Seno Se caracter = : Ento Trata Atribuio Seno Se caracter {+,-,*} Ento Trata Operador Aritmtico Seno Se caracter {<,>,=} EntoTrataOperadorRelacional Seno Se caracter {; ,,, (, ), .} Ento Trata Pontuao Seno ERRO Fim. Algoritmo Trata Dgito Def num : Palavra Inicio num caracter Ler(caracter) Enquanto caracter dgito Faa { num num + caracter Ler(caracter) } token.smbolo snmero token.lexema num Fim. Algoritmo Trata Identificador e Palavra Reservada Def id: Palavra Inicio id caracter Ler(caracter) Enquanto caracter letra ou dgito ou _ Faa {id id + caracter Ler(caracter) } token.lexema id caso id = programa : token.smbolo sprograma id = se : token.smbolo sse id = entao : token.smbolo sentao id = senao : token.smbolo ssenao id = enquanto : token.smbolo senquanto id = faca : token.smbolo sfaca id = incio : token.smbolo sincio

Ricardo Lus de Freitas

Notas de Aula - Compiladores 61

id = fim : token.smbolo sfim id = escreva : token.smbolo sescreva id = leia :token.smbolo sleia id = var : token.smbolo svar id = inteiro : token.smbolo sinteiro id = booleano : token.smbolo sbooleano id = verdadeiro : token.smbolo sverdadeiro id = falso : token.smbolo sfalso id = procedimento : token.smbolo sprocedimento id = funcao : token.smbolo sfuncao id = div : token.smbolo sdiv id = e : token.smbolo se id = ou : token.smbolo sou id = nao : token.smbolo snao seno : token.smbolo sidentificador Fim. Exerccios: Fazer os algoritmos para: Trata Atribuio Trata Operador Aritmtico Trata Operador Relacional Trata Pontuao

Ricardo Lus de Freitas

Notas de Aula - Compiladores 62

5 Tabela de Smbolos
Uma funo essencial do compilador registrar os identificadores usados no programa fonte e coletar as informaes sobre os seus diversos atributos. Esses atributos podem ser informaes sobre a quantidade de memria reservada para o identificador, seu tipo, escopo, (onde vlido o programa) e, no caso de nomes de procedimentos, coisas tais como o nmero e os tipos de seus argumentos, o mtodo de transmisso de cada um (por exemplo, por referncia) e o tipo retornado, se algum. Para armazenar estas informaes existe a tabela de smbolos. Uma tabela de smbolos uma estrutura de dados contendo um registro para cada identificador, com os campos contendo os atributos do identificador. As informaes sobre o identificador so coletadas pelas fases de anlise de um compilador e usada pelas fases de sntese de forma a gerar o cdigo-alvo. Durante a anlise lxica a cadeia de caracteres que forma um identificador armazenada em uma entrada da tabela de smbolos. As fases seguintes do compilador acrescentam informaes a esta entrada. A fase de gerao utiliza as informaes armazenadas para gerar o cdigo adequado. Um mecanismo de tabela de smbolos precisa permitir que adicionemos novas entradas e encontremos eficientemente as j existentes. til para um compilador ser capaz de crescer a tabela de smbolos dinamicamente, se necessrio, em tempo de compilao. Se o tamanho da tabela for esttico, ele deve ser grande o suficiente para tratar qualquer programa fonte que lhe seja apresentado. Tal tamanho fixo traz o problema de desperdcio na maioria dos casos.

5.1 Entradas na Tabela de Smbolos


O formato das entradas na tabela de smbolos no tem que ser uniforme, porque a informao guardada a respeito de um nome depende do uso do mesmo. Cada entrada pode ser implementada como um registro consistindo em uma sequncia de palavras consecutivas na memria. Para manter a tabela de smbolos uniforme, pode ser conveniente que algumas das informaes a respeito de um nome sejam mantidas fora da entrada da tabela, com somente um apontador no registro apontando para cada uma destas informaes. Um aspecto importante que deve ser considerado quanto aos procedimento ou funes aninhados. Eles criam ambientes locais de variveis. Para tratar isso temos as seguintes possibilidades: Modelo de Pilha: uma vez terminada a compilao de um procedimento os smbolos locais so descartados. Compilao em duas etapas: aps a compilao de um procedimento ou funo a rvore de programa continua fazendo referncias aos smbolos locais. A tabela de smbolos deve ser organizada de forma que uma vez terminada a compilao de um procedimento ou funo, os smbolos locais continuem existindo, embora no faam parte do caminho de busca usado na compilao do restante do programa. Algumas das estratgias para resolver esse problema: gerar o cdigo para um procedimento imediatamente aps a rvore de programa correspondente ter sido construda. Aps a gerao de cdigo, os smbolos locais podem ser descartados (o modelo de pilha continua vlido);

Ricardo Lus de Freitas

Notas de Aula - Compiladores 63

implementar a tabela de smbolos como uma lista ligada. Ao final da compilao de um procedimento, os smbolos locais so transferidos para uma outra lista. Dessa forma as referncias aos smbolos feitas pela rvore de programa continuam vlidas.

5.2 Tabela de Smbolos como rvore Invertida


Uma forma simples de se implementar a tabela de smbolos construir uma lista ligada onde cada n aponta para o n inserido anteriormente na tabela, manter um apontador para o ltimo smbolo. Ao encerrar a compilao de um procedimento ou funo, os smbolos locais continuam na lista e as novas inseres passam a ser feitas a partir do n que escreve o procedimento.

Programa p ; Var a: inteiro ; Procedimento Q ; Var b,c: inteiro ; Incio . . . fim; Procedimento R ; Var d, e: inteiro ; Procedimento S ; Var f ,g: inteiro ; Incio . . . fim ; Incio . . . fim ; ... fim .

Caminho de busca usado na compilao do programa

c Caminho de busca usado na compilao de Q

Caminho de busca usado na compilao de R

Caminho de busca usado ao se compilar S

Ricardo Lus de Freitas

Notas de Aula - Compiladores 64

5.3 Visibilidade dos Smbolos


A tabela smbolos deve ser organizada de forma a refletir a visibilidade de smbolos definida na linguagem.
Programa P ; Var a : inteiro ; Procedure T ; Procedimento W ; Incio ...T; ... end ; incio { T } ... W; ... end ; procedimento Q ; var b : inteiro ; procedimento R ; var c ,d : inteiro ; procedimento S ; var d : inteiro incio . . . . . . a :=b+c+d;R; . . . end ;

incio {R } . . . T; S;a: =b+c+d ; . . . end ;

incio { Q } ... R; ... end ; incio ... Q; ... end ;

O procedimento T, visvel dentro do procedimento W (embora o seu corpo possa ainda no ter sido compilado). S enxerga as variveis a, b, e c definidas em nvel mais externo. A varivel d, definida em R inacessvel em S porque existe em S uma outra definio do nome d que esconde a anterior.

Ricardo Lus de Freitas

Notas de Aula - Compiladores 65

R enxerga as variveis a, b, c e d, e os procedimentos Q e T, mais externos. V tambm o procedimento S, interno a ele, mas no as definies internas a S, ou seja, a varivel d.

EXEMPLO No exemplo acima, os nomes visveis em cada procedimento so: Em T, W e a so visveis Em W, T e a so visveis Em Q, T, a, b e R so visveis Em R, T, a, Q, b, c, d e S so visveis Em S, T, a, Q, b, c, R e d so visveis Em P, T, a e Q so visveis Durante a compilao de um procedimento, devem estar visveis os nomes definidos localmente, e os nomes definidos dentro dos escopos mais externos dentro dos quais o procedimento est contido. A prioridade de busca deve ser tal que, no caso de um mesmo nome estar definido em mais de um escopo, a definio feita no escopo mais interno prevalece. Uma vez completada a compilao de um procedimento, os smbolos internos a ele deixam de ser visveis. O prprio procedimento continua visvel dentro do escopo onde ele definido.

5.4 A Tabela de Smbolos Organizada como um Vetor


Uma forma simples de se organizar a tabela de smbolos como um vetor onde os smbolos so inseridos na mesma ordem em que so declarados. As buscas nessa tabela so feitas sempre do mais recente para o mais antigo. Ao se encerrar a compilao de um procedimento, todos os smbolos locais so removidos da tabela. Exemplo (situao de tabela durante a compilao do procedimento S, acima):
P a T Q b R c d S d ltimo Caso o smbolo procurado seja d, ser localizado o mais recente.

Ricardo Lus de Freitas

Notas de Aula - Compiladores 66

Como as inseres so sempre no fim da tabela e como as retiradas sempre so dos smbolos mais recentes (locais ao procedimento que acabou de ser compilado), a tabela funciona como uma pilha (!).

Este modelo para a tabela, usando um vetor, supe que as buscas sero sequenciais. Isso pode ser proibitivo se o nmero de smbolos for muito grande. A mesma lgica de funcionamento pode ser aplicada a outras organizaes de tabela visando a melhoria no tempo de acesso.

5.5 Tabela de Smbolos no CSD


A Tabela de Smbolos no CSD dever seguir um dos padres vistos anteriormente. A nica restrio ficar por conta do registro a ser definido, que dever representar as seguintes informaes: Nome do identificador (lexema) Escopo (nvel de declarao) Tipo (padro do identificador) Memria (endereo de memria alocado) Alm do registro devero ser implementados os seguintes procedimentos bsicos: Procedimentos: Insere na Tabela: inserir os identificadores na Tabela. Consulta a Tabela: percorre a Tabela procurando por um identificador. Devolve todos os campos do registro. Coloca Tipo nas Variveis: percorre a tabela do final para o comeo substituindo todos os campos tipo que possuem o valor varivel pelo tipo agora localizado.

Ricardo Lus de Freitas

Notas de Aula - Compiladores 67

6 Anlise Sinttica
Cada linguagem de programao possui as regras que descrevem a estrutura sinttica dos programas bem-formados. Em Pascal, por exemplo, um programa constitudo por blocos, um bloco por comandos, um comando por expresses, uma expresso por tokens e assim por diante. A sintaxe das construes de uma linguagem de programao pode ser descrita pelas gramticas livres de contexto (usando possivelmente a notao BNF). As gramticas oferecem vantagens significativas tanto para os projetistas de linguagens quanto para os escritores de compiladores. Uma gramtica oferece, para uma linguagem de programao, uma especificao sinttica precisa e fcil de entender. Para certas classes de gramticas, podemos construir automaticamente um analisador sinttico que determine se um programa-fonte est sintaticamente bem-formado. Como benefcio adicional, o processo de construo do analisador pode revelar ambiguidades sintticas bem como outras construes difceis de se analisar gramaticalmente, as quais poderiam, de outra forma, seguir indetectadas na fase de projeto inicial de uma linguagem e de seu compilador. Uma gramtica propriamente projetada implica uma estrutura de linguagem de programao til traduo correta de programas-fonte em cdigos-objeto e tambm deteco de erros. Existem ferramentas disponveis para a converso de descries de tradues, baseadas em gramticas, em programas operativos. As linguagens evoluram ao longo de um certo perodo de tempo, adquirindo novas construes e realizando tarefas adicionais. Essas novas construes podem ser mais facilmente includas quando existe uma implementao baseada numa descrio gramatical da linguagem. O ncleo desta seo est devotado aos mtodos de anlise sinttica que so tipicamente usados nos compiladores. Apresentamos primeiramente os conceitos bsicos, em seguida as tcnicas adequadas implementao manual e finalmente os algoritmos usados.

6.1 O Papel do Analisador Sinttico


Em nosso modelo de compilador, o analisador sinttico obtm uma cadeia de tokens proveniente do analisador lxico, como mostrado na Figura 6.1, e verifica se a mesma pode ser gerada pela gramtica da linguagem-fonte. Esperamos que o analisador sinttico relate quaisquer erros de sintaxe de uma forma inteligvel. token rvore Programa representao Fonte
Analisador lxico Analisador sinttico Resto da interface de vanguarda

Obter prximo Token


Tabela de smbolos

gramatical

intermediria

Figura 6.1: Posio de um analisador sinttico num modelo de compilador

Ricardo Lus de Freitas

Notas de Aula - Compiladores 68

Existem trs tipos gerais de analisadores sintticos. Os mtodos universais de anlise sinttica podem tratar qualquer gramtica. Esses mtodos, entretanto, so muito ineficientes para se usar num compilador comercial. Os mtodos mais comumente usados nos compiladores so classificados como descendentes (top-down) ou ascendentes (bottom-up). Como indicado por seus nomes, os analisadores sintticos descendentes constroem rvores do topo (raiz) para o fundo (folhas), anquanto que os ascendentes comeam pelas folhas e trabalham rvore acima at a raiz. Em ambos os casos, a entrada varrida da esquerda para a direita, um smbolo de cada vez. Os mtodos de anlise sinttica mais eficientes, tanto descendentes quanto ascendentes, trabalham somente em determinadas subclasses de gramticas, mas vrias dessas subclasses, como as das gramticas LL(left-left) e LR(left-right), so suficientemente expressivas para descrever a maioria das construes sintticas das linguagens de programao. Os analisadores implementados manualmente trabalham frequentemente com gramticas LL. Os da classe mais ampla das gramticas LR so usualmente construdos atravs de ferramentas automatizadas. Nesta seo, assumimos que a sada de um analisador sinttico seja alguma representao da rvore gramatical para o fluxo de tokens produzido pelo analisador lxico. Na prtica existe um certo nmero de tarefas que poderiam ser conduzidas durante a anlise sinttica, tais como coletar informaes sobre os vrios tokens na tabela de smbolos, realizar a verificao de tipos e outras formas de anlise semntica, assim como gerar o cdigo intermedirio. Juntamos todos esses tipos de atividades na caixa resto da interface da vanguardada Figura 6.1.

6.2 Anlise Sinttica Ascendente


Neste tipo de anlise sinttica a construo da rvore de derivao para uma determinada cadeia comea pelas folhas da rvore e segue em direo de sua raiz. Caso seja obtida uma rvore cuja raiz tem como rtulo o smbolo inicial da gramtica, e na qual a sequncia dos rtulos das folhas forma a cadeia dada, ento a cadeia uma sentena da linguagem, e a rvore obtida a sua rvore de derivao. O processo de se partir das folhas em direo raiz de uma rvore de derivao conhecido como reduo. A cada passo procura-se reduzir uma cadeia (ou sub-cadeia) ao seu smbolo de origem, objetivando-se atingir o smbolo inicial da gramtica. Funcionamento geral: 1) Toma-se uma determinada cadeia . 2) Procura-se por uma sub-cadeia a1,a2,...an de que possa ser substituda pelo seu smbolo de origem . Ou seja, a1,a2,...an. Assim = 1 2. a1 a2 ......... an

3) Repetir o passo (2) at que = smbolo inicial da gramtica. Caso isso no seja possvel tem-se que a cadeia analisada no pertence a linguagem especificada.

Ricardo Lus de Freitas

Notas de Aula - Compiladores 69

Exemplo: G= ({E,T,F},{a,b,+,*,(,)},P,E) P: E E + T | T TT*F|F F a | b | (E) Verificando se a cadeia a+b*a pertence a linguagem utilizando-se de anlise sinttica ascendente. a+b*a => F+b*a => T+b*a => E+b*a => E+F*a => E+T*a => E+T*F => a E+T => E T*F E+T F T b F a

possvel dizer que os maiores problemas na anlise sinttica ascendente residem na dificuldade de se determinar qual a parcela da cadeia (sub-cadeia) que dever ser reduzida, bem como qual ser a produo a ser utilizada na reduo, para o caso de existirem mais do que uma possibilidade.

6.3 Anlise Sinttica Descendente


Neste tipo de anlise sinttica tem-se procedimento inverso ao da anterior. Aqui a anlise parte da raiz da rvore de derivao e segue em direo as folhas, ou seja, a partir do smbolo inicial da gramtica vai-se procurando substituir os smbolos no-terminais de forma a obter nas folhas da rvore a cadeia desejada. Funcionamento geral: 1) Toma-se uma determinada cadeia e o smbolo inicial S da gramtica. 2) Procura-se por uma regra de derivao que permita derivar em sua totalidade ou pelo menos se aproximar desta. 3) Repetir o passo (2) at que a cadeia no apresente mais smbolos no terminais. Nesta situao verificado se a cadeia obtida coincide com . Caso isso no seja possvel temse que a cadeia analisada no pertence a linguagem especificada. Embora apresente os mesmos problemas que a anterior, apresenta a possibilidade de se poder implementar facilmente compiladores para linguagens obtidas de gramticas LL(1) (anlise da cadeia da esquerda para a direita e derivaes esquerdas observando apenas o primeiro smbolo da cadeia para decidir qual regra de derivao ser utilizada).

Ricardo Lus de Freitas

Notas de Aula - Compiladores 70

Nas gramticas LL(1) cada regra de derivao apresenta smbolo inicial da cadeia resultante diferenciado dos demais, o que facilita sua escolha. Como nas linguagens de programao isso ocorre com frequncia, ela se mostra adequada para uso em compiladores. No resto desta seo, consideraremos a natureza dos erros sintticos e as estratgias gerais para sua recuperao. Duas dessas estratgias, chamadas modalidade do desesperoe recuperao em nvel de frase, so discutidas mais pormenorizadamente junto com os mtodos individuais de anlise sinttica. A implementao de cada estratgia requer o julgamento do desenvolvedor do compilador, mas daremos algumas diretrizes gerais relacionadas a essas abordagens.

6.4 Tratamento dos Erros de Sintaxe


Se um compilador tivesse que processar somente programas corretos, seu projeto e sua implementao seriam grandemente simplificados. Mas os programadores frequentemente escrevem programas incorretos, e um bom compilador deveria assistir o programador na identificao e localizao de erros. gritante que, apesar dos erros serem lugar-comum, poucas linguagens sejam projetadas tendo-se o tratamento de erros em mente. Nossa civilizao seria radicalmente diferente se as linguagens faladas tivessem as mesmas exigncias de correo sinttica que as das linguagens de computadores. A maioria das especificaes das linguagens de programao no descreve como um compilador deveria responder aos erros; tal tarefa deixada para o projetista do compilador. O planejamento do tratamento de erros exatamente desde o incio poderia tanto simplificar a estrutura de um compilador quanto melhorar sua resposta aos erros. Sabemos que os programas podem conter erros em muitos nveis diferentes. Por exemplo, os erros podem ser: lxicos, tais como errar a grafia de um identificador, palavra-chave ou operador sintticos, tais como uma expresso aritmtica com parnteses no-balanceados semnticos, tais como um operador aplicado um operando incompatvel lgicos, tais como uma chamada infinitamente recursiva

Frequentemente, boa parte da deteco e recuperao de erros num compilador gira em torno da fase de anlise sinttica. Isto porque os erros ou so sintticos por natureza ou so expostos quando o fluxo de tokens proveniente do analisador lxico desobedece s regras gramaticais que definem a linguagem de programao. Outra razo est na preciso dos modernos mtodos de anlise sinttica; podem detectar muito eficientemente a presena de erros sintticos num programa. Detectar precisamente a presena de erros semnticos ou lgicos em tempo de compilao uma tarefa muito mais difcil. O tratador de erros num analisador sinttico possui metas simples de serem estabelecidas: Deve relatar a presena de erros clara e acuradamente. Deve se recuperar de cada erro suficientemente rpido a fim de ser capaz de detectar erros subsequentes. No deve retardar significativamente o processamento de programas corretos. A realizao efetiva dessas metas apresenta desafios difceis.

Ricardo Lus de Freitas

Notas de Aula - Compiladores 71

Felizmente, os erros comuns so simples e frequentemente basta um mecanismo de tratamento de erros relativamente direto. Em alguns casos, entretanto, um erro pode ter ocorrido muito antes de sua presena ter sido detectada e sua natureza precisa pode ser muito difcil de ser deduzida. Em casos difceis, o tratador de erros pode ter que adivinhar o que o programador tinha em mente quando o programa foi escrito. Vrios mtodos de anlise sinttica, tais como os mtodos LL e LR, detectam os erros to cedo quando possvel. Mais precisamente, possuem a propriedade do prefixo vivel, significando que detectam que um erro ocorreu to logo tenham examinado um prefixo da entrada que no seja o de qualquer cadeia da linguagem. Exemplo: A fim de ter uma apreciao dos tipos de erros que ocorrem na prtica, vamos examinar os erros que Ripley e Druseikis encontraram numa amostra de programa Pascal de estudantes. Ripley e Druseikis descobriram que os erros no ocorrem com tanta frequncia; 60% dos programas compilados estavam semntica e sintaticamente corretos. Mesmo quando os erros ocorriam de fato, eram um tanto dispersos; 80% do enunciados contendo erros possuam apenas um, 13% dois. Finalmente, a maioria constitua-se de erros triviais; 90% eram erros em um nico token. Muitos dos erros poderiam ser classificados simplificadamente: 60% eram erros de pontuao, 20% de operadores e operandos, 15% de palavras-chave e os 5% restantes de outros tipos. O grosso dos erros de pontuao girava em torno do uso incorreto do ponto-evrgula. Para alguns erros concretos, consideremos o seguinte programa Pascal.
(1) (2) (3) (4) (5) (6) (7) (8) (9) (10) (11) (12) (13) programa prmax; var x, y: inteiro; funcao max (i: inteiro; j: inteiro) : { retorna maximo de i e j } incio se i > j entao max := i senao max := j fim; incio leia (x, y) ; escreva (max (x, y) ) fim.

Um erro comum de pontuao o de se usar uma vrgula em lugar de ponto-e-vrgula na lista de argumentos de uma declarao de funo (por exemplo, usar uma vrgula em lugar do primeiro ponto-e-vrgula linha (4)); outro o de omitir um ponto-e-vrgula obrigatrio ao final de uma linha (por exemplo, o ponto-e-vrgula ao final da linha (4)); um terceiro o de colocar um ponto-e-vrgula estranho ao fim de uma linha antes de um senao (por exemplo, colocar um ponto-e-vrgula ao fim da linha (7)). Talvez uma razo pela qual os erros de ponto-e-vrgula sejam to comuns que seu uso varia grandemente de uma linguagem para outra. Em Pascal, um ponto-e-vrgula um separador de enunciados; em PL/1 e C um terminador. Alguns estudos tm sugerido que a ltima utilizao menos propensa a erros.

Ricardo Lus de Freitas

Notas de Aula - Compiladores 72

Um exemplo tpico de um erro de operador o de omitir os dois pontos em :=. Erros de grafia em palavras-chave so usualmente raros, mas omitir o i de escreva seria um exemplo representativo. Muitos compiladores Pascal no tm dificuldades em tratar os erros comuns de insero, remoo e transformao. De fato, vrios compiladores Pascal iro tratar corretamente o programa acima com um erro comum de pontuao ou de operador; iro emitir somente um diagnstico de alerta, apontando a construo ilegal. No entanto, um outro tipo de erro muito mais difcil de se reparar corretamente. o caso de um incio ou fim ausente (por exemplo, a omisso da linha (9)). A maioria dos compiladores no ir tentar reparar esse tipo de erro. Como deveria um tratador de erros reportar a presena de um erro? No mnimo, deveria informar o local no programa-fonte onde o mesmo foi detectado, uma vez que existe uma boa chance de o erro efetivo ter ocorrido uns poucos tokens antes. Uma estratgia comum empregada por muitos compiladores a de imprimir a linha ilegal com um apontador para a posio na qual o erro foi detectado. Se existir um razovel prognstico do que o erro realmente foi, uma mensagem de diagnstico informativa tambm includa; por exemplo, ponto-e-vrgula ausente nesta posio. Uma vez que o erro tenha sido detectado, como deveria o analisador sinttico se recuperar? Como veremos, existe um nmero de estratgias gerais, mas nenhum mtodo claramente se impe sobre os demais. At pouco tempo atrs, no era adequado para o analisador sinttico encerrar logo aps detectar o primeiro erro, porque o processamento da entrada restante ainda poderia revelar outros. Assim, existia alguma forma de recuperao de erros na qual o analisador tentava restaurar a si mesmo para um estado onde o processamento da entrada pudesse continuar com uma razovel esperana de que o resto correto da entrada fosse analisado e tratado adequadamente pelo compilador. Um trabalho inadequado de recuperao pode introduzir uma avalancha de erros esprios, que no foram cometidos pelo programador, mas introduzidos pelas modificaes no estado do analisador sinttico durante a recuperao de erros. Numa forma similar, uma recuperao de erros sintticos pode introduzir erros semnticos esprios que sero detectados posteriormente pelas fases de anlise semntica e de gerao de cdigo. Por exemplo, ao se recuperar de um erro, o analisador pode pular a declarao de alguma varivel, digamos zap. Quando zap for posteriormente encontrada nas expresses, no haver nada sintaticamente errado, mas como no h uma entrada na tabela de smbolos para zap, a mensagem zap no definidoser gerada. Uma estratgia cautelosa para o compilador a de inibir as mensagens de erro que provenham de erros descobertos muito proximamente no fluxo de entrada. Em alguns casos, pode haver erros demais para o compilador continuar um processamento sensvel (por exemplo, como deveria um compilador Pascal responder ao receber um programa Fortran como entrada?). Parece que uma estratgia de recuperao de erros tem que ser um compromisso cuidadosamente considerado levando em conta os tipos de erros que so mais propensos a ocorrer e razoveis de processar. Como mencionamos, alguns compiladores tentavam reparar os erros, num processo em que tentam adivinhar o que o programador queria escrever. Exceto, possivelmente, num ambiente de pequenos programas escritos por estudantes principiantes, a reparao extensiva de erros no propensa a pagar o seu custo. De fato, com a nfase crescente na computao interativa e bons ambientes de programao, a tendncia est na direo de mecanismos simples de recuperao de erros.

Ricardo Lus de Freitas

Notas de Aula - Compiladores 73

6.5 Estratgia de Recuperao de Erros


Existem muitas estratgia gerais diferentes que um analisador sinttico pode empregar para se recuperar de um erro sinttico. Apesar de nenhuma delas ter provado ser universalmente aceitvel, uns poucos mtodos tm ampla aplicabilidade. Introduzimos aqui as seguintes estratgias: modalidade do desespero nvel de frase produes de erro correo global

Recuperao na modalidade do desespero. Este o mtodo mais simples de implementar e pode ser usado pela maioria dos mtodos de anlise sinttica. Ao descobrir um erro, o analisador sinttico descarta smbolos de entrada, um de cada vez, at que seja encontrado um token pertencente a um conjunto designado de tokens de sincronizao. Os tokens de sincronizao so usualmente delimitadores, tais como o ponto-e-vrgula ou o fim, cujo papel no programa-fonte seja claro. Naturalmente, o projetista do compilador precisa selecionar os tokens de sincronizao apropriados linguagem-fonte. A correo na modalidade do desespero, que frequentemente pula uma parte considervel da entrada sem verific-la, procurando por erros adicionais, possui a vantagem da simplicidade e, diferentemente dos outros mtodos a serem enfocados adiante, tem a garantia de no entrar num lao infinito. Nas situaes em que os erros mltiplos num mesmo enunciados sejam raros, esse mtodo pode ser razoavelmente adequado. Recuperao de frases. Ao descobrir um erro, o analisador sinttico pode realizar uma correo local na entrada restante. Isto , pode substituir um prefixo da entrada remanescente por alguma cadeia que permita ao analisador seguir em frente. Correes locais tpicas seriam substituir uma vrgula por ponto-e-vrgula, remover um ponto-evrgula estranho ou inserir um ausente. A escolha da correo local deixada para o projetista do compilador. Naturalmente devemos ser cuidadosos, escolhendo substituies que no levem a laos infinitos, como seria o caso, por exemplo, se inserssemos para sempre na entrada algo frente do seu smbolo corrente. Esse tipo de substituio pode corrigir qualquer cadeia e foi usado em vrios compiladores de correo de erros. O mtodo foi primeiramente usado na anlise sinttica descendente. Sua maior desvantagem est na dificuldade que tem ao lidar com situaes nas quais o erro efetivo ocorreu antes do ponto de deteco. Regras de Produes para erro. Se tivssemos uma boa idia dos erros comuns que poderiam ser encontrados, poderamos aumentar a gramtica para a linguagem em exame com as produes que gerassem construes ilegais. Usamos, ento, a gramtica aumentada com essas produes de erro para construir um analisador sinttico. Se uma produo de erro for usada pelo analisador, podemos gerar diagnsticos apropriados para indicar a construo ilegal que foi reconhecida na entrada. Correo global. Idealmente, gostaramos que um compilador fizesse to poucas mudanas quanto possvel, ao processar uma cadeia de entrada ilegal. Existem algoritmos para escolher uma sequncia mnima de mudanas de forma a se obter uma correo global de menor custo. Dadas uma cadeia de entrada incorreta x e uma gramtica G, esses algoritmos iro encontrar uma rvore gramatical para uma cadeia relacionada y, de tal forma que as inseres, remoes e mudanas de tokens requeridas para transformar x em y sejam to

Ricardo Lus de Freitas

Notas de Aula - Compiladores 74

pequenas quanto possvel. Infelizmente, esses mtodos so em geral muito custosos de implementar, em termos de tempo e espao e, ento, essas tcnicas so correntemente apenas de interesse terico.Devemos assinalar que o programa correto mais prximo pode no ser aquele que o programador tinha em mente. Apesar de tudo, a noo de correo de custo mnimo fornece um padro de longo alcance para avaliar as tcnicas de recuperao de erros e foi usada para encontrar cadeias timas de substituio para a recuperao em nvel de frase. evidente que com a crescente e irreversvel tendncia de uso de computadores pessoais interligados em rede, em substituio ao antigos computadores de grande porte, tem-se que a compilao passou a ser uma tarefa de caracterstica interativa. Assim, a nova tendncia concentra-se no projeto de compiladores que interrompem a compilao a cada erro encontrado, restringindo a recuperao simplesmente a emisso de uma mensagem compreensvel do erro detectado.

6.6 Anlise Sinttica no CSD


Para fornecer um guia na implementao do analisador sinttico do CSD, tem-se a seguir os algoritmos levando em considerao as caractersticas de sintaxe da Linguagem LPD. Considera-se que sempre que encontrar um ERRO tem-se o processo de compilao interrompido. No algoritmo a seguir existem exemplos no exaustivos de trechos do analisador semntico (em azul) e da gerao de cdigo para rtulos (em vermelho).
Algoritmo Analisador Sinttico <programa> Def rotulo inteiro incio rotulo:= 1 Lxico(token) se token.simbolo = sprograma ento incio Lxico(token) se token.simbolo = sidentificador ento incio insere_tabela(token.lexema,nomedeprograma,,) Lxico(token) se token.simbolo = spontovirgula ento incio analisa_bloco se token.simbolo = sponto ento se acabou arquivo ou comentrio ento sucesso seno ERRO seno ERRO fim seno ERRO fim seno ERRO fim seno ERRO fim.

Ricardo Lus de Freitas

Notas de Aula - Compiladores 75

Algoritmo Analisa_Bloco <bloco> incio Lxico(token) Analisa_et_variveis Analisa_subrotinas Analisa_comandos fim Algoritmo Analisa_et_variveis <etapa de declarao de variveis> incio se token.simbolo = svar ento incio Lxico(token) se token.smbolo = sidentificador ento enquanto(token.smbolo = sidentificador) faa incio Analisa_Variveis se token.smbolo = spontvirg ento Lxico (token) seno ERRO fim seno ERRO fim Algoritmo Analisa_Variveis <declarao de variveis> incio repita se token.smbolo = sidentificador ento incio Pesquisa_duplicvar_ tabela(token.lexema) se no encontrou duplicidade ento incio insere_tabela(token.lexema, varivel) Lxico(token) se (token.smbolo = Svrgula) ou (token.smbolo = Sdoispontos) ento se token.smbolo = Svrgula ento incio lxico(token) se token.simbolo = Sdoispontos ento ERRO fim seno ERRO fim seno ERRO seno ERRO at que (token.smbolo = sdoispontos) Lxico(token) Analisa_Tipo fim

Ricardo Lus de Freitas

Notas de Aula - Compiladores 76

Algoritmo Analisa_Tipo <tipo> incio se (token.smbolo (sinteiro ou sbooleano)) ento ERRO seno coloca_tipo_tabela(token.lexema) Lxico(token) fim Algoritmo Analisa_comandos <comandos> incio se token.simbolo = sinicio ento incio Lxico(token) Analisa_comando_simples enquanto (token.simbolo sfim) faa incio se token.simbolo = spontovirgula ento incio Lxico(token) se token.simbolo sfim ento Analisa_comando_simples fim seno ERRO fim Lxico(token) fim seno ERRO fim Analisa_comando_simples <comando> incio se token.simbolo = sidentificador ento Analisa_atrib_chprocedimento seno se token.simbolo = sse ento Analisa_se seno se token.simbolo = senquanto ento Analisa_enquanto seno se token.simbolo = sleia ento Analisa_leia seno se token.simbolo = sescreva ento Analisa_ escreva seno Analisa_comandos fim Algoritmo Analisa_atrib_chprocedimento <atribuio_chprocedimento> incio Lxico(token) se token.simbolo = satribuio ento Analisa_atribuicao seno Chamada_procedimento fim

Ricardo Lus de Freitas

Notas de Aula - Compiladores 77

Algoritmo Analisa_leia <comando leitura> incio Lxico(token) se token.simbolo = sabre_parenteses ento incio Lxico(token) se token.simbolo = sidentificador ento se pesquisa_declvar_tabela(token.lexema) ento incio (pesquisa em toda a tabela) Lxico(token) se token.simbolo = sfecha_parenteses ento Lxico(token) seno ERRO fim seno ERRO seno ERRO fim seno ERRO fim Algoritmo Analisa_escreva <comando escrita> incio Lxico(token) se token.simbolo = sabre_parenteses ento incio Lxico(token) se token.simbolo = sidentificador ento se pesquisa_ declvarfunc_tabela(token.lexema) ento incio Lxico(token) se token.simbolo = sfecha_parenteses ento Lxico(token) seno ERRO fim seno ERRO seno ERRO fim seno ERRO fim Algoritmo Analisa_enquanto <comando repetio> Def auxrot1,auxrot2 inteiro incio auxrot1:= rotulo Gera(rotulo,NULL, , ) {incio do while} rotulo:= rotulo+1 Lxico(token) Analisa_expresso se token.simbolo = sfaa ento incio auxrot2:= rotulo Gera( ,JMPF,rotulo, ) {salta se falso} rotulo:= rotulo+1 Lxico(token)

Ricardo Lus de Freitas

Notas de Aula - Compiladores 78

Analisa_comando_simples Gera( ,JMP,auxrot1, Gera(auxrot2,NULL, , fim seno ERRO fim Algoritmo Analisa_se <comando condicional> incio Lxico(token) Analisa_expresso se token.smbolo = sento ento incio Lxico(token) Analisa_comando_simples se token.smbolo = Sseno ento incio Lxico(token) Analisa_comando_simples fim fim seno ERRO fim

) {retorna incio loop} ) {fim do while}

Algoritmo Analisa_Subrotinas <etapa de declarao de sub-rotinas> Def. auxrot inteiro incio auxrot:= rotulo GERA( ,JMP,rotulo, ) {Salta sub-rotinas} rotulo:= rotulo + 1 enquanto (token.simbolo = sprocedimento) ou (token.simbolo = sfuno) faa incio token.simbolo = sprocedimento) ento analisa_declarao_procedimento seno analisa_ declarao_funo se token.smbolo = sponto-vrgula ento Lxico(token) seno ERRO fim Gera(auxrot,NULL, , ) {incio do principal} fim Algoritmo Analisa_ declarao_procedimento <declarao de procedimento> incio Lxico(token) nvel := L (marca ou novo galho) se token.smbolo = sidentificador ento incio pesquisa_declproc_tabela(token.lexema) se no encontrou ento incio Insere_tabela(token.lexema,procedimento,nvel, rtulo) {guarda na TabSimb} Gera(rotulo,NULL, , ) {CALL ir buscar este rtulo na TabSimb}

Ricardo Lus de Freitas

Notas de Aula - Compiladores 79

rotulo:= rotulo+1 Lxico(token) se token.simbolo = sponto_vrgula ento Analisa_bloco seno ERRO fim seno ERRO fim seno ERRO DESEMPILHA OU VOLTA NVEL fim Algoritmo Analisa_ declarao_funo <declarao de funo> incio Lxico(token) nvel := L (marca ou novo galho) se token.smbolo = sidentificador ento incio pesquisa_declfunc_tabela(token.lexema) se no encontrou ento incio Insere_tabela(token.lexema,,nvel,rtulo) Lxico(token) se token.smbolo = sdoispontos ento incio Lxico(token) se (token.smbolo = Sinteiro) ou (token.smbolo = Sbooleano) ento incio se (token.smbolo = Sinteger) ento TABSIMB[pc].tipo:= funo inteiro seno TABSIMB[pc].tipo:= funo boolean Lxico(token) se token.smbolo = sponto_vrgula ento Analisa_bloco fim seno ERRO fim seno ERRO fim seno ERRO fim seno ERRO DESEMPILHA OU VOLTA NVEL fim

Ricardo Lus de Freitas

Notas de Aula - Compiladores 80

Algoritmo Analisa_expresso <expresso> incio Analisa_expresso_simples se (token.simbolo = (smaior ou smaiorig ou sig ou smenor ou smenorig ou sdif)) ento inicio Lxico(token) Analisa_expresso_simples fim fim Algoritmo Analisa_expresso_simples <expresso simples> incio se (token.simbolo = smais) ou (token.simbolo = smenos) ento Lxico(token) Analisa_termo enquanto ((token.simbolo = smais) ou (token.simbolo = smenos) ou (token.simbolo = sou)) faa inicio Lxico(token) Analisa_termo fim fim Algoritmo Analisa_termo <termo> incio Analisa_fator enquanto ((token.simbolo = smult) ou (token.simbolo = sdiv) ou (token.simbolo = se)) ento incio Lxico(token) Analisa_fator fim fim Algoritmo Analisa_fator <fator> Incio Se token.simbolo = sidentificador (* Varivel ou Funo*) Ento inicio Se pesquisa_tabela(token.lexema,nvel,ind) Ento Se (TabSimb[ind].tipo = funo inteiro) ou (TabSimb[ind].tipo = funo booleano) Ento Analisa_chamada_funo Seno Lxico(token) Seno ERRO Fim Seno Se (token.simbolo = snumero) (*Nmero*) Ento Lxico(token) Seno Se token.smbolo = snao (*NAO*) Ento incio Lxico(token) Analisa_fator Fim Seno Se token.simbolo = sabre_parenteses (* expresso entre parenteses *)

Ricardo Lus de Freitas

Notas de Aula - Compiladores 81

Fim

Ento incio Lxico(token) Analisa_expresso(token) Se token.simbolo = sfecha_parenteses Ento Lxico(token) Seno ERRO Fim Seno Se (token.lexema = verdadeiro) ou (token.lexema = falso) Ento Lxico(token) Seno ERRO

Exerccio: Elaborar os algoritmos para os seguinte procedimentos: Analisa Chamada de Procedimento Analisa Chamada de Funo

Ricardo Lus de Freitas

Notas de Aula - Compiladores 82

7 Analisador Semntico
At agora a preocupao foi em analisar sintaticamente os programas-fonte de acordo com as suas respectivas gramticas, considerando que um programa-fonte fosse simplesmente uma sequncia de caracteres. Entretanto, para gerar corretamente os cdigosobjeto de um programa-fonte, um compilador deve ser capaz de reconhecer os tipos de smbolos (por exemplo, se eles so do tipo inteiro, do tipo ponto flutuante ou de um novo tipo construdo) e a consistncia do seu uso (por exemplo, o operador aritmtico mod em Pascal ou o operador /). Os programas em linguagem de alto nvel contm normalmente uma seo de declarao de dados (identificadores) e uma de comandos e expresses propriamente ditos. A consistncia do uso de um identificador na seo de comandos depende da sua declarao (explcita ou implcita). Este tipo de dependncia s pode ser satisfatoriamente contemplado por uma gramtica sensitiva ao contexto. Entretanto, existem poucos resultados prticos que formalizam e processam, de forma satisfatria, as gramticas sensitivas.

7.1 Gramtica com Atributos


Uma soluo prtica comumente adotada para a especificao da semntica de uma linguagem consiste em atribuir s produes da sua gramtica as aes semnticas, que qualificam semanticamente os smbolos que aparecem na rvore sinttica de uma sentena. Essa gramtica estendida conhecida como gramtica com atributos. A principal funo de uma gramtica com atributos incluir restries semnticas s construes sintaticamente corretas. As aes semnticas estabelecem a dependncia semntica entre todos os smbolos de uma gramtica. Atravs delas, pode-se propagar os valores conhecidos de atributos pela rvore sinttica e determinar os desconhecidos. Com uma arvore sinttica com os atributos, e possvel controlar em muitas situaes a consistncia semntica. Um analisador descendente apropriado para incluir este mecanismo de atribuio de valores para os identificadores. Normalmente, os valores dos atributos de cada smbolo so identificados e armazenados numa tabela de smbolos durante o processo de anlise sinttica. A partir da o analisador semntico usa as informaes existentes na tabela para validar os tipos de dados. Em muitos compiladores, o analisador semntico considerado como parte do analisador sinttico, porque a construo da rvore sinttica e a inferncia dos valores dos atributos de seus smbolos ocorrem paralelamente.

7.2 Tabela de Smbolos


Como visto anteriormente, a tabela de smbolos guarda a definio dos tipos de dados construdos pelos usurios. Em linguagens que suportam o uso de um mesmo nome simblico em diferentes nveis de blocos de programas, os compiladores usam a tabela de smbolos para distinguir o escopo de validade de cada smbolo. Outra utilidade da tabela de smbolos durante o processo de anlise semntica e reconhecer o escopo para o qual um smbolo ativado. Em programas escritos em linguagem estruturada, como Pascal, o conceito de escopo de validade ou nvel lxico importante, porque para estas linguagens um nome no precisa ter uma entrada nica na tabela de smbolos. admissvel o uso de um mesmo nome em nveis distintos com distintas interpretaes semnticas. Os outros atributos associados a um smbolo dependem da categoria dele. Por exemplo, ao nome de um procedimento deve-se especificar ainda o nmero de parmetros

Ricardo Lus de Freitas

Notas de Aula - Compiladores 83

formais, tipo, mecanismo de passagem de cada parmetro e, dependendo da linguagem, o tipo de dado retornado; e ao nome de uma varivel precisa-se acrescentar o seu tipo de dado. Devido a diversidade do nmero de atributos associados a cada smbolo, comum utilizar em implementaes o mecanismo de referncia para atributos cuja quantidade e cujo comprimento so variveis. A informao sobre a categoria de smbolos na tabela usada pelo analisador semntico para, por exemplo: evitar que o nome de uma varivel seja utilizado no contexto do nome de uma subrotina a ser chamada; evitar que o nome de um procedimento aparea no lado esquerdo do operador de atribuio ou numa expresso sem a sua lista de argumentos; evitar que um numeral seja colocado no lado esquerdo do operador de atribuio; otimizar o uso de memria atribuindo a todas as constantes idnticas um mesmo endereo. As tabelas de smbolo provm ainda um campo para o atributo <endereo> de cada smbolo. Este endereo pode ser textual ou pode ser uma posio de memria, dependendo dos cdigos intermedirios serem gerados Linguagens que suportam a construo de novos tipos de dados, como Pascal e C, requerem que os compiladores armazenem na tabela de smbolos os nomes dos novos tipos construdos e os seus componentes. Com isso, o analisador semntico pode validar facilmente as referncias aos campos de uma varivel do tipo construdo. A medida que o analisador sinttico reconhece um smbolo, o analisador semntico verifica se o smbolo j est na tabela de smbolos. Se no estiver, ele armazenado. Caso contrrio, o analisador semntico procura verificar a compatibilidade entre os atributos do smbolo inserido e a forma corrente do seu uso. A complexidade de pesquisa na tabela de smbolos um fator importante para analisar o desempenho de um compilador.

7.3 Erros Semnticos no CSD


A anlise semntica no compilador CSD ser composta basicamente das seguintes tarefas: 1) Verificao da ocorrncia da duplicidade na declarao de um identificador (nome do programa, procedimento, funo ou varivel). Sempre que for detectado um novo identificador, deve ser feita uma busca para verificar as seguintes possibilidades: a) se ele for uma varivel verificar se j no existe outra varivel visvel1 de mesmo nome no mesmo nvel de declarao e verificar se j no existe outro identificador de mesmo nome (que no seja uma varivel) em qualquer nvel inferior ou igual ao da varivel agora analisada. b) Se for o nome de um procedimento ou funo verificar se j no existe um outro identificador visvel de qualquer tipo em nvel igual ao inferior ao agora analisado. 2) Verificao de uso de identificadores no declarados. Sempre que for detectado um identificador, verificar se ele foi declarado (est visvel na tabela de smbolos) e
1

Por visvel considera-se como aquele que pode ser encontrado na Tabela de Smbolos atual.

Ricardo Lus de Freitas

Notas de Aula - Compiladores 84

compatvel com o uso (exemplo: varivel usada que existe como nome de programa ou de procedimento na tabela de smbolos deve dar erro). 3) Verificao de compatibilidade de tipos. Sempre que ocorrer um comando de atribuio, verificar se a expresso tem o mesmo tipo da varivel ou funo que a recebe. 4) Verificao dos comandos escreva e leia. 5) Verificao de chamadas de procedimento e funo. 6) Verificao dos operadores unrios , + , nao. fcil perceber que as chamadas para o analisador semntico no passam de linhas de comandos a serem inseridos no corpo do analisador sinttico, nos locais apropriados. Vale lembrar que a Linguagem LPD no permite a passagem de parmetros nos procedimentos e funes. Caso isso fosse permitido, ento deveriamos tambm verificar a consistncia no nmero de argumentos e parmetros, bem como sua compatibilidade de tipos.

Ricardo Lus de Freitas

Notas de Aula - Compiladores 85

8 Mquina Virtual e Gerao de Cdigo


Esta seo foi retirada do livro do Kowaltowski (vide bibliografia), o qual, embora normalmente com a edio esgotada, recomendo fortemente aos alunos. As nicas diferenas residem na nomenclatura adotada. O nosso objetivo final construir um compilador para LPD, isto , construir um programa que traduz um programa-fonte em LPD para um programa-objeto em linguagem de mquina de um dado computador. Antes de empreender a tarefa de escrever um compilador, devemos estabelecer precisamente a traduo que corresponde a cada construo de LPD. Entretanto, traduzir para a linguagem de mquina de um computador real , em geral, uma tarefa muito trabalhosa. As linguagens de mquina tm muitas caractersticas com as quais teramos que nos preocupar, perdendo de vista a correspondncia entre as construes do programa-fonte e a sua traduo. Ao invs de traduzir, ento, os programas em LPD para a linguagem de mquina de um computador real, definiremos uma mquina hipottica, mais conveniente para nossas finalidades. Esta abordagem muito comum na implementao de linguagens de programao. Os prximos tpicos so dedicados, ento, ao desenvolvimento de um computador hipottico que chamaremos de MVD (Mquina Virtual Didtica). A mesma sigla ser usada para denotar a linguagem de montagem desta mquina. O desenvolvimento ser gradual, acompanhando a discusso de vrios mecanismos de LPD. Frequentemente, seremos obrigados a rever as decises j tomadas sobre o funcionamento da MVD, a fim de acomodar um mecanismo, Desta maneira ficaro mais claras as razes para as vrias caractersticas da MVD, e a sua relao com as construes de LPD.

8.1 Caractersticas Gerais da MVD


Descreveremos nesta seo a estrutura bsica da MVD, que bastante simples. Como veremos nas sees subsequentes, o repertrio de instrues que complexo. Uma deciso importante que tomaremos agora que a MVD dever ser uma mquina a pilha. Isto muito natural, pois a LPD permite o uso de procedimentos recursivos, e a recurso est intimamente ligada com o uso da pilha. As razes para esta deciso ficaro mais claras, portanto, quando tratarmos de procedimentos recursivos. A nossa mquina ter uma memria composta de trs regies: A regio de programa P que conter as instrues da MVD. O formato exato de cada instruo irrelevante para a nossa discusso. A regio da pilha de dados M que conter os valores manipulados pelas instrues da MVD. Suporemos que esta regio compe-se de palavras que podem conter valores inteiros ou ento indefinidos.

Suporemos que cada uma das trs regies tm palavras numeradas com 0, 1, 2,..., e no nos preocuparemos com as limitaes de tamanho de cada regio, nem de cada palavra. A MVD ter dois registradores especiais que sero usados para descrever o efeito das instrues: O registrador do programa i conter o endereo da prxima instruo a ser executada, que ser, portanto, P [i]. O registrador s indicar o elemento no topo da pilha cujo valor ser dado, portanto, por M [s].

Ricardo Lus de Freitas

Notas de Aula - Compiladores 86

Uma vez que o programa da MVD est carregado na regio P, e os registradores tm os seus valores iniciais, o funcionamento da mquina muito simples. As instrues indicadas pelo registrador i so executadas at que seja encontrada a instruo de parada, ou ocorra algum erro. A execuo de cada instruo incrementa de um o valor de i, exceto as instrues que envolvem desvios. Passaremos a desenvolver nas sees seguintes o repertrio de instrues da MVD motivado pelas vrias construes da LPD.

8.2 Avaliao de Expresses


Suponhamos que E uma expresso em LPD da forma E = E1 E2, onde E1 eE2 so duas expresses mais simples, e um operador binrio como +, -, *, <, =, etc. A expresso E deve ser avaliada calculando-se em primeiro lugar os valores de E1 e E2 e aplicando-se, em seguida, a operao correspondente a . Este clculo pode ser implementado de vrias maneiras, guardando-se os valores intermedirios de E1 e E2 em localizaes de memria especiais. Numa mquina como a MVD, uma maneira conveniente guardar estes valores intermedirios na prpria pilha M. Assim, supondo que os valores v1 e v2 das expresses E1 e E2 so calculados de maneira semelhante, a pilha ter as configuraes sucessivas indicadas na Figura 8.1. Denotados por m o endereo do topo da pilha antes de iniciar a avaliao da expresso E, e por v, o valor final calculado. O smbolo ? Denota valores irrelevantes que j estavam na pilha.
* * * ? ? s-> ? * * * m+2 m+1 m s-> * * * ? v1 ? * * * m+2 m+1 m s-> * * * v2 v1 ? * * * v=v1 * v2 m+2 m+1 m s-> * * * v2 v ? * * * m+2 m+1 m

*** clculo de v 1

*** clculo de v 2 Figura 8.1

Note-se que estamos resolvendo o problema de avaliar expresses de maneira indutiva, supondo em primeiro lugar que sabemos resolv-lo para expresses mais simples, isto , mais curtas, como E1 e E2. Assim, supusemos na Figura 8.1 que os valores v1 e v2 so calculados possivelmente em vrios passos, ficando no fim o valor correspondente no topo da pilha, uma posio acima da posio inicial. A base desta induo corresponde s expresses o mais simples possvel, isto , s constantes e variveis. Para estas, basta colocar os seus valores respectivos no topo da pilha. Os operadores unrios sero tratados de maneira anloga. O caso de chamadas de funes que devolvem resultados ser tratado mais adiante, mas importante notar desde j que qualquer que seja a implementao destas chamadas, o seu efeito dever ser sempre o de deixar o resultado final no topo da pilha, uma posio acima da inicial. Podemos concluir da discusso acima que a MVD deve possuir instrues que carregam na pilha valores de constantes e de variveis, e outras que executam operaes correspondentes aos operadores da LPD. Definiremos, portanto, uma srie de instrues

Ricardo Lus de Freitas

Notas de Aula - Compiladores 87

para a MVD, mas devemos notar que algumas dessas definies so provisrias, e sero modificadas mais adiante. O efeito de cada instruo est descrito numa notao semelhante da LPD, indicando as modificaes no estado dos registradores e da memria da MVD. Omitimos nesta descrio a operao i:=i+1 que est implcita em todas as instrues, exceto quando h desvio. Adotaremos, tambm, a conveno de representar os valores booleanos por inteiros: verdadeiro por 1 e falso por 0. LDC k (Carregar constante): S:=s + 1 ; M [s]: = k LDV n (Carregar valor): S:=s+1 ; M[s]:=M[n] ADD (Somar): M[s-1]:=M[s-1]+M[s]; s:=s-1 SUB (Subtrair): M[s-1]:=M[s-1]-M[s]; s:=s-1 MULT (Multiplicar): M[s-1]:=M[s-1]*M[s]; s:=s-1 DIVI (Dividir): M[s-1]:=M[s-1]div M[s]; s:=s-1 INV (Inverter sinal): M[s]:=-M[s] AND (Conjuno): Se M [s-1]=1 e M[s]=1 ento M[s-1]:=1 seno M[s-1]:=0; S:=s-1 OR (Disjuno): Se M[s-1]=1 ou M[s]=1 ento M[s-1]:=1 seno M[s-1]:=0; s:=s-1 NEG (Negao): M[s]:=1-M[s] CME (Comparar menor): Se M[s-1]<M[s] ento M[s-1]:=1 seno M[s-1]:=0; s:=s-1 CMA (Comparar maior): Se M[s-1] >M[s] ento M[s-1]:=1 seno M[s-1]:=0;s:=s-1 CEQ (comparar igual): Se M[s-1]=M[s] ento M[s-1]:=1 seno M[s-1]:=0;s:=s-1 CDIF (Comparar desigual): Se M[s-1] M[s] ento M[s-1]:=1 seno M[s-1]:=0; s:=s-1 CMEQ (Comparar menor ou igual) Se M[s-1] M[s] ento M[s-1]:=1 seno M[s-1]:=0;s:=s-1 CMAQ (Comparar maior ou igual): Se M[s-1] M[s] ento M[s-1]:=1 seno M[s-1]:=0; s:=s-1 Exemplo: Consideremos a expresso a + (b div 9 - 3) * c, e suponhamos que os endereos atribudos pelo compilador s variveis a, b e c so, respectivamente, 100, 102, e 99. Ento o trecho do programa-objeto correspondente traduo desta expresso seria: LDV LDV LDC DIVI LDC 100 102 9 3

Ricardo Lus de Freitas

Notas de Aula - Compiladores 88

SUB LDV 99 MULT ADD Suponhamos que os valores armazenados nas posies 99, 100 e 102 da pilha so 2, 10 e 100, respectivamente, e que o registrador s contm o valor 104. As configuraes sucessivas da pilha ao executar as instrues acima so dadas na Figura 8.2. Os valores sucessivos de s esto indicados pelas flechas. Uma observao interessante que o cdigo da MVD gerado para expresses est diretamente ligado com a notao polonesa posfixa, que no caso da expresso do exemplo acima seria ab9 div 3-c*+. Esta sequncia de smbolos deve ser comparada com a sequncia de instrues da MVD desse exemplo.
* * * ? ? ? 107 106 105 * * * ? ? 10 * * * ? 100 10 * * * 9 100 10 * * * 9 11 10

? ? 100 ? 10 -2 * * *

104 103 102 101 100 99

? ? 100 ? 10 -2 * * *

? ? 100 ? 10 -2 * * * LDV 102 LDC 9

? ? 100 ? 10 -2 * * * DIVI

? ? 100 ? 10 -2 * * * LDC 3

LDV 100

Ricardo Lus de Freitas

Notas de Aula - Compiladores 89

* * * 3 107

* * * 3

* * * -2

* * * -2

* * * -2

11 10 ? ? 100 ? 10

106 105 104 103 102 101 100

8 10 ? ? 100 ? 10

8 10 ? ? 100 ? 10

-16 10 ? ? 100 ? 10

-16 -6 ? ? 100 ? 10

-2 * * *

99

-2 * * *

-2 * * * LDV 99 MULT Figura 8.2

-2 * * * ADD

-2 * * *

SUB

8.3 Comandos de Atribuio


Consideramos, por enquanto, apenas as atribuies a variveis simples da forma V:=E, onde V o nome de uma varivel e E uma expresso que j sabemos traduzir. Uma maneira simples de implementar este comando dada por uma instruo de armazenamento: STR n (Armazenar valor): M[n]:=M[s]; s:=s-1 Esta instruo seguir o cdigo-objeto que corresponde expresso E, e n ser o endereo atribudo pelo compilador varivel V.

Ricardo Lus de Freitas

Notas de Aula - Compiladores 90

Exemplo: Consideremos o comando a:=a+b*c e suponhamos que os endereos e os valores destas variveis so os mesmos do exemplo anterior. O cdigo da MVD para este comando ser: LDV LDV LDV MULT ADD STR 100 102 99 100

A Figura 8.3 apresenta as configuraes sucessivas da pilha ao ser executado este cdigo-objeto. Note-se que, devido maneira como definimos a instruo STR, o valor final do registrador s, aps a execuo do cdigo-objeto correspondente a um comando de atribuio, ser igual ao seu valor inicial. Esta uma propriedade importante que ser verdadeira para qualquer comando em LPD, como verificaremos mais tarde. As nicas excees so os comandos de desvio, e de chamada de procedimentos e funes quando estes no retornam por causa de desvios.

8.4 Comandos Condicionais e Iterativos


Para implementar comandos condicionais definiremos duas instrues de desvio para a MVD: JMP p (Desviar sempre): i:=p JMPF p (Desviar se falso): Se M[s]=0 ento i:=p seno i:=i+1; S:=s-1 Nestas instrues, p um nmero inteiro que indica um endereo de programa da MVD. Nos exemplos que se seguem utilizaremos rtulos simblicos no lugar de nmeros. Note-se que, haja ou no desvio, a instruo JMPF elimina o valor que foi testado, e que est no topo da pilha. Introduziremos, por convenincia, mais uma instruo que no estritamente necessria, mas que simplifica o processo de traduo e que no tem nenhum efeito sobre a execuo: NULL (Nada):

Ricardo Lus de Freitas

Notas de Aula - Compiladores 91

* * * ? ? ? 107 106 105

* * * ? ? 10

* * * ? 100 10

* * * -2 100 10

? ? 100

104 103 102

? ? 100

? ? 100

? ? 100

? 10 -2 * * *

101 100 99

? 10 -2 * * *

? 10 -2 * * * LDV 102 LDV 99

? 10 -2 * * * MULT

LDV 100

Ricardo Lus de Freitas

Notas de Aula - Compiladores 92

* * * -2 107

* * * -2

* * * -2

-200 10 ? ? 100 ? 10 -2 * * *

106 105 104 103 102 101 100 99

-200 -190 ? ? 100 ? 10 -2 * * *

-200 -190 ? ? 100 ? -190 -2 * * * STR 100 Figura 8.3

ADD

Um comando condicional da forma se E entao C 1 senao C 2, onde E uma expresso e C 1 e C2 so comandos, ser traduzido por: * * * JMPF l 1 * * * JMP l 2 L 1 NULL * * * l 2 NULL traduo de E

traduo de C 1

traduo de C 2

Ricardo Lus de Freitas

Notas de Aula - Compiladores 93

Caso o comando tenha a forma se E entao C, podemos traduzi-lo por: * * * JMPF l * * * l NULL

traduo de E

traduo de C

As mesmas instrues de desvio podem ser usadas para implementar comandos repetitivos. No caso do comando enquanto E faca C teremos a traduo: L 1 NULL * * * JMPF l 2 * * * JMP l 1 L 2 NULL

traduo de E

traduo de C

fcil mostrar que estas tradues de comandos condicionais e repetitivos so tais que, ao serem executadas, fazem com que o nvel final da pilha seja igual ao inicial. Exemplo: Indicaremos a seguir as tradues correspondentes a trs comandos em LPD: 1. se q entao a:=1 senao a:=2 LDV JMPF LDC STR JMP L1 NULL LDC STR L2 NULL Q L1 1 A L2 2 A

2. se a>b entao q:=p e q senao se a < 2*b entao p:=verdadeiro senao q:=falso

Ricardo Lus de Freitas

Notas de Aula - Compiladores 94

LDV A LDV B CMA JMPF L3 LDV P LDV Q AND STR Q JMP L4 L3 NULL LDV A LDC 2 LDV B MULT CME JMPF L5 LDC 1 STR P JMP L6 L5 NULL LDC 0 STR Q L6 NULL L4 NULL 3. enquanto s< =n faca s:=s+3*s L7 NULL LDV S LDV N CMEQ JMPF L8 LDV S LDC 3 LDV S MULT ADD STR S JMP L7 L8 NULL

8.5 Comandos de Entrada e de Sada


Um comando da forma leia (v1) deve ler o prximo valor inteiro do arquivo de entrada e atribu-lo varivel inteira v1. A fim de implementar o comando de leitura definiremos a seguinte instruo para a MVD. RD (Leitura): S:=s+1; M[s]:= prximo valor de entrada.

Ricardo Lus de Freitas

Notas de Aula - Compiladores 95

Usando esta instruo, podemos traduzir leia(v1) por: RD STR V1 Onde V1 o endereo da varivel v1. O comando de sada de LPD tem a forma escreva (v1), indicando que o valor da varivel inteira v1 deve ser impresso no arquivo de sada. Definiremos ento a instruo: PRN (Impresso): Imprimir M[s]; s:=s-1

Assim, o comando indicado acima pode ser traduzido por: LDV PRN V1

Exemplo:

1. leia(a) RD STR 2. escreva(x) LDV PRN X (endereo de x) A (endereo de a)

8.6 Sub-Programas
A Figura 8.4 mostra um programa muito simples, sem procedimentos. Deveria ser claro que, neste caso, o programa-objeto deveria reservar as cinco posies iniciais da pilha para as variveis, e em seguida comear a executar as instrues Programa exemplo5; Var n, k: inteiro; Fl f2 f3; inteiro; Incio Leia(n); fl:=0; f2:=1;k:=1; Enquanto k<=n faca incio F3:=f1+f2; F1:=f2; f2:=f3; K:=k+1 Fim; Escreva (n); Escreva (f1) Fim.
Figura 8.4

Ricardo Lus de Freitas

Notas de Aula - Compiladores 96

MVD.

Que correspondem ao bloco de comandos. Definiremos ento duas instrues para a START ALLOC m (Iniciar programa principal): S:=-1 (Alocar memria): S:=s+m

A instruo START ser sempre a primeira instruo de um programa-fonte. Uma declarao da forma v1, v2,...vm: tipo ser traduzida por ALLOC m. Note-se que o compilador pode calcular facilmente os endereos das variveis v1, v2, ...,vm que devero ser 0, 1,...,m-1, respectivamente (quando esta a primeira declarao de variveis). Para completar a traduo de programas, definiremos uma instruo de trmino de execuo: HLT (Parar): Pra a execuo da MVD

Exemplo: Indicamos a seguir o programa-objeto que resulta da traduo do programa da Figura 8.4. Fragmentos do programa-fonte so usados como comentrios a fim de tornar mais clara a traduo: START ALLOC 2 ALLOC 3 RD STR 0 LDC 0 STR 2 LDC 1 STR 3 LDC 1 STR 1 NULL LDV 1 LDV 0 CMEQ JMPF L2 LDV 2 LDV 3 ADD STR 4 LDV 3 STR 2 LDV 4 STR 3 LDV 1 LDC 1 ADD STR 1 programa var n, k fl, f2, f3 leia (n) fl:=0 f2:=1 k:=1 enquanto k<=n faca

L1

f3:=f1+f2 f1:=f2 f2:=f3

k:=k+1

Ricardo Lus de Freitas

Notas de Aula - Compiladores 97

L2

JMP L1 NULL LDV 0 PRN escreva (n) LDV 2 PRN escreva (f1) DALLOC 2 DALLOC 3 HLT fim.

Note-se que a traduo de um comando composto delimitado pelos smbolos incio e fim obtida pela justaposio das tradues dos comandos componentes. Uma observao importante sobre o nosso sistema de execuo que ele muito complicado para o caso de considerar apenas os programas sem procedimentos. fcil perceber que, neste caso, o compilador pode determinar os endereos de todas as variveis e de todas as posies intermedirias na pilha. Poderamos ter definido, portanto, instrues mais simples para MVD que fizessem acesso a localizaes de memria sem a manipulao explcita da pilha. Esta observao mantm-se tambm verdadeira para programas que tm procedimentos mas que no so recursivos.

8.7 Procedimentos sem Parmetros


Consideremos o programa indicado na Figura 8.5, em que p um procedimento recursivo sem parmetros. Supondo que o valor lido pelo comando de entrada seja 4, obtm-se o diagrama de execuo indicado na Figura 8.6. O nmero de ativaes do procedimento p depender, em geral, do valor de n que foi lido, no sendo possvel determinar-se um limite. Consequentemente, num certo instante de execuo, podero existir vrias instanciaes da varivel local z de p. Por outro lado, as instrues da MVD que definimos at agora usam endereos fixos de memria, como por exemplo LDV 3 ou STR 7. Isto significa que, ao traduzir expresses que envolvem a varivel z, o compilador dever usar um endereo fixo para esta varivel. Entretanto, as vrias instanciaes no podem ocupar a mesma posio de memria. Programa exemplo6; Var x, y: inteiro; Procedimento p; Var z: inteiro; Incio Z:= x; x:=x-1; Se z>1 entao p (1) senao y:=1; Y:=y*z Fim { p }; Incio Leia(x); p; (2) Escreva (y); Escreva (x) Fim.
Figura 8.5

Ricardo Lus de Freitas

Notas de Aula - Compiladores 98

X: 4,3,2,1,0

y: 1,1,2,6,24

P/ 2

z:4

P/ 1

z:3

P/1 P/1

z:2 z:1

O problema pode ser resolvido notando-se que a criao e a destruio das instanciaes de z seguem uma disciplina de pilha, isto , a ltima instncia a ser alocada a primeira a desaparecer. Um outro fato, que podemos concluir observando as flechas estticas da Figura 8.6, num dado instante o programa s tem acesso instncia de z criada por ltimo. O problema de endereamento ser resolvido, ento, usando-se a prpria pilha. Sempre que o procedimento p for chamado, o valor anterior de z ser temporariamente guardado no topo da pilha, liberando a posio fixa, atribuda pelo compilador varivel z, para a prxima instncia. O valor anterior de z ser restaurado antes de executar o retorno. A Figura 8.7 indica as configuraes sucessivas da pilha para cada chamada do procedimento p. Aps cada retorno, a configurao prvia ser restaurada. Os smbolos z1,z2,z3 e z4 denotam os valores das instanciaes sucessivas de z. No difcil ver que esta soluo aplica-se no caso geral de procedimentos sem parmetros. Cada procedimento alocar a sua memria, salvando no topo da pilha o contedo prvio das posies de memria correspondentes s suas variveis locais. Estes valores sero restaurados antes de executarem-se os retornos. A fim de tornar o processo de traduo uniforme, o programa inteiro tambm ser tratado como um procedimento. Redefiniremos, ento, a intruo ALLOC, e introduziremos uma nova instruo DALLOC: ALLOC m,n (Alocar memria): Para k:=0 at n-1 faa {s:=s+1;M[s]:=M[m+k]} DALLOC m,n (Desalocar memria): Para k:=n-1 at 0 faa

Figura 8.6

Ricardo Lus de Freitas

Notas de Aula - Compiladores 99

{M[m+k]:=M[s];s:=s-1}

z3 * * *

z2 * * *

z2 * * *

z1 * * *

z1 * * *

z1 * * *

z1

z2

z3

z4

y x

y x

y x Figura 8.7

y x

y x

Um outro problema a ser resolvido o prprio mecanismo de chamada de procedimentos. A nica informao necessria para executar o retorno, neste estgio da MVD, o endereo da instruo qual a execuo deve retornar. O lugar natural para guardar esta informao a prpria pilha. Definiremos, portanto, as instrues: CALL p (Chamar procedimento ou funo): S:=s+1; M[s]:=i+1;i:=p RETURN (Retornar de procedimento): I:=M[s]; s:=s-1 Exerccio: fazer retorno de funo: RETURNF. Note-se que a instruo RETURN sempre encontra a informao correta no topo da pilha.

Ricardo Lus de Freitas

Notas de Aula - Compiladores 100

Exemplo: O programa da Figura 8.5 produz a seguinte traduo: START ALLOC 0,2 JMP L1 NULL ALLOC 2,1 LDV 0 STR 2 LDV 0 LDC 1 SUB STR 0 LDV 2 LDC 1 CMA JMPF L3 CALL L2 JMP L4 NULL LDC 1 STR 1 NULL LDV 1 LDV 2 MULT STR 1 DALLOC 2,1 RETURN NULL RD STR 0 CALL L2 LDV 0 PRN LDV 1 PRN DALLOC 0,2 HLT programa var x,y procedimento p var z z:=x

L2

x:=x-1 se z>1 entao p senao y:=1

L3 L4

y:=y*z fim

L1

leia(x) p escreva (x) escreva (y) fim.

Note-se o uso da instruo JMP L1 para pular o cdigo do procedimento p ao iniciar-se a execuo. Desta maneira, a traduo segue a mesma ordem do programa-fonte. Deve-se notar, tambm, a maneira como o compilador atribui endereos s variveis x, y e z, que so, no caso, 0, 1 e 2, respectivamente. Uma regra geral que pode ser adotada para atribuir endereos a variveis, por quanto da ausncia de parmetros : se um procedimento q, que tem k variveis locais, est diretamente encaixado dentro de um procedimento p cuja ltima varivel local recebeu

Ricardo Lus de Freitas

Notas de Aula - Compiladores 101

endereo m, ento as variveis de q recebem os endereos m+1, m+2,..., m+k. Suporemos que o programa principal um procedimento encaixado num outro tal que m=-1; consequentemente, as k variveis do programa principal tm endereos 0, 1,...,k-1. importante notar que, tambm no caso de comandos que so chamadas de procedimentos, vale a propriedade enunciada anteriormente, ou seja, de que a execuo das instrues do programa-objeto correspondentes mantm o nvel da pilha final (aps o retorno) igual ao inicial (antes da chamada).

Ricardo Lus de Freitas

Notas de Aula - Compiladores 102

9 Bibliografia
Aho,A.V.; Sethi,R.; Ullman,J.D. Compiladores: Princpios, Tcnicas e Ferramentas Livros Tcnicos e Cientficos. Hopcroft,J.E; Ullman,J.D. Formal Languages end their relation to Automata - AddisonWesley Series. Hopcroft,J.E; Ullman,J.D. Introduction do Automata Theory, Languages and Computation - Addison-Wesley Series. Kowaltowski,T. Implementao de Linguagens de Programao - Ed. Guanabara Dois.

Anda mungkin juga menyukai