You are on page 1of 89

Compiladores: PASCAL

jr
Rogerio Eduardo da Silva, M.Sc.
2005/2
Sumario
1 Introducao 1
1.1 Evolucao das Linguagens de Programac ao . . . . . . . . . . . . . . . . . . 1
1.2 Introducao `a Compilac ao . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.2.1 Fases da Compilac ao . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.3 Ferramentas para Geracao de Compiladores . . . . . . . . . . . . . . . . . 6
2 Um Compilador Simples de uma Passagem 7
2.1 Denicao da Sintaxe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.2 Analise Gramatical . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.2.1 Exerccios Propostos . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.3 Caractersticas da linguagem PASCAL
jr
. . . . . . . . . . . . . . . . . . . 10
2.3.1 Exerccios Propostos . . . . . . . . . . . . . . . . . . . . . . . . . . 12
3 Analise Lexica 13
3.1 O Papel do Analisador Lexico . . . . . . . . . . . . . . . . . . . . . . . . . 13
3.2 Buferizacao de Entrada . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
3.3 Gramaticas e Linguagens Regulares . . . . . . . . . . . . . . . . . . . . . . 15
3.3.1 Exerccios Propostos . . . . . . . . . . . . . . . . . . . . . . . . . . 16
3.4 Especicacao e Reconhecimento de Tokens . . . . . . . . . . . . . . . . . . 17
3.4.1 Trabalho Pratico #1 . . . . . . . . . . . . . . . . . . . . . . . . . . 19
4 Analise Sintatica 21
4.1 O Papel do Analisador Sint atico . . . . . . . . . . . . . . . . . . . . . . . . 21
4.2 Analise Sint atica Ascendente - BOTTOM UP . . . . . . . . . . . . . . . . 23
4.2.1 Algoritmo Empilhar-e-Reduzir . . . . . . . . . . . . . . . . . . . 23
4.3 Analise Sint atica Descendente - TOP DOWN . . . . . . . . . . . . . . . . 24
4.3.1 Analise Sintatica Preditiva . . . . . . . . . . . . . . . . . . . . . . . 25
4.3.2 Exerccios Propostos . . . . . . . . . . . . . . . . . . . . . . . . . . 26
4.4 Reconhecedor de Gramaticas Preditivas Descendentes . . . . . . . . . . . . 27
4.4.1 Algoritmo para Construcao da Tabela de Analise . . . . . . . . . . 29
4.4.2 Projeto de uma Gramatica para um Analisador Sintatico Preditivo
Ascendente . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
4.4.3 Projeto de uma Gramatica para um Analisador Sintatico Preditivo
Descendente . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
4.4.4 Exerccios Propostos . . . . . . . . . . . . . . . . . . . . . . . . . . 38
4.4.5 Trabalho Pratico #2 . . . . . . . . . . . . . . . . . . . . . . . . . . 38
i
5 Analise Semantica 41
5.1 Traduc ao Dirigida pela Sintaxe . . . . . . . . . . . . . . . . . . . . . . . . 41
5.1.1 Denic oes L-Atribudas . . . . . . . . . . . . . . . . . . . . . . . . . 43
5.1.2 Vericac oes de Contexto . . . . . . . . . . . . . . . . . . . . . . . . 44
5.2 Tabela de Smbolos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
5.2.1 Atributos dos Nomes dos Identicadores . . . . . . . . . . . . . . . 47
5.2.2 Hashing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
5.3 Projeto das Regras Semanticas . . . . . . . . . . . . . . . . . . . . . . . . . 50
5.3.1 Trabalho Pratico #3 . . . . . . . . . . . . . . . . . . . . . . . . . . 56
6 Geracao de Codigo Intermediario 59
6.1 Linguagens Intermedi arias . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
6.1.1 Representa coes Gracas . . . . . . . . . . . . . . . . . . . . . . . . 59
6.1.2 Notac ao Pos (e Pre) Fixadas . . . . . . . . . . . . . . . . . . . . . . 60
6.1.3 Codigo de Tres-Enderecos . . . . . . . . . . . . . . . . . . . . . . . 61
6.2 BackPatching (Retrocorrecao) . . . . . . . . . . . . . . . . . . . . . . . . . 64
7 Otimizacao de Codigo 67
7.1 Otimizacao Peephole . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
7.2 Otimizacao de Blocos Sequenciais atraves de grafos . . . . . . . . . . . . . 68
7.2.1 Algoritmo para Construir o GAD de um bloco . . . . . . . . . . . . 69
7.2.2 Algoritmo para Ordenacao de um GAD . . . . . . . . . . . . . . . . 70
8 Geracao de Codigo Objeto 71
8.1 Maquina Objeto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
8.1.1 Regras para Geracao de Codigo Objeto . . . . . . . . . . . . . . . . 76
8.1.2 Trabalho Pratico #4 . . . . . . . . . . . . . . . . . . . . . . . . . . 84
ii
Lista de Figuras
1.1 Processo de Compilacao . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.2 Fases da Compilacao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.3

Arvore resultante da analise de um comando de atribuicao em PASCAL . . 4
2.1 Representacao da arvore gramatical da produc ao AXYZ . . . . . . . . . 8
2.2 Ambig uidade Gramatical . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
3.1 O papel do analisador lexico . . . . . . . . . . . . . . . . . . . . . . . . . . 13
3.2 Buer de entrada para um analisador lexico . . . . . . . . . . . . . . . . . 15
3.3 Automato nito de reconhecimento de n umeros inteiros e reais . . . . . . . 17
3.4 AFD de reconhecimento de identicadores simples . . . . . . . . . . . . . . 18
3.5 AFD de reconhecimento de strings . . . . . . . . . . . . . . . . . . . . . . 18
4.1 Exemplo de

Arvore Sintatica . . . . . . . . . . . . . . . . . . . . . . . . . . 22
4.2 Derivac ao `a Esquerda e `a Direita . . . . . . . . . . . . . . . . . . . . . . . 22
4.3 Analise descendente com backtracking . . . . . . . . . . . . . . . . . . . . 25
4.4 Exemplos de Recursao `a Esquerda e `a Direita . . . . . . . . . . . . . . . . 27
4.5 Funcionamento de um Analisador Sint atico Descendente . . . . . . . . . . 28
5.1 Exemplo de

Arvore Decorada para a Expressao 3*5+4 . . . . . . . . . . . 42
5.2 Grafo de Dependencias . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
5.3 Tipos Simples e Construtor de Tipos . . . . . . . . . . . . . . . . . . . . . 44
5.4 Hashing com Encadeamento . . . . . . . . . . . . . . . . . . . . . . . . . . 49
6.1 Exemplo de Representac ao Graca de Operadores para a=b*c+b*2 . . . . 60
6.2 Backpatching para expressoes logicas . . . . . . . . . . . . . . . . . . . . . 65
7.1 Grafo Acclico Dirigido - GAD . . . . . . . . . . . . . . . . . . . . . . . . . 70
iii
Captulo 1
Introducao
Entende-se por linguagem como uma forma eciente de comunicac ao entre pessoas. Na
verdade a linguagem e um conjunto de palavras usadas, segundo certas regras, para a
formac ao de frases compreensveis por ambos os interlocutores (falantes).
Quando um dos interlocutores e o computador, se faz necessario o uso de uma lingua-
gem especial denominada linguagem de programac ao que permite a comunicacao entre
homem e maquina atraves da denic ao de comandos.
Uma L. P. e ser dita de baixo nvel, se esta somente aceitar comandos na propria
linguagem da maquina (0s e 1s) que e de difcil aplicacao. Ja as linguagens ditas de
alto nvel, sao representadas por ac oes proximas ao problema a ser resolvido que sao,
posteriormente, traduzidas para a linguagem de maquina, atraves de um agente especial
denominado compilador ou interpretador.
Concluindo: compilador e um programa capaz de traduzir um certo programa fonte
(escrito em uma linguagem fonte) para outro programa objeto (escrito em uma linguagem
objeto) geralmente a propria linguagem de maquina.
1.1 Evolucao das Linguagens de Programacao
Cronologicamente, as L. P.s sao classicadas em cinco gerac oes: (1
a
) linguagens de
maquina; (2
a
) linguagens simbolicas (Assembly); (3
a
) linguagens orientadas ao usuario;
(4
a
) linguagens orientadas `a aplicacao e (5
a
) linguagens de conhecimento.
As duas primeiras sao consideradas linguagens de baixo nvel, enquanto que as demais
de alto nvel.
Os primeiros computadores so podiam ser programados atraves da sua propria lingua-
gem de maquina (codigo binario), onde cada operacao possua sua representacao binaria
que era passada `a maquina atraves de circuitos eletricos. Esse processo, alem de extrema-
mente difcil e cansativo, era altamente sujeito a erros devido a sua grande complexidade
de execucao.
A seguir, como uma primeira tentativa de simplicac ao, surgem as linguagens simb oli-
cas ou de montagem (Assembly). Agora, extensas seq uencias binarias sao substitudas por
mnemonicos que sao palavras especiais que representam certas ac oes basicas. Exemplo
MOV, JMP, etc. Os mnemonicos precisavam ser traduzidos para a linguagem de maquina
antes da sua execuc ao.
1
A 3
a
geracao surgiu na decada de 60, com as linguagens procedimentais como FOR-
TRAN, PASCAL e ALGOL e declarativas como LISP e PROLOG. Nas linguagens pro-
cedimentais, um programa especica uma seq uencia de passos a serem seguidos para a
soluc ao do problema. Ja as linguagens declarativas sao subdivididas em funcionais e
logicas. A programacao funcional se baseia na teoria das funcoes recursivas, enquanto
que, as linguagens logicas se baseiam em proposic oes da logica de predicados (fatos e
regras).
Devido ao fato de programas escritos em linguagens de 3
a
geracao serem muito ex-
tensos e de difcil manutenc ao, surgiram as linguagens de aplicacao (4
a
geracao), onde o
desenvolvedor deixa de se preocupar com atividades secundarias e trata apenas da co-
dicac ao do problema (foco do programador deixa de ser a codicac ao para ser a analise
do problema). Aspectos como: interface de entrada e sada, relatorios, etc. sao resol-
vidos pela propria linguagem atraves de um banco de dados e dicionarios associados `as
aplicac oes desenvolvidas.
A 5
a
geracao das linguagens de programacao atua em problemas altamente comple-
xos onde a representac ao de conhecimento se faz necessaria para sua soluc ao, como os
problemas enfrentados pela inteligencia articial. A linguagem PROLOG e aceita como
pertencente a esta geracao.
1.2 Introducao `a Compilacao
Conforme ja dito, um compilador nada mais e do que um programa tradutor responsavel
por converter uma certa linguagem fonte em outra linguagem objeto (ver Figura 1.1).
Usualmente a linguagem objeto e a propria linguagem de maquina, mas nao necessaria-
mente.
Programa
Fonte
Programa
Objeto
COMPILADOR
Mensagem
de Erro
Figura 1.1: Processo de Compilacao
Existem dois tipos basicos de tradutores: os compiladores e os interpretadores. Os
primeiros fazem uma analise completa sobre o programa fonte, caso nao encontre erros
faz a traduc ao de todo o codigo fonte para a linguagem objeto que sera posteriormente
executado em uma maquina capaz de faze-lo. Ja os interpretadores nao tem essa preo-
cupac ao holstica (analise completa) sobre o programa fonte. Um interpretador traduz
um comando fonte por vez e o executa em uma maquina virtual (programa que simula o
funcionamento de um computador) sem a necessidade da criac ao do programa objeto.
Interpretadores sao mais simples de serem implementados, porem, compiladores geram
execuc oes mais rapidas de programas, pois nao ha a perda de tempo de traducoes virtuais
a cada nova instruc ao executada.
2
1.2.1 Fases da Compilacao
O processo de compilacao pode ser dividido em dois grupos de etapas: as etapas de analise
e as etapas de sntese. Na analise, o programa fonte e percorrido em busca de erros
de programac ao (inconsistencias com a linguagem fonte), ja na etapa de sntese (apos a
vericac ao da corretude do programa de origem), efetua-se a traducao, propriamente dita,
do codigo fonte para a linguagem objeto em questao. A gura 1.2 abaixo ilustra todo o
processo:
Tabela de
Smbolos
Anlise Lxica
Anlise Sinttica
Anlise Semntica
Gerao de Cdigo Intermedirio
Otimizao de Cdigo
Gerao de Cdigo Objeto
Manipulador
de Erros
ANLISE
SNTESE
Programa Fonte
Programa Objeto
Figura 1.2: Fases da Compilacao
A analise lexica ou scanning e a primeira etapa do processo de compilacao. Ela
e responsavel por analisar linearmente os caracteres do programa fonte e agrupa-los em
unidades lexicas denominadas tokens. O token e o elemento mais basico da programac ao;
ele e representado por um conjunto de caracteres que apresentam um signicado claro
para o programa. Exemplo: Para o seguinte codigo em PASCAL:
Media := Nota1 + Nota2 * 2
Os caracteres poderiam ser agrupados da seguinte forma:
1. O identicador Media
2. O smbolo de atribuicao :=
3. O identicador Nota1
4. O sinal de adic ao +
5. O identicador Nota2
6. O sinal de multiplicac ao *
3
7. O n umero 2
Os espacos em branco presentes na sentenca sao ignorados durante a analise.
O resultado da analise lexica e uma lista contendo todos os tokens encontrados no
programa fonte. Essa lista lexica e ent ao o elemento de entrada para a analise sintatica
ou analise gramatical (parsing), onde e vericado se os tokens podem ser agrupados em
sentencas validas (comandos, expressoes, etc.) da linguagem fonte. Normalmente, esses
agrupamentos sao realizados atraves da construc ao de uma arvore sintatica conforme e
apresentado na gura 1.3:
Comando de
Atribuio
Identificador
Smbolo de
Atribuio
Expresso
Expresso Expresso
Operador
Aritmtico
Expresso Expresso
Operador
Aritmtico
Media :=
Nota1 +
Nota2 * 2
Figura 1.3:

Arvore resultante da analise de um comando de atribuicao em PASCAL
A estrutura hierarquica de um programa e usualmente expressa por regras recursivas.
Por exemplo, poderamos ter as seguintes regras como parte denic ao de expressoes:
1. Qualquer identicador e uma expressao
2. Qualquer n umero e uma expressao
3. Se expressao
1
e expressao
2
sao expressoes validas, ent ao expressao
1
op. aritmetico
expressao
2
tambem e
A estrutura utilizada para a representacao dessas regras e a gramatica livre de contexto
(GLC), normalmente apresentada na Forma Normal de Backus (BNF).
Exemplo:
comando ::= while | atribuic

ao | . . .
while ::= while expr bool do comando
atribuic

ao ::= identicador := expr aritm


expr bool ::= expr aritm op.Logico expr aritm
expr aritm ::= expr aritm op.Aritm termo | termo
termo ::= n umero | identicador
Apos a analise sintatica, tem-se a certeza de que o programa esta escrito corretamente
(respeita as regras gramaticais da linguagem fonte), porem, sera que o programa escrito
faz algum sentido? Ou seja, executa de forma apropriada?
4
A analise semantica tem por objetivo validar os comandos e expressoes atraves de
analises como compatibilidade de tipos e escopo de identicadores. Esta etapa analisa,
por exemplo, se um identicador declarado como variavel e usado como tal, ou se uma
expressao atribuda a uma vari avel retorna um tipo compatvel com o qual foi declarada
a variavel (em algumas linguagens, uma vari avel inteira nao pode receber uma expressao
real).
Ate aqui foi realizada a etapa de analise do programa fonte, ou seja, a procura por
erros de programac ao. Caso nenhum erro seja encontrado, o processo de compilac ao passa
ent ao para a etapa de sntese, ou seja, a construc ao do programa objeto.
A geracao do codigo intermediario e a primeira fase da construcao do programa
objeto. O que ela faz e a representac ao do programa fonte em uma linguagem inter-
mediaria simplicada (maquina abstrata), o que permite a realizacao da proxima etapa
mais facilmente.
A proxima etapa e a otimizacao de codigo, que tem por objetivo tentar modicar
o codigo intermedi ario no intuito de melhorar a velocidade de execuc ao, bem como a
utilizac ao do espaco de memoria, fazendo com isso, um uso mais racional dos recursos da
maquina.
A ultima etapa do processo de compilac ao e a geracao de codigo objeto propria-
mente dita. Esta fase tem como objetivos: produc ao de codigo objeto, reserva de memoria
para constantes e vari aveis, selec ao de registradores, etc.

E a fase mais difcil, pois re-
quer uma selec ao cuidadosa das instruc oes e dos registradores da maquina alvo a m de
produzir codigo objeto eciente.
Exemplo de geracao de codigo para o codigo fonte:
While I < 100 do I := J + I
Codigo Intermediario Otimizacao Codigo Objeto
L0: if I<100 goto L1 L0: if I 100 goto L2 L0: MOV AX, I
goto L2 I := J+I CMP AX, 100
goto L0 JGE L2
MOV AX, J
MOV BX, I
ADD BX
MOV I, AX
JMP L0
L1: Temp := J+I L2: . . . L2: . . .
I := Temp
goto L0
L2: . . .
Alem dessas fases, ha tambem os modulos de gerenciamento de tabelas e mani-
pulacao de erros.
O gerenciamento de tabelas consiste de um conjunto de tabelas e rotinas associadas
que sao utilizadas por quase todas as fases do tradutor. A principal estrutura deste
modulo e a Tabela de Smbolos, que e responsavel por armazenar informac oes acerca dos
identicadores do programa sob analise, como por exemplo: declarac ao das vari aveis,
procedimentos e sub-rotinas, lista de parametros, etc..
5
Os dados a serem armazenados dependem do projeto do tradutor, mas os mais co-
muns sao: identicador, classe (vari avel, parametro, procedimento, etc.), tipo, endereco,
tamanho.
A tabela de smbolos deve ser estruturada de uma forma que permita rapida insercao
e extracao de informacoes, porem deve ser tao compacta quanto possvel.
O modulo de manipulacao de erros tem por objetivo tratar os erros que sao de-
tectados em todas as fases de analise do programa fonte e deve dispor de mecanismos
(recuperacao de erros) que permitam que o processo de analise prossiga mesmo que erros
tenham sido detectados.
1.3 Ferramentas para Geracao de Compiladores
Existem diversas ferramentas para auxiliar a construcao de compiladores chamadas de
geradores de compiladores ou sistemas de escritas de tradutores. A seguir sao apresentados
alguns exemplos:
Geradores de Analisadores Gramaticais responsaveis por desenvolver analisadores
sint aticos, normalmente a partir de entrada baseada numa gramatica livre de con-
texto.
Geradores de Analisadores Lexicos geram automaticamente analisadores lexicos a
partir de uma especicac ao baseada em expressoes regulares.
Dispositivos de traducao dirigida pela sintaxe produzem colec oes de rotinas que
percorrem uma arvore gramatical, gerando codigo intermedi ario.
Geradores automaticos de codigo tal ferramenta toma uma colec ao de regras que
denem a traducao de cada operacao da linguagem intermedi aria para linguagem
alvo. Tais regras precisam incluir detalhamento suciente para que possamos lidar
com os diferentes metodos de acesso possveis para os dados.
Dispositivos de uxo de dados Ferramentas que auxiliam na etapa de otimizacao de
codigo.
Nao e de escopo desta disciplina o estudo de ferramentas de implementacao de com-
piladores, mais detalhes podem ser obtidos na bibliograa de apoio.
6
Captulo 2
Um Compilador Simples de uma
Passagem
2.1 Denicao da Sintaxe
A especicacao da sintaxe de uma linguagem de programacao pode ser obtida atraves de
uma gramatica livre de contexto.
Exemplo: Seja o comando condicional da forma:
IF Express

ao THEN Comando ELSE Comando


se Expr denotar a construcao de uma expressao e Cmd denotar um comando (ou enun-
ciado), pode-se usar as regras de produc ao de uma GLC
1
para representar tal estrutura
da seguinte forma:
< Cmd > IF < Expr > THEN < Cmd > ELSE < Cmd >
as palavras-chave como IF, THEN e ELSE representam os smbolos terminais, enquanto
que os termos Cmd e Expr, representam os nao-terminais.
Exemplo de uma GLC simples para denir expressoes aritmeticas baseadas apenas em
adic ao e subtrac ao:
< Lista > < Lista > + < Digito >
< Lista > < Lista > < Digito >
< Lista > < Digito >
< Digito > 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
onde os smbolos 0 a 9 e + ou - sao os elementos terminais, enquanto que Lista e Digito
representam os nao-terminais. Convencionalmente, o primeiro nao-terminal representa o
axioma da gramatica. Expressoes exemplo: 1+1, 3-6+9, 1+2+3+4+5+6
1
Gramatica Livre de Contexto
7
2.2 Analise Gramatical
A analise gramatical e feita atraves de deriva coes de cadeias a partir do axioma da
gramatica. Se um nao-terminal A possui uma producao A XYZ ent ao, uma arvore
gramatical pode ter um no rotulado de A com 3 lhos X, Y e Z da esquerda para a direita,
conforme a gura 2.1.
A
X Z Y
Figura 2.1: Representac ao da arvore gramatical da producao AXYZ
Formalmente, segundo uma GLC, a arvore gramatical resultante apresenta as seguintes
propriedades:
A raiz e rotulada pelo smbolo de partida (axioma);
Cada folha e rotulada por um terminal ou por ;
Cada no interno e rotulado por um elemento nao-terminal;
Se A X
1
X
2
. . . X
n
e uma producao ent ao, algum no interno da arvore sera rotulado
por A sendo X
1
X
2
. . . X
n
os rotulos dos lhos desse no.
Ambiguidade
Uma gramatica pode ter mais de uma arvore gramatical gerando uma dada cadeia, neste
caso, ela e dita ser ambgua. Ambos os exemplos da gura 2.2 geram a sentenca 9-5+2.
Cadeia
Cadeia Cadeia
+
Cadeia Cadeia
-
9 5
2
Cadeia
Cadeia Cadeia
+ Cadeia Cadeia
-
9
5 2
Figura 2.2: Ambig uidade Gramatical
8
Associatividade de Operadores
Convencionalmente, 9+5+2 e equivalente `a (9+5)+2, pois, ao analisarmos o operando 5
precisamos decidir qual operac ao sera realizada primeiro. Pela conven cao da matematica a
adic ao e associativa `a esquerda, sendo assim o resultado (9+5)+2 e obtido. Na maioria das
linguagens de programacao, as quatro operac oes basicas (adic ao, subtracao, multiplicac ao
e divisao) sao associativas `a esquerda.
A exponenciac ao e um exemplo de operador associativo `a direita (em Fortran) 5**2**3
e equivalente a 5**(2**3). Outro exemplo e o operador de atribuicao, onde a expressao
a=b=c (em linguagem C) e tratada como a=(b=c).
Precedencia de Operadores
Considere a expressao 9+52. Existem duas interpretacoes possveis: (9+5)2 e 9+(52).
Quando mais de um tipo de operadores estiverem presentes em uma expressao e necessario
se denir a ordem de precedencia entre eles.
Na aritmetica, os operadores e / tem precedencia mais alta do que + e -; assim, na
expressao anterior o operador de multiplicacao e capturado antes da adic ao.
2.2.1 Exerccios Propostos
1. Prova, atraves da construcao da arvore de derivac ao, que os exemplos anteriores sao
validos para a gramatica de expressoes aritmeticas vista.
2. Considere a gramatica livre de contexto: S SS+ | SS | a
(a) Mostre que a cadeia aa+a pode ser gerada por esta gramatica.
(b) Construa a arvore gramatical para esta cadeia.
(c) Qual e a linguagem gerada por esta gramatica? Justique sua resposta.
3. Quais sao as linguagens geradas pelas seguintes gramaticas?
(a) S 0S1 | 01
(b) S +SS | -SS | a
(c) S S(S)S |
(d) S aSbS | bSaS |
(e) S a | S+S | SS | S* | (S)
4. Construa uma gramatica livre de contexto para os n umeros romanos (1 a 10).
5. Construa uma G.L.C. para as expressoes aritmeticas de inteiros e identicadores
com as quatro operac oes basicas (+, -, , /).
9
2.3 Caractersticas da linguagem PASCAL
jr
1. Nao e caso sensitivo (A = a)
2. Suporta os tipos: integer, real, char, string e boolean
3. Comandos:
Atribuic ao com operadores: :=, +=, -=, *=, /=, ++, - -
Entrada com o comando read( )
Sada com os comandos write( ) e writeln()
Condicional com o comando if - then - else
Repeticoes:
Pre teste com o comando while - do
Pos teste com o comando repeat - until
Contada com o comando for - to - do
Sub-rotinas atraves dos comando procedure e function.
Retorno de funcoes com o comando result
Nome de identicador de subrotinas inicia obrigatoriamente com
(ex.: Tela)
4. Constantes caracteres delimitados por ( ) e constantes strings por ( )
5. Operadores relacionais: =, >=, <=, >, <, <>
6. Operadores logicos and, or, xor (ou exclusivo), not
7. Operadores aritmeticos: +, -, *, /, ** (potenciac ao)
8. Suporta operadores ternarios: Expr ? valor1 : valor2
9. Precedencia de operadores:
(a) =, +=, -=, *=, /=, ++, - -
(b) and, or, xor
(c) =, >=, <=, >, <, <>
(d) not
(e) +, -
(f) *, /
(g) **
(h) ( )
(i) -
10. Smbolos especiais: ,, :, ;, (, ), .
10
11. Bloco de comandos delimitados por begin e end
12. Coment ario de linha com operador //
13. Coment ario de bloco com os delimitadores { e }
14. Lista de Palavras Reservadas: var, const, while, do, for, read, write, writeln, if,
then, else, true, false, integer, real, char, string, boolean, result, procedure,
function,and,or,xor,not,to,repeat,until,program,downto
Exemplos de programas a serem reconhecidos pela linguagem PASCAL
jr
:
{
PILOTO.TXT
Exemplo completo de programa na linguagem PASCALjr
Desenvolvido por Rogerio Eduardo da Silva
Agosto, 2005
}
Program Piloto;
// declarac~oes de variaveis e constantes globais
var: integer cont; real Nota1, Nota2, Media_das_medias, med;
const: integer total = 10;
// Subrotina de preenchimento de tela
procedure _Tela()
begin
writeln("******** ENTRADA DE DADOS ***************");
writeln("Digite os valores da entrada:");
end;
// Calculo da media aritmetica entre duas notas
func real _Media(real a , b)
var: real media;
begin
media := (a+b)/2.0;
result := media;
end;
// Inicio do Programa Principal
begin
Media_das_medias := 0;
for cont=0 to total do
begin
_Tela();
read(Nota1, Nota2);
med := _Media(Nota1, Nota2);
Media_das_medias += med;
11
write("Media = ",med);
end;
write("Media Geral = ",Media_das_medias/total);
end.
2.3.1 Exerccios Propostos
Usando a linguagem PASCAL
jr
faca:
1. Um programa para calculo do fatorial de N.
2. Um programa para calculo de N-esimo termo da serie de Fibonacci
12
Captulo 3
Analise Lexica
3.1 O Papel do Analisador Lexico
A analise lexica e a primeira fase de um compilador e tem por objetivo fazer a leitura
do programa fonte, caracter a caracter, e traduzi-lo para uma seq uencia de smbolos
lexicos denominados tokens, os quais sao utilizados pelo analisador sint atico. Exemplos
de tokens sao os identicadores, palavras reservadas, operadores da linguagem, etc.
A intera cao entre analise lexica e sint atica e normalmente implementada fazendo-se
com que o analisador lexico seja uma sub-rotina ou co-rotina do parser (ver gura 3.1).
Ao receber do parser um comando do tipo obter proximo token, o analisador lexico le
os caracteres de entrada ate que possa identicar o proximo token.
Programa
Fonte
Analisador
Lxico
Analisador
Sinttico
Tabela de
Smbolos
Token
Obter Prximo
Token
Figura 3.1: O papel do analisador lexico
Um analisador lexico classico pode ser entendido como um sistema de estados ni-
tos e, portanto, utiliza-se um automato nito para sua implementa cao. As principais
caractersticas desse automato:
O alfabeto de entrada sao os caracteres pertencentes ao arquivo fonte
Cada estado nal reconhece uma classe especca de tokens da linguagem fonte

E denominado erro lexico a qualquer evento (durante o processo de analise lexica)


que impossibilite a interpretacao de um token.
Uma lista de tokens e o resultado do processo de analise lexica, caso nenhum erro
lexico tenha sido encontrado.
13
Porque efetuar analise lexica?
Simplicacao de Projeto e mais simples implementar dois analisadores distintos (para
tarefas distintas) do que um analisador sintatico que faca todo trabalho de forma
unicada;
Melhor Eciencia a analise lexica e potencialmente mais lenta que a sint atica (pois
efetua leitura de caracteres em disco). Tecnicas de buferizacao de leitura podem
acelerar signicativamente este processo;
Portabilidade as peculiaridades do alfabeto de entrada de cada linguagem podem ser
tratadas exclusivamente pelo scanner.
Tokens, Padr oes e Lexemas
Um token e um smbolo terminal da gramatica da linguagem fonte sob analise. Em geral,
existem diversas cadeias de caracteres para as quais o mesmo token e gerado.
Essas cadeias respeitam um determinado padrao ou regra associada a esse token.
Um lexema e um conjunto de caracteres que e reconhecido pelo padrao de um deter-
minado token.
Exemplo:
const pi = 3.14159;
a subcadeia pi e um lexema para o token identicador, pois respeita o padrao para os
identicadores (letra)(letra | digito)

.
Atributos para os tokens
Um token e comumente representado como um par [LEXEMA, CLASSE], onde a classe
indica qual foi o padrao utilizado para reconhecer o lexema.
Outras informacoes adicionais podem ser incorporadas `a descricao do token, de acordo
com as necessidades das fases subseq uentes, como por exemplo, n umero da linha e co-
luna onde o token foi reconhecido no arquivo fonte e n umero de caracteres lidos ate o
reconhecimento, seria exemplos de informacoes adicionais uteis caso um erro lexico seja
detectado.
3.2 Buferizacao de Entrada
Conforme ja visto, o processo de analise lexica e normalmente realizado efetuando-se uma
leitura do arquivo fonte de entrada, caracter a caracter, o que resulta em um processo
signicativamente lento.
Existem 3 alternativas de implementac ao de analisadores lexicos (listados em ordem
crescente de complexidade de implementacao):
1. Usar ferramentas de construc ao de analisadores lexicos (como o Lex), atraves de
expressoes regulares;
14
2. Escrever um programa numa linguagem de programacao convencional, usando seus
recursos de entrada e sada;
3. Escrever um programa numa linguagem de montagem e manipular explicitamente
a entrada e a sada.
Alguns aspectos a serem considerados no projeto de implementac ao de um scanner:
Buer
Em muitas linguagens, existem momentos que o analisador lexico precisa examinar varios
caracteres `a frente do lexema, antes que seja anunciado um reconhecimento.
Os caracteres que foram lidos e nao foram aproveitados no lexema sob analise, sao
ent ao, devolvidos ao uxo de entrada para que possam ser lidos novamente na analise de
outro lexema posterior.
Assim sendo, um buer de entrada que acumula varios caracteres e criado, conforme
a gura 3.2. O processo de analise lexica e realizado sobre este buer. Os tokens que
foram reconhecidos sao eliminados do buer e novos caracteres sao adicionados a ele ate
que todo o arquivo fonte seja lido e analisado.
E = m * c * c eof
apontador
Figura 3.2: Buer de entrada para um analisador lexico
Em casos mais simples, a entrada pode ser realizada caracter a caracter, contendo
apenas um buer de armazenamento dos caracteres lidos.
3.3 Gramaticas e Linguagens Regulares
A seguir, serao revisados alguns conceitos importantes da disciplina linguagens formais e
maquinas (LFM) para ent ao prosseguir na analise lexica.
Gramatica
Uma gramatica e um mecanismo gerador de sentencas de uma dada linguagem.

E denida
pela quadrupla (V
N
, V
T
, P, S), onde: V
N
representa o conjunto de smbolos nao-terminais
da linguagem; V
T
representa o conjunto de smbolos terminais ou alfabeto; P e um con-
junto de regras de produc ao e S e o axioma da gramatica (smbolo inicial).
As regras de producao sao denidas na forma
1
|
2
| . . . |
N
, onde representa
um smbolo nao-terminal e os
N
representam sentencas podendo conter tanto smbolos
terminais quanto nao-terminais.
15
Seq uencia de Derivacao
Entende-se por derivac ao ao processo de substituicao de por um dos
N
na regra de
producao, desta forma obtendo-se uma nova sentenca que por sua vez, pode ser novamente
derivada por outra regra. Uma seq uencia de derivac ao e uma serie de derivac oes sucessivas
que permitem a geracao de uma determinada sentenca da linguagem.
Gramatica Regular
Uma gramatica e dita ser regular se todas as suas regras de produc ao respeitam a forma
A B ou A , onde A,B sao smbolos nao-terminais e e uma sentenca contendo
somente smbolos terminais.
Gramatica Linearmente `a Esquerda e `a Direita
Quando uma regra de producao e da forma A B, ou seja, novos smbolos nao-terminais
sao inseridos `a direita da sentenca, diz-se se tratar de uma gramatica linearmente `a direita.
Se a producao for da forma A B denomina-se como linearmente `a esquerda.
Expressoes Regulares
Uma expressao regular representa uma determinada linguagem atraves de formulas in-
dutivas.
Simbologia adotada:
= sentenca vazia (comprimento = 0);
a | b = representa uma selec ao entre a sentenca a ou b;
A

