• Nenhum resultado encontrado

Tradu¸c˜ao Dirigida pela Sintaxe

No documento Compiladores: P ASCAL jr (páginas 45-50)

A id´eia ´e associar informa¸c˜oes aos s´ımbolos gramaticais que representam a constru¸c˜ao de uma LLC; tais informa¸c˜oes s˜ao atributos dos s´ımbolos segundo certas “regras semˆanticas” associadas `as produ¸c˜oes da gram´atica.

Existem duas nota¸c˜oes para associar regras semˆanticas `as produ¸c˜oes: defini¸c˜oes diri- gidas pela sintaxe e esquemas de tradu¸c˜ao.

Defini¸c˜oes Dirigidas pela Sintaxe

Uma defini¸c˜ao dirigida pela sintaxe ´e uma GLC na qual cada s´ımbolo gramatical pos- sui um conjunto associado de atributos, particionados em dois subconjuntos: atributos sintetizados e herdados.

Um atributo ´e dito ser sintetizado se seu valor foi obtido a partir da computa¸c˜ao dos valores dos filhos daquele n´o da ´arvore e dito ser herdado se foi obtido a partir da computa¸c˜ao dos irm˜aos e pai do respectivo n´o.

Uma ´arvore gramatical mostrando os valores dos atributos a cada n´o ´e denominada de uma ´arvore gramatical anotada ou decorada.

Para cada produ¸c˜ao do tipo A → α, temos associado a ela uma regra semˆantica da forma b := f (c1, c2, . . . , cn), onde f ´e uma fun¸c˜ao que:

• Ou b ´e um atributo sintetizado de A e c1, c2, . . . , cn s˜ao atributos pertencentes aos

s´ımbolos gramaticais da produ¸c˜ao ou,

• b ´e um atributo herdado, pertencente a um dos s´ımbolos gramaticais do lado direito

de produ¸c˜ao e c1, c2, . . . , cn s˜ao atributos pertencentes aos s´ımbolos da produ¸c˜ao.

Numa defini¸c˜ao dirigida pela sintaxe, assume-se que os terminais tenham apenas atri- butos sintetizados visto que para os mesmos n˜ao existem regras semˆanticas. Se, para todas as produ¸c˜oes, s´o forem utilizados atributos sintetizados diz-se se tratar de uma defini¸c˜ao

S-atribu´ıda.

Exemplo: Seja a gram´atica abaixo respons´avel pelo funcionamento de uma calcula- dora simples e tendo como ´unico atributo sintetizado o valor val respons´avel pelo arma- zenamento de um n´umero inteiro, ent˜ao as regras semˆanticas (para determina¸c˜ao do valor resultante de uma express˜ao aritm´etica) s˜ao:

Produ¸c˜ao Regras Semˆanticas L → E imprimir(E.val) E → E + T E.val = E’.val+T.val E → T E.val = T.val T → T ∗ F T.val = T’.val*F.val T → F T.val = F.val

F → (E) F.val = E.val

F → inteiro F.val = inteiro.lexema

E L E T T F T F F 3 5 4 * + Imprimir(19) E.val = 15+4 = 19 T.val = 4 F.val = 4 Inteiro.Lexval = 4 E.val = 15 T.val = 3*5 = 15 F.val = 5 F.val = 3 T.val = 3 Inteiro.Lexval = 5 Inteiro.Lexval = 3

Figura 5.1: Exemplo de ´Arvore Decorada para a Express˜ao 3*5+4

Atributos herdados s˜ao convenientes para expressar a dependˆencia de uma constru¸c˜ao de linguagem de programa¸c˜ao no contexto em que a mesma figurar. Por exemplo, podemos usar um atributo herdado para controlar se um identificador aparece ao lado esquerdo ou direito de um comando de atribui¸c˜ao a fim de decidirmos se ´e necess´ario usar o endere¸co ou o valor do mesmo.

Exemplo: Declara¸c˜ao de vari´aveis: int x,y,z

Produ¸c˜ao Regras Semˆanticas

D → T L L.in = T.tipo

T → int T.tipo = inteiro

T → f loat T.tipo = real

L → L0, id L’.in = L.in

incluir tipo(id, L.in)