= conjunto de todas as senten cas de comprimento 0 sobre A;


A
+
= A

{} = fechamento positivos sobre A


A
?
= representa que a expressao A ocorre zero ou uma vez.
Exemplos: Digito(Digito)

= representa a descricao de n umeros inteiros.


Letra(Letra|Digito)

= representa a descric ao de identicadores.


3.3.1 Exerccios Propostos
1. Dena expressoes regulares e sua respectiva gramatica regular para as seguintes
linguagens:
todas as palavras contendo a e/ou b.
todas as palavras contendo a e/ou b com suxo aa.
todas as palavras contendo a e/ou b com aaa como sub-palavra.
todas as palavras contendo a e/ou b com exatamente dois b.
2. Para a gramatica G=({S,A,B},{0,1},P,S), indique a linguagem reconhecida.
16
P: S 0S | A
A A1 | B
B 0 | 1 |
3.4 Especicacao e Reconhecimento de Tokens
A especicacao de tokens e feita atraves de expressoes regulares e reconhecida atraves dos
reconhecedores de gramaticas regulares chamados de automatos nitos.
Exemplo:
< Numero > < Digitos >< Frac Opc >< Exp Opc >
< Frac Opc > . < Digitos >|
< Exp Opc > (E | e)(+ | | ) < Digitos >|
< Digitos > < Digito >< Digitos >|< Digito >
< Digito > 0 | 1 | 2 | . . . | 9
esta gramatica e capaz de reconhecer n umeros inteiros como 1, 100, 1234, etc. e tambem
n umeros reais expressos ou nao por notacao exponencial como: 1.5, 10.34, 1.3e15, 1E+2;
porem, e incapaz de reconhecer n umeros como 1., sem a parte fracionaria. A gura 3.3
reconhece esta gramatica, enquanto que a gura 3.4 reconhece identicadores simples
1
.
0 1
8
DGITO
DIGITO
.
INICIO
* Retornar(Num_Inteiro, Obter_Token())
2
DIGITO
3
DGITO
4
E | e
5
+ | -
6
DIGITO
DGITO
7
* Retornar(Num_Real,
Obter_Token())
OUTRO
O
U
T
R
O
E | e DIGITO
OUTRO
Figura 3.3: Automato nito de reconhecimento de n umeros inteiros e reais
O reconhecimento de strings e apresentado na gura 3.5, onde caracteres validos
representa o alfabeto valido para strings, geralmente letras, n umeros, espacos e sinais
ortogracos.
Exerccio: Criar um AFD capaz de reconhecer os tokens da linguagem PASCAL
jr
:
smbolos (Dois Pontos, Ponto e Vrgula, Vrgula, Abre e Fecha Parenteses, Atribui cao),
Operadores Relacionais e Aritmeticos, Constante Caracter e identicadores de sub-rotinas
1
Exceto identicadores de sub-rotinas
17
0 1 2
LETRA OU DGITO
LETRA OUTRO
INICIO
* Retornar(ID, Obter_Token())
Figura 3.4: AFD de reconhecimento de identicadores simples
0 1
CARACTERES
VLIDOS
"
INICIO
2
Retornar(String,Obter_Token())
"
Figura 3.5: AFD de reconhecimento de strings
(iniciam obrigatoriamente com e tem pelo menos 2 caracteres), e ainda, ser capaz de
tratar os caracteres nulos: espacos, enter, tab e comentarios, sem reconhecer token.
Reconhecendo palavras reservadas como identicadores simples:
Criar uma funcao de identicacao de palavras reservadas (enumerac ao) que retorna a
classe palavra reservada ou identicador.
USO: Retornar(ObterClasse(Lexema),Lexema)
Erros Lexicos
1. Caracter Invalido : uso de um caracter (simbolo) de entrada (arquivo fonte)
que nao pertenca ao alfabeto da linguagem. Exemplo: # ou %
2. Delimitador Nao Balanceado : denicao de uma cadeia literal (ou constante
caracter) sem o correto balanceamento das aspas. Exemplo: Entrada de Dados
3. N umero Real Invalido : denic ao incorreta ou incompleta de um n umero real.
Exemplos: 1., 1.0e3, .8, 1e+
O codigo abaixo apresenta algum erro lexico? Apresente a lista lexica.
begin ; <>media==10.5E-5
/===//%_ Media 1.P
Teste?
Solucao:
begin Palavra Reservada
; Smbolo Ponto e Virgula
18
<> Operador Relacional Diferente
media Identicador
= Operador Relacional de Igualdade
= Operador Relacional de Igualdade
10.5E-5 N umero Real
/= Smbolo de Atribuicao
= Operador Relacional de Igualdade
= Operador Relacional de Igualdade
Teste Identicador
? Smbolo Interrogac ao
3.4.1 Trabalho Pratico #1
Implementar um modulo (sub-rotina) analisador lexico para um prototipo de compilador
para a linguagem PASCAL
jr
vista em aula.
Caractersticas:
Do modulo scanner:
A sub-rotina retorna um token (classe e lexema) cada vez que for chamada.
Considera que o programa fonte para analise ja esta aberto.
Nao retorna nada quando atingir o m de arquivo (ag de controle).
Implementa um AFD para o reconhecimento de tokens.
Do programa a ser criado:
Abre um arquivo fonte para analise.
Chama (sucessivas vezes) a rotina de scanner e exibe o valor do token.
Fecha o arquivo fonte ao nal da compilacao.
Para o processo de compilac ao caso um erro seja encontrado.
Exibe erros de compilac ao (se ocorrerem) ou mensagem de sucesso.
Criterios de Avaliacao:
Implementa cao usando linguagem C ou C++.
Entrega de fontes e executavel (em um arquivo zipado) via disquete/CD ou e-mail:
rsilva@joinville.udesc.br ou professor.rogerio@gmail.com
19
Grupo de 02 alunos (maximo).
Valor do trabalho: 10.0 (25% da nota pratica).
Data de Entrega: A Definir
Punic oes:
de 10% por cada analise incorreta.
de 20% do valor do trabalho por dia de atraso.
de 20% do valor do trabalho para a entrega nao conforme dos arquivos pedidos.
de 50% do valor do trabalho para o caso de nao executar ou travar (apos teste
em 2 computadores, sendo um o do professor).
de 100% do valor do trabalho para o caso de copias (mesmo de trabalhos de
semestres anteriores).
Prazo maximo para defesa e arguic ao sobre o trabalho: 5 dias letivos apos entrega.
Punic oes:
de 25% para arguicao nao respondida ou respondida incorretamente. Obs.: A
arguicao e individual.
de 33% ponto por dia de atraso da defesa.
20
Captulo 4
Analise Sintatica
4.1 O Papel do Analisador Sintatico
A analise sint atica constitui a segunda etapa de um tradutor. Sua func ao e vericar
se as construc oes usadas no programa estao gramaticalmente corretas. Normalmente, as
estruturas sint aticas validas sao especicadas atraves de uma gramatica livre de contexto.
Dada uma GLC e uma sentenca (programa fonte) s, o objetivo do parser e vericar
se s pertence a GLC, atraves da construc ao de uma arvore de derivac ao.
O processo de construc ao dessa arvore pode ser feito de forma explcita (construindo-
se o TDA) ou implcita, atraves de chamadas recursivas das rotinas que aplicam as regras
de produc ao da gramatica durante o reconhecimento.
Existem duas estrategias basicas: Descendente (Top-Down) e Ascendente (Bottom-
Up). Na estrategia top-down constroi-se a arvore a partir da raiz em direcao `as folhas
(tokens), enquanto que na bottom-up, o processo e invertido e a construc ao e realizada
partindo-se das folhas, agrupando-se os tokens ate que a raiz da arvore seja gerada.
A arvore gramatical e ent ao a sada para as proximas fases da compilac ao.
Revisao sobre Gramaticas Livre de Contexto (GLC)
Uma gramatica livre de contexto e qualquer gramatica da forma: A , onde A e um
smbolo nao-terminal e um elemento pertencente a (V
N
V
T
)

.
Exemplo de producoes de uma G.L.C.: S SS+ | SS | a.

Arvores de Derivacao

Arvore de derivacao e a representac ao graca de uma derivac ao de senten ca.


Exemplo: Considerando a gramatica abaixo, gerar arvore de derivac ao que comprova
que a sentenca 45 e valida (ver Figura 4.1).
21
< Numero > < Num >
< Num > < Num >< Digito >|< Digito >
< Digito > 0 | 1 | 2 | . . . | 9
<Numero>
<Num>
<Num>
<Digito>
<Digito>
4
5
Figura 4.1: Exemplo de

Arvore Sintatica
Derivacao mais `a Esquerda e mais `a Direita
Derivac ao mais `a esquerda e obtida por gramaticas que geram inicialmente, os smbolos
mais `a esquerda da sentenca sob analise; analogamente para as derivac ao mais `a direita.
Exemplo: Seja a gramatica: E E +E | E E | E E | E/E | (E) | x. Pode obter
a expressao x+x*x de duas formas, conforme a gura 4.2:
E
X
E
E
+
E
E
*
X
X
E
X
E
E
+
E
E
*
X
X
Figura 4.2: Derivacao `a Esquerda e `a Direita
Exerccio: Para a gramatica G = ({S,A},{0,1},P,S) sendo P: S 0S | A A 1A | 1,
provar as seguintes sentencas: 0001, 01, 0011.
22
4.2 Analise Sintatica Ascendente - BOTTOM UP
A criac ao da arvore gramatical e realizada no sentido folhas raiz, ou seja, gerac ao de
sentencas e feita atraves do processo de empilhar e reduzir. A ideia e reduzir a sentenca
original ate o axioma da gramatica atraves de sucessivas substituicoes por nao-terminais.
Exemplo: S aABe A Abc | b B d
Vericar se a sentenca abbcde pode ser reduzida pela gramatica:
abbcde

aAbcde

aAde

aABe

S
4.2.1 Algoritmo Empilhar-e-Reduzir
Este procedimento de analise sint atica ascendente consiste de dois passos:
1. Escolha de um candidato a reduc ao (handle);
2. Reduc ao do candidato pelo nao-terminal A `a esquerda da produc ao A ;
3. Repetir os passos 1 e 2 ate que a sentenca tenha sido reduzida ao axioma da
gramatica.
Um candidato e uma subcadeia que reconhece o lado direito de uma produc ao e cuja
reduc ao ao nao-terminal do lado esquerdo da produc ao representa um passo ao longo do
percurso de uma derivac ao.

E denominado de poda do candidato ao processo de substitu-lo pelo nao-terminal


`a esquerda da regra de producao, obtendo desta forma, uma reduc ao na sentenca sob
analise.
Uma forma conveniente de implementar um analisador sint atico de empilhar e reduzir
e usar uma pilha para guardar os smbolos gramaticais. O analisador sintatico opera
empilhando zero ou mais smbolos ate que um candidato surja no topo da pilha. Uma
poda do candidato e entao feita. Repete-se este processo ate que no topo da pilha esteja
o axioma da gramatica ou um erro seja encontrado (nenhuma poda seja possvel).
Exemplo: E E +E | E E | E E | E/E | (E) | id.
Sentenca sob analise: id + id * id
23
Entrada Pilha Ac

ao
id+id*id $ empilhar
+id*id $id reduzir E id
+id*id $E empilhar
id*id $E+ empilhar
*id $E+id reduzir E id
*id $E+E reduzir E E +E
*id $E empilhar
id $E* empilhar
$ $E*id reduzir E id
$ $E*E reduzir E E E
$ $E aceitar
Sao apenas 4 as operacoes possveis por este metodo: empilhar, reduzir, aceitar ou
erro.
Conitos durante a Analise Sintatica de Empilhar e Reduzir
Existem gramaticas livres de contexto para as quais o procedimento empilhar-e-reduzir
nao pode ser utilizado, porque, em certos casos, o analisador pode atingir um estado tal,
que:
Mesmo conhecendo toda a pilha e o proximo smbolo de entrada, nao pode decidir
entre empilhar e reduzir. Isto e chamado de conito empilhar/reduzir.
Outro conito possvel, o reduzir/reduzir, ocorre quando nao e possvel optar entre
as diversas reducoes possveis.
4.3 Analise Sintatica Descendente - TOP DOWN
A analise sint atica top-down pode ser vista como uma tentativa de se encontrar uma
derivac ao mais `a esquerda para uma cadeia de entrada, ou ainda, como de se construir a
arvore gramatical a partir da raiz em direc ao `as folhas.
O processo de analise pode ser feito de forma recursiva ou nao, onde a forma recur-
siva pode ser realizada com ou sem retrocesso (backtracking), dependendo das regras de
producao gramatica.
Analise Sintatica Recursiva com Retrocesso
A construcao da arvore e feita a partir da raiz, expandindo sempre o nao-terminal mais `a
esquerda primeiro. Quando existe mais de uma regra de produc ao para o nao-terminal a
ser expandido, a opc ao escolhida e func ao do smbolo corrente na ta de entrada (token
sob analise). Se o token nao dene a producao a ser usada, entao todas as alternativas
vao ser tentadas ate que se obtenha sucesso (ou todas falhem).
Exemplo 1:S cAd A ab | a.
Vericar se a gramatica gera a sentenca cad.
Exemplo 2: S cA A aB B D | bD D d
24
S
S
c A d
S
c A d
a b
S
c A d
a
falha!
sucesso!
Figura 4.3: Analise descendente com backtracking
A analise sint atica e dita ser uma analise sintatica preditiva caso nao seja necessario a
realizac ao de retrocesso no processo e pode ser implementada de forma recursiva ou nao
(atraves da utilizac ao de uma pilha).
4.3.1 Analise Sintatica Preditiva
O processo de analise preditiva (sem retrocesso) exige modicac oes na gramatica original
para analise:
eliminac ao de recursao `a esquerda;
fatorac ao `a esquerda das regras de produc ao;
os nao-terminais que apresentarem mais de uma regra de producao, tenham o pri-
meiro terminal derivavel unico (capaz de identicar a producao a ser analisada).
Ou seja, deve ser possvel determinar, para um dado smbolo a, qual das producoes
deve ser derivada.
Exemplo: No exemplo 2 visto acima a produc ao B D | bD D d apresenta duas
alternativas de derivac ao. A escolha e feita a partir do primeiro terminal para cada regra
(d ou b).
O conjunto de smbolos terminais que iniciam senten cas derivaveis a partir de uma
producao b e denominado FIRST() ou PRIMEIRO().
Exemplo: FIRST(S) = {c}; FIRST(A) = {a}; FIRST(B) = {b, d}; FIRST(D) = {d}.
As regras que denem o conjunto FIRST sao:
25
Se , ent ao e um elemento de FIRST.
Se a, sendo a um smbolo terminal, entao a pertence a FIRST.
Se X
1
X
2
. . . X
N
, sendo X
1
X
2
. . . X
N
elementos nao-terminais, entao FIRST()
= FIRST(X
1
). Se em FIRST(X
1
) constar o elemento , entao incluir FIRST(X
2
)
em FIRST() e assim por diante.
Eliminacao da Recursao `a Esquerda

E possvel que um analisador gramatical descendente recursivo execute indenidamente.


O problema ocorre em produc oes recursivas `a esquerda, tais como: A A0 | 1.
Este tipo de producao gera uma arvore que cresce recursivamente `a esquerda ate que
um terminal 1 seja gerado `a esquerda da seq uencia de 0s.
Para se evitar isso deve-se substituir o elemento causador da recursao `a esquerda, que e
do tipo A A | , onde , representam outras seq uencias de terminais e nao-terminais
nao iniciadas por A .
Para eliminar a recursao `a esquerda deve-se reescrever essa producao, da seguinte
forma: A A

e A

| . A gura 4.4 apresenta as arvors de derivac ao para uma


sentenca qualquer da forma .
4.3.2 Exerccios Propostos
Para as gramaticas abaixo elimine sua recursao `a esquerda.
1. G=({S,A,B},{a,b},P,S) onde P: S Sa | Sb | A | B A Aa | a B bB | b
2. G=({S,A},{0,1,2},P,S) onde P: S S0 | S1 | A | 0 A S2
3. G=({S,A,B},{0,1},P,S) onde P: S SA | A A A0B | 0 B B1 |
4. G=({A},{0,1},P,A) onde P: A A0A | 1
Apresente a clausula First para as produc oes das gramaticas abaixo:
1. G=({S,X,Y,Z},{0,1,2,3},P,S) onde P: S XY Z X OXO | 1 Y 2Y 2 |
3 Z 0Z1 |
2. G=({S,A,B,C},{a,b,c},P,S) onde P: S Sa | aA A aA | Bb B cB |
3. G=({S,X,Y,Z},{0,1},P,S) onde P: S XY Z X 0X | 1Y | Y 1Y |
Z 01Z |
Fatoracao `a Esquerda
A fatorac ao `a esquerda e uma transformac ao gramatical util para a criac ao de uma
gramatica adequada `a analise sintatica preditiva. A ideia basica esta em, quando nao
estiver claro qual das duas producoes alternativas usar para expandir um nao-terminal A,
estarmos capacitados a reescrever as producoes A e postergar a decisao ate que tenhamos
visto o suciente da entrada para realizarmos a escolha certa.
Exemplo: S aXbY cZ | aXbY
26
A

A
A'
A
A
A
A

A'

A'

A'

A'

Figura 4.4: Exemplos de Recursao `a Esquerda e `a Direita


Ao analisarmos o token a nao ha como saber qual das duas alternativas utilizar (o
comando com ou sem o cZ). Quando houver duas producoes A
1
|
2
, devemos
postergar a decisao expandindo A para A

e ent ao expandir A para


1
|
2
. Fatorando
esta gramatica temos: S aXbY S

cZ | .
4.4 Reconhecedor de Gramaticas Preditivas Descen-
dentes
Um reconhecedor preditivo descendente (orientado por tabela) compreende uma ta de
entrada, uma pilha e uma tabela de analise, conforme e mostrado na gura 4.5. A ta
contem a sentenca a ser analisada seguida de $. A pilha contem os smbolos utilizados
durante o processo de analise. A tabela de analise e uma matriz com n linhas (correspon-
dendo aos smbolos nao-terminais) e t+1 colunas (correspondendo aos smbolos terminais
mais o smbolo especial $).
Considerando X o elemento no topo da pilha e a o smbolo de entrada sob analise, o
analisador executa uma de tres acoes possveis:
1. se X = a = $, o analisador para, aceitando a sentenca;
2. se X = a = $, o analisador desempilha a e avan ca o cabecote de leitura para o
proximo smbolo na ta de entrada;
3. se X e um smbolo nao-terminal, o analisador consulta a tabela M[X,a] da tabela
de analise. Essa entrada podera conter uma producao da gramatica ou ser vazia.
Supondo M[X,a] = { X XY Z }, o analisador substitui X (no topo da pilha) por
ZYX (cando X no topo). Se M[X,a] for vazio isto e um erro sint atico.
Na implementac ao de um analisador sintatico, a maior diculdade esta na construcao
da tabela de analise. Para construir essa tabela, e necessario computar duas funcoes
associadas `a gramatica: FIRST e FOLLOW.
27
Tabela de
Anlise
Parser
a + b $
X
Y
Z
Figura 4.5: Funcionamento de um Analisador Sintatico Descendente
O algoritmo para calcular a funcao FIRST ja foi visto anteriormente. O algoritmo
para calcular a funcao FOLLOW e apresentado a seguir:
1. Se S e o smbolo inicial da gramatica e $ e o marcador de m de sentenca, entao $
esta em FOLLOW(S);
2. Se existe producao do tipo A X, ent ao todos os terminais de FIRST(), fazem
parte de FOLLOW(X);
3. Se existe produc ao do tipo A X, ou A X, sendo que , entao todos
os terminais que estiverem em FOLLOW(A) fazem parte de FOLLOW(X).
Dada a gramatica G = ({E, E

, T, T

, F}, {, , , id}, P, E) para expressoes logicas:


E TE

TE

|
T FT

FT

|
F F | id
Clausula First
Convem iniciar o processo pelos nao-terminais que gerem conjuntos triviais. No exemplo,
temos os nao-terminais F, E e T que so geram elementos terminais (ou vazio):
F = {, id}
E

= {, }
T

= {, }
Como T deriva apenas em FT e F nao leva em vazio, conclui-se que FIRST(T) =
FIRST(F). E ainda, FIRST(E) = FIRST(T) = FIRST(F) = {, id}.
28
Clausula Follow
Pela regra 1 temos que FOLLOW(E) = {$}. Pela regra 3 tem-se que FOLLOW(E)
= FOLLOW(E). FOLLOW(T) e obtido a partir da uniao dos conjuntos obtidos pela
aplicac ao da regra 2 em (E

TE

) e regra 3 em (E

). Sendo assim temos:


FOLLOW(T) = FIRST(E) + FOLLOW(E) = {, $}.
FOLLOW(T) = FOLLOW(T) pela aplicac ao da regra 3 em T FT

. E nalmente,
FOLLOW(F) = FIRST(T) + FOLLOW(T). Aplicac ao das regras 2 e 3 em T

FT