L → id incluir tipo(id, L.in) Grafos de Dependˆencia

Se um atributo b a um n´o da ´arvore depender de um atributo c, a regra semˆantica para b `aquele n´o precisa ser avaliada ap´os a regra semˆantica para c. As interdependˆencias entre os atributos herdados e sintentizados s˜ao delineadas atrav´es de um grafo de dependˆencia.

Exemplo: Supondo que a produ¸c˜ao A → XY tenha uma regra semˆantica da forma A.a = f(X.x, Y.y), ou seja, o atributo sintentizado a em A depende dos atributos x e y. A representa¸c˜ao para esta dependˆencia em um grafo de dependˆencia ficaria (conforme a figura 5.2):

1. Existem trˆes n´os A.a, X.x e Y.y

2. Existe um arco partindo de X.x para A.a pois a depende de x 3. Existe um arco partindo de Y.y para A.a pois a depende de y

A.a

X.x

Y.y

Figura 5.2: Grafo de Dependˆencias

5.1.1

Defini¸c˜oes L-Atribu´ıdas

O nome L prov´em de left, onde a an´alise gramatical ´e feita sempre a partir do filho mais `a esquerda na ´arvore sint´atica atrav´es do seguinte algoritmo:

Algoritmo de pesquisa em profundidade (depth-first order ): Procedimento Visitar(n: n´o);

Inicio

Para cada filho m de n da esquerda para a direita fa¸ca Inicio

Avaliar os atributos herdados de m; Visitar(m);

Fim

Avaliar os atributos sintetizados de m; Fim

Uma defini¸c˜ao dirigida pela sintaxe ´e L-atribu´ıda se cada atributo herdado de Xj, i ≤ j ≤ n, do lado direito de A → X1, X2, . . . , Xn depender somente:

• Dos atributos dos s´ımbolos X1, X2, . . . , Xj−1 `a esquerda de Xj na produ¸c˜ao e • Dos atributos herdados de A.

Note-se que cada defini¸c˜ao S-atribu´ıda ´e L-atribu´ıda porque as restri¸c˜oes (1) e (2) se aplicam somente aos atributos herdados.

5.1.2

Verifica¸c˜oes de Contexto

Um compilador precisa fazer uma verifica¸c˜ao est´atica das estruturas do programa, para assegurar que o mesmo esteja livre de certos tipos de erros, tais como:

Verifica¸c˜ao de Tipos verifica se um operador est´a sendo aplicado a operandos de tipos incompat´ıveis. Exemplo: 10 + TRUE.

Verifica¸c˜ao de Fluxo de Controle os enunciados de fluxo de controle (repeti¸c˜oes, p. ex.) precisam ter algum local de retorno para onde transferir o controle. Exemplo: um comando tipo break em C precisa estar envolvido por algum comando de fluxo de controle (while, for ou switch).

Verifica¸c˜oes de Unicidade verifica se os identificadores foram declarados de forma un´ıvoca, ou seja, sem duplicidade.

Verifica¸c˜oes relacionadas aos nomes existem linguagens que apresentam particulari- dades acerca dos identificadores do programa. Essa etapa da an´alise verifica se essas particularidades foram respeitadas. Exemplo: A linguagem ADA exige que blocos de comandos comecem e terminem com o mesmo identificador.

Sistema de Tipos

Define-se como um sistema de tipos ao conjunto de regras de aplicabilidade entre os tipos dos operandos e os operadores da linguagem. Exemplo: Seja o comando X = A + B. Um sistema de tipos iria validar se os tipos associados aos operandos A e B s˜ao v´alidos para a adi¸c˜ao e, em caso afirmativo, qual seria o tipo resultante, e ainda, se esse tipo resultante ´e compat´ıvel com o tipo associado `a vari´avel X.

Todo o processo de an´alise semˆantica para verifica¸c˜ao de tipos ´e realizado a partir da constru¸c˜ao de express˜oes de tipo, que podem ser compostas: ou por um tipo simples ou por um construtor de tipos (tipo resultante da aplica¸c˜ao de um operador).

Voltando no exemplo: X = A+B; supor que X e B sejam declarados do tipo inteiro e A seja do tipo real, assim temos:

= X + A B = int + float int Tipo Simples = int + float int (float) (inválido) Construção de Tipos

Figura 5.3: Tipos Simples e Construtor de Tipos

O processo de verifica¸c˜ao de tipos consiste da aplica¸c˜ao de regras semˆanticas `as produ¸c˜oes da gram´atica sob an´alise. Usualmente, um atributo sintetizado tipo ´e sufi- ciente para tal an´alise.

Exemplo1: Para uma produ¸c˜ao do tipo E → id ter´ıamos uma regra semˆantica como

{ E.tipo = id.tipo }.

Exemplo2: Imagine uma linguagem que permita apenas opera¸c˜oes com tipos idˆenticos, ent˜ao para uma produ¸c˜ao do tipo E → E + T ter´ıamos a regra semˆantica { E.tipo = se E.tipo = T.tipo ent˜ao E.tipo sen˜ao inv´alido }

Verifica¸c˜ao de Tipos em Express˜oes

As seguintes regras semˆanticas podem ser abstra´ıdas de forma geral:

E → tipo simples {E.tipo = tipo simples}

E → id {E.tipo = ProcurarTS(id).tipo}

E → E1 {E.tipo = E1.tipo}

E → E1 op E2 {E.tipo = SistemaT ipos[E1.tipo, op, E2, tipo]}

Constru¸c˜ao de um Sistema de Tipos para Operadores

Apresenta as rela¸c˜oes de compatibilidade, para cada operador, em fun¸c˜ao dos operandos. Exemplo na linguagem Pascal:

Op1 Op2 + - * /

integer integer integer integer integer real integer real real real real real integer char Erro Erro Erro Erro integer string Erro Erro Erro Erro integer boolean Erro Erro Erro Erro real integer real real real real real real real real real real real char Erro Erro Erro Erro real string Erro Erro Erro Erro real boolean Erro Erro Erro Erro char integer Erro Erro Erro Erro char real Erro Erro Erro Erro char char String Erro Erro Erro char string String Erro Erro Erro char boolean Erro Erro Erro Erro string integer Erro Erro Erro Erro string real Erro Erro Erro Erro string char String Erro Erro Erro string string String Erro Erro Erro string boolean Erro Erro Erro Erro boolean integer Erro Erro Erro Erro boolean real Erro Erro Erro Erro boolean char Erro Erro Erro Erro boolean string Erro Erro Erro Erro boolean boolean Erro Erro Erro Erro

Exerc´ıcio: Construir as tabelas de sistema de tipos para todos os operadores utilizados

na gram´atica da linguagem P ASCALjr.

Operadores Aritm´eticos: +, -, *, /, **

Operadores Relacionais: ==, !=, >, <, >=, <= S´ımbolos Atribui¸c˜ao: =, +=, -=, *=, /= Operadores L´ogicos: &&, ||, & |

Operadores Un´arios: - , ! , ++, - -

Op1 Op2 + - * / **

inteiro inteiro inteiro inteiro inteiro real inteiro inteiro real real real real real real inteiro caracter Erro Erro Erro Erro Erro inteiro cadeia Erro Erro Erro Erro Erro inteiro logico Erro Erro Erro Erro Erro real inteiro real real real real real real real real real real real real real caracter Erro Erro Erro Erro Erro real cadeia Erro Erro Erro Erro Erro real logico Erro Erro Erro Erro Erro caracter inteiro Erro Erro Erro Erro Erro caracter real Erro Erro Erro Erro Erro caracter caracter cadeia Erro Erro Erro Erro caracter cadeia cadeia Erro Erro Erro Erro caracter logico Erro Erro Erro Erro Erro cadeia inteiro Erro Erro Erro Erro Erro cadeia real Erro Erro Erro Erro Erro cadeia caracter cadeia Erro Erro Erro Erro cadeia cadeia cadeia Erro Erro Erro Erro cadeia logico Erro Erro Erro Erro Erro logico inteiro Erro Erro Erro Erro Erro logico real Erro Erro Erro Erro Erro logico caracter Erro Erro Erro Erro Erro logico cadeia Erro Erro Erro Erro Erro logico logico Erro Erro Erro Erro Erro

No documento Compiladores: P ASCAL jr (páginas 45-50)

Documentos relacionados