|
, ou seja FOLLOW(F) = {, , $}.
4.4.1 Algoritmo para Construcao da Tabela de Analise
Metodo:
Para cada producao X , execute os passos 2 e 3 (para criar a linha X da tabela
M);
Para cada terminal a de FIRST(), adicione a produc ao X a M[X,a];
Se FIRST() inclui a palavra vazia, ent ao adicione X a M[X,b] para cada b
em FOLLOW(X);
Aplicando-se o algoritmo acima `a gramatica de expressoes logicas temos:
Para E TE

tem-se FIRST(TE) = {, id} entao, M[E, ] = M[E,id] = E TE

.
Para E

TE

tem-se FIRST(TE

) = {} entao, M[E, ] = E

TE

.
Para E

tem-se FOLLOW(E) = {$} ent ao, M[E, $] = E

.
Para T FT

tem-se FIRST(FT) = {, id} entao, M[T, ] = M[T,id] = T FT

.
Para T

FT

tem-se FIRST(FT

) = {} ent ao, M[T, ] = T

FT

.
Para T

tem-se FOLLOW(T) = {, $} ent ao, M[T, ] = M[T,$] = T

.
Para F F tem-se FIRST(F) = {} entao, M[F, ] = F F.
Para F id tem-se FIRST(id) = {id} ent ao,M[F,id] = F id.
id $
E E TE

E TE

E E

TE


T T FT

T FT

T T

FT


F F id F id
Se, em cada entrada da Tabela de Analise, existe apenas uma producao, entao a
gramatica que originou a tabela e dita ser do tipo LL(1), ou seja: as sentencas geradas
pela gramatica sao passveis de serem analisadas da esquerda para a direita (Left to
Right), produzindo uma deriva cao mais `a esquerda (Leftmost Derivation), levando
em conta apenas um smbolo da entrada.
Exerccio: Considerando a gramatica para a linguagem a ser reconhecida pelo prototi-
po de compilador para analise descendente, construir a tabela de analise resultante.
29
4.4.2 Projeto de uma Gramatica para um Analisador Sintatico
Preditivo Ascendente
Analisa gramaticas do tipo LR(k), ou seja, left-to-right e rightmost derivation com k
smbolos lidos da entrada a cada etapa de analise.
Porque usar analise sint atica ascendente LR?
porque e possvel ser elaborados reconhecedores para todas as GLC, sem restricao;
porque o metodo de analise LR e tao eciente quanto os demais metodos de analise;
porque um analisador LR consegue encontrar um erro sint atico o mais cedo possvel
em uma analise da esquerda para a direita.
As gramaticas GLC para as quais e viavel a implementacao manual de reconhece-
dores ascendentes (devido `a complexidade de implementa cao) apresentam as seguintes
restric oes:
nenhum lado direito das producoes seja
nenhum lado direito tenha dois nao-terminais adjacentes (gramatica de operadores)
Exemplo: E E +E | E E | E E | E/E | (E) | E | id
Um forma simples de se implementar um reconhecedor ascendente e atraves da analise
de precedencia de operadores, porem, justamente devido `a sua simplicidade, uma serie de
restric oes estao associadas a estes:
diculdades de analisar operadores com mais de um signicado semantico (ex.: ope-
rador unario e binario de subtracao)
somente uma pequena classe de linguagens pode ser analisada por esta alternativa,
apesar disso, ja foram desenvolvidos analisadores de precedencia para linguagens
inteiras.
Na analise de precedencia temos denidos as relac oes de precedencia entre os opera-
dores, sendo (a < b) onde a confere precedencia a b; (a = b) onde a possui a mesma
precedencia de b e (a > b) a tem precedencia sobre b.
Seja o exemplo da gramatica anterior onde a precedencia dos operadores e dada por:
id + * $
id > > >
+ < > < >
* < > > >
$ < < <
Analisando a expressao: id+id*id temos as seguintes relacoes de precedencia:
$ < id > + < id > < id > $
O algoritmo para se determinar o handle para reducao e:
30
1. Percorrer a cadeia, a partir da esquerda ate que o primeiro > seja encontrado.
2. Percorrer, entao, de volta (para a esquerda) por sobre quaisquer relacoes (=) ate
que < seja encontrado.
3. O handle contem tudo `a esquerda do primeiro > e `a direita do < , incluindo
quaisquer nao-terminais presentes.
No exemplo acima, o primeiro handle e dado pelo primeiro id encontrado que pode
ser reduzido para o nao-terminal E (segundo a gramatica vista), seguido pelos proximos
dois ids da sentenca. A seguir, a senten ca obtida caria $ E + E * E $; removendo-se os
nao-terminais e acrescentando-se as relac oes de precedencia temos: $ < + < > $,
indicando que a proxima reducao deve ser realizada sobre o operador * (e seus respec-
tivos operandos associados E* E).
Devido ao fato da sua implementa cao nao ser trivial, a solucao de implementacao mais
viavel para este tipo de gramatica e fazer uso de um gerador de analisadores sint aticos,
como o YACC ou BISON.
4.4.3 Projeto de uma Gramatica para um Analisador Sintatico
Preditivo Descendente
Considerando o uso de analisadores sintaticos descendentes preditivo algumas preocupa-
c oes quanto a gramatica a ser utilizada, devem ser tomadas: eliminar ambig uidade, eli-
minar as recursoes `a esquerda e fatorar `a esquerda a gramatica.
Analisando um Programa Simples
A seguir, e apresentado um exemplo de um programa simples na linguagem PASCAL
jr
:
var: float N1, N2, M; int Ct;
const: int Qtde = 10;
func float _Media(float a,float b)
float media;
{
media = (a+b)/2.0;
return media;
}
main( ) {
Ct = 0;
do {
print("Digite duas notas:");
scanf(N1,N2);
printl("Media = ",_Media(N1,N2));
Ct ++;
} while(Ct != Qtde);
}
Todo programa em PASCAL
jr
respeita a seguinte estrutura:
31
[ Declarac ao de Variaveis e Constantes ]
[ Declaracao de Sub-Rotinas ]
<Programa Principal>
onde: [ ] indica secao opcional e <> indica sec ao obrigatoria.
Pode-se descrever esta estrutura na forma de uma regra de producao de uma GLC da
seguinte forma, onde o nao-terminal Programa sera o axioma da gramatica da linguagem
PASCAL
jr
:
Programa AreaDecl AreaSubRot Principal
Analisando a Secao de Declaracao de Variaveis e Constantes
Esta sec ao declara todas as variaveis e constantes utilizadas pelo programa.

E possvel a
declarac ao de varias areas de declaracao de variaveis e/ou constantes simultaneamente.
Um programa pode ainda nao conter esta secao.
AreaDecl AreaDeclVar AreaDecl |
AreaDeclConst AreaDecl |
AreaDeclVar prVar DoisPt DeclVars
DeclVars Tipo ListaID PtVirg DeclVars
DeclVars Tipo ListaID PtVirg DeclVars |
Tipo prInt | prFloat | prChar | prString | prBool
ListaID Identicador ListaID
ListaID Virg Identicador ListaID |
AreaDeclConst prConst DoisPt DeclConsts
DeclConsts Tipo ListaIDConst PtVirg DeclConsts
DeclConsts Tipo ListaIDConst PtVirg DeclConsts |
ListaIDConst Identicador Atrib Valor ListaIDConst
ListaIDConst Virg Identicador Atrib Valor ListaIDConst |
Valor OpAritSubt Numeros | Numeros |
ConstChar | ConstString | prTrue | prFalse
Numeros NumeroInteiro | NumeroReal
Analisando a Secao de Declaracao de Procedimentos e Funcoes
A secao de declaracao de procedimentos e funcoes declara todas as sub-rotinas utilizadas
pelo programa.

E possvel a declaracao de varias areas de declaracao de sub-rotinas
simultaneamente. Um programa pode ainda nao conter esta secao.
32
AreaSubRot AreaProc AreaSubRot |
AreaFunc AreaSubRot |
AreaProc prProc IdentSR AbrePar ListaParam
FechaPar AreaDecl BlocoCom
ListaParam Tipo Identicador ListaParam |
ListaParam Virg Tipo Identicador ListaParam |
AreaFunc prFunc Tipo IdentSR AbrePar ListaParam
FechaPar AreaDecl BlocoCom
Analisando o Programa Principal
O programa principal e o ponto onde inicia-se a execucao do codigo fonte. Ela e denida
pela func ao main. Apesar da linguagem PASCAL
jr
nao permitir a passagem de
parametros para esta func ao, ainda sim utilizar-se-ao os parenteses ( ) na sintaxe do
comando meramente por uma questao didatica. Esta sec ao e obrigatoria em qualquer
programa.
Principal prMain AbrePar FechaPar BlocoCom
Analisando um Bloco de Comandos
Um bloco de comandos pode ser entendido como um comando composto por uma lista
de outros comandos simples (ou outros blocos) podendo (em alguns casos) ser separados
por ; e delimitados por { e }. Sendo assim:
BlocoCom AbreChaves ListaCom FechaChaves
ListaCom Comando ListaCom |
Comando Condicional | RepetPre | RepetPos PtVirg |
RepetCont | Entrada PtVirg | Saida PtVirg |
Atrib PtVirg | SubRot PtVirg | BlocoCom |
Retorno PtVirg |
Analisando o comando Atribuicao
Pode ser realizado atraves de 7 diferentes operadores:
= atribuic ao simples
+= atribuic ao apos adic ao (X+ = Y X = X +Y )
33
-= atribuicao apos subtrac ao (X = Y X = X Y )
*= atribuicao apos multiplica cao (X = Y X = X Y )
/= atribuicao apos divisao (X/ = Y X = X/Y )obs.:Nao preve divisao por zero
++ atribuicao incremental (X + + X = X + 1)
- - atribuicao decremental (X X = X 1)
Exemplo de uma gramatica que reconhece esses comandos:
Atrib Identicador SimbAtrib Expr |
Identicador SimbAtribSoma Expr |
Identicador SimbAtribSubt Expr |
Identicador SimbAtribMult Expr |
Identicador SimbAtribDivi Expr |
Identicador SimbIncr | Identicador SimbDecr
porem, temos problemas de fatoracao. Fatorando `a esquerda estas producoes temos:
Atrib Identicador Atrib
Atrib SimbAtrib Expr |
SimbAtribSoma Expr |
SimbAtribSubt Expr |
SimbAtribMult Expr |
SimbAtribDivi Expr |
SimbIncr | SimbDecr
Analisando o comando Condicional
O comando condicional (sem fatorac ao) caria:
Condic prIf AbrePar Expr FechaPar Comando |
prIf AbrePar Expr FechaPar Comando
prElse Comando
e apos fatoracao teremos:
Condic prIf AbrePar Expr FechaPar Comando Condic
Condic prElse Comando |
34
Analisando os comandos de Repeticao
Os comandos de repeticao podem ser reconhecidos por:
RepetPos prDo ListaCom prWhile AbrePar Expr FechaPar
RepetPre prWhile AbrePar Expr FechaPar Comando
RepetCont prFor AbrePar Atrib PtVirg Expr PtVirg Atrib
FechaPar Comando
Analisando os comandos para chamada a Sub-Rotinas
Os comandos para chamadas a sub-rotinas incluem o comando < Retorno > que deve
ser usado nas chamadas a func oes.
SubRot IdentSR AbrePar ListaExpr FechaPar
Retorno prReturn Expr
Analisando os comandos de Entrada e Sada
Para os comandos de entrada e sada temos:
35
Entrada prScanf AbrePar ListaVar FechaPar
Saida prPrint AbrePar ListaExpr FechaPar |
prPrintl AbrePar ListaExpr FechaPar
ListaExpr Expr ListaExpr |
ListaExpr Virg Expr ListaExpr |
Analisando Expressoes Logicas e Aritmeticas
Para descrever sentencas que formam expressoes aritmeticas compostas das cinco opera-
c oes basicas (adicao, subtracao, multiplica cao, divisao e potenciac ao), tendo como ope-
randos: identicadores de variaveis e constantes, n umeros inteiros e reais, chamadas a
sub-rotinas e ainda permitir o uso de parenteses e do operador unario de sinal -; a
representac ao mais simples possvel seria:
ExprAr ExprAr OpAdic ExprAr |
ExprAr OpSubt ExprAr |
ExprAr OpMult ExprAr |
ExprAr OpDivi ExprAr |
ExprAr OpPote ExprAr |
AbrePar ExprAr FechaPar |
OpSubt ExprAr | SubRot |
Identicador | NumeroInteiro | NumeroReal |
ConstCaracter | ConstString
Exerccio: Montar a arvore gramatical para a expressao 2 (X 5.0) + 10/B
Apesar de que, com esta gramatica, e possvel gerar qualquer expressao aritmetica sim-
ples, esta nao leva em considerac ao todas as restricoes ja estudadas para a implementacao
de reconhecedores de gramatica TOP-DOWN.
O primeiro problema que se percebe e o fato da gramatica anterior nao considerar a
questao da precedencia de operadores. Para resolver este problema deve-se inserir novos
elementos nao-terminais `a gramatica:
ExprAr ExprAr OpAdic TermoAr |
ExprAr OpSubt TermoAr | TermoAr
TermoAr TermoAr OpMult FatorAr |
TermoAr OpDivi FatorAr | FatorAr
FatorAr FatorAr OpPote ElementoAr | ElementoAr
ElementoAr AbrePar ExprAr FechaPar |
36
OpSubt ExprAr | SubRot |
Identicador | NumeroInteiro | NumeroReal |
ConstCaracter | ConstString
Exerccio: Montar a arvore gramatical para a expressao 2 (X 5.0) + 10/B
A ideia e gerar os elementos de menor precedencia mais proximos `a raiz da arvore
sint atica e os de maior precedencia, mais proximos `as folhas.
Novamente temos problemas com a solucao proposta: recursao `a esquerda. A nova
gramatica apos realizado o processo (ja estudado) de eliminac ao da recursao `a esquerda,
temos:
ExprAr TermoAr ExprAr
ExprAr OpAdic TermoAr ExprAr |
OpSubt TermoAr ExprAr |
TermoAr FatorAr TermoAr
TermoAr OpMult FatorAr TermoAr |
OpDivi FatorAr TermoAr |
FatorAr ElementoAr FatorAr
FatorAr OpPote ElementoAr FatorAr |
ElementoAr AbrePar ExprAr FechaPar |
OpSubt ExprAr | SubRot |
Identicador | NumeroInteiro | NumeroReal |
ConstCaracter | ConstString
Exerccio: Montar a arvore sintatica para a expressao: 2 (X 5.0) + 10/B.
Analisando Expressoes Logicas
Uma expressao logica e, na verdade, uma comparac ao entre resultados de expressoes
aritmeticas, ou ainda, a uniao de duas expressoes aritmeticas atraves de um operador
relacional.
Sao possveis ainda, expressoes logicas mais complexas atraves da uniao de duas ex-
pressoes logicas simples por operadores logicos.
Expr TermoLog Expr Ternario
Ternario Interrog Expr DoisPt Expr |
Expr OpLogAnd TermoLog Expr |
OpLogOr TermoLog Expr |
OpLogXor TermoLog Expr |
TermoLog FatorLog TermoLog
37
TermoLog OpRelacMaior FatorLog |
OpRelacMenor FatorLog |
OpRelacMenorIgual FatorLog |
OpRelacMaiorIgual FatorLog |
OpRelacIgual FatorLog |
OpRelacDifer FatorLog |
FatorLog ExprAr | OpLogNeg Expr |
prTrue | prFalse
e ainda, ElementoAr AbrePar Expr FechaPar.
4.4.4 Exerccios Propostos
1. Montar a arvore sint atica da expressao (A + 5 == B/C 2) && D || ! A >= B
2. Criar a clausula FIRST para as produc oes da gramatica preditiva descendente como
forma de vericar sua implementac ao.
3. Criar a arvore gramatical para o programa abaixo:
var: float A, B, C;
main() {
scanf(A,B);
C=A+B*2;
print(C);
}
4.4.5 Trabalho Pratico #2
Implementar um modulo (sub-rotina) analisador sint atico descendente para um prototipo
de compilador para a linguagem PASCAL
jr
vista em aula.
Caractersticas:
Do modulo parser:
A sub-rotina retorna um ag indicando sucesso ou nao da analise sint atica.
Utiliza os tokens provenientes do modulo scanner (ja implementado) para simular a
lista lexica.
Implementa uma pilha de execuc ao (fsica ou por recursividade) para analise das
regras de produc ao da gramatica vista.
Do programa a ser criado:
Abre um arquivo fonte para analise.
38
Executa a analise da produc ao axioma da gramatica.
Fecha o arquivo fonte ao nal da compilacao.
Para o processo de compilac ao caso um erro seja encontrado.
Exibe erros de compilac ao (se ocorrerem) ou mensagem de sucesso.
Criterios de Avaliacao:
Implementa cao usando linguagem C ou C++.
Entrega de fontes e executavel (em um arquivo zipado) via e-mail:
rsilva@joinville.udesc.br ou professor.rogerio@gmail.com
Obrigatoriamente o mesmo grupo do trabalho anterior.
Valor do trabalho: 10.0 (25% da nota pratica).
Data de Entrega: A definir
Punic oes:
de 10% por erro sint atico nao analisado corretamente.
de 12.5% por erro lexico nao analisado corretamente.
de 20% do valor do trabalho por dia de atraso.
de 20% do valor do trabalho para a entrega nao conforme dos arquivos e/ou
formato pedidos.
de 50% do valor do trabalho para o caso de nao executar ou travar (apos teste
em 2 computadores, sendo um o do professor).
de 100% do valor do trabalho para o caso de copias (mesmo de trabalhos de
semestres anteriores).
Prazo maximo para defesa e arguic ao sobre o trabalho: 5 dias letivos apos entrega.
Punic oes:
de 25% para arguicao nao respondida ou respondida incorretamente. Obs.: A
arguicao e individual.
de 33% ponto por dia de atraso da defesa.
39
40
Captulo 5
Analise Semantica
5.1 Traducao Dirigida pela Sintaxe
A ideia e associar informacoes aos smbolos gramaticais que representam a construc ao de
uma LLC; tais informac oes sao atributos dos smbolos segundo certas regras semanticas
associadas `as produc oes da gramatica.
Existem duas notacoes para associar regras semanticas `as produc oes: denicoes diri-
gidas pela sintaxe e esquemas de traducao.
Denicoes Dirigidas pela Sintaxe
Uma denicao dirigida pela sintaxe e uma GLC na qual cada smbolo 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 computacao
dos valores dos lhos daquele no da arvore e dito ser herdado se foi obtido a partir da
computac ao dos irmaos e pai do respectivo no.
Uma arvore gramatical mostrando os valores dos atributos a cada no e denominada
de uma arvore gramatical anotada ou decorada.
Para cada produc ao do tipo A , temos associado a ela uma regra semantica da
forma b := f(c
1
, c
2
, . . . , c
n
), onde f e uma funcao que:
Ou b e um atributo sintetizado de A e c
1
, c
2
, . . . , c
n
sao atributos pertencentes aos
smbolos gramaticais da producao ou,
b e um atributo herdado, pertencente a um dos smbolos gramaticais do lado direito
de producao e c
1
, c
2
, . . . , c
n
sao atributos pertencentes aos smbolos da produc ao.
Numa denicao dirigida pela sintaxe, assume-se que os terminais tenham apenas atri-
butos sintetizados visto que para os mesmos nao existem regras semanticas. Se, para todas
as produc oes, so forem utilizados atributos sintetizados diz-se se tratar de uma denic ao
S-atribuda.
Exemplo: Seja a gramatica abaixo responsavel pelo funcionamento de uma calcula-
dora simples e tendo como unico atributo sintetizado o valor val responsavel pelo arma-
zenamento de um n umero inteiro, ent ao as regras semanticas (para determinacao do valor
resultante de uma expressao aritmetica) sao:
41
Producao Regras Semanticas
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 Expressao 3*5+4
Atributos herdados sao convenientes para expressar a dependencia de uma construc ao
de linguagem de programac ao no contexto em que a mesma gurar. Por exemplo, podemos
usar um atributo herdado para controlar se um identicador aparece ao lado esquerdo ou
direito de um comando de atribuic ao a m de decidirmos se e necessario usar o endereco
ou o valor do mesmo.
Exemplo: Declarac ao de variaveis: int x,y,z
Producao Regras Semanticas
D TL L.in = T.tipo
T int T.tipo = inteiro
T float T.tipo = real
L L

, id L.in = L.in
incluir tipo(id, L.in)
L id incluir tipo(id, L.in)
Grafos de Dependencia
Se um atributo b a um no da arvore depender de um atributo c, a regra semantica para b
`aquele no precisa ser avaliada apos a regra semantica para c. As interdependencias entre
os atributos herdados e sintentizados sao delineadas atraves de um grafo de dependencia.
42
Exemplo: Supondo que a producao A XY tenha uma regra semantica da forma
A.a = f(X.x, Y.y), ou seja, o atributo sintentizado a em A depende dos atributos x e y.
A representac ao para esta dependencia em um grafo de dependencia caria (conforme a
gura 5.2):
1. Existem tres nos 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 Dependencias
5.1.1 Denicoes L-Atribudas
O nome L provem de left, onde a analise gramatical e feita sempre a partir do lho mais
`a esquerda na arvore sintatica atraves do seguinte algoritmo:
Algoritmo de pesquisa em profundidade (depth-rst order):
Procedimento Visitar(n: no);
Inicio
Para cada filho m de n da esquerda para a direita faca
Inicio
Avaliar os atributos herdados de m;
Visitar(m);
Fim
Avaliar os atributos sintetizados de m;
Fim
Uma denic ao dirigida pela sintaxe e L-atribuda se cada atributo herdado de X
j
,
i j n, do lado direito de A X
1
, X
2
, . . . , X
n
depender somente:
Dos atributos dos smbolos X
1
, X
2
, . . . , X
j1
`a esquerda de X
j
na producao e
Dos atributos herdados de A.
Note-se que cada denicao S-atribuda e L-atribuda porque as restricoes (1) e (2) se
aplicam somente aos atributos herdados.
43
5.1.2 Vericacoes de Contexto
Um compilador precisa fazer uma vericacao estatica das estruturas do programa, para
assegurar que o mesmo esteja livre de certos tipos de erros, tais como:
Vericacao de Tipos verica se um operador esta sendo aplicado a operandos de tipos
incompatveis. Exemplo: 10 + TRUE.
Vericacao de Fluxo de Controle os enunciados de uxo de controle (repetic 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 uxo
de controle (while, for ou switch).
Vericacoes de Unicidade verica se os identicadores foram declarados de forma
unvoca, ou seja, sem duplicidade.
Vericacoes relacionadas aos nomes existem linguagens que apresentam particulari-
dades acerca dos identicadores do programa. Essa etapa da analise verica se essas
particularidades foram respeitadas. Exemplo: A linguagem ADA exige que blocos
de comandos comecem e terminem com o mesmo identicador.
Sistema de Tipos
Dene-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 sao validos para a
adic ao e, em caso armativo, qual seria o tipo resultante, e ainda, se esse tipo resultante
e compatvel com o tipo associado `a vari avel X.
Todo o processo de analise semantica para vericac ao de tipos e realizado a partir da
construc ao de expressoes de tipo, que podem ser compostas: ou por um tipo simples ou
por um construtor de tipos (tipo resultante da aplicac 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)
(invlido)
Construo de Tipos
Figura 5.3: Tipos Simples e Construtor de Tipos
O processo de vericac ao de tipos consiste da aplicac ao de regras semanticas `as
producoes da gramatica sob analise. Usualmente, um atributo sintetizado tipo e su-
ciente para tal analise.
44
Exemplo1: Para uma producao do tipo E id teramos uma regra semantica como
{ E.tipo = id.tipo }.
Exemplo2: Imagine uma linguagem que permita apenas operac oes com tipos identicos,
ent ao para uma produc ao do tipo E E + T teramos a regra semantica { E.tipo = se
E.tipo = T.tipo ent ao E.tipo senao inv alido }
Vericacao de Tipos em Expressoes
As seguintes regras semanticas podem ser abstradas de forma geral:
E tipo simples {E.tipo = tipo simples}
E id {E.tipo = ProcurarTS(id).tipo}
E E
1
{E.tipo = E
1
.tipo}
E E
1
op E
2
{E.tipo = SistemaTipos[E
1
.tipo, op, E
2
, tipo]}
Construcao de um Sistema de Tipos para Operadores
Apresenta as relac oes de compatibilidade, para cada operador, em funcao dos operandos.
Exemplo na linguagem Pascal:
Op
1
Op
2
+ - * /
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
45
Exerccio: Construir as tabelas de sistema de tipos para todos os operadores utilizados
na gramatica da linguagem PASCAL
jr
.
Operadores Aritmeticos: +, -, *, /, **
Operadores Relacionais: ==, !=, >, <, >=, <=
Smbolos Atribuic ao: =, +=, -=, *=, /=
Operadores Logicos: &&, ||, & |
Operadores Unarios: - , ! , ++, - -
Op
1
Op
2
+ - * / **
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
5.2 Tabela de Smbolos

E uma estrutura de dados gerada pelo compilador com o objetivo de armazenar in-
formac oes sobre os nomes (identicadores de vari aveis, de parametros, de func oes, etc.)
denidos no programa fonte.
Ela associa atributos tais como tipo, escopo, tamanho, limite (no caso de vetores,
n umero de parametros (no caso de subrotinas) a cada identicador armazenado na tabela.
Em geral, uma tabela de smbolo pode comecar a ser construda ja na fase de analise
lexica, mas geralmente nesta fase ainda nao e possvel se determinar as informac oes asso-
ciadas aos atributos dos identicadores que foram reconhecidas pelo compilador. Assim
46
sendo, essas tarefas sao realizadas nas fases de analise sint atica e/ou semantica, onde se
referencia `a tabela, cada vez que um identicador for encontrado no programa.
Os problemas enfrentados ao se projetar uma tabela de smbolos sao:
a quantidade de smbolos armazenados na tabela, depende do programa fonte sob
analise, ou seja, e desejavel uma estrutura dinamica de alocacao de memoria para
a tabela. Se uma estrutura estatica for construda, esta deve ter um tamanho
sucientemente grande para suportar qualquer programa (limitac ao de tamanho);
a quantidade de acesso `a tabela (inclusoes e consultas), pode ser bastante grande,
dependendo do programa. Pode-se organizar os dados na tabela atraves de listas
lineares, arvores binarias ou tabelas hash. O mecanismo linear, apesar de simples, e
ineciente para programas grandes, ja o hashing tem melhor desempenho mas exige
maior esforco de programac ao.
cada entrada na TS esta associada a um nome de identicador. Estas entradas
podem nao ser uniformes, ou seja, os atributos de um identicador de vari avel
nao sao os mesmos de um identicador de funcao, por exemplo. O uso de registros
variantes pode ser uma alternativa elegante para se organizar a estrutura que contera
tais atributos.
Enm, ao se projetar uma tabela de smbolos deve se levar em conta: a quantidade de
dados a serem armazenados, a natureza desses dados, o tempo de acesso e a facilidade de
modicacao da estrutura de armazenamento desses dados. Essas preocupac oes poderao
estar relacionadas `a aplicac ao que se deseja desenvolver.
5.2.1 Atributos dos Nomes dos Identicadores
De maneira geral, qualquer informacoes acerca dos identicadores denidos em um pro-
grama fonte, podem (e devem) ser armazenados em uma tabela de smbolos. O conjunto
de atributos e inerente `as caractersticas da linguagem sendo reconhecida.
Atributos como nome, tipo, uso no programa (isto e: vari avel, constante, procedi-
mento, funcao, rotulo), tamanho de memoria a ser alocada (em bytes), endereco (onde foi
alocada), escopo, etc.
Para efeito da disciplina (implementa cao do prototipo) apenas os atributos: nome,
tipo, endereco, natureza (var ou const).
5.2.2 Hashing
A funcao de espalhamento e responsavel por determinar qual endereco (na tabela Hash),
uma determinada chave k deve ser inserida.
Exemplo: int Hash(int Key){return Key%K TAM HASH; } onde, K TAM HASH
indica o tamanho (n

de posic oes) do vetor hash.


A funcao hash acima gera valores entre 0 e K TAM HASH-1 em func ao do valor de
Key (chave a ser inserida).
Problema!: Caso exista duas chaves que possuam o mesmo valor de chave, a func ao
hash ira gerar o mesmo endereco de vetor. Isto e chamado de colisao ou conito de
espalhamento.
47
Existem dois metodos basicos para manipular colisoes de espalhamento: reespalha-
mento ou encadeamento.
Solucionando colisoes atraves de reespalhamento
Requer o uso de uma funcao de espalhamento secundaria sobre a chave, sucessivas vezes
ate que um endereco valido (disponvel) seja encontrado para insercao do elemento.
No processo de busca ocorre ideia semelhante, exemplo: desejase localizar uma deter-
minada chave k:
1. usa-se a funcao de espalhamento principal
2. caso nao encontrado, usa-se a func ao de espalhamento secundaria
3. caso nao encontrado, repete-se o passo 2.
1. Inserindo elemento MEDIA: Hash(MEDIA)=6
1
2
3
4
5
6 MEDIA
2. Inserindo elemento X: Hash(X)=2
1
2 X
3
4
5
6 MEDIA
3. Inserindo elemento MEDIA FINAL: Hash(MEDIA FINAL)=6 (conito!)
Hash2(MEDIA FINAL)=1 (endereco valido)
1 MEDIA FINAL
2 X
3
4
5
6 MEDIA
4. Inserindo elemento CONT: Hash(CONT)=1 (conito!)
Hash2(CONT)=2 (conito!)
Hash2(CONT)=3 (endereco valido)
1 MEDIA FINAL
2 X
3 CONT
4
5
6 MEDIA
48
O metodo mais simples de solucionar colisoes de espalhamento e colocar o registro na
proxima posic ao disponvel no vetor.
OBS.: Deve-se trabalhar os dados no vetor da mesma forma que em uma lista circular,
ou seja, a proxima posicao apos o ultimo elemento e novamente o primeiro elemento.
Solucionando colisoes atraves de encadeamento
Usa-se uma lista encadeada para armazenar os elementos conitantes no local do conito.
Cada posic ao do vetor e o inicio de uma lista de elementos.
Sempre que um conito na inserc ao de dados ocorrer, o novo elemento (conitante) e
inserido em uma lista encadeada na posic ao.
Media
X1
A
Res
Cont
X2
B C
Figura 5.4: Hashing com Encadeamento
49
5.3 Projeto das Regras Semanticas
Os smbolos semanticos no prototipo PASCAL
jr
armazenarao as seguintes informacoes:
Lexema, Tipo, Endereco, Natureza (VAR ou CONST), Valor (No caso de constantes).
O TDA (Hashing) e acessado atraves dos seguintes metodos:
CriaTS aloca a tabela de smbolos vazia
InsereTS insere um novo smbolo na tabela de smbolos
BuscaTS retorna as informacoes de um determinado smbolo na tabela
DestroiTS desaloca toda a tabela de smbolos
Os possveis erros semanticos sao:
1. Identicador Nao Declarado
2. Identicador de Vari avel Esperado
3. Tipos Incompatveis
4. Identicador Duplicado
5. Retorno de Func ao Esperado
6. Uso Incorreto de Chamada de Sob-Rotina
As seguintes regras semanticas serao aplicadas `as regras da gramatica da linguagem
PASCAL
jr
. Obs.: Nao esquecer de considerar os grafos de dependencia entre os atributos
semanticos.
50
Programa AreaDecl AreaSubRot Principal
{ CriaTS(); EnderecoLivre=0; }
AreaDecl AreaDeclVar AreaDecl | AreaDeclConst AreaDecl |
{ Nenhuma Ac ao Semantica }
AreaDeclVar prVar DoisPt DeclVars
{ Nenhuma Ac ao Semantica }
DeclVars Tipo ListaID PtVirg DeclVars
{ ListaID.Acao = DeclV ar; ListaID.Tipo = Tipo.Tipo }
DeclVars Tipo ListaID PtVirg DeclVars
{ ListaID.Acao = DeclV ar; ListaID.Tipo = Tipo.Tipo }
DeclVars { Nenhuma Acao Semantica }
Tipo prInt { Tipo.Tipo = Inteiro }
Tipo prFloat { Tipo.Tipo = Real }
Tipo prChar { Tipo.Tipo = Caracter }
Tipo prString { Tipo.Tipo = Cadeia }
Tipo prBool { Tipo.Tipo = Logico }
ListaID Identicador ListaID
{ ListaID.Acao = ListaID.Acao; ListaID.Tipo = ListaID.Tipo;
if(ListaID.Acao==DeclVar){
if(!InsereTS(VAR, Identicador.Lexema, ListaID.Tipo, EnderecoLivre + +)
ERRO SEM 4; }
else Entrada=BuscaTS(Identicador.Lexema);
if(!Entrada) ERRO SEM 1 else if(Entrada.Natureza != VAR) ERRO SEM 2 }
ListaID
1
Virg Identicador ListaID
2
{ ListaID
2
.Acao = ListaID
1
.Acao; ListaID
2
.Tipo = ListaID
1
.Tipo;
if(ListaID
1
.Acao==DeclVar){
if(!InsereTS(VAR, Identicador.Lexema, ListaID.Tipo, EnderecoLivre + +)
ERRO SEM 4; }
else Entrada=BuscaTS(Identicador.Lexema);
if(!Entrada) ERRO SEM 1 else if(Entrada.Natureza != VAR) ERRO SEM 2 }
ListaID { Nenhuma Ac ao Semantica }
AreaDeclConst prConst DoisPt DeclConsts
{ Nenhuma Ac ao Semantica }
DeclConsts Tipo ListaIDConst PtVirg DeclConsts
{ ListaIDConst.Tipo = Tipo.Tipo }
DeclConsts Tipo ListaIDConst PtVirg DeclConsts
{ ListaIDConst.Tipo = Tipo.Tipo }
DeclConsts { Nenhuma Ac ao Semantica }
ListaIDConst Identicador Atrib Valor ListaIDConst
{ ListaIDConst.Tipo = ListaIDConst.Tipo;
InsereTS(CONST, Identicador.Lexema, ListaIDConst.Tipo,
EnderecoLivre + +, Valor.V alor) }
51
ListaIDConst
1
Virg Identicador Atrib Valor ListaIDConst
2
{ ListaIDConst
2
.Tipo = ListaIDConst
1
.Tipo;
InsereTS(CONST, Identicador.Lexema, ListaIDConst
1
.Tipo,
EnderecoLivre + +, Valor.V alor) }
ListaIDConst { Nenhuma Acao Semantica }
Valor OpAritSubt Numeros { Valor.V alor = Numeros.V alor }
Valor Numeros { Valor.V alor = Numeros.V alor }
Valor ConstCaracter { Valor.V alor = ConstCaracter.Lexema }
Valor ConstString { Valor.V alor = ConstString.Lexema }
Valor prTrue { Valor.V alor = true }
Valor prFalse { Valor.V alor = false }
Numeros NumeroInteiro { Numeros.V alor = NumeroInteiro.Lexema }
Numeros NumeroReal { Numeros.V alor = NumeroReal.Lexema }
BlocoCom AbreChaves ListaCom FechaChaves
{ Nenhuma Ac ao Semantica }
ListaCom ComSimp ListaCom { Nenhuma Ac ao Semantica }
ListaCom { Nenhuma Acao Semantica }
ListaCom PtVirg ComSimp ListaCom { Nenhuma Ac ao Semantica }
< ListaCom > { Nenhuma Acao Semantica }
< ComSimp >< Atrib > { Nenhuma Ac ao Semantica }
< ComSimp >< RepetPre > { Nenhuma Acao Semantica }
< ComSimp >< RepetPos >
{ Nenhuma Ac ao Semantica }
< ComSimp >< RepetCont >
{ Nenhuma Ac ao Semantica }
< ComSimp >< Entrada >
{ Nenhuma Ac ao Semantica }
< ComSimp >< Saida >
{ Nenhuma Ac ao Semantica }
< ComSimp >< Condic >
{ Nenhuma Ac ao Semantica }
< ComSimp >< BlocoCom >
{ Nenhuma Ac ao Semantica }
< ComSimp >
{ Nenhuma Ac ao Semantica }
< Atrib > Identicador < Atrib >
{Entrada = BuscaTS(Identicador);
if(!Entrada)ERRO SEM 1 else if(Entrada.Natureza! = V AR)ERRO SEM 2;
< Atrib > .Tipo = Entrada.Tipo;}
52
< Atrib > SimbAtrib < Expr >
{if(!SistemaTipos(< Atrib > .Tipo, SimbAtrib, < Expr > .Tipo))ERRO SEM 3}
< Atrib > SimbAtribSoma < Expr >
{if(!SistemaTipos(< Atrib > .Tipo, SimbAtribSoma, < Expr > .Tipo))ERRO SEM 3}
< Atrib > SimbAtribSubt < Expr >
{if(!SistemaTipos(< Atrib > .Tipo, SimbAtribSubt, < Expr > .Tipo))ERRO SEM 3}
< Atrib > SimbAtribMult < Expr >
{if(!SistemaTipos(< Atrib > .Tipo, SimbAtribMult, < Expr > .Tipo))ERRO SEM 3}
< Atrib > SimbAtribDivi < Expr >
{if(!SistemaTipos(< Atrib > .Tipo, SimbAtribDivi, < Expr > .Tipo))ERRO SEM 3}
< Atrib > SimbIncr
{if(!SistemaTipos(< Atrib > .Tipo, SimbIncr))ERRO SEM 3}
< Atrib > SimbDecr
{if(!SistemaTipos(< Atrib > .Tipo, SimbDecr))ERRO SEM 3}
< Condic > prSe < Expr > prEntao < ComSimp >< Condic >
{if(< Expr > .Tipo! = Logico)ERRO SEM 3}
< Condic > prSenao < ComSimp >
{ Nenhuma Acao Semantica }
< Condic >
{ Nenhuma Acao Semantica }
< RepetPos > prRepita < ListaCom > prAte < Expr >
{if(! < Expr > .Tipo == Logico)ERRO SEM 3}
< RepetPre > prEnquanto < Expr > prFaca < CompSimp >
{if(! < Expr > .Tipo == Logico)ERRO SEM 3}
< RepetCont > prPara Identicador SimbAtribValor > prAte
< Expr > prFaca < RepetCont >< ComSimp >
{Entrada = BuscaTS(Identicador);
if(Entrada.Tipo! =< Valor > .Tipo || Entrada.Tipo! = Inteiro)ERRO SEM 3
elseif(< Expr > .tipo! = inteiro)ERRO SEM 3
< RepetCont > prPasso < Expr >
if(< Expr > .tipo! = inteiro)ERRO SEM 3
< RepetCont >
{ Nenhuma Acao Semantica }
< Valor > NumeroInteiro
{ < Valor > .Tipo = inteiro }
< Valor > Identicador
{ < Valor > .Tipo = BuscaTS(Identicador).Tipo }
< Entrada > prLeia AbrePar < ListaID > FechaPar
{ < ListaID > .Acao = Leia; }
< Saida > prImprima Abrepar < ListaExpr > FechaPar
{ Nenhuma Acao Semantica }
53
< ListaExpr >< Expr >< ListaExpr >
{ Nenhuma Acao Semantica }
< ListaExpr > Virg < Expr >< ListaExpr >
{ Nenhuma Acao Semantica }
< ListaExpr >
{ Nenhuma Acao Semantica }
< Expr >< TermoLog >< Expr >< Ternario >
{< Expr > .in =< TermoLog > .out; < Ternario > .in =< Expr > .out;
< Expr > .tipo =< Ternario > .out; }
< Ternario > Interrog < Expr >
1
DoisPt < Expr >
2
{if(< Ternario > .in ! = Logico)ERRO SEM 3 else
if(< Expr >
1
.Tipo ! = < Expr >
2
.Tipo) ERRO SEM 3 else
< Ternario > .out =< Expr >
1
.Tipo}
< Ternario >
{< Ternario > .out =< Ternario > .in}
< Expr > OpLogAnd < TermoLog >< Expr >
1
{< Expr >
1
.in = SistemaTipos[< Expr > .in, OpLogAnd, < TermoLog > .out];
< Expr > .out =< Expr >
1
.out}
< Expr > OpLogOr < TermoLog >< Expr >
{< Expr >
1
.in = SistemaTipos[< Expr > .in, OpLogOr, < TermoLog > .out];
< Expr > .out =< Expr >
1
.out}
< Expr > OpLogXor < TermoLog >< Expr >
{< Expr >
1
.in = SistemaTipos[< Expr > .in, OpLogXor, < TermoLog > .out];
< Expr > .out =< Expr >
1
.out}
< Expr >
{< Expr > .out =< Expr > .in}
< TermoLog >< FatorLog >< TermoLog >
{< TermoLog > .in =< FatorLog > .out;
< TermoLog > .out =< TermoLog > .out; }
< TermoLog > OpRelacMaior < FatorLog >
{< TermoLog > .out = SistemaTipos[< TermoLog > .in, OpRelacMaior,
< FatorLog > .out]; }
< TermoLog > OpRelacMenor < FatorLog >
{< TermoLog > .out = SistemaTipos[< TermoLog > .in, OpRelacMenor,
< FatorLog > .out]; }
< TermoLog > OpRelacMenorIgual < FatorLog >
{< TermoLog > .out = SistemaTipos[< TermoLog > .in, OpRelacMenorIgual,
< FatorLog > .out]; }
< TermoLog > OpRelacMaiorIgual < FatorLog >
{< TermoLog > .out = SistemaTipos[< TermoLog > .in, OpRelacMaiorIgual,
< FatorLog > .out]; }
54
< TermoLog > OpRelacIgual < FatorLog >
{< TermoLog > .out = SistemaTipos[< TermoLog > .in, OpRelacIgual,
< FatorLog > .out]; }
< TermoLog > OpRelacDifer < FatorLog >
{< TermoLog > .out = SistemaTipos[< TermoLog > .in, OpRelacDifer,
< FatorLog > .out]; }
< TermoLog >
{< TermoLog > .out =< TermoLog > .in}
< FatorLog >< ExprAr >
{< FatorLog > .out =< ExprAr > .out}
< FatorLog > OpLogNeg < Expr >
{< FatorLog > .out = SistemaTipos[< Expr > .out, OpLogNeg]; }
< FatorLog > prVerdadeiro
{< FatorLog > .out = V erdadeiro}
< FatorLog > prFalso
{< FatorLog > .out = Falso}
< ExprAr >< TermoAr >< ExprAr >
{< ExprAr > .in =< TermoAr > .out;
< ExprAr > .out =< ExprAr > .out; }
< ExprAr > OpAdic < TermoAr >< ExprAr >
1
{< ExprAr >
1
.in = SistemaTipos[< ExprAr > .in, OpAdic, < TermoAr > .out];
< ExprAr > .out =< ExprAr >
1
.out; }
< ExprAr > OpSubt < TermoAr >< ExprAr >
1
{< ExprAr >
1
.in = SistemaTipos[< ExprAr > .in, OpSubt, < TermoAr > .out];
< ExprAr > .out =< ExprAr >
1
.out; }
< ExprAr >
{< ExprAr > .out =< ExprAr > .in}
< TermoAr >< FatorAr >< TermoAr >
{< TermoAr > .in =< FatorAr > .out;
< TermoAr > .out =< TermoAr > .out; }
< TermoAr > OpMult < FatorAr >< TermoAr >
1
{< TermoAr >
1
.in = SistemaTipos[< TermoAr > .in, OpMult, < FatorAr > .out];
< TermoAr > .out =< TermoAr >
1
.out; }
< TermoAr > OpDivi < FatorAr >< TermoAr >
1
{< TermoAr >
1
.in = SistemaTipos[< TermoAr > .in, OpDivi, < FatorAr > .out];
< TermoAr > .out =< TermoAr >
1
.out; }
< TermoAr >
{< TermoAr > .out =< TermoAr > .in}
< FatorAr >< ElementoAr >< FatorAr >
1
{< FatorAr >
1
.in =< ElementoAr > .out;
< FatorAr > .out =< FatorAr >
1
.out; }
55
< FatorAr > OpPote < ElementoAr >< FatorAr >
1
{< FatorAr >
1
.in = SistemaTipos[< FatorAr > .in, OpPote,
< ElementoAr > .out];
< FatorAr > .out =< FatorAr >
1
.out; }
< FatorAr >
{< FatorAr > .out =< FatorAr > .in}
< ElementoAr > AbrePar < Expr > FechaPar
{< ElementoAr > .out =< Expr > .out; }
< ElementoAr > OpSubt < ExprAr >
{< ElementoAr > .out = SistemaTipos[< ExprAr > .out, OpSubt]; }
< ElementoAr > Identicador
{< ElementoAr > .out = BuscaTS(Identicador).Tipo; }
< ElementoAr > NumeroInteiro
{< ElementoAr > .out = Inteiro}
< ElementoAr > NumeroReal
{< ElementoAr > .out = Real}
< ElementoAr > ConstCaracter
{< ElementoAr > .out = Caracter}
< ElementoAr > ConstString
{< ElementoAr > .out = Cadeia}
5.3.1 Trabalho Pratico #3
Implementar um modulo analisador semantico para um prototipo de compilador para a
linguagem PASCAL
jr
(simplicada) vista em aula.
Caractersticas:
Do modulo semantico:
Cada chamada a elementos nao-terminais processa as ac oes semanticos necessarias
para cada produc ao da gramatica.
Utiliza a arvore gramatical criada no modulo parser.
Implementa uma tabela de smbolos (Hashing) a m de armazenar os smbolos
reconhecidos durante a compilac ao.
Do programa a ser criado:
Abre um arquivo fonte para analise.
Executa a analise semantica a partir da producao axioma da gramatica.
Fecha o arquivo fonte ao nal da compilacao.
Para o processo de compilac ao caso um erro seja encontrado.
Exibe erros de compilac ao (se ocorrerem) ou mensagem de sucesso.
Criterios de Avaliacao:
56
Implementa cao usando linguagem C ou C++.
Entrega de fontes e executavel (em um disquete identicado).
Grupo de 02 alunos (maximo).
Valor do trabalho: 10.0 (25% da nota pratica).
Data de Entrega: 08/11/2004.
Punic oes:
de 20% do valor do trabalho por dia de atraso.
de 20% por erro lexico nao analisado corretamente.
de 15% por erro sint atico nao analisado corretamente.
de 10% por erro semantico nao analisado corretamente.
de 20% do valor do trabalho para a entrega nao conforme dos arquivos pedidos.
de 50% do valor do trabalho para o caso de nao executar ou travar (apos teste
em 2 computadores, sendo um o do professor).
de 100% do valor do trabalho para o caso de copias (mesmo de trabalhos de
semestres anteriores).
Prazo maximo para defesa e arguic ao sobre o trabalho: 7 dias letivos apos entrega.
Punic oes:
de 33% ponto por dia de atraso da defesa.
de 25% para arguicao nao respondida ou respondida incorretamente. Obs.: A
arguicao e individual.
57
58
Captulo 6
Geracao de Codigo Intermediario

E a primeira fase da etapa de sntese, responsavel por transformar a arvore de derivac ao


em um trecho de codigo (que pode eventualmente ser o proprio codigo objeto nal).
Freq uentemente porem, o codigo gerado nao especica detalhes da maquina alvo, tais
como quais registradores serao usados ou quais enderecos de memoria serao referenciados,
etc.
Existem vantagens e desvantagens de se usar a etapa de gerac ao de codigo inter-
mediario. Vantagens:
Permite otimizac oes de codigo, a m de tornar o codigo nal mais eciente;
Simplica a implementacao do compilador;
Possibilita que um mesmo codigo intermediario possa ser traduzido para diferentes
linguagens objeto.
Desvantagens:
Uma etapa a mais e executada durante o processo de compilac ao, tornando o pro-
cesso mais lento.
6.1 Linguagens Intermediarias
Sao divididas em 3 categorias:
Representa coes gracas;
Notac ao pos (ou pre) xadas;
Codigo de tres-enderecos.
6.1.1 Representac oes Gracas

E uma forma condensada de arvore de derivac ao na qual somente os operandos da lin-


guagem aparecem como folhas; os operadores constituem nos interiores da arvore (gura
6.1).
Exerccio: Gerar as representa coes graca para as expressoes abaixo:
59
=
a
b c b
+
* *
2
Figura 6.1: Exemplo de Representac ao Graca de Operadores para a=b*c+b*2
1. a = b +c d/4
2. exp = b b 4 a c >= 0 && a! = 0
3. d = (a a) (b b)
6.1.2 Notacao Pos (e Pre) Fixadas
Dada uma certa expressao E1 q E2, onde E1 e E2 sao os operandos e q um operador, a
expressao pos-xada e representada por E1 E2 q, enquanto que a representa cao pre-xada
por q E1 E2.
Exemplos:
Infixa P

os-Fixada Pr

e-Fixada
(a +b) c ab +c +abc
a (b +c) abc + a +bc
a +b c abc + +a bc
a = b c +d abc d+ = = a +bcd
Exerccios: Gerar as notacoes pre e pos xas das expressoes abaixo:
1. a +a b +b
2. a +b 4/d c
3. (a +a) (b +b)
4. a = b +c d/4
5. exp = b b 4 a c >= 0 && a! = 0
6. d = (a a) (b b)
A seguir e apresentado um esquema de traducao para expressoes pos xadas:
E E1 +T {E.cod = E1.cod T.cod +}
E T {E.cod = T.cod}
T T1 F {T.cod = T1.cod T.cod *}
T F {T.cod = F.cod}
F id {F.cod = id.nome}
60
6.1.3 Codigo de Tres-Enderecos
Cada instrucao faz referencia, no maximo, a tres vari aveis (enderecos de memoria). As
instruc oes dessa linguagem intermediaria sao:
A = B op C
A = op B
A = B
goto L
if A oprel B goto L
Exemplo: A = X+Y*Z
T1 = Y*Z
T2 = X+T1
A = T2
Um codigo de tres-endere cos pode ser implementado atraves de quadruplas (um opera-
dor, dois operandos e um resultado) ou triplas (um operador e dois operandos), conforme
os exemplos abaixo.
Exemplo: A = B*(-C+D)
oper arg
1
arg
2
result
(0) - C T1
(1) + T1 D T2
(2) * B T2 T3
(3) = T3 A
oper arg
1
arg
2
(0) - C
(1) + (0) D
(2) * B (1)
(3) = A (2)
Na representac ao por triplas existentes apontadores para a propria estrutura, evitando
assim o uso de temporarios.
Esquema de Traducao para um comando de atribuicao
Atrib ID=Expr {Atrib.cod = Expr.cod;
Geracod(ID.nome=Expr.nome); }
Expr Expr
1
+Expr
2
{Expr.nome = GeraTemp;
Expr.cod = Expr
1
.cod || Expr
2
.cod ||
Geracod(Expr.nome=Expr
1
.nome+Expr
2
.nome); }
Expr Expr
1
*Expr
2
{Expr.nome = GeraTemp;
Expr.cod = Expr
1
.cod || Expr
2
.cod ||
Geracod(Expr.nome=Expr
1
.nome*Expr
2
.nome); }
Expr (Expr
1
) {Expr.nome = Expr
1
.nome; Expr.cod = Expr
1
.cod; }
Expr ID {Expr.nome = ID.nome; Expr.cod =

}
61
O atributo nome armazena o nome de uma vari avel (ou temporario). O atributo
cod armazena o codigo fonte gerado para o comando. A funcao geracod gera um texto
correspondente a(s) instruc ao(oes) fornecida(s) como parametro. A func ao geratemp gera
o nome de uma variavel temporaria.
Exemplo para o comando A=X+Y*Z gera o seguinte codigo:
T1 = Y * Z
T2 = X + T1
A = T2
Esquema de Traducao para Expressoes Logicas
Existem dois metodos principais: representacao numerica e representac ao por uxo de
controle.
Representac ao Numerica
Codica numericamente as constantes true (=1) e false (=0) e avalia o resultado logico
numa vari avel temporaria.
Exemplo: Supondo que o codigo gerado seja armazenado a partir da quadrupla 100 o
comando A < B seria traduzido para:
099: . . .
100: if A < B goto 103
101: T1=0
102: goto 104
103: T1=1
104: . . .
Expr Expr
1
|| Expr
2
{Expr.nome = GeraTemp;
Geracod(Expr.nome = Expr
1
.nome || Expr
2
.nome)}
Expr Expr
1
&& Expr
2
{Expr.nome = GeraTemp;
Geracod(Expr.nome = Expr
1
.nome && Expr
2
.nome)}
Expr ! Expr
1
{Expr.nome = GeraTemp;
Geracod(Expr.nome = ! Expr
1
.nome); }
Expr (Expr
1
) {Expr.nome = Expr
1
.nome; }
Expr ID
1
opRel ID
2
{Expr.nome = GeraTemp;
Geracod(if ID
1
.nome opRel ID
2
.nome goto Proxq + 3);
Geracod(Expr.nome =0); Geracod(goto Proxq + 2);
Geracod(Expr.nome =1); }
Expr true {Expr.nome = GeraTemp; Geracod(Expr.nome=1); }
Expr false {Expr.nome = GeraTemp; Geracod(Expr.nome=0); }
A vari avel proxq indica o ndice da proxima quadrupla disponvel.
Exemplo: A < B || C < D && E < F
62
100: if A < B goto 103 107: T2=1
101: T1=0 108: if E < F goto 111
102: goto 104 109: T3=0
103: T1=1 110: goto 112
104: if C < D goto 107 111: T3=1
105: T2=0 112: T4=T2 && T3
106: goto 108 113: T5 = T1 || T4
O valor nal da expressao e sempre no ultimo temporario gerado (no exemplo T5). O
nome desse temporario e ent ao armazenado no nao-terminal expressao da gramatica.
Esquema de Traducao para o comando Enquanto
O comando < Enquanto > prEnquanto < Expr > prFaca < ComSimp >, segue
o seguinte esquema de traducao:
Inicio: Expr.cod
if Expr.nome == 0 goto Prox
ComSimp.cod
goto Inicio
Prox: . . .
Atraves da seguinte regra de traducao:
S prEnquanto Expr prFaca {S.inicio = GeraRotulo; S.prox = GeraRotulo;
ComSimp S.cod = Expr.cod ||
Geracod(if Expr.nome == 0goto S.prox);
ComSimp.cod; || Geracod(goto S.inicio); }
Representac ao por Fluxo de Controle
Este metodo traduz expressoes logicas para um codigo formado por instruc oes if-goto.
Sao gerados rotulos true e false, que armazenam os enderecos de desvio de execucao caso
a avaliac ao resulte em true ou false respectivamente. Por este motivo, e mais eciente que
o metodo de avaliacao numerica.
Traduc ao de expressoes logicas por uxo de controle
Expr Expr
1
|| Expr
2
{Expr
1
.true = Expr.true; Expr
1
.false = GeraRotulo;
Expr
2
.true = Expr.true; Expr
2
.false = Expr.false;
Expr.cod = Expr
1
.cod || Expr
2
.cod; }
Expr Expr
1
&& Expr
2
{Expr
1
.true = GeraRotulo; Expr
1
.false = Expr.false;
Expr
2
.true = Expr.true; Expr
2
.false = Expr.false;
Expr.cod = Expr
1
.cod || Expr
2
.cod; }
Expr ! Expr
1
{Expr
1
.true = Expr.false; Expr
1
.false = Expr.true;
Expr.cod = Expr
1
.cod; }
Expr (Expr
1
) {Expr
1
.true = Expr.true; Expr
1
.false = Expr.false;
Expr.cod = Expr
1
.cod; }
Expr ID
1
opRel ID
2
{Expr.cod = Geracod(if ID
1
.nome opRel ID
2
.nome
goto Expr.true); Geracod(goto Expr.false); }
Expr true {Expr.cod = Geracod(goto Expr.true); }
Expr false {Expr.cod = Geracod(goto Expr.false); }
63
Exemplo: A < B || C < D && E < F
if A < B goto RT
goto L1
L1 if C < D goto L2
goto RF
L2 if E < F goto RT
goto RF
Supondo que os atributos true e false tenham recebido os rotulos RT e RF.
Esquema de Traducao para Comandos de Controle de Fluxo
S prSe Expr prEntao S
1
{Expr.true = GeraRotulo; Expr.false = S.prox;
S
1
.prox = S.prox; S.cod = Expr.cod || S
1
.cod; }
S prSe Expr prEntao S
1
{Expr.true = GeraRotulo; Expr.false = GeraRotulo;
prSenao S
2
S
1
.prox = S.prox; S
2
.prox = S.prox;
S.cod = Expr.cod || S
1
.cod; ||
Geracod(goto S.prox); || S
2
.cod; }
S prEnquanto Expr S
1
{S.inicio = GeraRotulo; Expr.true = GeraRotulo;
Expr.false = S.prox; S
1
.prox = S.inicio;
S.cod = Expr.cod || S
1
.cod; ||
Geracod(goto S.inicio); }
6.2 BackPatching (Retrocorrecao)
O principal problema, na geracao de codigo, e que o codigo gerado deve incluir comandos
de desvio para enderecos que, em geral, ainda nao sao conhecidos. Isso inviabiliza a
gerac ao de codigo num unico passo.
A solucao e utilizar geracao de codigos incompletos para os comandos (sem os en-
derecos) que serao devidamente completados quando o endereco destino for conhecido.
Chama-se de backpatching ao preenchimento desses enderecos nao resolvidos.
Sao necessarias tres func oes para isso:
makelist(i) cria uma lista contendo i (um unico elemento) e retorna um ponteiro para
a lista criada; o elemento i e um ndice do vetor de quadruplas;
merge(p1,p2) concatena as listas apontadas por p1 e p2, e retorna um ponteiro para
lista resultante;
backpatching(p,i) insere i (rotulo destino) no campo de endereco de cada uma das
quadruplas da lista apontada por p.
64
Backpatching para Expressoes Logicas
Foi acrescentado o smbolo nao-terminal M, que tem como objetivo guardar o endereco
da proxima quadrupla disponvel no momento em que M e empilhado (apos um && ou
||).
E E
1
|| E
2
{backpatching(E
1
.ListaFalse, M.quad);
E.ListaTrue = merge(E
1
.ListaTrue, E
2
.ListaTrue);
E.ListaFalse = E
2
.ListaFalse; }
E E
1
&& E
2
{backpatching(E
1
.ListaTrue, M.quad);
E.ListaTrue = E
2
.ListaFalse;
E.ListaFalse = merge(E
1
.ListaFalse, E
2
.ListaFalse); }
E !E
1
{E.ListaTrue = E
1
.ListaFalse; E.ListaFalse = E
1
.ListaTrue; }
E (E
1
) {E.ListaTrue = E
1
.ListaTrue; E.ListaFalse = E
1
.ListaFalse; }
E ID
1
opRel ID
2
{E.ListaTrue = makelist(Proxq);
E.ListaFalse = makelist(Proxq + 1);
Geracod(if ID
1
.nome opRel ID
2
.nome goto );
Geracod(goto ); }
E ID {E.ListaTrue = makelist(Proxq);
E.ListaFalse = makelist(Proxq + 1);
Geracod(if ID.nome goto );
Geracod(goto ); }
M {M.quad = Proxq; }
Neste esquema, E.ListaTrue e E.ListaFalse sao atributos sintetizados (listas) que in-
dicam quadruplas com comandos de desvio incompletos. Os enderecos sao preenchidos
com o valor armazenado em M.quad quando um backpatching ocorre na lista.
Exemplo: a < b || c < d && e < f
E
E E
E E
M
M
||
&&
A < B
C < D E < F
ListaTrue=100
ListaFalse=101
ListaTrue=102
ListaFalse=103
ListaTrue=104
ListaFalse=105
ListaTrue=104
ListaFalse=103,105
ListaTrue=100,104
ListaFalse=103,105
Quad=102
Quad=104
Figura 6.2: Backpatching para expressoes logicas
100: if A < B goto 100: if A < B goto
101: goto 101: goto 102
102: if C < D goto 102: if C < D goto 104
103: goto 103: goto
104: if E < F goto 104: if E < F goto
105: goto 105: goto
65
Backpatching para Comandos de Controle
Entendendo-se o esquema de traduc ao anterior, e introduzido um nao-terminal N antes
do comando senao para ocasionar um salto sobre o bloco do senao se for o caso.
S Se E entao M S
1
{backpatching(E.ListaTrue, M.quad);
S.prox = merge(E.ListaFalse, S
1
.prox); }
S Se E entao M
1
S
1
N {backpatching(E.ListaTrue, M
1
.quad);
senao M
2
S
2
backpatching(E.ListaFalse, M
2
.quad);
S.prox = merge(S
1
.prox, merge(N.go, S
2
.prox)); }
N {N.go = makelist(Proxq); Geracod(goto ); }
S Enquanto M
1
E Faca {backpatching(S
1
.prox, M
1
.quad);
M
2
S
1
backpatching(E.ListaTrue, M
2
.quad);
S.prox = E.ListaFalse; Geracod(goto M
1
.quad); }
S {L} {S.prox = L.prox;
S A {S.prox = makelist(NULL); }
A ID = E Ac oes semanticas ja vistas em aula
L L
1
; M S {backpatching(L
1
.prox, M.quad); L.prox = S.prox; }
L S {L.prox = S.prox; }
P S. {backpatching(S.prox, EOF); }
O endereco indicado por EOF representa o m do codigo fonte e o retorno ao sistema
operacional.
Exerccio: Gere o codigo para o trecho de programa abaixo (supor primeira instrucao
no endereco 000):
Enquanto A < B entao
se C < D entao
X = Y+Z
senao
X = Y-Z
Codigo resultante:
000: if A < B goto 002 006: goto 000
001: goto EOF 007: T2 = Y-Z
002: if C < D goto 004 008: X = T2
003: goto 007 009: goto 000
004: T1 = Y+Z EOF:
005: X = T1
66
Captulo 7
Otimizacao de Codigo
Trata-se do problema da geracao de codigo eciente: uso racional da memoria e rapidez
na execucao do codigo fonte. Porem, muitas vezes esses aspectos sao conitantes, ou seja,
apela-se para um maior tempo de execuc ao para se conseguir um ganho no consumo de
memoria e vice-versa.
Compiladores que aplicam transformacoes de melhorias no codigo gerado sao denomi-
nados compiladores otimizantes.
Normalmente este processo e feito em duas fases: otimizacoes do codigo intermediario
e otimizacoes do codigo objeto. No codigo intermediario pode-se eliminar atribuic oes
redundantes, sub-expressoes comuns, temporarios desnecessarios, etc., no intuito de di-
minui o codigo intermedi ario, enquanto que no codigo objeto e feita uma substituicao de
instruc oes por equivalentes mais rapidos que permitem melhor uso dos registradores.
7.1 Otimizacao Peephole
Uma tecnica simples para melhorar localmente o codigo gerado e a otimizacao peephole,
que trabalha substituindo seq uencias de instrucoes (peepholes) por outras mais ecientes.
As principais ac oes da otimizac ao peephole sao:
eliminac ao de instruc oes redundantes
otimizac oes de uxo de controle
simplicac oes algebricas
Eliminacao de Instruc oes Redundantes
Uma seq uencia de instruc oes do tipo a = b e b = a, pode ser substitudo somente por a
= b, pois o resultado logico e o mesmo.
Otimizacao de Fluxo de Controle
Os algoritmos de geracao de codigo intermedi ario freq uentemente produzem: (1) desvios
para desvios, (2) desvios para desvios condicionais ou (3) desvios condicionais para desvios.
Uma otimizacao peephole pode remover tais instruc oes redundantes:
Exemplo 1:
67
goto L1 goto L2
. . . . . .
L1: goto L2 L1: goto L2
Neste caso, se nao houverem outras instruc oes que levem a L1, esta instrucao pode
ser removida do codigo.
Exemplo 2:
if a < b goto L1 if a < b goto L2
. . . . . .
L1: goto L2 L1: goto L2
Exemplo 3:
goto L1 if a < b goto L2
. . . goto L3
L1: if a < b goto L2 . . .
L3: . . . L3: . . .
Simplicacao Algebrica
Remoc ao de redundancias que ocorrem em expressoes algebricas, tais como: x=x+0 ou
y=y*1.
7.2 Otimizacao de Blocos Sequenciais atraves de gra-
fos
O uso de grafos acclicos dirigidos (GAD) para se representar uma seq uencia de instruc oes,
permite mais facilmente rearranjar a ordem das instrucoes a m de reduzir o codigo objeto
nal.
Exemplo: (a+b)-(e-(c+d))
68
Codigo Intermediario Codigo Objeto
T1 = a+b MOV a, R0
T2 = c+d ADD b, R0
T3 = e-T2 MOV c, R1
T4 = T1-T3 ADD d, R1
MOV, R0, T1
MOV E, R0
SUB R1, R0
MOV T1, R1
SUB R0, R1
MOV R1, T4
T2 = c+d MOV c, R0
T3 = e-T2 ADD d, R0
T1 = a+b MOV e, R1
T4 = T1-T3 SUB R0, R1
MOV a, R0
ADD b, R0
SUB R1, R0
MOV R0, T4
7.2.1 Algoritmo para Construir o GAD de um bloco
O algoritmo supoe que cada instruc ao (de tres-enderecos) segue um dos seguintes tres
formatos: (1) x = y op z; (2) x = op y; (3) x = y. Instruc oes if-goto sao tratadas como o
caso (1).
Passos:
1. Se o no y ainda nao existe no grafo, crie uma folha para y (e para z se for o caso 1);
2. No caso 1, verique se existe um no op com lhos y e z (nessa ordem). Se sim,
chame-o, tambem de x; senao, crie um no op com nome x e dois arcos dirigidos do
no op para y e z. No caso 2, verique se existe um no op com um unico lho y. Se
nao existir, cria tal no e um arco para y; chame de x o no criado ou encontrado. No
caso 3, chame tambem de x o no y.
Exemplo: y = ((a+b)*(a-b))+((a+b)*(a-c))
T1 = a+b
T2 = a-b
T3 = T1*T2
T4 = a+b
T5 = a-c
T6 = T4*T5
T7 = T3+T6
y = T7
69
+
+
* *
a
-
b c
- T1,T4 T2 T5
T3 T6
T7,y
Figura 7.1: Grafo Acclico Dirigido - GAD
7.2.2 Algoritmo para Ordenacao de um GAD
Cria-se uma lista de ordenac ao dos nos internos do GAD atraves do algoritmo a seguir:
Enquanto existirem nos interiores n~ao listados faca inicio
1. Selecionar um no n n~ao listado do qual todos os pais ja foram listados;
2. Listar n;
Enquanto o filho mais `a esquerda m de n tiver todos os pais listados
e n~ao for uma folha faca inicio
3. Listar m;
4. n := m
fim
fim
O codigo e entao gerado atraves da ordem inversa da obtida pela lista resultante.
Exemplo para o codigo intermediario visto anteriormente: y (ou T7), T3, T6, T1 (ou
T4), T5, T2.
70
Captulo 8
Geracao de Codigo Objeto

E a fase nal de um modelo de compilador. Recebe como entrada a representac ao inter-


mediaria do programa-fonte e produz como sada um programa-alvo equivalente.
Por ser impraticavel a criac ao de um gerador de codigo otimo, contenta-se com a
criac ao (atraves de heursticas) de bons geradores de codigo. A maioria dos problemas
de gerac ao de codigo envolve aspectos como gerencia de memoria, selec ao de instrucoes,
alocacao de registradores e ordem de avaliacao.
As principais caractersticas de um bom gerador de codigo: deve ser correto (essencial),
usar de forma eciente os recursos da maquina e o proprio gerador deve ser implementado
de forma eciente.
Uma entrada usual para um gerador de codigo e o codigo intermediario juntamente
com as informac oes armazenadas na tabela de smbolos. Ja a sada pode ser uma lingua-
gem absoluta de maquina (carrega em uma posicao xa de memoria antes da execucao),
linguagem relocavel (cria modulos que podem ou nao, serem executados em conjunto,
sendo para tal necessario uma etapa de linkedic ao dos modulos) ou linguagem de monta-
gem (gera instruc oes simbolicas que sao traduzidas atraves de um montador). A terceira
opc ao sera a escolhida para a implementac ao do trabalho pratico #4.
Selecao de Instruc oes
Se nao nos importarmos com a eciencia do codigo-objeto gerado, a selec ao de instrucoes e
um processo direto. Para cada tipo de instrucao intermediaria (codigo de tres-enderecos)
gerada, projeta-se um esqueleto de codigo nal equivalente. Exemplo: x = y + z.
MOV y, R0 (carregar y no registrador R0)
ADD z,R0 (adicionar z a R0)
MOV R0, x (armazenar R0 em x)
Infelizmente, o codigo nal gerado por esta alternativa freq uentemente e extenso e
ineciente. Exemplo:
a = b+c MOV b, R0
d = a+e ADD c, R0
MOV R0, a
MOV a, R0
ADD e, R0
MOV R0, d
71
Operacao com Registradores
O uso de registradores no processo de execuc ao de instruc oes e interessante pois:
Operac ao com registrador e mais rapida
Conjunto de registradores e pequeno
Utilizac ao eciente = otimizac ao
Desvantagem: a ordem das instrucoes e muito importante no aspecto eciencia.
8.1 Maquina Objeto
Para se criar um gerador de codigo para uma determinada maquina objeto, primeiramente
e necessario conhecer seu conjunto de instruc oes.
Por motivos didaticos optou-se por uma maquina hipotetica (MAQHIPO), que tem
as seguintes caractersticas:


E baseada em uma pilha;
Trabalha com os mesmos tipos de dados das fases anteriores;
Sua memoria e dividida em duas partes:

Area de Codigo contem uma lista (CODIGO) das instruc oes geradas pelo com-
pilador (codigo de tres-enderecos);

Area de Dados composta por uma pilha (DADOS) que conter a os registradores
manipulados pelas instruc oes da maquina (so existe em tempo de execuc ao de
um programa) e uma lista (MEMO) que armazena as variaveis e constantes
manipuladas pelo programa. Para efeito de simplicac ao, todas as variaveis
terao tamanho 1;
Possui um registrador especial (PROXINST) para a proxima instrucao (na area de
codigo) a ser executada, outro (TOPODADOS) que indica o topo da pilha de dados
e TOPOMEMO a quantidade de memoria alocada;
O funcionamento da MAQHIPO e bastante simples:
1. Carrega-se o programa-objeto (gerado pelo compilador) na area de codigo.
2. Todas as instrucoes (indicadas pelo ponteiro PROXINST) sao executadas seq uenci-
almente ate a instruc ao de parada ou ate que ocorra algum erro de execuc ao;
3. A execucao de cada instrucao incrementa o valor de PROXINST (exceto para ins-
truc oes de desvio);
O conjunto de instrucoes validas para a MAQHIPO e:
Inicializacao e Finalizacao
72
INIP inicializa a execucao do programa {TopoMemo = TopoDesvio = 0; TopoDados =
1; }
FIMP encerra a execuc ao do programa {}
Alocacao de Memoria
ALME m t Aloca m posicoes de memoria, todas do tipo t
{for(i = TopoMemo; i < TopoMemo +m; i + +)Memo[i].tipo = t;
TopoMemo+ = m; }
DEAL m Desloca m posicoes de memoria
{TopoMemo = m; }
Comandos de E/S
ENTR Entrada de dados {gets(Dados[+ +TopoDados]); }
IMPR Impressao de valores {printf(%s

, Dados[TopoDados ]); }
Comandos para Expressoes
CRCT k t Carrega uma constante do tipo t. {Dados[+ +TopoDados] = (k, t); }
CRVL n t Transporta o conte udo do endereco de memoria n para a pilha de dados.
{Dados[+ +TopoDados] = Memo[n]; }
SOMA substitui os dois elementos mais ao topo da pilha por sua soma.
{Dados[TopoDados 1]+ = Dados[TopoDados ]; }
SUBT substitui os dois elementos mais ao topo da pilha por sua diferenca.
{Dados[TopoDados 1] = Dados[TopoDados ]; }
MULT substitui os dois elementos mais ao topo da pilha por seu produto.
{Dados[TopoDados 1] = Dados[TopoDados ]; }
DIVI substitui os dois elementos mais ao topo da pilha por seu quociente.
{Dados[TopoDados 1]/ = Dados[TopoDados ]; }
POTE substitui os dois elementos mais ao topo da pilha pela sua potencia.
{Dados[TopoDados 1] = pow(Dados[TopoDados 1], Dados[TopoDados ]); }
INVE inverte o sinal do elemento no topo da pilha.
{Dados[TopoDados] = 1; }
CONJ substitui os dois elementos mais ao topo da pilha por sua conjuncao (&&).
{Dados[TopoDados 1] = Dados[TopoDados 1] && Dados[TopoDados];
TopoDados ; }
DISJ substitui os dois elementos mais ao topo da pilha por sua disjuncao (||).
{Dados[TopoDados 1] = Dados[TopoDados 1] + Dados[TopoDados] == 1;
TopoDados ; }
73
DISX substitui os dois elementos mais ao topo da pilha por sua disjunc ao exclusiva (& |).
{Dados[TopoDados 1] = Dados[TopoDados 1] & | Dados[TopoDados];
TopoDados ; }
NEGA inverte o valor logico do elemento no topo da pilha .
{Dados[TopoDados] =!Dados[TopoDados]; }
CPME substitui os dois elementos mais ao topo da pilha pela comparac ao de menor.
{Dados[TopoDados 1] = Dados[TopoDados 1] < Dados[TopoDados];
TopoDados ; }
CMAI substitui os dois elementos mais ao topo da pilha pela comparac ao de maior.
{Dados[TopoDados 1] = Dados[TopoDados 1] > Dados[TopoDados];
TopoDados ; }
CPIG substitui os dois elementos mais ao topo da pilha pela comparacao de igualdade.
{Dados[TopoDados 1] = Dados[TopoDados 1] == Dados[TopoDados];
TopoDados ; }
CDIF substitui os dois elementos mais ao topo da pilha pela comparac ao de desigualdade.
{Dados[TopoDados 1] = Dados[TopoDados 1] ! = Dados[TopoDados];
TopoDados ; }
CPMI substitui os dois elementos mais ao topo da pilha pela comparacao de menor ou
igual.
{Dados[TopoDados 1] = Dados[TopoDados 1] <= Dados[TopoDados];
TopoDados ; }
CPMA substitui os dois elementos mais ao topo da pilha pela comparac ao de maior ou
igual.
{Dados[TopoDados 1] = Dados[TopoDados 1] >= Dados[TopoDados];
TopoDados ; }
74
Comando de Atribuicao
ARMZ n Transporta o conte udo do topo da pilha para o endereco de memoria n.
{Memo[n] = Dados[TopoDados ]; }
Comandos Condicionais e Iterativos
DSVF p Desvio se condicional falso para a instruc ao p.
{ProxInst = Dados[TopoDados]?ProxInst + 1 : p; }
DSVI p Desvio incondicional para a instruc ao p. {ProxInst = p; }
EXEC n Executa a chamada a uma sub-rotina com inicio na instrucao n e empilha o
endereco de retorno
{Desvios[+ +TopoDesvio] = ProxInst + 1; ProxInst = n; }
RETR Retorna a execucao para a proxima instruc ao apos a chamada `a sub-rotina
{ProxInst = Desvios[TopoDesvio ]; }
Exemplo de Geracao de Codigo Objeto na Linguagem Hipo:
Programa Fonte Programa Objeto
Var: inteiro F, N; 01 INIP
02 ALME 1 i
03 ALME 1 i
Inicio
Leia(N); 04 ENTR
05 ARMZ 1
F=1; 06 CRCT 1 i
07 ARMZ 0
Enquanto N >= 1 faca Inicio 08 CRVL 1 i
09 CRCT 1 i
10 CPMA
11 DSVF 21
F = N; 12 CRVL 0 i
13 CRVL 1 i
14 MULT
15 ARMZ 0
N ; 16 CRVL 1 i
17 CRCT 1 i
18 SUBT
19 ARMZ 1
Fim 20 DSVI 8
Escreva(F); 21 CRVL 0 i
22 IMPR
Fim 23 FIMP
75
8.1.1 Regras para Geracao de Codigo Objeto
Programa AreaDecl AreaSubRot Principal
{ Geracod(INIP);
Gerar codigo para AreaDecl
Quad = ProxQ; Geracod(DSVI);
Gerar codigo para AreaSubRot
Backpatching(Quad, ProxQ);
Gerar codigo para Principal
if(TS.Qtde 0) Geracod(DEAL TS.Qtde); Geracod(FIMP);}
AreaDecl AreaDeclVar AreaDecl
{ Gerar codigo para AreaDeclVar
Gerar codigo para AreaDecl }
AreaDecl AreaDeclConst AreaDecl
{ Gerar codigo para AreaDeclConst
Gerar codigo para AreaDecl }
AreaDecl {}
AreaDeclVar prVar DoisPt DeclVars
{ Gerar codigo para DeclVars }
DeclVars Tipo ListaID PtVirg DeclVars
{ ContIds=0;
Gerar codigo para ListaID
Gerar codigo para DeclVars }
DeclVars Tipo ListaID PtVirg DeclVars
{ ContIds=0;
Gerar codigo para ListaID
Gerar codigo para DeclVars }
DeclVars {}
Tipo prInt {}
Tipo prFloat {}
Tipo prChar {}
Tipo prString {}
Tipo prBool {}
76
ListaID Identicador ListaID
{ if(Acao == DeclV ar)ContIds + +;
else{Geracod(ENTREntrada.Tipo); Geracod(ARMZ Entrada.Endereco Entrada.Tipo); }
Gerar codigo para ListaID }
ListaID Virg Identicador ListaID
{ if(Acao == DeclV ar)ContIds + +;
else{Geracod(ENTREntrada.Tipo); Geracod(ARMZ Entrada.Endereco Entrada.Tipo); }
Gerar codigo para ListaID }
ListaID
{ if(Acao == DeclV ar)Geracod(ALME ContIds); }
AreaDeclConst prConst DoisPt ListaConst
{ Gerar codigo para ListaConst }
ListaConst Tipo ListaIDConst PtVirg ListaConst
{ Gerar codigo para ListaIDConst
Gerar codigo para ListaConst }
ListaConst Tipo ListaIDConst PtVirg ListaConst
{ Gerar codigo para ListaIDConst
Gerar codigo para ListaConst }
ListaConst {}
ListaIDConst Identicador Atrib Valor ListaIDConst
{ Geracod(ALME 1 Identicador.tipo);
Gerar codigo para Valor
Geracod(ARMZ Identicador.Endereco); Gerar codigo para ListaIDConst }
ListaIDConst Virg Identicador Atrib Valor ListaIDConst
{ Geracod(ALME 1 Identicador.tipo);
Gerar codigo para Valor
Geracod(ARMZ Identicador.Endereco); Gerar codigo para ListaIDConst }
ListaIDConst {}
Valor OpAritSubt Numeros
{ Gerar codigo para Numeros
Geracod(INVE); }
Valor Numeros
{ Gerar codigo para Numeros }
77
Valor ConstCaracter
{ Geracod(CRCT ConstCaracter.lexema c); }
Valor ConstString
{ Geracod(CRCT ConstString.lexema s); }
Valor prTrue
{ Geracod(CRCT true b); }
Valor prFalse
{ Geracod(CRCT False b); }
Numeros NumeroInteiro
{ Geracod(CRCT NumeroInteiro.lexema i); }
Numeros NumeroReal
{ Geracod(CRCT NumeroReal.lexema f); }
AreaSubRot AreaProc AreaSubRot
{ Gerar codigo para AreaProc
Gerar codigo para AreaSubRot }
AreaSubRot AreaFunc AreaSubRot
{ Gerar codigo para AreaFunc
Gerar codigo para AreaSubRot }
AreaSubRot { }
AreaProc prProc IdentSR AbrePar ListaParam FechaPar
AreaDecl BlocoCom
{ Gerar codigo para ListaParam
Gerar codigo para AreaDecl
Gerar codigo para BlocoCom
if(TS.qtde 0) Geracod(DEAL TS.qtde);
Geracod(RETR); }
ListaParam Tipo Identicador ListaParam
{ Geracod(ARMZ Identicador.endereco);
Gerar codigo para ListaParam }
ListaParam { }
ListaParam Virg Tipo Identicador ListaParam
{ Geracod(ARMZ Identicador.endereco);
Gerar codigo para ListaParam }
78
ListaParam { }
AreaFunc prFunc Tipo IdentSR AbrePar ListaParam FechaPar
AreaDecl BlocoCom
{ Gerar codigo para ListaParam
Gerar codigo para AreaDecl
Gerar codigo para BlocoCom
if(TS.qtde 0) Geracod(DEAL TS.qtde);
Geracod(RETR); }
Principal prMain Abrepar FechPar BlocoCom
{ Gerar codigo para BlocoCom }
BlocoCom AbreChaves ListaCom FechaChaves
{ Gerar codigo para ListaCom }
ListaCom Comando ListaCom
{ Gerar codigo para Comando
Gerar codigo para ListaCom }
ListaCom {}
Comando Atrib PtVirg
{ Gerar codigo para Atrib }
Comando RepetPre
{ Gerar codigo para RepetPre }
Comando RepetPos PtVirg
{ Gerar codigo para RepetPos }
Comando RepetCont
{ Gerar codigo para RepetCont }
Comando Entrada PtVirg
{ Gerar codigo para Entrada }
Comando Saida PtVirg
{ Gerar codigo para Saida }
Comando Condic
{ Gerar codigo para Condic }
Comando BlocoCom
{ Gerar codigo para BlocoCom }
79
Comando Retorno PtVirg
{ Gerar codigo para Retorno }
Comando SubRot PtVirg
{ Gerar codigo para SubRot }
Atrib Identicador Atrib
{ Gerar codigo para Atrib; Geracod(ARMZ Identicador.Endereco) }
Atrib SimbAtrib Expr
{ Gerar codigo para Expr }
Atrib SimbAtribSoma Expr
{ Geracod(CRVL Entrada.Endereco Entrada.tipo)
Gerar codigo para Expr
Geracod(SOMA) }
Atrib SimbAtribSubt Expr
{ Geracod(CRVL Entrada.Endereco Entrada.tipo)
Gerar codigo para Expr
Geracod(SUBT) }
Atrib SimbAtribMult Expr
{ Geracod(CRVL Entrada.Endereco Entrada.tipo)
Gerar codigo para Expr
Geracod(MULT) }
Atrib SimbAtribDivi Expr
{ Geracod(CRVL Entrada.Endereco Entrada.tipo)
Gerar codigo para Expr
Geracod(DIVI) }
Atrib SimbIncr
{ Geracod(CRVL Entrada.Endereco Entrada.tipo)
Geracod(CRCT 1 i)
Geracod(SOMA) }
Atrib SimbDecr
{ Geracod(CRVL Entrada.Endereco Entrada.tipo)
Geracod(CRCT 1 i)
Geracod(SUBT) }
Condic prIf AbrePar Expr FechPar Comando Condic
{ Gerar codigo para Expr; Quad1 = Proxq
Geracod(DSVF); Gerar codigo para Comando
Gerar codigo para Condic }
80
Condic prElse Comando
{ Quad2 = ProxQ; Geracod(DSVI)
Backpatching(Quad1, ProxQ); Gerar codigo para Comando
Backpathing(Quad2, ProxQ); }
Condic
{ Backpatching(Quad1, ProxQ) }
RepetPos prDo BlocoCom prWhile AbrePar Expr FechaPar
{ Quad1 = ProxQ; Gerar codigo para BlocoCom
Gerar codigo para Expr; Geracod(DSVF ProxQ+2); Geracod(DSVI Quad1) }
RepetPre prWhile AbrePar ExprFechaPar Comando
{ Quad1 = ProxQ; Gerar codigo para Expr
Quad2 = ProxQ; Geracod(DSVF); Gerar codigo para Comando
Geracod(DSVI Quad1); Backpatching(Quad2, ProxQ) }
RepetCont prFor AbrePar Atrib PtVirg Expr PtVirg Atrib FechaPar
Comando
{ Gerar codigo para Atrib; Quad1 = ProxQ;
Gerar codigo para Expr; Quad2 = ProxQ
Geracod(DSVF); Buer = Gerar codigo para Atrib
Gerar codigo para Comando
Descarrega o buer temporario; Geracod(DSVI Quad1)
Backpatching(Quad2, ProxQ) }
Entrada prScanf AbrePar ListaID FechaPar
{ Gerar codigo para ListaID }
Saida prPrint Abrepar ListaExpr FechaPar
{ Gerar codigo para ListaExpr }
Saida prPrintl Abrepar ListaExpr FechaPar
{ Gerar codigo para ListaExpr }
ListaExpr Expr ListaExpr
{ Gerar codigo para Expr; Gerar codigo para ListaExpr }
ListaExpr VirgExpr ListaExpr
{ Gerar codigo para Expr; Gerar codigo para ListaExpr }
ListaExpr {}
Retorno prReturn Expr
{ Gerar codigo para Expr }
81
SubRot IdentSR AbrePar ListaArg FechaPar
{ Gerar codigo para ListaArg; Geracod(EXEC IdentSR.Endereco) }
ListaArg ListaExpr
{ Gerar codigo para ListaExpr }
ListaArg {}
Expr TermoLog Expr Ternario
{ Gerar codigo para TermoLog; Gerar codigo para Expr
Gerar codigo para Ternario }
Ternario Interrog Expr
1
DoisPt Expr
2
{ Quad1 = ProxQ; Geracod(DSVF); Gerar codigo para Expr
1
Quad2 = ProxQ; Geracod(DSVI); Backpatching(Quad1, ProxQ)
Gerar codigo para Expr
2
; Backpatching(Quad2, ProxQ) }
Ternario {}
Expr OpLogAnd TermoLog Expr
{ Gerar codigo para TermoLog; Geracod(CONJ)
Gerar codigo para Expr }
Expr OpLogOr TermoLog Expr
{ Gerar codigo para TermoLog; Geracod(DISJ)
Gerar codigo para Expr }
Expr OpLogXor TermoLog Expr
{ Gerar codigo para TermoLog; Geracod(DISX)
Gerar codigo para Expr }
Expr {}
TermoLog FatorLog TermoLog
{ Gerar codigo para FatorLog; Gerar codigo para TermoLog; }
TermoLog OpRelacMaior FatorLog
{ Gerar codigo para FatorLog; Geracod(CMAI); }
TermoLog OpRelacMenor FatorLog
{ Gerar codigo para FatorLog; Geracod(CPME); }
TermoLog OpRelacMenorIgual FatorLog
{ Gerar codigo para FatorLog; Geracod(CPMI); }
82
TermoLog OpRelacMaiorIgual FatorLog
{ Gerar codigo para FatorLog; Geracod(CPMA); }
TermoLog OpRelacIgual FatorLog
{ Gerar codigo para FatorLog; Geracod(CPIG); }
TermoLog OpRelacDifer FatorLog
{ Gerar codigo para FatorLog; Geracod(CDIF); }
TermoLog {}
FatorLog ExprAr
{ Gerar codigo para ExprAr; }
FatorLog OpLogNeg Expr
{ Gerar codigo para Expr; Geracod(NEGA); }
FatorLog prTrue
{ Geracod(CRCT true l); }
FatorLog prFalse
{ Geracod(CRCT false l); }
ExprAr TermoAr ExprAr
{ Gerar codigo para TermoAr; Gerar codigo para ExprAr; }
ExprAr OpAdic TermoAr ExprAr
{ Gerar codigo para TermoAr; Geracod(SOMA);
Gerar codigo para ExprAr; }
ExprAr OpSubt TermoAr ExprAr
{ Gerar codigo para TermoAr; Geracod(SUBT);
Gerar codigo para ExprAr; }
ExprAr {}
TermoAr FatorAr TermoAr
{ Gerar codigo para FatorAr; Gerar codigo para TermoAr; }
TermoAr OpMult FatorAr TermoAr
{ Gerar codigo para FatorAr; Geracod(MULT);
Gerar codigo para TermoAr; }
TermoAr OpDivi FatorAr TermoAr
{ Gerar codigo para FatorAr; Geracod(DIVI);
Gerar codigo para TermoAr; }
83
TermoAr {}
FatorAr ElementoAr FatorAr
{ Gerar codigo para ElementoAr; Gerar codigo para FatorAr; }
FatorAr OpPote ElementoAr FatorAr
{ Gerar codigo para ElementoAr; Geracod(POTE);
Gerar codigo para FatorAr; }
FatorAr {}
ElementoAr AbrePar Expr FechaPar
{ Gerar codigo para Expr; }
ElementoAr OpSubt ExprAr
{ Gerar codigo para ExprAr; Geracod(INVE); }
ElementoAr Identicador
{ Geracod(CRVL identicador.Endereco); }
ElementoAr Numeros
{ Gerar codigo para Numeros }
ElementoAr SubRot
{ Gerar codigo para SubRot }
ElementoAr ConstCaracter
{ Geracod(CRCT ConstCaracter.lexema c); }
ElementoAr ConstString
{ Geracod(CRCT ConstString.lexema s); }
8.1.2 Trabalho Pratico #4
Implementar um modulo analisador semantico para um prototipo de compilador para a
linguagem PASCAL
jr
(simplicada) vista em aula.
Caractersticas:
Do modulo gerador de codigo:
Cada chamada a elementos nao-terminais processa esquemas de traduc ao de codigo
necessarios para cada producao da gramatica.
Utiliza a arvore decorada criada no modulo semantico.
Utiliza a tabela de smbolos (altera e consulta dados) construda na fase anterior.
84
Do programa a ser criado:
Abre um arquivo fonte para analise.
Executa todas as fases de analise e, caso nenhum erro seja encontrado, armazena a
sequencia de instruc oes em linguagem HIPO na lista CODE da MaqHipo.
Fecha o arquivo fonte ao nal da compilacao.
Para o processo de compilac ao caso um erro seja encontrado.
Exibe erros de compilac ao (se ocorrerem) ou mensagem de sucesso.
Inicia o processo de execucao da maquina objeto, segundo as regras denidas para
cada instruc ao.
Para o processo de execucao ao atingir a instruc ao FIMP (neste caso informa m de
execuc ao) ou algum erro de execuc ao seja detectado (neste caso informa mensagem
de erro).
Criterios de Avaliacao:
Implementa cao usando linguagem C ou C++.
Entrega de fontes e executavel (em um disquete identicado ou e-mail).
Grupo de 02 alunos (maximo).
Valor do trabalho: 10.0 (25% da nota pratica).
Data de Entrega: 30/06/2005.
Punic oes:
de 20% do valor do trabalho por dia de atraso.
de 1.75 por erro lexico nao analisado corretamente.
de 1.5 por erro sint atico nao analisado corretamente.
de 1.25 por erro semantico nao analisado corretamente.
de 1.0 por erro semantico nao analisado corretamente.
de 0.5 do valor do trabalho para a entrega nao conforme dos arquivos pedidos.
de 50% do valor do trabalho para o caso de nao executar ou travar (apos teste
em 2 computadores, sendo um o do professor).
de 100% do valor do trabalho para o caso de copias (mesmo de trabalhos de
semestres anteriores).
85

You might also like