Vous êtes sur la page 1sur 89

Notas de Aula de Compiladores

Luiz Eduardo da Silva


25 de setembro de 2014

Sum
ario
1 Introduc
ao
1.1 Aspectos basicos da compilacao
1.2 Analise Lexica . . . . . . . . . .
1.3 Tabela de Smbolos . . . . . . .
1.4 Analise Sintatica . . . . . . . .
1.5 Analise Semantica . . . . . . . .
1.6 Tratamento de erros . . . . . .
1.7 Geracao de codigo intermediario
1.8 Otimizacao geral . . . . . . . .
1.9 Otimizacao local . . . . . . . .
1.10 Geracao de codigo objeto . . . .

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

3
3
5
6
7
7
8
8
8
9
9

2 An
alise L
exica
2.1 Revisao de Alfabeto, Gramatica e Linguagem
2.1.1 Alfabeto (ou vocabulario) . . . . . . .
2.1.2 Linguagens . . . . . . . . . . . . . . .
2.1.3 Gramatica . . . . . . . . . . . . . . . .
2.1.4 Gramatica Regular . . . . . . . . . . .
2.1.5 Gramatica Livre de Contexto . . . . .
2.1.6 Derivacao . . . . . . . . . . . . . . . .

2.1.7 Arvores
de Derivacao . . . . . . . . . .
2.1.8 Gramatica Ambgua . . . . . . . . . .
2.1.9 Exerccios . . . . . . . . . . . . . . . .
2.2 Lex/Flex - Geradores e Analisadores Lexicos .
2.2.1 Metacaracteres Lex . . . . . . . . . . .
2.2.2 Alguns Exemplos de Lex . . . . . . . .
2.3 Analisador Lexico para Linguagem Simples . .

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

10
10
10
11
11
11
11
12
12
12
15
15
16
19
20

.
.
.
.
.
.
.
.

27
27
28
28
29
32
38
41
48

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

3 An
alise Sint
atica
3.1 Analise LL . . . . . . . . . . . . . . . . . . . . . . . .
3.1.1 Funcao F IRST . . . . . . . . . . . . . . . . .
3.1.2 Funcao F OLLOW . . . . . . . . . . . . . . .
3.2 Analise LR . . . . . . . . . . . . . . . . . . . . . . .
3.2.1 Implementacao do Algoritmo LR . . . . . . .
3.2.2 Construcao da Tabela de Analise Sintatica LR
3.3 Yacc/Bison - Geradores e Analisadores Sintaticos . .
3.4 Analisador Sintatico para a Linguagem Simples . . .

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

2
4 MVS - M
aquina Virtual Simples
53
4.1 Caractersticas gerais da MVS . . . . . . . . . . . . . . . . . . . . . . . . . 53
4.1.1 Descricao das instrucoes MVS . . . . . . . . . . . . . . . . . . . . . 54
5 An
alise Sem
antica e Gerac
ao de C
odigo
5.1 Funcoes Utilitarias . . . . . . . . . . . .
5.2 Modificacao do analisador lexico . . . . .
5.3 Modificacao do analisador sintatico . . .
5.4 Simulador da Maquina MVS . . . . . . .

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

6 Projeto - Rotinas e Passagem de Par


ametro
6.1 Instrucoes MVS para traducao de rotinas . . . . . .
6.2 Modificacao da gramatica para incluir rotinas . . .
6.3 Modificacao da Tabela de Smbolos . . . . . . . . .
6.4 Exemplos de Traducao de Procedimentos e Funcoes
6.4.1 Teste 1 - Simples . . . . . . . . . . . . . . .
6.4.2 Teste 2 - Simples . . . . . . . . . . . . . . .
6.4.3 Teste 3 - Simples . . . . . . . . . . . . . . .
6.4.4 Teste 4 - Simples . . . . . . . . . . . . . . .
6.4.5 Teste 5 - Simples . . . . . . . . . . . . . . .
6.4.6 Teste 6 - Simples . . . . . . . . . . . . . . .
6.4.7 Teste 7 - Simples . . . . . . . . . . . . . . .
6.4.8 Teste 8 - Simples . . . . . . . . . . . . . . .
6.4.9 Teste 9 - Simples . . . . . . . . . . . . . . .
6.4.10 Teste 10 - Simples . . . . . . . . . . . . . .

.
.
.
.

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

.
.
.
.

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

.
.
.
.

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

.
.
.
.

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

.
.
.
.

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

.
.
.
.

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

.
.
.
.

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

.
.
.
.

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

.
.
.
.

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

.
.
.
.

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

.
.
.
.

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

.
.
.
.

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

.
.
.
.

61
61
63
64
69

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

74
74
74
76
78
78
78
79
80
81
81
83
84
85
87

Captulo 1

Introdu
c
ao
Com os computadores surgiu a necessidade de linguagens de programacao para quebrar
a barreira de comunicacao entre o homem e a maquina. As primeiras linguagens de
programacao foram chamadas linguagens de montagem (assembly languages).
Na decada de 50 surgiram as linguagens de alto nvel FORTRAN e Algol 60. Desde
entao surgiram centenas de linguagens para facilitar a especificacao de tarefas para o
computador.
Com a introducao das linguagens de alto nvel, surgiu a necessidade de programas
tradutores, ou seja, sistemas para converter programas fonte (escritos em linguagem que
pode ser entendida pelo usuario humano) para programa objeto (em linguagem que pode
ser entendida pela maquina.

Figura 1.1: Processo de traducao


Um processo tpico de traducao esta ilustrado na figura 1.1. Vale observar que o
compilador faz uma traducao offline, i. e., o compilador traduz todo o programa e so
depois dessa traducao o programa pode ser executado. O interpretador faz a traducao
online, onde partes do programa sao traduzidas para serem executada imediatamente.

1.1

Aspectos b
asicos da compila
c
ao

Existem tres aspectos fundamentais com relacao a implementacao de linguagens de


programacao:
Aspecto sint
atico identificacao das seq
uencias de caracteres que correspondem
a construcoes permitidas da linguagem.
Aspecto sem
antico o significado de cada construcao valida.
Aspecto pragm
atico corresponde ao problema de integracao do compilador para
um sistema hospedeiro.
Os problemas sintaticos estao formalizados e praticamente resolvidos. Os problemas
semanticos nao estao formalizados mas dependendo da linguagem nao sao difceis de
resolver. O aspecto pragmatico e o que apresenta mais variabilidade nos diversos sistemas
de computacao. Ha grande diferenca nas arquiteturas basicas.
Por nao poder tratar com generalidade os problemas de compilacao, usaremos um
subconjunto da linguagem pascal para centralizar nossa discussao.
3


CAPITULO 1. INTRODUC
AO

A compilacao pode ser dividida nas seguintes fases:


Fase An
alise L
exica: Transforma seq
uencia de caracteres do programa em codigos
internos (tokens)
Fase An
alise Sint
atica: Verifica se uma frase no programa fonte e uma construcao
permitida da linguagem.
Fase An
alise Sem
antica: Extrai da estrutura sintatica informacoes que serao
necessarias na fase de sntese.
Otimizac
ao Global: Introduz melhorias que independem da linguagem de maquina.
Otimizac
ao Local: Introduz melhorias no programa objeto, aproveitando o repertorio de instrucoes de um dado computador.

Figura 1.2: As fases da compilacao


O funcionamento basico do Compilador, com suas diversas fases de compilacao, esta
ilustrado na Figura 1.2.
Durante a analise do programa sao encontrados erros (lexicos, sintaticos, semanticos),
que devem ser tratados pelo compilador. As varias fases de compilacao podem ser executadas em sequencia (compilacao em varios passos) ou ter a sua execucao combinada


CAPITULO 1. INTRODUC
AO

(compilacao num u
nico passo). Na compilacao em varios passos a execucao de uma fase
termina antes da execucao das fases seguintes. Numa compilacao em um passo, o programa objeto e gerado a` medida que o programa fonte e processado.
Para compilacao numa u
nica passada pode-se utilizar o esquema de traducao dirigido
por sintaxe. Nesse modelo, o codigo principal do compilador esta no analisador sintatico.
No meio das regras de producao da gramatica do analisador sintatico sao includos comandos (acoes semanticas) que sao executados concomitantes com as verificacoes sintaticas.
Essas acoes servem tanto para as verificacoes semanticas, como para geracao do codigo
objeto correspondente as estruturas sintaticas compiladas.
No projeto do compilador proposto nesse curso usaremos esta u
ltima alternativa de
compilacao com auxlio de algumas ferramentas (flex e bison) para automatizar a construcao dos analisadores lexico e sintatico.
Para a construcao do analisador lexico usaremos a ferramenta flex, que transforma
os padroes lexicos especificados usando expressoes regulares, no codigo fonte de uma
automato finito que reconhece esses padroes.
Para construcao do analisador sintatico usaremos a ferramenta bison, que transforma
o arquivo fonte com a gramatica livre de contexto da linguagem, no automato de pilha
que reconhece essa linguagem.

1.2

An
alise L
exica

A analise lexica e executada pelo Analisador Lexico ou scanner, e tem como objetivo
principal identificar e classificar, dentro do arquivo fonte, os smbolos pertencentes a
linguagem. Suas funcoes sao:
1. Fazer uma varredura no texto em todas as linhas do texto, de cima para baixo e da
esquerda para direita.
2. Agrupar os caracteres consecutivos que compoe o mesmo smbolo lexico e que tem
uma significado u
nico no programa, como as palavras reservadas, constantes, identificadores, smbolos especiais, operadores.
3. Atribuir um codigo numerico token para os smbolos lexicos encontrados. A codificacao numerica simplifica a comparacao dos smbolos nas outras fases da compilacao.
4. Excluir os espacos em branco e os comentarios do programa fonte.
5. Detectar erros lexicos, i. e., smbolos que nao fazem parte do vocabulario da linguagem:
caracteres invalidos: ex: a := 2#3
tamanhos dos identificadores, literais e constantes (overflow)
Exemplo: Para o Codigo 1.1 o resultado obtido pelo analisador lexico e apresentado
na Tabela 1.1.
Codigo Fonte 1.1: Programa Exemplo em Pascal
1
2

program exemplo ;
var
A , B : byte ;


CAPITULO 1. INTRODUC
AO

Item Token
Descric
ao
1
program
palavra reservada
2
exemplo
identificador
3
;
smbolo ponto e vrgula
4
var
palavra reservada
5
A
identificador
6
,
smbolo vrgula
7
B
identificador
8
:
smbolo dois pontos
9
byte
identificador
10
;
smbolo ponto e vrgula
11
begin
palavra reservada
12
A
identificador
13
:=
smbolo atribuicao
14
B
identificador
15
+
smbolo mais
16
0.5
n
umero
17
;
smbolo ponto e vrgula
18
end
palavra reservada
19
.
smbolo ponto final
Tabela 1.1: Resultado da analise lexica do Codigo 1.1
Nome Tipo
A
int
B
int

Endereco
0
1

Tabela 1.2: Exemplo de tabela de smbolos


3
4
5

begin
A := B + 0 . 5 ;
end .

Para o exemplo anterior, temos os tokens identificados por uma analisador lexico,
conforme a Tabela 1.1. Observe que um smbolo lexico pode ser simples como uma
vrgula (,) ou composto como uma palavra (program) ou uma sequencia de smbolos (:=).

1.3

Tabela de Smbolos

A tabela de smbolos e uma estrutura de dados fundamental para a eficiencia do


compilador. Na tabela de smbolos ficam armazenados as informacoes relacionadas aos
identificadores (nomes das entidades do programa), como variaveis, rotinas, constantes,
tipos. Durante todas as fases da compilacao a tabela de smbolos e atualizada e consultada.
O acesso dos smbolos do compilador deve ser o mais eficiente possvel para garantir a
eficiencia do compilador. Uma estrutura comumente usada para manutencao da tabela
de smbolos e a Tabela Hash.
A Tabela 1.2 e um exemplo de uma tabela de smbolos simples, com as informacoes
relacionadas as variaveis de um programa, por exemplo.


CAPITULO 1. INTRODUC
AO

Figura 1.3: Exemplo de arvore sintatica

1.4

An
alise Sint
atica

A analise sintatica e executada pelo parser e sua funcao principal e agrupar os tokens, retornados do analisar lexico, em estruturas sintaticas (comando, bloco, expressao,
identicador, n
umero, etc). Uma estrutura que pode ser empregada e a arvore sintatica.
A arvore representa a aplicacao das regras sintaticas da linguagem e definem, de certa
forma, um significado para a estrutura do programa compilado. O programa esta sintaticamente correto se for possvel construir uma u
nica arvore sintatica, no qual a raiz e o
smbolo inicial da gramatica da linguagem (smbolo de partida) e as folhas sao os tokens
retornados do analisado lexico.
A Figura 1.3 representa a arvore sintatica para a estrutura de repeticao do Codigo 1.2.
Codigo Fonte 1.2: Repeticao
1
2

while i < 100 do


i := j + i ;

1.5

An
alise Sem
antica

O analise semantica e a fase da compilacao em que e extrado o significado das es a partir dessa significacao e que e possvel a traducao (geracao) e
truturas sintaticas. E
otimizacao de codigo. Na analise semantica sao verificados tambem aspectos semanticos
do codigo com:


CAPITULO 1. INTRODUC
AO

1. Compatibilidade de tipos. Por exemplo, para algumas linguagens, o tipo da expressao no lado direito de uma atribuicao deve ser compatvel com o tipo da variavel
no lado esquerdo da atribuicao.
2. Verificacao do aspecto de visibilidade (escopo) de uma variavel. Por uma questao
logica, nao e permitido duas variaveis com o mesmo nome, no mesmo escopo do
codigo.
3. Compatibilidades entre declaracoes e uso de entidades. Por exemplo, nao faz sentido,
declarar um vetor e tentar usar como se fosse um registro.
4. Referencias nao resolvidas. Todo nome de entidade deve ter uma correspondencia
no codigo. Por exemplo, o nome de um rotulo de desvio deve marcar alguma posicao
no codigo.

1.6

Tratamento de erros

Identificado um erro em qualquer fase da compilacao, o modulo de tratamento de erro


do compilador e invocado. O tratador de erro deve diagnosticar o erro e emitir uma
mensagem o coerente possvel para explicar a situacao de erro. A partir dessa mensagem
duas estrategias podem ser adotadas:
a estrategia mais simples de implementar.
Panico: abortar a compilacao. E
Recuperacao: tentar recuperar a situacao de erro, permitindo que todo o programa
fonte possa ser analisado, mesmo na ocorrencia do erro.

1.7

Gerac
ao de c
odigo intermedi
ario

Para simplificar o processo de traducao, pode-se empregar uma codificacao intermediaria. Por exemplo, para traducao de expressoes aritmeticas pode-se gerar tuplas.
Exemplo:
Codigo Fonte 1.3: Atribuicao
A :=

(B C) (D + E)

(+ , B , C , T1)
gera-se quadruplas: (- , D , E , T2)
(* , T1 , T2 , A)

1.8

Otimizac
ao geral

A principal funcao da otimizacao do codigo e melhorar o codigo a fim de que ocupe


menos espaco (otimizacao de espaco) ou que execute mais rapido (otimizacao de execucao).
As principais otimizacao realizadas sao:
1. Agrupamento das subexpressoes comuns numa expressao aritmetica. Exemplo, considerando as quadruplas que representam operacoes aritmeticas, o calculo A + B
na expressao C := (A+B) * (A+B), pode ser calculada uma u
nica vez e utilizado
duas vezes na expressao.


CAPITULO 1. INTRODUC
AO

2. Eliminacao de saltos (jumps) desnecessarios no codigo. Na traducao de estruturas


de repeticao e de selecao, acontecem situacoes de jumps encadeados no codigo. Essa
fase pode eliminar esse problema.
3. Realocacao de comandos invariantes dentro de uma repeticao. Exemplo: a atribuicao J := X pode ser colocada fora de uma repeticao sem alterar o programa:
Codigo Fonte 1.4: Atribuicao invariante
1
2
3
4
5

1.9

i := 1 ;
repeat
J := X;
i := i + 1 ;
u n t i l i >= 1 0 0 ;

Otimizac
ao local

Essa otimizacao leva em consideracao o conjunto especfico de instrucoes da maquina


uma fase fortemente dependente da maquina
alvo que pode deixar o codigo mais rapido. E
para qual esta sendo gerado o codigo traduzido.

1.10

Gerac
ao de c
odigo objeto

Nessa fase e gerado o codigo objeto correspondente a cada estrutura sintatica identificada no programa.

Captulo 2

An
alise L
exica
O analisador lexico e a fase do compilador responsavel por fazer a leitura do texto
(programa fonte) caracter por caracter e traduzir os smbolos lexicos em tokens.
Os smbolos lexicos sao as palavras reservadas, os operadores, os identificadores, as
constantes literais, as constantes numericas, os comentarios, os espacos em branco e as tabulacoes. Os comentarios, os espacos em branco e as tabulacoes ajudam na documentacao
e identacao do codigo fonte, mas sao excludos do programa, pelo analisador lexico, para
as outras fases da compilacao.
Os identificadores reconhecidos nessa fase da compilacao devem ser cadastrados e
consultados da tabela de smbolos. Essa verificacao e cadastramento e realizado a partir
do reconhecimento desses smbolos lexicos.
Os tokens do analisador lexico sao utilizados com entrada para a fase da analise
sintatica, quando entao esses tokens sao agrupados em estruturas sintaticas, seguindo
as regras de producao da gramatica da linguagem de programacao.
Para a fase de analise lexica, especificamos os tokens a serem reconhecidos usando uma
gramatica regular. Especificamente para as ferramentas que geram automaticamente os
analisadores lexicos, como a ferramenta flex, os tokens sao definidos atraves de expressoes
regulares. A partir dessas expressoes regulares a ferramenta gera o automato finito para
o seu reconhecimento, na forma de uma programa de reconhecimento.
Um processo similar e empregado para construcao do analisador sintatico, que veremos
no proximo captulo. A sintaxe da linguagem de programacao e especificada, para as
ferramentas que geram automaticamente analisadores sintaticos, atraves de gramaticas
livres de contexto (GLC). O utilitario bison, traduz GLC no automato de pilha que e o
analisador sintatico da linguagem.
Na proxima secao serao revistos alguns conceitos relacionados a gramaticas, linguagens, automatos apresentados na disciplina de Linguagens Formais e Automatos e que
serao utilizados nas fases de analise lexica e sintatica do projeto do compilador.

2.1

Revis
ao de Alfabeto, Gram
atica e Linguagem

Apresentamos nessa secao uma serie de conceitos relacionados a linguagens formais e


automatos e que sao u
teis para o melhor entendimento do projeto do compilador.

2.1.1

Alfabeto (ou vocabul


ario)

O alfabeto e um conjunto finito e nao vazio de smbolos que podem ser simples como
dgitos, letras e caracteres especiais, ou entao compostos, como begin, :=, que serao
tratados, em geral, como smbolos indivisveis (tokens). Seja um alfabeto. Uma cadeia
(ou uma frase) sobre e ma sequencia finita de smbolos de . e o conjunto de todas
as cadeias sobre .

10

CAPITULO 2. ANALISE
LEXICA

2.1.2

11

Linguagens

Uma linguagem sobre um alfabeto e um subconjunto de , formalmente, podemos


escrever L { }. Sao exemplos de linguagem sobre o alfabeto {a, b}, L1 = {
{a, b} : || 2} e L2 = {an bn : n 1}. Considerando todos os smbolos lexicos
(identificadores, palavras reservadas, operadores, etc.) que podem ser combinados das
mais diversas formas, como em: a var b integer : ;, a linguagem padroniza, atraves de
regras de sintaxe, a forma correta como esses smbolos devem ser combinados, como em:
var a, b : integer;.

2.1.3

Gram
atica

A gramatica pode ser definida de maneira formal como uma quadrupla G = (V, , R, P ),
onde V e vocabulario de smbolos nao-terminais de G, tambem chamados de variaveis da
gramatica. e o vocabulario de smbolos terminais de G, disjunto de V . R sao as regras
de producao ou regras de sintaxe. P e um smbolo de V (raiz, smbolo inicial ou smbolo
de partida da gramatica G).

2.1.4

Gram
atica Regular

A gramatica regular e uma gramatica, em que cada regra tem uma das formas: X a
ou X aY ou X , onde X e Y sao smbolos nao-terminais e a e um smbolo terminal.
Gramaticas Regulares, Expressoes Regulares e Automatos finitos sao tres formalismos
alternativos usados para especificar linguagens regulares. Usamos essas especificacoes
para definir os padroes lexicos que sao reconhecidos pelo analisador lexico. Usaremos a
ferramenta flex para traduzir as especificacoes em expressoes regulares, no automato finito
que e o analisador lexico.

2.1.5

Gram
atica Livre de Contexto

A gramatica livre de contexto (GLC) e uma gramatica cujas as regras de producao


sao da forma: X , onde X e qualquer smbolo nao terminal e e uma elemento
de {V } . As GLCs sao usadas para especificar, atraves de definicoes indutivas,
todas as construcoes sintaticas validas para as linguagens de programacao. Usamos GLC
para especificar a sintaxe das linguagens que sao reconhecidas pelo analisador sintatico
de compilador. Exemplo:
G = ({C, E, I, O}, {a, b, +, , (, ), :=, ;}, R, C}
onde:

E
R=
O

I := E|C; C
I|EOE|(E)
+|
a|b

CAPITULO 2. ANALISE
LEXICA

12

Figura 2.1: Arvore


de Derivacao

2.1.6

Deriva
c
ao

A derivacao, representada atraves da relacao significa a aplicacao de uma regra de


producao numa sequencia que contem smbolos nao-terminais a fim de se obter uma
sequencia so de smbolos terminais. Exemplo: Considere a gramatica de expressoes
(para abreviar a notacao da gramatica estamos indicando apenas o conjunto de regras de
producao):
G1 : E a|b|E + E|E E|(E).
A sentenca (a + b) a pode ser obtida por varias derivacoes distintas:
E E E (E) E (E + E) E (a + E) E (a + b) E (a + b) a
E E E E a (E) a (E + E) a (E + b) a (a + b) a

2.1.7

Arvores
de Derivac
ao

Se observarmos o exemplo anterior, verificamos que o que muda numa sequencia de


derivacao para outra e a ordem na qual as producoes sao aplicadas. Num certo sentido
todas as derivacoes sao equivalentes. Um meio usado para representar todas as derivacoes
que indicam a mesma estrutura sao as arvores de derivacao (arvores sintaticas). Na arvore
de derivacao a aplicacao da regra E E1 E2 ...En e representada da seguinte forma, o
smbolo nao terminal E, do lado esquerdo da regra e a raiz da subarvore e os smbolos
E1 , E2 , ..., En , os smbolos nao terminais e/ou terminais do lado direito da regra sao os
filhos desta raiz. Exemplo: Para gramatica G1 e a sequencia (a + b) a, temos a arvore
de derivacao, conforme ilustrado na Figura 2.1.

2.1.8

Gram
atica Ambgua

Consideremos a cadeia a+b*a para gramatica G1 . Existem duas arvores de derivacao


distintas, conforme ilustrado na Figura 2.2.
Uma gramatica G e dita ambgua se a linguagem L(G) contem uma sentenca para
qual existe mais de uma arvore de derivacao, usando a gramatica G. Consideremos agora
a seguinte sentenca a+a+a:
E E+E E+E+E a+E+E a+a+E a+a+a

CAPITULO 2. ANALISE
LEXICA

13

Figura 2.2: Exemplo de ambiguidade

Figura 2.3: Exemplo de ambiguidade


Devido `a maneira como foi definido o conceito de derivacao nao esta claro no passo
E+E+E, qual das duas ocorrencias de E foi substituda. Esta derivacao corresponde a
duas arvores distintas, conforme ilustrado na Figura 2.3.
A causa da ambiguidade esta no fato dela nao indicar as precedencias entre os operadores * e +. Consideremos agora a seguinte gramatica G2 :
E E+T | T
T T F | F
F a | b | (E)
Pode-se demonstrar que a gramatica G1 e a G2 definem a mesma linguagem e que G2
nao e ambgua. Ha varias derivacoes para as sentencas a+b+a e a+a+a:
E E +T T +T F +T a+T a+T F a+F F a+b+F a+b+a
E E +T E +T F E +T a E +F a E +ba F +ba a+ba
Ha porem, uma u
nica arvore de derivacao para cada sentenca, conforme ilustrado na
Figura 2.4.
Deve-se notar que nem sempre e possvel eliminar ambiguidade. Um outro exemplo
famoso de ambiguidade e o chamado else pendente. Consideremos a seguinte gramatica
G3 :
C a | if

b then C

else C

| if

b then

Esta gramatica e ambgua, pois temos duas arvores de derivacao para a sentenca
if b then if b then a else a, conforme ilustrado na Figura 2.5.
Isto se deve ao fato da parte else a poder ser associada tanto com o primeiro como
com o segundo if. Ainda neste caso podemos eliminar a ambiguidade:
C a | if
D a | if

b then D
b then D

else C | if
else D

b then C

Note-se que esta gramatica sempre associa o else com o if mais proximo possvel.

CAPITULO 2. ANALISE
LEXICA

Figura 2.4: Exemplo de arvore nao ambgua

Figura 2.5: Ambiguidade do else pendente

14

CAPITULO 2. ANALISE
LEXICA

2.1.9

15

Exerccios

1. Escreva gramaticas para geras as linguagens:


a) L1 = {am bn |m n 1}
b) L2 = {an b|n 1}
2. Enumere as derivacoes possveis para a cadeia b a + a, usando as gramaticas G1 e
G2 abaixo:
G1 : E a|b|E + E|E E|(E).
G2 : E E + T | T
T T F | F
F a | b | (E)
3. Determine duas sentencas validas para a gramatica: S aS

| bS

| c.

4. Escreva uma gramatica qualquer para os smbolos terminais a, b e c e determine


duas sentencas validas para esta gramatica.

2.2

Lex/Flex - Geradores e Analisadores L


exicos

A primeira fase do compilador deve ler o arquivo fonte e converter sequencia de caracteres em tokens. A construcao dessa rotina nao e tao complicada de se implementar,
no entanto, existem ferramentas que podem ser utilizadas para automatizar essa fase da
traducao. Lex e uma ferramenta usada para geracao de analisadores lexicos. Especifica-se
padroes lexicos para lex usando expressoes regulares. E para cada smbolo encontrado
associa-se uma acao que pode ser, por exemplo, retornar a codificacao numerica (token)
do smbolo encontrado. A seguinte expressao regular pode ser usada para pesquisar por
identificadores (nomes escolhidos pelo programados):
letra(letra|digito)
Onde:
letra representa qualquer letra do alfabeto
digito representa qualquer dgito.
a barra vertical (|), significa alternativa.
o asterisco (), significa repeticao (zero ou mais vezes a expressao precedente).
os smbolos em sequencia representam concatenacao.
Toda expressao regular pode ser expressa como um automato de estados finitos (finite state automaton -FSA). Um automato de estados finitos e composto de estados e
transicoes entre estados. Existe um estado denominado estado inicial e um ou mais estados finais ou estados de aceitacao.

CAPITULO 2. ANALISE
LEXICA

16

Figura 2.6: Automato de Estados Finitos para identificadores


Na Figura 2.6, o estado 0 e o estado inicial e o estado 2 e o estado de aceitacao. Para
cada caracter lido e realizada a transicao de um estado para outro. Se o caracter lido
for uma letra, faz-se a transicao do estado 0 para o estado 1. O automato permanece
no estado 1 enquanto letras e dgitos sao lidos. A partir do estado 1, qualquer caracter
lido diferente de letra ou dgito, determina a transicao para o estado 2, que e o estado da
aceitacao.
Os automatos podem ser codificados como rotinas de um programa de computador.
Por exemplo, a maquina de 3 estados da Figura 2.6 pode ser facilmente programada como:
1

inicio :

goto e s t a d o 0

2
3
4
5

e s t a d o 0 : read c
i f c = l e t r a goto e s t a d o 1
goto e s t a d o 0

6
7
8
9
10

e s t a d o 1 : read
if c
if c
goto

c
= l e t r a goto e s t a d o 1
= d i g i t o goto e s t a d o 1
estado2

11
12

estado2 : accept i d e n t i f i c a d o r

A ferramenta lex funciona basicamente dessa forma, traduzindo as expressoes regulares num codigo em linguagem C que programa um automato de estados finitos para
reconhecimento dos smbolos lexicos. O proximo estado e determinado pela indexacao
numa tabela de estados gerada pelo computador usando o proximo caracter de entrada e
o estado corrente.
Lex tem algumas limitacoes. Por exemplo, lex nao pode ser usado para reconhecer
estruturas aninhadas tal como parenteses. Estruturas aninhadas sao manipuladas com
auxlio de pilhas. Quando encontramos um ( nos empilhamos este caracter. Quando
encontramos um ) nos comparamos como o topo da pilha e desempilhamos um smbolo.
Lex, entretanto so tem estados e transicoes entre estados. Como nao tem pilha, nao e
indicada para analisar estruturas aninhadas. A ferramenta Yacc/Bison uma pilha ao
automato finito e podem, dessa forma, processar as estruturas aninhadas, caractersticas
das linguagens de programacao.

2.2.1

Metacaracteres Lex

Alguns carateres tem um significado especial nas expressoes regulares escritas para
Lex. Os principais sao apresentados na Tabela 2.1.
Alguns exemplos de correspondencias entre expressoes regulares para Lex e os smbolos
que sao reconhecidos estao representados na Tabela 2.2.

CAPITULO 2. ANALISE
LEXICA

Metacaracter
x
.
\n
*
+
?

$
a |b
(ab)+
a+b
[abc]

Correspond
encia
caracter x, exceto nova linha
Qualquer caracter exceto nova linha
Nova linha
Zero ou mais copias da expressao precedente
Uma ou mais copias da expressao precedente
Zero ou uma copia da expressao precedente
Incio da linha
Fim da linha
Alternativa a ou b
Uma ou mais copias de ab (agrupamento)
Literal a+b
Classe de caracteres. Nesse caso, a, b ou c.

Tabela 2.1: Metacaracteres de Lex

Expressao Regular Lex


Smbolos Reconhecidos
abc
abc
abc*
ab, abc, abcc, abccc, ...
abc+
abc, abcc, abccc, ...
a(bc)+
abc, abcbc, abcbcbc, ...
a(bc)?
a, abc
[abc]
a ou b ou c
[a-z]
qualquer letra no intervalo a ate z.
[a\-z]
a ou - ou z
[ab]
qualquer smbolo exceto a ou b.
[ab]
a ou ou b
[a|b]
a ou |ou b
a|b
a ou b
Tabela 2.2: Exemplos de Expressoes Regulares para Lex

17

CAPITULO 2. ANALISE
LEXICA

18

As expressoes regulares em lex sao compostas de metacaracteres (Tabela 2.1). Os


exemplos de casamento de padroes sao mostrados na Tabela 2.2. Com uma classe de
caracteres, os caracteres normais perdem seu significado. Os dois caracteres usados em
classes de caracteres (entre colchetes) sao o hfen (-) e o circunflexo (). Quando
usado entre dois caracteres o hfen significa o intervalo de caracteres. O circunflexo,
quando usado como o primeiro caracter, nega a expressao. Se dois padroes reconhecem o
mesmo string, o casamento mais longo e utilizado. No caso de dois casamentos de padroes
com o mesmo comprimento, entao o primeiro padrao listado e usado.
O arquivo de entrada para Lex tem o seguinte formato:
1
2
3
4
5

. . . definicoes . . .
%%
. . . regras . . .
%%
. . . subrotinas . . .

O arquivo de entrada Lex e dividido em tres secoes, com %% dividindo as secoes.


Vamos ilustrar isto com um exemplo. O primeiro exemplo e o menor arquivo de entrada
Lex possvel:
1

%%

A entrada e copiada para a sada, um caracter por vez. O primeiro %% e obrigatorio,


iniciando a secao de regras. Se nenhuma regra e especificada entao a acao padrao e
reconhecer tudo e copiar para a sada. Os arquivos de entrada e sada padrao sao stdin e
stdout, respectivamente. Aqui o mesmo exemplo, com os valores default explicitamente
codificados:
1

%%

2
3

4
5

\n

/ match e v e r y t h i n g e x c e p t n e w l i n e /
ECHO;
/ match n e w l i n e /
ECHO;

6
7

%%

8
9
10
11

i n t yywrap ( v o i d ) {
return 1;
}

12
13
14
15
16

i n t main ( v o i d ) {
yylex ();
return 0;
}

Dois padroes foram especificados na secao de regras. Cada padrao tem que comecar
na primeira coluna do arquivo texto. Estes sao seguidos por caracter em branco (espaco,
tabulacao ou nova linha) e uma acao opcional associada com o padrao. A acao pode ser um
u
nico comando C ou m
ultiplos comandos delimitados por chaves. Qualquer comando que
nao comeca na primeira coluna e copiado como esta para o arquivo C gerado. Podemos
usar comentarios no arquivo lex. Neste exemplo ha dois padroes . e \n, com a acao
ECHO associada com cada padrao. Varias macros e variaveis sao pre-definidas por lex.
ECHO e uma macro que escreve o codigo reconhecido pelo padrao lexico. Esta e a acao
default para qualquer string nao reconhecido. Normalmente, ECHO e definido como:
1

#d e f i n e ECHO f w r i t e ( y yte xt , yyleng , 1 , yyout )

CAPITULO 2. ANALISE
LEXICA
Nome
int yylex(void)
char *yytext
yyleng
yylval
int yywrap(void)
FILE *yyout
FILE *yyin
INITIAL
BEGIN condition
ECHO

19

Func
ao
Funcao principal do analisador que retorna o proximo token.
Ponteiro para o padrao lexico (string) reconhecido.
Tamanho do string reconhecido.
Valor associado com o token.
wrapup, retorna 1 se acabou, 0 se nao acabou.
Arquivo de sada.
Arquivo de entrada.
Condicao inicial.
Troca a condicao inicial.
Escreve o string reconhecido.

Tabela 2.3: Variaveis, Macros e Funcoes geradas por Lex


A variavel yytext e um ponteiro para o string reconhecido (terminado por NULL), e
yyleng e o tamanho do string reconhecido. A variavel yyout e o arquivo de sada, e o default e stdout. A funcao yywrap e chamada por lex quando a entrada e esgotada. Retorna
um se terminou, ou 0 se mais processamento e necessario. Todo programa C completo
precisa de uma funcao main. Neste exemplos, nos simplesmente chamamos yylex, o ponto
de entrada principal para lex. Algumas implementacoes de lex incluem copias de main e
yywrap na biblioteca, eliminando a necessidade de codifica-las explicitamente.
Algumas das funcoes, macros e variaveis pre-definidas no arquivo gerado por Lex estao
listados na Tabela 2.3.

2.2.2

Alguns Exemplos de Lex

O primeiro exemplo apresenta um arquivo de especificacao lex que gera um programa


que nao faz nada. Todas as entradas sao reconhecidas mas nao existe nenhuma acao
associada com qualquer padrao, tal que nada sera apresentado na sada.
1
2
3

%%
.
\n

O seguinte exemplo numera cada linha do arquivo. Algumas implementacoes de lex


predefinem e calculam a variavel yylineno. O arquivo de entrada para lex e yyin, e o
arquivo de entrada default e stdin.
1

%{

int yylineno ;
%}
%%
(.)\n
p r i n t f (%4d\ t%s , ++y y l i n e n o , y y t e x t ) ;
%%
i n t main ( i n t argc , char argv [ ] ) {
yyin = fopen ( argv [ 1 ] , r ) ;
yylex ();
f c l o s e ( yyin ) ;
}

3
4
5
6
7
8
9
10
11

A secao de definicoes e composta de substituicoes, codigos e estados iniciais. O codigo


na secao de definicoes e copiado como esta para o topo do arquivo C gerado e precisa

CAPITULO 2. ANALISE
LEXICA

20

ser delimitado com os marcadores %{and %}. As substituicoes simplificam as regras


para casamento de padroes. Por exemplo, podemos definir dgitos e letras como segue:
1
2
3
4
5
6
7
8
9
10
11
12
13
14

digit
[0 9]
letter
[ AZaz ]
%{
i n t co u nt ;
%}
%%
/ match i d e n t i f i e r /
{ l e t t e r } ( { l e t t e r } | { d i g i t } )
count++;
%%
i n t main ( v o i d ) {
yylex ();
p r i n t f ( number o f i d e n t i f i e r s = %d\n , c o un t ) ;
return 0;
}

Espacos em branco precisam separar o termo definido e a expressao associada. As


referencias para as substituicoes nas regras devem estar delimitadas por chaves ({letter})
para diferencia-las de literais. Quando o padrao lexico e reconhecido nas regras, o codigo C
associado e executado. Aqui um exemplo de analisador que conta o n
umero de caracteres,
palavras e linhas no arquivo (similar ao comando Unix wc):
1

%{

i n t nchar , nword , n l i n e ;
%}
%%
\n
{ n l i n e ++; nchar++; }
[ \ t \n]+ { nword++, nchar += y y l e n g ; }
.
{ nchar++; }
%%
i n t main ( v o i d ) {
yylex ();
p r i n t f (%d\ t%d\ t%d\n , nchar , nword , n l i n e ) ;
return 0;
}

3
4
5
6
7
8
9
10
11
12
13

2.3

Analisador L
exico para Linguagem Simples

A linguagem Simplesr , na sua versao inicial, e composta dos seguintes smbolos lexicos:
Palavras Reservadas: programa, inicio, fimprograma, leia, escreva, se, entao,
senao, fimse, enquanto, faca, fimenquanto.
Operadores: +, -, *, div, >, <, +, e, ou, nao, <, (, )
tipos: inteiro, logico
constantes: V, F
identificadores: (letra)(letra|digito)*
n
umeros: (digito)+

CAPITULO 2. ANALISE
LEXICA

21

Utilizando a ferramenta flex pode-se construir um classificador do codigo da linguagem


Simples. Esse classificador e uma versao basica do analisador lexico que recebe como
entrada um codigo de Simples e apresenta na sada uma tabela onde todos os smbolos
lexicos encontrados no codigo sao classificados. Dado o seguinte codigo Simples:
1
2
3
4
5
6
7
8

programa t e s t e
inteiro A B
inicio
A < 5
leia B
B < A B
escreva B
fimprograma

Obtem-se como sada a seguinte tabela:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

programa :
teste :
inteiro :
A:
B:
inicio :
A:
<:
5:
leia :
B:
B:
<:
A:
:
B:
escreva :
B:
fimprograma :

palavra reservada
identificador
palavra reservada
identificador
identificador
palavra reservada
identificador
o p e r a d o r de a t r i b u i c a o
numero
palavra reservada
identificador
identificador
o p e r a d o r de a t r i b u i c a o
identificador
operador a r i t m e t i c o m u l t i p l i c a c a o
identificador
palavra reservada
identificador
palavra reservada

O arquivo de especificacao Lex que implementa esse classificador de smbolos da linguagem Simples e:
1
2
3
4

identificador
numero
espaco
novalinha

[ azAZ ] ( [ azAZ0 9])


[0 9]+
[ \ t ]+
[\n ]

5
6

%%

7
8
9
10

programa
inicio
fimprograma

p r i n t f ( %11s : p a l a v r a r e s e r v a d a \n , y y t e x t ) ;
p r i n t f ( %11s : p a l a v r a r e s e r v a d a \n , y y t e x t ) ;
p r i n t f ( %11s : p a l a v r a r e s e r v a d a \n , y y t e x t ) ;

leia
escreva

p r i n t f ( %11s : p a l a v r a r e s e r v a d a \n , y y t e x t ) ;
p r i n t f ( %11s : p a l a v r a r e s e r v a d a \n , y y t e x t ) ;

se
entao
senao
fimse

p r i n t f ( %11s :
p r i n t f ( %11s :
p r i n t f ( %11s :
p r i n t f ( %11s :

enquanto

p r i n t f ( %11s : p a l a v r a r e s e r v a d a \n , y y t e x t ) ;

11
12
13
14
15
16
17
18

palavra
palavra
palavra
palavra

r e s e r v a d a \n ,
r e s e r v a d a \n ,
r e s e r v a d a \n ,
r e s e r v a d a \n ,

yytext ) ;
yytext ) ;
yytext ) ;
yytext ) ;

19
20

CAPITULO 2. ANALISE
LEXICA

22

faca
fimenquanto

p r i n t f ( %11s : p a l a v r a r e s e r v a d a \n , y y t e x t ) ;
p r i n t f ( %11s : p a l a v r a r e s e r v a d a \n , y y t e x t ) ;

26

p r i n t f ( %11s : o p e r a d o r a r i t m e t i c o soma\n , y y t e x t ) ;
p r i n t f ( %11s : o p e r a d o r a r i t m e t i c o s u b t r a c a o \n , y y t e x t ) ;
p r i n t f ( %11s : o p e r a d o r a r i t m e t i c o m u l t i p l i c a c a o \n , y y t e x t )

27

div

p r i n t f ( %11s : o p e r a d o r a r i t m e t i c o d i v i s a o \n , y y t e x t ) ;

>
<
=

p r i n t f ( %11s : o p e r a d o r r e l a c i o n a l maior \n , y y t e x t ) ;
p r i n t f ( %11s : o p e r a d o r r e l a c i o n a l menor\n , y y t e x t ) ;
p r i n t f ( %11s : o p e r a d o r r e l a c i o n a l i g u a l \n , y y t e x t ) ;

e
ou
nao

p r i n t f ( %11s : o p e r a d o r l o g i c o c o n j u n c a o \n , y y t e x t ) ;
p r i n t f ( %11s : o p e r a d o r l o g i c o d i s j u n c a o \n , y y t e x t ) ;
p r i n t f ( %11s : o p e r a d o r l o g i c o negacao \n , y y t e x t ) ;

<
(
)

p r i n t f ( %11s : o p e r a d o r de a t r i b u i c a o \n , y y t e x t ) ;
p r i n t f ( %11s : s i m b o l o a b r e p a r e n t e s e s \n , y y t e x t ) ;
p r i n t f ( %11s : s i m b o l o f e c h a p a r e n t e s e s \n , y y t e x t ) ;

inteiro
logico
V
F

p r i n t f ( %11s :
p r i n t f ( %11s :
p r i n t f ( %11s :
p r i n t f ( %11s :

{ identificador }
{numero}
{ espaco }
{ novalinha }
.

p r i n t f ( %11s : i d e n t i f i c a d o r \n , y y t e x t ) ;
p r i n t f ( %11s : numero\n , y y t e x t ) ;
/ nao f a z nada /
/ nao f a z nada /
p r i n t f ( %11s : ERRO SIMBOLO NAO RECONHECIDO! \ n , y y t e x t ) ;

21
22
23
24
25

;
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

p a l a v r a r e s e r v a d a \n , y y t e x t ) ;
p a l a v r a r e s e r v a d a \n , y y t e x t ) ;
c o n s t a n t e l o g i c a de verdade \n , y y t e x t ) ;
c o n s t a n t e l o g i c a de f a l s i d a d e \n , y y t e x t ) ;

45
46
47
48
49
50
51
52

%%

53
54

int yywrap ( void ) { return 1 ; }

55
56
57
58
59

int main ( void ) {


yylex () ;
return 0 ;
}

A exclusao dos comentarios tem um tratamento especial na sintaxe Lex/Flex. A marca


de incio de comentario, normalmente representada por uma sequencia de smbolos como
/* e (*, determina uma configuracao especial para o automato. A partir dessa sequencia,
o analisador lexico deve descartar todos os smbolos, exceto a marca de fim de linha que
e utilizada na contagem de linhas do arquivo fonte. Essa contagem e necessaria para
que as rotinas de tratamento de erro possam indicar a linha correta do erro. E quando
o automato identifica a sequencia que fecha o comentario (/* ou *)), o automato deve
retornar ao seu estado normal. A Figura 2.7 representa o automato para o tratamento
de comentario de linhas. O automato vai para o estado X quando encontra a marca de
incio de comentario. Nesse estado, o automato consome os smbolos da entrada, quando
encontra a sequencia que marca o fim do comentario, o automato volta ao estado inicial
de aceitacao.
O novo arquivo de especificacao Flex que inclui o tratamento para comentario de linha
(//), comentario de m
ultiplas linhas (/* ... */) e a contagem do n
umero das linhas no

CAPITULO 2. ANALISE
LEXICA

Figura 2.7: Comentario para automatos de estados finitos

23

CAPITULO 2. ANALISE
LEXICA

24

arquivo fonte e:
1

%{
int nLinha = 1 ;

2
3

%}

4
5
6
7
8

identificador
numero
espaco
novalinha

[ azAZ ] ( [ azAZ0 9])


[0 9]+
[ \ t ]+
[\n ]

9
10

%x c o m e n t a r i o

11
12

%%

13
14

15

16

programa
yytext ) ;
inicio
yytext ) ;
fimprograma
yytext ) ;

p r i n t f ( Linha=%2d>%12s : p a l a v r a r e s e r v a d a \n , nLinha ,

leia
yytext ) ;
escreva
yytext ) ;

p r i n t f ( Linha=%2d>%12s : p a l a v r a r e s e r v a d a \n , nLinha ,

p r i n t f ( Linha=%2d>%12s : p a l a v r a r e s e r v a d a \n , nLinha ,
p r i n t f ( Linha=%2d>%12s : p a l a v r a r e s e r v a d a \n , nLinha ,

17
18

19

p r i n t f ( Linha=%2d>%12s : p a l a v r a r e s e r v a d a \n , nLinha ,

20
21

22

23

24

p r i n t f ( Linha=%2d>%12s : p a l a v r a r e s e r v a d a \n , nLinha ,

se
yytext ) ;
entao
yytext ) ;
senao
yytext ) ;
fimse
yytext ) ;

p r i n t f ( Linha=%2d>%12s : p a l a v r a r e s e r v a d a \n , nLinha ,
p r i n t f ( Linha=%2d>%12s : p a l a v r a r e s e r v a d a \n , nLinha ,
p r i n t f ( Linha=%2d>%12s : p a l a v r a r e s e r v a d a \n , nLinha ,

25
26

27

28

enquanto
yytext ) ;
faca
yytext ) ;
fimenquanto
yytext ) ;

p r i n t f ( Linha=%2d>%12s : p a l a v r a r e s e r v a d a \n , nLinha ,

p r i n t f ( Linha=%2d>%12s : o p e r a d o r a r i t m e t i c o soma\n , nLinha

p r i n t f ( Linha=%2d>%12s : p a l a v r a r e s e r v a d a \n , nLinha ,
p r i n t f ( Linha=%2d>%12s : p a l a v r a r e s e r v a d a \n , nLinha ,

29
30

, yytext ) ;
31

32

33

p r i n t f ( Linha=%2d>%12s : o p e r a d o r a r i t m e t i c o s u b t r a c a o \n ,
nLinha , y y t e x t ) ;

p r i n t f ( Linha=%2d>%12s : o p e r a d o r a r i t m e t i c o m u l t i p l i c a c a o \n
, nLinha , y y t e x t ) ;
div
p r i n t f ( Linha=%2d>%12s : o p e r a d o r a r i t m e t i c o d i v i s a o \n ,
nLinha , y y t e x t ) ;

34
35

36

37

38

p r i n t f ( Linha=%2d>%12s : o p e r a d o r r e l a c i o n a l maior \n ,
nLinha , y y t e x t ) ;
<
p r i n t f ( Linha=%2d>%12s : o p e r a d o r r e l a c i o n a l menor\n ,
nLinha , y y t e x t ) ;
=
p r i n t f ( Linha=%2d>%12s : o p e r a d o r r e l a c i o n a l i g u a l \n ,
nLinha , y y t e x t ) ;
>

CAPITULO 2. ANALISE
LEXICA

39

40

41

25

p r i n t f ( Linha=%2d>%12s : o p e r a d o r l o g i c o c o n j u n c a o \n ,
nLinha , y y t e x t ) ;
ou
p r i n t f ( Linha=%2d>%12s : o p e r a d o r l o g i c o d i s j u n c a o \n ,
nLinha , y y t e x t ) ;
nao
p r i n t f ( Linha=%2d>%12s : o p e r a d o r l o g i c o negacao \n , nLinha ,
yytext ) ;
e

42
43

44

45

<
yytext ) ;
(
yytext ) ;
)
, yytext ) ;

p r i n t f ( Linha=%2d>%12s : o p e r a d o r de a t r i b u i c a o \n , nLinha ,
p r i n t f ( Linha=%2d>%12s : s i m b o l o a b r e p a r e n t e s e s \n , nLinha ,
p r i n t f ( Linha=%2d>%12s : s i m b o l o f e c h a p a r e n t e s e s \n , nLinha

46
47

48

49

50

inteiro
p r i n t f ( Linha=%2d>%12s :
yytext ) ;
logico
p r i n t f ( Linha=%2d>%12s :
yytext ) ;
V
p r i n t f ( Linha=%2d>%12s :
nLinha , y y t e x t ) ;
F
p r i n t f ( Linha=%2d>%12s :
nLinha , y y t e x t ) ;

p a l a v r a r e s e r v a d a \n , nLinha ,
p a l a v r a r e s e r v a d a \n , nLinha ,
c o n s t a n t e l o g i c a de verdade \n ,
c o n s t a n t e l o g i c a de f a l s i d a d e \n ,

51
52
53
54
55

{ identificador }
{numero}
{ espaco }
{ novalinha }

p r i n t f ( Linha=%2d>%12s : i d e n t i f i c a d o r \n , nLinha , y y t e x t ) ;
p r i n t f ( Linha=%2d>%12s : numero\n , nLinha , y y t e x t ) ;
/ nao f a z nada /
nLinha++;

// .

/ nao f a z nada /

56
57
58
59
60
61
62
63

/
BEGIN ( c o m e n t a r i o ) ;
<comentario >[\n ]
/ nao f a z nada /
<comentario > [ ] + [ / \ n ]
/ nao f a z nada /
<comentario >\n
nLinha++;
<comentario > + /
BEGIN ( INITIAL ) ;

64
65

p r i n t f ( Linha=%2d>%12s : ERRO SIMBOLO NAO RECONHECIDO! \ n ,


nLinha , y y t e x t ) ;

66
67

%%

68
69

int yywrap ( void ) { return 1 ; }

70
71
72
73
74

int main ( void ) {


yylex () ;
return 0 ;
}

Para o arquivo Simples de entrada:


1
2
3
4
5
6
7
8
9

programa t e s t e
i n t e i r o A B // e s t e eh um c o m e n t a r i o de l i n h a
inicio
/ v a r i a v e l A
r e c e b e o v a l o r 5 /
A < 5
leia B
B < A B
escreva B

CAPITULO 2. ANALISE
LEXICA

10

26

fimprograma

A sada produzida como resultado do classificador de smbolos (analisador lexico simplificado) e:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

Linha= 1>
programa :
Linha= 1>
teste :
Linha= 2>
inteiro :
Linha= 2>
A:
Linha= 2>
B:
Linha= 3>
inicio :
Linha= 6>
A:
Linha= 6>
<:
Linha= 6>
5:
Linha= 7>
leia :
Linha= 7>
B:
Linha= 8>
B:
Linha= 8>
<:
Linha= 8>
A:
Linha= 8>
:
Linha= 8>
B:
Linha= 9>
escreva :
Linha= 9>
B:
Linha=10> fimprograma :

palavra reservada
identificador
palavra reservada
identificador
identificador
palavra reservada
identificador
o p e r a d o r de a t r i b u i c a o
numero
palavra reservada
identificador
identificador
o p e r a d o r de a t r i b u i c a o
identificador
operador a r i t m e t i c o m u l t i p l i c a c a o
identificador
palavra reservada
identificador
palavra reservada

Captulo 3

An
alise Sint
atica
O objetivo principal da analise sintatica e decidir se uma cadeia pertence ou nao `a
linguagem definida por uma gramatica. Existem duas importantes estrategias para o
problema de analise sintatica:
Analise Sintatica Ascendente
Analise Sintatica Descendente
Na primeira, a arvore sintatica e construda partindo-se da cadeia a ser analisada,
subindo-se ate atingir o smbolo inicial da gramatica. Na segunda, parte-se do smbolo
inicial e vai-se descendo ate atingir todos os smbolos da cadeia que esta sendo analisada.
Apresentamos nesse captulo um estrategia (existem outras) para analise descendente
e uma estrategia para analise ascendente.

3.1

An
alise LL

Os analisadores descendentes (top-down) podem ser construdos com uma classe de


gramatica chamada LL(1). O primeiro L se refere a forma como e lida a cadeia de
entrada na analise, nesse caso da direita para esquerda (Left-to-right). O segundo L se
refere a forma como e obtida a sequencia de derivacao para obtencao da sentenca avaliada,
nesse caso derivacao mais a` esquerda (leftmost). O n
umero 1 se refere ao n
umero de
smbolos a frente deve-se olhar para decidir que regra da gramatica deve ser utilizada.
Para construcao de Analisadores LL(k), sao necessarias duas funcoes sobre smbolos
da gramatica: funcao FIRST e FOLLOW. A Figura 3.1 e usada para ilustrar o calculo
dessas funcoes. Intuitivamente, todos os smbolos que iniciam derivacoes de A compoe
o conjunto FIRST de A (por exemplo, o terminal c da Figura). Todo smbolo terminal
que segue o smbolo A em qualquer derivacao faz parte do conjunto FOLLOW de A (por
exemplo, o terminal a da Figura 3.1)

Figura 3.1: Ilustracao para os conjuntos First/Follow

27

CAPITULO 3. ANALISE
SINTATICA

3.1.1

28

Fun
c
ao F IRST

Para calcular F IRST de todos os simbolos X de uma gramatica, execute as seguintes


regras ate que nenhum novo smbolo possa ser acrescentado a qualquer conjunto F IRST .
1. Se X e um smbolo terminal, entao F IRST (X) = {X}
2. Se X e um nao-terminal e X Y1 Y2 ...Yk e uma regra de producao para algum
k 1, entao acrescente a a F IRST (X) se, para algum i, a estiver em F IRST (Yi ),
e estiver em todos os F IRST (Y1 ), ..., F IRST (Yi1 ). Se esta em F IRST (Yj )
para todo j = 1, 2, ..., k, entao adicione a F IRST (X).
3. Se X e um regra de producao, entao acrescente a F IRST (X)

3.1.2

Fun
c
ao F OLLOW

Para calcular F OLLOW de todos os simbolos NAO-TERMINAIS


S de uma gramatica,
execute as seguintes regras ate que nenhum novo smbolo possa ser acrescentado a qualquer conjunto F OLLOW .
1. Coloque # em F OLLOW (S), onde S e o smbolo inicial da gramatica e # e o
marcador de fim de sentenca, que e incluido antes da avaliacao da sentenca.
2. Se houver uma producao A B, entao tudo que esta em F IRST () exceto ,
deve estar em F OLLOW (B).
3. Se houver uma producao A B ou A B, onde F IRST () contem , entao
inclua F OLLOW (A) em F OLLOW (B).
Exemplo:
Considere a seguinte gramatica:
0

E TE
0
0
E +T E |
0
T FT
0
0
T F T |
F a|(E)
Conjuntos FIRST e FOLLOW:

E
0
E
T
0
T
F

FIRST FOLLOW
{(, a}
{), #}
{+, }
{), #}
{(, a}
{+, ), #}
{, }
{+, ), #}
{(, a} {, +, ), #}

Algoritmo para construir a Tabela de An


alise Preditiva LL(1):
Para cada producao A da gramatica, faca:
1. Para cada terminal a de F IRST (), adicione a producao A a T [A, a]

CAPITULO 3. ANALISE
SINTATICA

29

2. Se F IRST () inclui a palavra vazia, entao adicione A a T [A, b] para cada


b em F OLLOW (A).
A tabela LL(1) e:
a
0
E TE

E
0
E
T
0
T
F

E +T E
T FT

(
0
E TE

T FT
0

F a

#
0

E E

T F T

F (E)

A seguinte definicao permite identificar as gramaticas LL(1):


Definic
ao 1 Uma gramatica G nao recursiva `a esquerda e LL(1)se e somente se, sempre
que A e A sao regras de producao de G, ocorre que:
1. a intersecao dos conjuntos F IRST () e F IRST () e vazia;
2. no maximo um dos dois, ou , deriva a palavra vazia; e

3. se , entao a intersecao de F IRST () e F OLLOW (A) e vazia;

3.2

An
alise LR

Os analisadores ascendentes (bottom-up) podem ser construdos com uma classe de


gramatica chamada LR(1). A letra L se refere a forma como e lida a cadeia de entrada
na analise, nesse caso da direita para esquerda (Left-to-right). A letra R do nome se
refere a forma como e obtida a sequencia de derivacao para obtencao da sentenca avaliada,
nesse caso derivacao mais `a direita (rigthmost). O n
umero 1 se refere ao n
umero de
smbolos a frente deve-se olhar para decidir que regra da gramatica deve ser utilizada.
O funcionamento de um algoritmo de analise sintatica ascendente pode ser descrito,
informalmente da seguinte maneira:
1. = cadeia dada
2. Decompor = X1 X2 ...Xn tal que exista uma regra de producao X X1 X2 ...Xn .
Adotar a cadeia = X, associando-se uma arvore onde X e a raiz e X1 X2 ...Xn
sao as subarvores da raiz X. (Este processo inverso da derivacao e denominado

REDUC
AO).
3. O passo 2 e repetido ate que o valor de seja reduzido para o smbolo inicial da
gramatica.
Na descricao generica do algoritmo de analise ascendente usa-se a intuicao para decidir que regra de producao utilizar para reducao. Em algumas situacoes temos mais de
uma reducao possvel. Para automatizar o processo de analise sintatica existem alguns
algoritmos que utilizam uma tabela (matriz) representando a gramatica para decidir de
forma automatica as reducoes. A ideia basica deste metodo e que para cada smbolo da
cadeia de entrada e feita uma consulta na tabela. O valor obtido da tabela (um estado) e
empilhado. Em cada passo, o u
ltimo estado empilhado e utilizado para decidir sobre uma

CAPITULO 3. ANALISE
SINTATICA

30

eventual reducao. O processo continua ate que seja encontrada uma situacao de erro, ou
entao, ate que a cadeia de entrada seja reconhecida.
A tabela de analise e uma matriz retangular cujas linhas sao indexadas pelos estados,
e as colunas pelos smbolos do vocabulario da gramatica (terminais e nao-terminais). Os
elementos da matriz indicam as acoes que podem ser tomadas pelo algoritmo que podem
ser:
Empilhar o estado ei
Reduzir usando a j-esima regra de producao.
Aceitar
Rejeitar
Consideremos a gramatica abaixo cujas producoes foram numeradas para fins de referencia:
(1)
(2)
(3)
(4)

E
E
E
E

+EE
EE
a
b

A tabela de analise LR(k) para esta gramatica e:


Tabela
eo
e1
e2
e3
e4
e5
e6
e7
e8
e9

E
e1

+
e2

*
e3

a
e4

b
e5

e6
e7

e2
e2
r3
r4
e2
e2
r1
r2

e3
e3
r3
r4
e3
e3
r1
r2

e4
e4
r3
r4
e4
e4
r1
r2

e5
e5
r3
r4
e5
e5
r1
r2

#
a

e8
e9

r3
r4

r1
r2

Tabela 3.1: Tabela de Analise LR


O smbolo # e utilizado para marcar o fim da sentenca. As acoes indicadas em cada
celula da tabela sao:
ei = significa empilhar o estado ei .
rj = significa reduzir usando a j-esima regra de producao.
a = aceitar.
branco = rejeitar.
Considerando essa tabela, o algoritmo que reconhece automaticamente as construcoes
validas para a gramatica pode ser resumido da seguinte forma:

CAPITULO 3. ANALISE
SINTATICA

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

31

Inicio
P [ 0 ] eo
i 0
termino f a l s o
reduzido f a l s o
Simbolo PROXIMO ( )
R ep it a
Se r e d u z i d o
Entao s SimboloReduzido
Senao s Simbolo
Fims e
Caso Tabela [ P [ i ] , s ] de
Empilha ( ej ) :
i i + 1
P [ i ] ej
Se r e d u z i d o
Entao r e d u z i d o f a l s o
Senao Simbolo PROXIMO ( )
Re duz ir ( A ) :
i i | |
Reduzido v e r d a d e i r o
SimboloReduzido A
Aceitar : termino verdadeiro
R e j e i t a r : ERRO ( )
Fimc a s o
Ate t e r m i n o
Fim

As estruturas e variaveis desse algoritmo sao:


P: e a pilha de estados
i: e o topo da pilha de estados
termino: condicao de parada do algoritmo. Determina a aceitacao da sentenca que
esta sendo avaliada.
reduzido: variavel booleana que indica se houve reducao no passo anterior do algoritmo
Simbolo: e o u
ltimo smbolo lido na sentenca de entrada.
PROXIMO ( ): funcao que retorna o proximo smbolo da sentenca de entrada (corresponde a uma versao primitiva do analisador lexico, i. e., funcao yylex() gerada
pela ferramenta FLEX).
Tabela: e a tabela de analise LR, em questao.
ERRO ( ): funcao de tratamento de erro.
A Tabela 3.2 apresenta o acompanhamento dos passos do algoritmo de analise LR(k)
usando a tabela para a sentenca +*a+baa#
Algumas observacoes:
Conforme pode ser observado no algoritmo, o proximo smbolo a ser consultado pode
ser o proximo smbolo da cadeia de entrada ou o nao-terminal da u
ltima reducao
(se houve reducao no passo anterior).

CAPITULO 3. ANALISE
SINTATICA

32

A fim de tornar o processo de analise mais claro, os estados empilhados sao indicados
por si , onde s representa o smbolo que determinou a inclusao do estado na pilha e
i representa o estado propriamente dito.
Na reducao sao removidos k estados da pilha, onde k representa o n
umero de
smbolos no lado direito da regra de producao considerada.
Passo Pilha
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

eo
eo +2
eo +2 3
eo +2 3 a4
eo +2 3
eo +2 3 E7
eo +2 3 E7 +2
eo +2 3 E7 +2 b5
eo +2 3 E7 +2
eo +2 3 E7 +2 E6
eo +2 3 E7 +2 E6 a4
eo +2 3 E7 +2 E6
eo +2 3 E7 +2 E6 E8
eo +2 3 E7
eo +2 3 E7 E9
eo +2
eo +2 E6
eo +2 E6 a4
eo +2 E6
eo +2 E6 E8
eo
eo E1

Smbolo
Reduzido

E
E
E

E
E

Cadeia de
Ac
ao
Entrada
+*a+baa#
e2
*a+baa#
e3
a+baa#
e4
+baa#
r3
+baa#
e7
+baa#
e2
baa#
e5
aa#
r4
aa#
e6
aa#
e4
a#
r3
a#
e8
a#
r1
a#
e9
a#
r2
a#
e6
a#
e4
#
r3
#
e8
#
r1
#
e1
#
ACEITAR

Tabela 3.2: Acompanhamento do algoritmo LR


Exerccio: Fazer o acompanhamento do algoritmo de analise LR(k) usando a gramatica
e a tabela anterior, para a cadeia de entrada ++*abaa#.

3.2.1

Implementa
c
ao do Algoritmo LR

Na listagem de codigo seguinte e apresentada uma implementacao para o algoritmo


LR. Na implementacao em questao a cadeia de entrada e restrita a cada smbolo ocupando
uma u
nica posicao de caracter no string sentenca. O codigo apresenta varias tabelas para
diversas gramaticas distintas. Ao final da execucao, se a sentenca verificada for aceita, o
programa apresenta a sequencia de derivacoes mais a` esquerda.
1
2
3
4

/++
| Implementacao do a l g o r i t m o de a n a l i s e s i n t a t i c a LR(K) .
|
| Por L u i z Eduardo da S i l v a
|
++/

CAPITULO 3. ANALISE
SINTATICA

5
6
7

33

#include <s t d i o . h>


#include < s t d l i b . h>
#include <s t r i n g . h>

8
9
10
11
12

/++
| V o c a b u l a r i o , Regras de Producao de uma g r a m a t i c a
|
| e a Tabela de A n a l i s e LR( k ) para a e s t a g r a m a t i c a .
|
++/

13
14
15
16
17
18
19
20
21
22

#define NSIMBOLOS 7
#define NREGRAS
4
#define NESTADOS 9
char a l f a b e t o [NSIMBOLOS+1] = SLa [ ] ; # ;
char r e g r a s [NREGRAS] =
{ S : : = a ,
S : : = [ L ] ,
L : : = S ,
L : : = L ; S } ;

23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

struct {
char acao ;
int i n d i c e ;
} TabSint [NESTADOS ] [ NSIMBOLOS] =
{ e ,1 , ,0 , e ,2 , e ,3 ,
,0 , ,0 , ,0 , ,0 ,
,0 , ,0 , r ,1 , r ,1 ,
e ,4 , e ,5 , e ,2 , e ,3 ,
,0 , ,0 , r ,3 , r ,3 ,
,0 , ,0 , ,0 , ,0 ,
,0 , ,0 , r ,2 , r ,2 ,
e ,8 , ,0 , e ,2 , e ,3 ,
,0 , ,0 , r ,4 , r ,4 ,
};



r

r
e
r

r

,0 ,
,0 ,
,1 ,
,0 ,
,3 ,
,6 ,
,2 ,
,0 ,
,4 ,



r

r
e
r

r

,0 ,
,0 ,
,1 ,
,0 ,
,3 ,
,7 ,
,2 ,
,0 ,
,4 ,

38
39
40
41
42
43
44
45
46
47
48

/
#d e f i n e NSIMBOLOS 6
#d e f i n e NREGRAS
4
#d e f i n e NESTADOS 10
cha r a l f a b e t o [NSIMBOLOS+1] = E+ab #;
cha r r e g r a s [NREGRAS] =
{ E::=+EE ,
E: : = EE ,
E: : = a ,
E: : = b } ;

49
50
51
52
53
54
55
56
57
58
59
60
61
62

struct {
ch ar acao ;
int indice ;
} TabSint [NESTADOS ] [ NSIMBOLOS] =
{ e ,1 , e ,2 , e ,3 , e ,4 ,
,0 , ,0 , ,0 , ,0 ,
e ,6 , e ,2 , e ,3 , e ,4 ,
e ,7 , e ,2 , e ,3 , e ,4 ,
,0 , r ,3 , r ,3 , r ,3 ,
,0 , r ,4 , r ,4 , r ,4 ,
e ,8 , e ,2 , e ,3 , e ,4 ,
e ,9 , e ,2 , e ,3 , e ,4 ,
,0 , r ,1 , r ,1 , r ,1 ,

e
e
r
r
e
e
r

,5 ,
,0 ,
,5 ,
,5 ,
,3 ,
,4 ,
,5 ,
,5 ,
,1 ,

,0 ,
a ,0 ,
,0 ,
,0 ,
r ,3 ,
r ,4 ,
,0 ,
,0 ,
r ,1 ,


a
r

r

r

r

,0 ,
,0 ,
,1 ,
,0 ,
,3 ,
,0 ,
,2 ,
,0 ,
,4 ,

CAPITULO 3. ANALISE
SINTATICA
,0 , r ,2 , r ,2 , r ,2 , r ,2 , r ,2

63
64

34

};

65
66
67
68
69
70
71
72

#d e f i n e NSIMBOLOS 5
#d e f i n e NREGRAS
2
#d e f i n e NESTADOS 6
cha r a l f a b e t o [NSIMBOLOS+1] = Sacb #;
cha r r e g r a s [NREGRAS] =
{ S : : = aSc ,
S : : = b } ;

73
74
75
76
77
78
79
80
81
82
83
84

struct {
cha r acao ;
int indice ;
} TabSint [NESTADOS ] [ NSIMBOLOS] =
{ e ,1 , e ,2 , ,0 , e ,3 ,
,0 , ,0 , ,0 , ,0 ,
e ,4 , e ,2 , ,0 , e ,3 ,
,0 , r ,2 , r ,2 , r ,2 ,
,0 , ,0 , e ,5 , ,0 ,
,0 , r ,1 , r ,1 , r ,1 ,
};

,0 ,
a ,0 ,
,0 ,
r ,2 ,
,0 ,
r ,1 ,

85
86
87
88
89
90
91
92
93
94

#d e f i n e NSIMBOLOS 7
#d e f i n e NREGRAS
4
#d e f i n e NESTADOS 9
cha r a l f a b e t o [NSIMBOLOS+1] = SL ( ) , a#;
cha r r e g r a s [NREGRAS] =
{ S : : = ( L) ,
S : : = a ,
L: : =L , S ,
L: : = S } ;

95
96
97
98
99
100
101
102
103
104
105
106
107
108
109

struct {
ch ar acao ;
int indice ;
} TabSint [NESTADOS ] [ NSIMBOLOS] =
{ e ,1 , ,0 , e ,2 , ,0 ,
,0 , ,0 , ,0 , ,0 ,
e ,4 , e ,5 , e ,2 , ,0 ,
,0 , ,0 , r ,2 , r ,2 ,
,0 , ,0 , r ,4 , r ,4 ,
,0 , ,0 , ,0 , e ,6 ,
,0 , ,0 , r ,1 , r ,1 ,
e ,8 , ,0 , e ,2 , ,0 ,
,0 , ,0 , r ,3 , r ,3 ,
};

r
r
e
r

,0 ,
,0 ,
,0 ,
,2 ,
,4 ,
,7 ,
,1 ,
,0 ,
,3 ,

110
111
112
113
114
115
116
117
118
119
120

#d e f i n e NSIMBOLOS 7
#d e f i n e NREGRAS
4
#d e f i n e NESTADOS 9
cha r a l f a b e t o [NSIMBOLOS+1] = SLa [ ] ; # ;
cha r r e g r a s [NREGRAS] =
{ S : : = a ,
S : : = [ L ] ,
L: : = S ,
L: : =L ; S } ;

e
r
r

r
e
r

,3 ,
,0 ,
,3 ,
,2 ,
,4 ,
,0 ,
,1 ,
,3 ,
,3 ,

,0 ,
a ,0 ,
,0 ,
r ,2 ,
r ,4 ,
,0 ,
r ,1 ,
,0 ,
r ,3 ,

CAPITULO 3. ANALISE
SINTATICA

35

121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136

struct {
cha r acao ;
int indice ;
} TabSint [NESTADOS ] [ NSIMBOLOS] =
{ e ,1 , ,0 , e ,2 , e ,3 ,
,0 , ,0 , ,0 , ,0 ,
,0 , ,0 , r ,1 , r ,1 ,
e ,4 , e ,5 , e ,2 , e ,3 ,
,0 , ,0 , r ,3 , r ,3 ,
,0 , ,0 , ,0 , ,0 ,
,0 , ,0 , r ,2 , r ,2 ,
e ,8 , ,0 , e ,2 , e ,3 ,
,0 , ,0 , r ,4 , r ,4 ,
};
/

r
e
r

,0 ,
,0 ,
,1 ,
,0 ,
,3 ,
,6 ,
,2 ,
,0 ,
,4 ,

r
e
r

,0 ,
,0 ,
,1 ,
,0 ,
,3 ,
,7 ,
,2 ,
,0 ,
,4 ,

,0 ,
a ,0 ,
r ,1 ,
,0 ,
r ,3 ,
,0 ,
r ,2 ,
,0 ,
r ,4 ,

137
138
139
140
141
142
143
144

/++
| P i l h a s i n t a t i c a u t i l i z a d a p e l o a l g o r i t m o de a n a l i s e LR(K) .
|
++/
struct {
char elem ;
int i n d ;
} P[20];

145
146
147

void t r a c o ( int ) ;
void s t r i n s ( char , int , char , int ) ;

148
149
150
151
152
153
154
155
156
157
158
159
160
161

/++
| Programa p r i n c i p a l que implementa o a l g o r i t m o de a n a l i s e LR(K) .
|
| E s t e programa LE uma s e n t e n c a e v e r i f i c a s e e s t a s e n t e n c a eh
|
| v a l i d a ou para a g r a m a t i c a r e p r e s e n t a d a na t a b e l a de a n a l i s e .
|
| Durante o p r o c e s s o de a n a l i s e o programa a p r e s e n t a , de forma
|
| t a b u l a r , os v a l o r e s das e s t r u t u r a s a cada p a s s o .
|
++/
int main ( )
{
int i , j , k , termino , r e d u z i d o , i n d i c e , ind , tam , passo ,
nreducao , i n d r e d u z = 1, r e d u c o e s [ 5 0 ] ;
char s e n t e n c a [ 4 0 ] , p i l h a [ 6 0 ] , c a d e i a [ 4 0 ] , s t r [ 4 0 ] ;
char s , s i m b o l o r e d u z i d o = , acao ;

162
163
164
165

P [ 0 ] . elem = e ;
P [ 0 ] . ind = 0 ;
i = termino = reduzido = 0 ;

166
167
168

p r i n t f ( \ nDigite a sentenca : ) ;
gets ( sentenca ) ;

169
170
171
172
173
174
175
176
177
178

s t r c a t ( s e n t e n c a , # ) ;
indice = 0;
passo = 0;
p r i n t f ( PASSO %30s S .R. %15s
traco (79) ;
while ( ! t e r m i n o ) {
i f ( reduzido )
s = simboloreduzido ;
else

%s \n , PILHA , SENTENCA , ACAO ) ;

CAPITULO 3. ANALISE
SINTATICA

179
180
181
182

183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226

227
228
229
230
231
232
233
234

36

s = sentenca [ indice ] ;
f o r ( j =0; a l f a b e t o [ j ] != s && j <= s t r l e n ( a l f a b e t o ) ; j ++) ;
i f ( a l f a b e t o [ j ] != s ) {
p r i n t f ( \nERRO: o s i m b o l o <%c> nao e r e c o n h e c i d o n e s t a linguagem ,
s);
p r i n t f ( \n\ n D i g i t e . para t e r m i n a r ! ) ;
while ( g e t c h a r ( ) != . ) ;
exit (10) ;
}
acao = TabSint [ P [ i ] . i n d ] [ j ] . acao ;
i n d = TabSint [ P [ i ] . i n d ] [ j ] . i n d i c e ;
f o r ( j = 0 , k = i n d i c e ; s e n t e n c a [ k ] ; j ++, k++)
cadeia [ j ] = sentenca [ k ] ;
c a d e i a [ j ] = \0 ;
strcpy ( pilha , ) ;
f o r ( k = 0 ; k <= i ; k++) {
s p r i n t f ( s t r , %c%d , P [ k ] . elem , P [ k ] . i n d ) ;
s t r c a t ( pilha , s t r ) ;
}
%30s %c
%15s %c%d\n ,
p r i n t f ( %3d
p a s s o ++, p i l h a , s i m b o l o r e d u z i d o , c a d e i a , acao , i n d ) ;
switch ( acao ) {
case e :
i ++;
P [ i ] . elem = s ;
P[ i ] . ind = ind ;
i f ( reduzido ) {
reduzido = 0;
simboloreduzido = ;
}
else
i n d i c e ++;
break ;
case r : tam = s t r l e n ( r e g r a s [ ind 1]) ;
i = i tam + 4 ;
reduzido = 1;
r e d u c o e s [++ i n d r e d u z ] = ind 1;
s i m b o l o r e d u z i d o = r e g r a s [ ind 1 ] [ 0 ] ;
break ;
case a : t e r m i n o = 1 ;
p r i n t f ( \nA s e n t e n c a <%s> e s t a c o r r e t a , s e n t e n c a ) ;
break ;
case :
p r i n t f ( \nA s e n t e n c a <%s> NAO e r e c o n h e c i d a , s e n t e n c a ) ;
p r i n t f ( \n\ n D i g i t e . para t e r m i n a r ! ) ;
while ( g e t c h a r ( ) != . ) ;
exit (1) ;
}
/ g e t c h a r ( ) ; /
}
/ Mostra a s e r i e de d e r i v a c o e s mais a d i r e i t a para p r o d u z i r a s e n t e n c a
/
p r i n t f ( \n\ nGramatica : ) ;
p r i n t f ( \n==========\n ) ;
f o r ( i = 0 ; i < NREGRAS; i ++)
p r i n t f ( (%d ) . %s \n , i +1, r e g r a s [ i ] ) ;
p r i n t f ( \n\ n S e q u e n c i a de D e r i v a c o e s mais a d i r e i t a : ) ;
p r i n t f ( \n=======================================\n\n ) ;
sentenca [ 0 ] = regras [ 0 ] [ 0 ] ;
s e n t e n c a [ 1 ] = \0 ;

CAPITULO 3. ANALISE
SINTATICA
p r i n t f ( %s , s e n t e n c a ) ;
while ( i n d r e d u z >= 0 )
{
i = s t r l e n ( sentenca ) 1;
while ( s e n t e n c a [ i ] < A | | s e n t e n c a [ i ] > Z ) i ;
nreducao = r e d u c o e s [ i n d r e d u z ];
s t r i n s ( r e g r a s [ nreducao ] , 4 , s e n t e n c a , i ) ;
p r i n t f ( =%d=> %s , nreducao +1, s e n t e n c a ) ;
}
p r i n t f ( \n\ n D i g i t e . para t e r m i n a r ! ) ;
while ( g e t c h a r ( ) != . ) ;

235
236
237
238
239
240
241
242
243
244
245
246

37

247
248
249
250
251
252
253
254
255
256

/++
| Desenha uma l i n h a de h i f e n s na t e l a .
|
++/
void t r a c o ( int i ) {
int k ;
f o r ( k = 0 ; k < i ; k++)
p r i n t f ( ) ;
p r i n t f ( \n ) ;
}

257
258
259
260
261
262
263
264
265
266
267
268
269
270

/++
| I n s e r e s u b s t r i n g da pos1 a t e o f i n a l de s1 na pos . pos2 do s t r i n g s2 |
++/
void s t r i n s ( char s1 , int pos1 , char s2 , int pos2 ) {
int i , tam s1 , tam s2 ;
f o r ( tam s1 = 0 ; s 1 [ tam s1 ] ; tam s1++) ;
f o r ( tam s2 = 0 ; s 2 [ tam s2 ] ; tam s2++) ;
f o r ( i = tam s2 ; i >= pos2 ; i )
s 2 [ i+tam s1pos1 1] = s 2 [ i ] ;
f o r ( i = pos1 ; i < tam s1 ; i ++)
s 2 [ i+pos2pos1 ] = s 1 [ i ] ;
s 2 [ tam s1+tam s2pos1 ]= \0 ;
}

O resultado da execucao desse programa, considerando a entrada da sentenca [a;[a;a]]


e:
1
2

3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

PASSO PILHA
S .R. SENTENCA
ACAO

0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

e0
e0 [ 3
e0 [ 3 a2
e0 [ 3
e0 [ 3 S4
e0 [ 3
e0 [ 3 L5
e0 [ 3 L5 ; 7
e0 [ 3 L5 ; 7 [ 3
e0 [ 3 L5 ; 7 [ 3 a2
e0 [ 3 L5 ; 7 [ 3
e0 [ 3 L5 ; 7 [ 3 S4
e0 [ 3 L5 ; 7 [ 3
e0 [ 3 L5 ; 7 [ 3 L5
e0 [ 3 L5 ; 7 [ 3 L5 ; 7
e0 [ 3 L5 ; 7 [ 3 L5 ; 7 a2

S
L

S
L

[ a ; [ a ; a ]]#
a ; [ a ; a ]]#
; [ a ; a ]]#
; [ a ; a ]]#
; [ a ; a ]]#
; [ a ; a ]]#
; [ a ; a ]]#
[ a ; a ]]#
a ; a ]]#
; a ]]#
; a ]]#
; a ]]#
; a ]]#
; a ]]#
a ]]#
]]#

e3
e2
r1
e4
r3
e5
e7
e3
e2
r1
e4
r3
e5
e7
e2
r1

CAPITULO 3. ANALISE
SINTATICA

19
20
21
22
23
24
25
26
27
28
29
30

16
17
18
19
20
21
22
23
24
25
26
27

e0 [ 3 L5 ; 7 [ 3 L5 ; 7
e0 [ 3 L5 ; 7 [ 3 L5 ; 7 S8
e0 [ 3 L5 ; 7 [ 3
e0 [ 3 L5 ; 7 [ 3 L5
e0 [ 3 L5 ; 7 [ 3 L5 ] 6
e0 [ 3 L5 ; 7
e0 [ 3 L5 ; 7 S8
e0 [ 3
e0 [ 3 L5
e0 [ 3 L5 ] 6
e0
e0S1

38
S
L

S
L

]]#
]]#
]]#
]]#
]#
]#
]#
]#
]#
#
#
#

e8
r4
e5
e6
r2
e8
r4
e5
e6
r2
e1
a0

31
32

A s e n t e n c a <[a ; [ a ; a]]#> e s t a c o r r e t a

33
34
35
36
37
38
39

Gramatica :
==========
(1) . S::= a
(2) . S ::=[L]
(3) . L::= S
(4) . L::=L ; S

40
41
42
43

S e q u e n c i a de D e r i v a c o e s mais a d i r e i t a :
=======================================

44
45

S =2=> [ L ] =4=> [ L ; S ] =2=> [ L ; [ L ] ] =4=> [ L ; [ L ; S ] ] =1=> [ L ; [ L ; a ] ] =3=> [ L ; [ S


; a ] ] =1=> [ L ; [ a ; a ] ] =3=> [ S ; [ a ; a ] ] =1=> [ a ; [ a ; a ] ]

3.2.2

Constru
c
ao da Tabela de An
alise Sint
atica LR

Ja temos um metodo automatico para verificar a sintaxe em linguagens de programacao: o algoritmo de analise LR(k). Nesse algoritmo, todo trabalho do analisador
sintatico e orientado por uma tabela de analise que e construda a partir da gramatica LR
para linguagem. A questao e: como definir as acoes da tabela de analise LR(k). Antes
de apresentar o algoritmo para o calculo da colecao de estados (linhas da tabela) e para
definicao dos valores da tabela, precisamos fazer algumas definicoes.
Definicoes:
uma regra de producao na qual foi marcada uma posicao na cadeia do lado
1. Item: E
direito; esta posicao sera indicada por meio do smbolo (ponto). Exemplo: Seja a
gramatica:
E
E
E
E

+EE
EE
a
b

O conjunto de itens derivados desta gramatica e: {E + EE| + EE| + E E| +


EE | EE| EE| E E| EE | a|a | b|b}. O conjunto de itens para
uma gramatica e sempre finito e sera utilizado para construir os estados da tabela.
um conjunto de itens. A presenca no topo da pilha de um estado
2. Estado: E
contendo um item da forma A indica que ja foi processada e deslocada para

CAPITULO 3. ANALISE
SINTATICA

39

pilha a parte inicial alpha do redutendo . O estado contendo o item da forma


A indica um redutendo completo (item completo), o que indica que a proxima

acao sera uma REDUC


AO.
3. Fecho: Diremos que um conjunto K de itens e fechado se para todo item K da
forma A B, todos os itens da forma B estao em K. Denotaremos por
FECHO(K) o menor conjunto fechado que contem K. Exemplo: Consideremos os
seguintes conjuntos de itens:
K1 = {E + EE}
K2 = {E +E E| EE| a}
K3 = {E b}
Para a gramatica:
E
E
E
E

+EE
EE
a
b

Entao seus fechos sao:


F ECHO(K1 ) = {E + EE| +EE| EE| a| b}
F ECHO(K2 ) = {E +E E| EE| a| +EE| EE| b}
F ECHO(K3 ) = {E b}
4. Transfere: Vamos agora analisar como determinar as entradas da forma ej na
tabela de analise. Suponhamos que um estado ei contenha um item incompleto da
forma A X. A presenca deste estado no topo da pilha de analise indica
que se o proximo smbolo a ser consultado for X, entao tera sido processada a parte
X do redutendo X, devendo ser empilhado portando um estado que contenha
o item A X (com a marca depois do smbolo X). Definiremos entao a funcao
TRANSFERE (K,X), como sendo o conjunto fechado de todos os itens da forma
A X tais que o item A X esta em K.
Consideremos a gramatica anterior e os conjuntos:
K1 = {E EE}
K2 = F ECHO(K1 ) = {E + EE| +EE| EE| a| b}
K3 = {E b}
Tem-se entao:
T RAN SF ERE(K1 , )
T RAN SF ERE(K1 , E)
T RAN SF ERE(K2 , +)
T RAN SF ERE(K2 , a)
T RAN SF ERE(K3 , E)
T RAN SF ERE(K3 , B)

=
=
=
=
=
=

{}
{E
{E
{E
{}
{E

EE| +EE| EE| a| b}


+ EE| +EE| EE| a| b} = K2
a}
b}

As funcoes FECHO e TRANSFERE permitem a construcao dos estados que serao


identificados como as linhas da tabela de analise. Assim:

CAPITULO 3. ANALISE
SINTATICA

40

Algoritmo para determinar a colec


ao C de estados de uma gram
atica:
0

1. Adota-se o estado e0 = F ECHO({S S#}) como sendo o valor inicial da colecao


C. Observe que deve ser acrescentada `a gramatica, uma regra para caracterizar o
instante que a sentenca toda sera reduzida para o smbolo inicial. O smbolo terminal
# e artificialmente acrescentado a gramatica para marcar o fim da sentenca que sera
analisada.
0

2. Se existe um estado e de C e um smbolo X de (vocabulario) tais que e =


0
0
T RAN SF ERE(e, X) 6= e e
/ C, entao e e acrescentado a` colecao C.
3. O passo 2 e repetido ate que nao se possam acrescentar mais estados a` colecao C.
C e o conjunto de estado tipo LR(0) da gramatica.
Exemplo: Consideremos a gramatica:
E
E
E
E
E

E#
+EE
EE
a
b

Aplicando-se o algoritmo anterior obtem-se os seguintes estados para esta gramatica:


e0 =
e1
e2
e3
e4
e5
e6

=
=
=
=
=
=

e7 =

e8 =

F ECHO({E 0 E#}) = {E 0 E#
E + EE| EE| a| b}
T RAN SF ERE(e0 , E) = {E 0 E #}
T RAN SF ERE(e0 , +) = {E + EE| +EE| EE| a| b}
T RAN SF ERE(e0 , ) = {E EE| +EE| EE| a| b}
T RAN SF ERE(e0 , a) = {E a}
T RAN SF ERE(e0 , a) = {E b}
T RAN SF ERE(e2 , E) = {E +E E| +EE| EE| a| b}
T RAN SF ERE(e2 , +) = e2
T RAN SF ERE(e2 , ) = e3
T RAN SF ERE(e2 , a) = e4
T RAN SF ERE(e2 , b) = e5
T RAN SF ERE(e3 , E) = {E E E| +EE| EE| a| b}
T RAN SF ERE(e3 , +) = e2
T RAN SF ERE(e3 , ) = e3
T RAN SF ERE(e3 , a) = e4
T RAN SF ERE(e3 , b) = e5
T RAN SF ERE(e6 , E) = {E +EE}
T RAN SF ERE(e6 , +) = e2
T RAN SF ERE(e6 , ) = e3
T RAN SF ERE(e6 , a) = e4
T RAN SF ERE(e6 , b) = e5

CAPITULO 3. ANALISE
SINTATICA
e9 =

41

T RAN SF ERE(e7 , E) = {E EE}


T RAN SF ERE(e7 , +) = e2
T RAN SF ERE(e7 , ) = e3
T RAN SF ERE(e7 , a) = e4
T RAN SF ERE(e7 , b) = e5

A tabela de analise LR construda com essa colecao de estados e:


Tabela
eo
e1
e2
e3
e4
e5
e6
e7
e8
e9

E
e1

+
e2

*
e3

a
e4

b
e5

e6
e7

e2
e2
r3
r4
e2
e2
r1
r2

e3
e3
r3
r4
e3
e3
r1
r2

e4
e4
r3
r4
e4
e4
r1
r2

e5
e5
r3
r4
e5
e5
r1
r2

#
a

e8
e9

r3
r4

r1
r2

Tabela 3.3: Tabela de Analise LR


Observacoes:
Nao foi calculado o estado T RAN SF ERE(e1 , #) pois esta situacao corresponde `a
aceitacao da sentenca de entrada.
Os estados calculados contem apenas um item completo (e4 , e5 , e8 , e9 ), ou apenas
itens incompletos (e0 , e1 , e2 , e3 , e6 , e7 ). Os estados constitudos de itens completos
indicam que os u
ltimos estados empilhados correspondem a um redutendo, e que
portanto deve haver reducao, independente do proximo smbolo.
Exerccios
1. Calcule a tabela de analise LR(0) para a seguinte gramatica:
E T
T $E
T a
2. Usando a tabela de analise da questao anterior e o algoritmo de analise LR(k), faca
um acompanhamento para verificar a validade da sentenca $a*#

3.3

Yacc/Bison - Geradores e Analisadores Sint


aticos

As gramaticas para Yacc estao definidas usando uma notacao similar a notacao de
Backus Naur Form (BNF). Esta tecnica foi criada por John Backus e Peter Naur, e
usada para descrever a sintaxe de ALGOL60. Uma gramatica BNF pode ser usada para

CAPITULO 3. ANALISE
SINTATICA

42

especificar gramaticas livres de contexto. Muitas construcoes sintaticas de linguagens de


programacao modernas podem ser expressas usando BNF. Por exemplo, a gramatica de
expressoes que multiplica e adiciona n
umeros e:
(1) E E + E
(2) E E E
(3) E id
Tres regras de producao foram especificadas. Os termos que aparecem no lado esquerdo
das regras de producao, como E, sao nao-terminais. Termos como id (identificadores) sao
terminais (tokens retornados pelo analisador lexico) e somente podem aparecer no lado
direito de uma regra de producao. Esta gramatica especifica que expressoes podem ser a
soma de duas expressoes, o produto de duas expressoes ou um identificador. Nos podemos
usar esta gramatica para gerar expressoes:
E

EE
Ez
E+Ez
E+yz
x+yz

(r2)
(r3)
(r1)
(r3)
(r3)

A cada passo expande-se um termo, trocando um smbolo nao-terminal no lado esquerdo de um regra pela sequencia de smbolos terminais e/ou nao terminais no lado
direito da mesma regra. O n
umero no lado direito indica que regra foi aplicada. Para
analisar a expressao, nos usamos uma operacao inversa. Ao inves de comecar com o
smbolo nao-terminal inicial e gerar a expressao da gramatica, nos devemos reduzir a
expressao para um u
nico smbolo nao-terminal (o smbolo inicial). Este metodo, mais
simples de implementar e chamado de analise ascendente ou analise de reducao e deslocamento (bottom-up or shift-reduce parsing), e usa uma pilha para armazenar os termos.
Aqui esta o mesma da derivacao, mas em ordem inversa:
1
2
3
4
5
6
7
8
9
10
11

x + y z
x +y z
E +y z
E + y z
E + y z
E + E z
E + E z
E + E z
E + E E
E + E
E

shif t
reduce(r3)
shif t
shif t
reduce(r3)
shif t
shif t
reduce(r3)
reduce(r2) emit multiply
reduce(r1) emit add
accept

Os termos do lado esquerdo do ponto estao na pilha, enquanto o restante da entrada


esta no lado direito do ponto. Quando o topo da pilha corresponde ao lado direito de uma
regra nos trocamos os tokens correspondentes com o smbolo nao terminal do lado esquerdo
da regra de producao. Conceitualmente, os tokens do lado direito sao desempilhados e
o smbolo nao terminal do lado esquerdo da regra e empilhado. Os seq
uencia de tokens
encontrados sao chamados de redutendo (handle), e nos estamos reduzindo o redutendo
para o smbolo do lado esquerdo da regra de producao. Este processo continua ate que

CAPITULO 3. ANALISE
SINTATICA

43

tenhamos deslocado todos os smbolos para a pilha e somente o smbolo nao terminal
inicial permanecer na pilha. No passo 1 nos deslocamos o x para a pilha. No passo 2
nos aplicamos a regra r3 para a pilha, trocando o smbolo x por um E. Nos continuamos
deslocando e reduzindo, ate que um u
nico nao terminal, o smbolo inicial, permaneca na
pilha. No passo 9, quando nos reduzimos usando a regra r2, escrevemos a instrucao de
multiplicacao. Da mesma forma, escrevemos a instrucao de soma no passo 10. Portanto
a multiplicacao tem precedencia maior que a soma.
Considere, entretanto, o deslocamento no passo 6. Ao inves de deslocar, nos poderamos ter reduzido, aplicando a regra r1. Isto resultaria na adicao tendo maior precedencia que a multiplicacao. Isto e conhecido como conflito de reducao-deslocamento
(shift-reduce conflict). Nossa gramatica e ambgua, pois existe mais de uma derivacao
que produzira a expressao. Neste caso, a precedencia dos operadores e afetada. Outro
exemplo, a associatividade na regra:
E E+E
e ambgua, pois podemos recursivamente substituir o nao terminal mais `a esquerda ou
mais a` direita na regra. Para resolver esta situacao, nos deveramos reescrever a gramatica,
ou indicar para Yacc a precedencia que existe entre os operadores. O u
ltimo metodo e
mais simples e sera demonstrado numa pratica posterior.
A seguinte gramatica tem um conflito de reducao e reducao. Com um id na pilha nos
podemos reduzir para T ou reduzir para E.
E T
E id
T id
Yacc executa uma acao default quando ha um conflito. Para conflito de reducaodeslocamento, yacc deslocara o smbolo para pilha. Para conflito de reducao-reducao ele
usara a primeira regra da listagem. Ele tambem apresenta uma mensagem indicando a
existencia do conflito. O aviso pode ser excludo tornando a gramatica nao ambgua.
Varios metodos para remover ambig
uidade serao apresentados na secao seguinte.
Implementac
ao de uma calculadora de express
oes usando Yacc
1
2
3
4
5

. . . definicoes . . .
%%
. . . regras . . .
%%
. . . subrotinas . . .

O arquivo de entrada para yacc e dividido em tres secoes. A secao de definicoes


consiste de declaracao de tokens, e codigo C delimintado por %e %. A gramatica
BNF e colocada na secao de regras e as rotinas do usuario sao colocados na secao de
subrotinas.
Podemos ilustrar isto melhor atraves de um exemplo que controi uma pequena calculadora que pode adicionar e subtrair n
umeros. Comecaremos examinando a ligacao entre
lex e yacc. Abaixo esta a secao de definicao para o arquivo de entrada yacc:
1

%token INTEGER

CAPITULO 3. ANALISE
SINTATICA

44

Esta definicao declara um token INTEGER. Quando nos rodamos yacc, ele gera o
analisador sintatico (parser) no arquivo y.tab.c, e tambem cria um arquivo (include file),
y.tab.h:
1
2
3
4
5

#i f n d e f YYSTYPE
#define YYSTYPE int
#endif
#define INTEGER 258
extern YYSTYPE y y l v a l ;

Lex inclui este arquivo e utiliza a definicao para o valor do token. Para obter tokens,
yacc chama yylex. A funcao yylex e do tipo int, e retorna o codigo numerico do token.
Valores associados com o token sao retornados por lex na variavel yylval. Por exemplo,
1

[0 9]+

{
yylval = at o i ( yytext ) ;
return INTEGER;

2
3

armazenaria o valor do inteiro em yylval, e retorna o token INTEGER para yacc.


O tipo de yylval e determinado por YYSTYPE. Como o tipo default e inteiro, o valor
retornado esta correto para este caso. Os valores de tokens entre 0 e 255 sao reservados
para os caracteres. Por exemplo, se voce tem um regra como
1

[+]

return y y t e x t ;

/ r e t u r n o p e r a t o r /

sera retornado o valor caracter para os operadores de subtracao e soma. Note que nos
colocamos o caracter menos antes do caracter mais porque senao ele poderia ser confundido
com o designador de intervalo numa classe de caracteres. Os valores do tokens gerados
comecam normalmente do valor 258 (Lex ainda reseva alguns valores para fim de arquivo
e codigos de erro). Aqui esta uma especificacao lex completa para nossa calculadora:
1

%{
#i n c l u d e y . tab . h
#i n c l u d e < s t d l i b . h>
void y y e r r o r ( char ) ;

2
3
4
5

%}

6
7

%%

8
9

[0 9]+

{
yylval = at o i ( yytext ) ;
return INTEGER;

10
11

12
13
14

[+\n ]

return y y t e x t ;

[ \t ]

; / s k i p w h i t e s p a c e /

yyerror ( invalid character ) ;

15
16
17
18
19
20

%%

21
22
23
24

int yywrap ( void ) {


return 1 ;
}

Internamente, Yacc mantem duas pilhas na memoria, a pilha de analise e a pilha de


valores. A pilha de analise contem terminais e nao-terminais e representa o estado de

CAPITULO 3. ANALISE
SINTATICA

45

analise corrente. A pilha de valores e um vetor de elementos do tipo YYSTYPE, e associa


um valor com cada elemento da pilha de analise. Por exemplo, quando lex retorna um
token INTEGER, yacc desloca este token para a pilha de analise. Ao mesmo tempo, o
yylval correspondente e deslocado para a pilha de valores. A pilha de analise e de valores
estao sempre sincronizadas. Abaixo esta a especificacao do arquivo de entrada yacc para
a nossa calculadora:
1

%{
int y y l e x ( void ) ;
void y y e r r o r ( char ) ;

2
3
4

%}

5
6
7

%token INTEGER

8
9

%%

10
11

program :

12
13
14

program expr \n
|
;

{ p r i n t f ( %d\n , $2 ) ; }

INTEGER
| expr + expr
| expr expr
;

{ $$ = $1 ; }
{ $$ = $1 + $3 ; }
{ $$ = $1 $3 ; }

15
16

expr :

17
18
19
20
21
22

%%

23
24
25
26

void y y e r r o r ( char s ) {
p r i n t f ( %s \n , s ) ;
}

27
28
29
30
31

int main ( void ) {


yyparse ( ) ;
return 0 ;
}

A secao de regras descreve a gramatica BNF discutida anteriormente. O lado esquerdo


da regra de producao, ou nao-terminal, deve estar todo justificado a` esquerda, seguido por
dois pontos. Este e seguido pelo lado direito da regra de producao. As acoes associadas as
regras devem estar entre chaves. Pela utilizacao da recursao a` esquerda, nos especificamos
que um programa consiste de zero ou mais expressoes. Cada expressao terminada por nova
linha (ENTER). Quando uma nova linha e detectada, nos escrevemos o valor associado
com a expressao. Quando nos aplicamos a regra:
1

expr : expr + expr

{ $$ = $1 + $3 ; }

Nos trocamos o lado direito da regra de producao na pilha de analise com o smbolo
nao terminal no lado esquerdo da mesma regra. Neste caso nos desempilhamos expr +
expre empilhamos expr. Nos reduzimos a pilha desempilhando tres termos e empilhando de volta um termo. Nos podemos referenciar as posicoes na pilha de valores no
codigo em C especificando $1para o primeiro termo no lado direito da regra de producao,
$2para o segundo termo, e assim por diante. $$determina o valor do topo da pilha
depois que a reducao e executada. As acoes acima adicionam os valores associados com

CAPITULO 3. ANALISE
SINTATICA

46

as duas expressoes, desempilha tres termos da pilha, e empilha de volta a soma. Entao a
pilha de analise e de valores permanecem sincronizadas.
Os valores numericos estao inicialmente todos na pilha quanto reduzimos de INTEGER
para expr. Depois que INTEGER e deslocado para a pilha, aplicamos a regra:
1

expr : INTEGER

{ $$ = $1 ; }

O token INTEGER e desempilhado da pilha de analise, seguido pelo empilhamento


de expr. Para a pilha de valores, nos desempilhamos o valor inteiro e entao empilhamos
ele de volta. Em outras palavras, nos nao fazemos nada. De fato , esta e uma operacao
default e nao precisa ser especificada. Finalmente, quando uma nova linha e encontrada,
o valor associado com expr sera apresentado na sada.
No caso de erro de sintaxe, yacc chama a funcao definida pelo usuario yyerror. Se
voce necessita modificar a interface para yyerror, voce pode alterar a implementacao que
Yacc inclui automaticamente para satisfazer as suas necessidades. A u
ltima funcao em
nossa especificacao Yacc e main. Este exemplo tem uma gramatica ambgua. Yacc emitira
avisos de conflito shift-reduce, mas processara a gramatica usando o deslocamento como
operacao default.
Nova vers
ao da calculadora
Nesta secao nos estenderemos a calculadora da secao anterior para incorporar algumas
novas funcionalidades. As novas caractersticas incluem operadores aritmeticos de multiplicacao e divisao. Parenteses pode ser usado para alterar a precedencia das operacoes
e variaveis de uma u
nica letra podem ser especificadas para comandos de atribuicao. O
exemplo seguinte ilustra algumas entradas e sadas da calculadora:
1
2
3
4
5
6
7
8
9
10

user :
calc :
user :
user :
user :
calc :
user :
calc :
user :
calc :

3
27
x =
y =
x
27
y
5
x +
37

(4 + 5)
3 (5 + 4)
5

2 y

O analisador lexico retorna os tokens VARIABLE e INTEGER. Para variavel, yylval


especifica o ndice para sym, nossa tabela de smbolos.Para este programa, sym simplesmente pega o valor da variavel associada. Quando o token INTEGER e retornado, yylval
contem o n
umero encontrado. Abaixo a especificacao para lex:
1

%{
#i n c l u d e < s t d l i b . h>
#i n c l u d e y . tab . h
void y y e r r o r ( char ) ;

2
3
4
5

%}

6
7

%%

8
9
10
11
12

/ v a r i a b l e s /
[ az ]
{
yylval = yytext a ;
return VARIABLE;

CAPITULO 3. ANALISE
SINTATICA

47

13
14
15
16
17
18
19

/ i n t e g e r s /
[0 9]+
{
yylval = at o i ( yytext ) ;
return INTEGER;
}

20
21
22

/ o p e r a t o r s /
[ +()=/ \n ] { r e t u r n y y t e x t ; }

23
24
25

/ s k i p w h i t e s p a c e /
[ \t ]
;

26
27
28

/ a n y t h i n g e l s e i s an e r r o r /
yyerror ( invalid character ) ;

29
30

%%

31
32
33
34

int yywrap ( void ) {


return 1 ;
}

A especificacao para Yacc e apresentada em seguida. Os tokens para INTEGER


e VARIABLE sao usados por yacc para criar definicoes do tipo #defines no arquivo
y.tab.h para usar em lex. Esta e seguida pela definicao da aritmetica de operadores. Nos
podemos especificar %left, para associatividade `a esquerda ou %right, para associatividade
a` direita.A u
ltima definicao listada e a quem tem maior precedencia. Entao multiplicacao
e divisao tem precedencia maior que adicao e subtracao. Todos os quatro operadores sao
associados a` esquerda. Usando esta tecnica simples, nos tiramos a ambiguidade de nossa
gramatica:
1
2
3

%token INTEGER VARIABLE


%l e f t +
%l e f t /

4
5

%{
void y y e r r o r ( char ) ;
int y y l e x ( void ) ;
int sym [ 2 6 ] ;

6
7
8
9

%}

10
11

%%

12
13

program :
program s t a t e m e n t \n
|
;

14
15
16
17
18
19
20
21

statement :
expr
| VARIABLE = expr
;

{ p r i n t f ( %d\n , $1 ) ; }
{ sym [ $1 ] = $3 ; }

22
23
24
25

expr :
INTEGER
| VARIABLE

{ $$ = sym [ $1 ] ; }

CAPITULO 3. ANALISE
SINTATICA
|
|
|
|
|
;

26
27
28
29
30
31

expr +
expr
expr
expr /
( expr

expr
expr
expr
expr
)

{
{
{
{
{

48
$$
$$
$$
$$
$$

=
=
=
=
=

$1 + $3 ;
$1 $3 ;
$1 $3 ;
$1 / $3 ;
$2 ; }

}
}
}
}

32
33

%%

34
35
36
37

void y y e r r o r ( char s ) {
p r i n t f ( %s \n , s ) ;
}

38
39
40
41
42

int main ( void ) {


yyparse ( ) ;
return 0 ;
}

3.4

Analisador Sint
atico para a Linguagem Simples

A gramatica da linguagem Simples e:


programa cabecalho variaveis T IN ICIO lista comandos T F IM
cabecalho T P ROGRAM A T IDEN T IF
variaveis
| declaracao variaveis
declaracao variaveis tipo lista variaveis declaracao variaveis
| tipo lista variaveis
tipo T LOGICO
| T IN T EIRO
lista variaveis T IDEN T IF lista variaveis
| T IDEN T IF
lista comandos comando lista comandos
|
comando entrada saida
| repeticao
| selecao
| atribuicao
entrada saida leitura | escrita
leitura T LEIA T IDEN T IF
escrita T ESCREV A expressao
repeticao T EN QT O expressao T F ACA
lista comandos T F IM EN QT O
selecao T SE expressao T EN T AO lista comandos
T SEN AO lista comandos T F IM SE

CAPITULO 3. ANALISE
SINTATICA

49

atribuicao T IDEN T IF T AT RIB expressao


expressao expressao T V EZES expressao
| expressao T DIV expressao
| expressao T M AIS expressao
| expressao T M EN OS expressao
| expressao T M AIOR expressao
| expressao T M EN OR expressao
| expressao T IGU AL expressao
| expressao T E expressao
| expressao T OU expressao
| termo
termo T IDEN T IF
| T N U M ERO
| T V
| T F
| T N AO termo
| T ABRE expressao T F ECHA
Os smbolos nao terminais (variaveis da gramatica) estao grafados com letras min
usculas
e sao: programa, cabecalho, variaveis, declaracao variaveis, tipo, lista variaveis, lista comandos,
comando, entrada saida, leitura, escrita, repeticao, condicao, atribuicao, expressao e termo.
O smbolo de partida e o nao-terminal programa.
Os smbolos terminais (alfabeto da gramatica) estao representados pelas constantes:
T PROGRAMA, T INICIO, T FIM, T IDENTIF, T INTEIRO, T LOGICO, T LEIA,
T ESCREVA, T ENQTO, T FACA, T FIMENQTO, T SE, T ENTAO, T SENAO, T FIMSE,
T ATRIB, T VEZES, T DIV, T MAIS, T MENOS, T MAIOR, T MENOR, T IGUAL,
T E, T OU, T V, T F, T NAO, T ABRE e T FECHA. Essas constantes representam
codificacoes numericas dos smbolos que sao reconhecidos e retornados pelo analisador
lexico.
Para bison, as constantes que definem as codificacoes numericas dos tokens sao definidas atraves da seguinte declaracao:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

%token
%token
%token
%token
%token
%token
%token
%token
%token
%token
%token
%token
%token
%token
%token
%token

T PROGRAMA
T INICIO
T FIM
T IDENTIF
T LEIA
T ESCREVA
T ENQTO
T FACA
T FIMENQTO
T SE
T ENTAO
T SENAO
T FIMSE
T ATRIB
T VEZES
T DIV

CAPITULO 3. ANALISE
SINTATICA

17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

%token
%token
%token
%token
%token
%token
%token
%token
%token
%token
%token
%token
%token
%token
%token

50

T MAIS
T MENOS
T MAIOR
T MENOR
T IGUAL
TE
T OU
TV
TF
T NUMERO
T NAO
T ABRE
T FECHA
T LOGICO
T INTEIRO

Os codigos utilizados aqui sao os mesmos retornados pelo analisador lexico. Basta
incluir o arquivo de cabecalho que e gerado com a declaracao dessas contantes pela ferramenta bison.
Como pode ser observado, a gramatica de expressoes usada na linguagem Simples e
ambgua. Essa ambiguidade e resolvida definindo-se prioridade entre as operacoes para a
ferramenta Yacc. Fazemos isso com a seguinte declaracao:
1
2
3
4
5

%l e f t
%l e f t
%l e f t
%l e f t
%l e f t

T E T OU
T IGUAL
T MAIOR T MENOR
T MAIS T MENOS
T VEZES T DIV

Com essa declaracao, definimos que a multiplicacao e a divisao tem associatividade


mais a` esquerda e precedencia sobre a soma e a subtracao. Soma e subtracao tem precedencia sobre Operadores relacionais Maior, Menor e Igual. Os operadores relacionais
tem precedencia sobre os operadores logicos E e OU.
As regras de producao da gramatica SIMPLES usando a notacao de bison fica:
1
2
3

programa
: c a b e c a l h o v a r i a v e i s T INICIO l i s t a c o m a n d o s T FIM
;

4
5
6
7

cabecalho
: T PROGRAMA T IDENTIF
;

8
9
10
11
12

variaveis
: / v a z i o /
| declaracao variaveis
;

13
14
15
16
17

declaracao variaveis
: tipo l i s t a v a r i a v e i s declaracao variaveis
| tipo l i s t a v a r i a v e i s
;

18
19
20
21
22

tipo
: T LOGICO
| T INTEIRO
;

CAPITULO 3. ANALISE
SINTATICA

23
24
25
26
27

lista variaveis
: T IDENTIF l i s t a v a r i a v e i s
| T IDENTIF
;

28
29
30
31
32

lista comandos
: / v a z i o /
| comando l i s t a c o m a n d o s
;

33
34
35
36
37
38
39

comando
:
|
|
|
;

entrada saida
repeticao
selecao
atribuicao

40
41
42
43
44

entrada saida
: leitura
| escrita
;

45
46
47
48

leitura
: T LEIA T IDENTIF
;

49
50
51
52

escrita
: T ESCREVA e x p r e s s a o
;

53
54
55
56

repeticao
: T ENQTO e x p r e s s a o T FACA l i s t a c o m a n d o s T FIMENQTO
;

57
58
59

60

selecao
: T SE e x p r e s s a o T ENTAO l i s t a c o m a n d o s T SENAO l i s t a c o m a n d o s
T FIMSE
;

61
62
63
64

atribuicao
: T IDENTIF T ATRIB e x p r e s s a o
;

65
66
67
68
69
70
71
72
73
74
75
76
77

expressao
: expressao
| expressao
| expressao
| expressao
| expressao
| expressao
| expressao
| expressao
| expressao
| termo
;

78
79

termo

T VEZES e x p r e s s a o
T DIV e x p r e s s a o
T MAIS e x p r e s s a o
T MENOS e x p r e s s a o
T MAIOR e x p r e s s a o
T MENOR e x p r e s s a o
T IGUAL e x p r e s s a o
T E expressao
T OU e x p r e s s a o

51

CAPITULO 3. ANALISE
SINTATICA

80
81
82
83
84
85
86

:
|
|
|
|
|
;

T IDENTIF
T NUMERO
TV
TF
T NAO termo
T ABRE e x p r e s s a o T FECHA

52

Captulo 4

MVS - M
aquina Virtual Simples
O objetivo principal do compilador para uma linguagem de programacao e construir
uma ferramenta de traducao que transforme os codigos numa linguagem de alto nvel para
instrucoes numa linguagem de maquina que possibilite a sua execucao.
Entretanto, traduzir para a linguagem de maquina de um computador real e, em geral,
uma tarefa muito trabalhosa. Envolve o conhecimento profundo da maquina alvo. Por
exemplo, o conjunto de instrucoes de uma maquina INTEL contem centenas de instrucoes,
que variam em cada versao do processador e que uma dezena de detalhes que devem ser
observados para a sua apropriada utilizacao.
Ao inves de traduzir, entao, os programas-fonte para a linguagem de maquina de um
computador real, definiremos uma maquina hipotetica, mais conveniente para o desenvolvimento de um compilador didatico. Desta forma, poderemos dar mais atencao para os
detalhes do compilador sem termos que nos preocupar com detalhes de uma maquina real.
Como efeito colateral, estaremos desenvolvendo um compilador de codigo 100% portavel
(como acontece com o codigo-objeto JAVA). A partir do momento que o programa estiver
traduzido para codigo desta maquina hipotetica (maquina virtual), basta ter o programa
de interpreta estes codigos para executar o programa em qualquer plataforma (arquitetura+sistema operacional).

4.1

Caractersticas gerais da MVS

A Maquina Virtual Simples (MVS) e uma maquina baseada na Maquina de Execucao


Pascal, proposta por Tomas Kowaltowski. Assim como MEPA e a maquina virtual Java
(JVM), MVS e uma maquina baseada em pilha. Essa caracterstica e muito apropriada
para traducao de estruturas encontradas em linguagens de programacao C-Like e PascalLike, como recursividade, estruturas aninhadas, etc.
A memoria da MVS e composta de duas regioes:
1. A regiao de programa P que contera as instrucoes do programa em MVS que a
maquina esta executando.
2. A regiao de pilha de dados M que contera os valores manipulados pelas instrucoes
MVS.
As regioes de memoria P e M funcionam como vetores com ndices numerados de zero
ate uma tamanho maximo. Alem disso, MVS tem tres registradores que sao usados para
indexar posicoes no programa P , nos dados M e enderecar as variaveis locais. Sao eles:
1. O registrador de programa i contem o endereco da proxima instrucao a ser executada, que sera, portanto, P [i]. Esse registrador e incrementado automaticamente
apos a execucao de cada instrucao. Exceto para as instrucoes de desvio, que alteram
de forma absoluta o valor de i.
53


CAPITULO 4. MVS - MAQUINA
VIRTUAL SIMPLES

54

2. O registrador s indicara o elemento no topo da pilha cujo valor sera dado, portanto,
por M [s]. Grande parte das instrucoes da MVS sao relativas as posicoes do topo da
pilha M , conforme sera apresentado na proxima secao.
3. O registrador de base d que contem o endereco de base no qual a variavel esta inserida. Esse u
nico registrador e suficiente para generalizar a forma de enderecamento
das variaveis locais e globais no programa. O enderecamento de variavel global pode
ser mais simples, no entanto, por questao de simplificacao da maquina, usaremos
enderecamento indireto para variaveis locais e globais.
Uma vez que o programa MVS esta carregado na regiao P , e os registradores tem seus
valores iniciais, o funcionamento da maquina e muito simples. As instrucoes indicadas
pelo registrador i sao executadas ate que seja encontrada uma instrucao de parada ou
um erro. A execucao de cada instrucao incrementa i de uma unidade para posicionar na
proxima instrucao do programa, i i + 1, exceto as instrucoes que envolvem desvio.

4.1.1

Descri
c
ao das instruc
oes MVS

Apresentamos o efeito de cada instrucao MVS numa pseudo-linguagem de programacao,


indicando as modificacoes no estado dos registradores e da memoria na MVS. Omitimos
nesta descricao a operacao i i + 1 que esta implcita em todas as instrucoes, exceto
quando ha desvio. Adotaremos, tambem, a convencao de representar os valores booleanos
(logicos) por inteiros: true por 1 e false por 0.
As instrucoes de MVS estao sintetizadas na Tabela 4.1.

Figura 4.1: Configuracoes da pilha de dados M na avaliacao de uma expressao

Traduc
ao de Express
oes
Como a maquina MVS e baseada em pilha, as expressoes em notacao infixa (com o
operacao entre os operandos) da linguagem fonte devem ser traduzidas para uma sequencia
de instrucoes em NPR (Notacao Polonesa Reversa, na qual a operacao e colocada apos
os seus operandos). A avaliacao de expressoes em NPR pela maquina baseada em pilha e
trivial.


CAPITULO 4. MVS - MAQUINA
VIRTUAL SIMPLES

Instruc
ao
CRCT k
CRVG n
ARZG n
CMMA
CMME
CMIG
DISJ
CONJ
NEGA
SOMA
SUBT
MULT
DIVI
DSVS p
DSVF p
LEIA
ESCR
NADA
INPP

FIMP
AMEM n

Tabela 4.1: Resumo das instrucoes da Maquina Virtual Simples


Micro-c
odigo
ss+1
M [s] k
ss+1
M [s] M [n]
M [n] M [s]
ss1
SE M [s 1] > M [s] ENTAO M [s 1] 1 SENAO M [s 1] 0;
ss1
SE M [s 1] < M [s] ENTAO M [s 1] 1 SENAO M [s 1] 0
ss1
SE M [s 1] = M [s] ENTAO M [s 1] 1 SENAO M [s 1] 0
ss1
SE M [s 1] ou M [s] ENTAO M [s 1] 1 SENAO M [s 1] 0
ss1
SE M [s 1] e M [s] ENTAO M [s 1] 1 SENAO M [s 1] 0
ss1
M [s] 1 M [s]
M [s 1] M [s 1] + M [s]
ss1
M [s 1] M [s 1] M [s]
ss1
M [s 1] M [s 1] M [s]
ss1
M [s 1] M [s 1]/M [s]
ss1
ip
SE M [s] = 0 ENTAO i p SENAO i i + 1
ss1
ss+1
M [s] Entrada
Escreve M [s]
ss1
Nao faz nada
s 1
i1
D 0;
Finaliza a execucao
ss+n

55


CAPITULO 4. MVS - MAQUINA
VIRTUAL SIMPLES

56

Exemplo 1 Considere a expressao B * (A + 30) - A e suponha que os enderecos atribudos


pelo compilador as variaveis A e B sao 1 e 3, respectivamente. Considere ainda que o
valor da variavel A e 10 e que o valor da variavel B e 20.
A traducao para MVS da expressao desse exemplo e:
1
2
3
4
5
6
7

CRVG
CRVG
CRCT
SOMA
MULT
CRVG
SUBT

3
1
10

Na execucao dessa sequencia de instrucoes pela MVS, obtemos as configuracoes da


pilha de dados M, conforme ilustrado na Figura 4.1. Para essa simulacao consideramos o
valor inicial do registrador s igual a 4.
Traduc
ao do comando de atribuic
ao
Para traducao da atribuicao na forma V < E, onde V representa uma variavel qualquer e E representa uma expressao, usa-se a seguinte instrucao de armazenamento:
Instruc
ao Micro-c
odigo
ARZG n M [n] M [s]
ss1
O compilador deve traduzir a expressao, conforme ja foi discutido anteriormente, e
apos essa traducao, o resultado da expressao deve ser armazenado na variavel no lado
esquerdo da atribuicao, usando a instrucao ARZG.
Exemplo 2 Considere o comando de atribuicao A < A + B, onde os enderecos das
variaveis A e B sao 10 e 12 respectivamente.
A traducao MVS para essa atribuicao e:
1
2
3
4

CRVG
CRVG
SOMA
ARZG

10
12
12

Traduc
ao do comando de repetic
ao e selec
ao
Para traduzir os comandos de repeticao e selecao sao usados as instrucoes de desvio
condicional DSVF (Desvia se Falso), o desvio incondicional DSVS (Desvia Sempre) e a
instrucao NADA para receber o rotulo para onde sera realizado o desvio da execucao do
programa MVS. O micro-codigo dessas instrucoes esta sintetizado na tabela seguinte:
Instruc
ao Micro-c
odigo
DSVS p
ip
DSVF p
SE M [s] = 0 ENTAO i p SENAO i i + 1
ss1
NADA
Nao faz nada
O operando p nas instrucoes DSVF e DSVS determinam um rotulo dentro do proprio
codigo MVS para onde a execucao devera ou nao ser desviada.


CAPITULO 4. MVS - MAQUINA
VIRTUAL SIMPLES

57

Figura 4.2: Esquema de traducao do comando de selecao para MVS


A instrucao NADA e usada somente para receber o rotulo. Numa fase de otimizacao
a instrucao NADA pode ser trocada pela proxima instrucao no programa MVS.
O comando de selecao da forma se E entao C1 senao C2, onde E representa uma expressao e C1 e C2 representam listas de comandos, pode ser traduzido usando o esquema
de Figura 4.2.
Observe que, na execucao do codigo MVS, se o resultado que restar da avaliacao da
expressao for falso, o desvio condicional DSVF L1 e realizado e somente os comandos
C2 sao executados. De outra forma, apos a execucao da lista de comandos C1, o desvio
incondicional DSVS L2 e realizado para evitar a execucao da lista de comandos C2.
Exemplo 3 Considere o seguinte trecho de programa com um comando de selecao em
linguagem Simples:
A < V
se A
e n t a o A < F
s e n a o A < V
fimse

1
2
3
4
5

A traducao MVS para essa selecao e (o endereco da variavel A e zero):


1
2
3
4
5
6
7
8

L1

9
10
11

L2

CRCT
ARZG
CRVG
DSVF
CRCT
ARZG
DSVS
NADA
CRCT
ARZG
NADA

1
0
0
L1
0
0
L2
1
0

O comando de repeticao da forma enquanto E faca C fimenquanto, onde E representa


uma expressao e C representa uma lista de comandos, pode ser traduzido usando o esquema de Figura 4.3.


CAPITULO 4. MVS - MAQUINA
VIRTUAL SIMPLES

58

Figura 4.3: Esquema de traducao do comando de repeticao para MVS


Observe que a palavra reservada enquanto marca um local programa (rotulo) para onde
a execucao deve ser desviada de forma incondicional toda vez que a lista de comandos
for executada. Por outro lado, se o resultado da avaliacao da expressao que condiciona a
repeticao for falso, o programa deve desviar a execucao para fora da repeticao.
Exemplo 4 Considere o seguinte trecho de programa com um comando de repeticao em
linguagem Simples:
x < 1
e n q u a n t o x < 10 f a c a
x < 2 x
fimenquanto

1
2
3
4

A traducao MVS para essa repeticao e (o endereco da variavel x e zero):


1
2
3

L1

4
5
6
7
8
9
10
11
12
13

L2

CRCT
ARZG
NADA
CRVG
CRCT
CMME
DSVF
CRCT
CRVG
MULT
ARZG
DSVS
NADA

1
0
0
10
L2
2
0
0
L1

Traduc
ao dos comandos de entrada e sada
Para traducao dos comandos leia V e escreva E, onde V e uma variavel e E uma
expressao, usaremos as instrucoes MVS:
Instruc
ao Micro-c
odigo
LEIA
ss+1
M [s] Entrada
ESCR
Escreve M [s]
ss1


CAPITULO 4. MVS - MAQUINA
VIRTUAL SIMPLES

59

Para traducao do leia X, primeiro gera-se uma instrucao LEIA e o resultado lido deve
ser armazenado na variavel X.
Para traducao de escreva A + B, primeiro traduz-se a expressao A + B e, ao final,
gera-se uma instrucao ESCR, para que o resultado a expressao seja apresentado na sada
padrao.
Exemplo 5 Considere o seguinte trecho de programa com comandos de leitura e escrita
em linguagem Simples:
1
2
3

leia A
leia B
escreva A + B

A traducao MVS e:
1
2
3
4
5
6
7
8

LEIA
ARZG
LEIA
ARZG
CRVG
CRVG
SOMA
ESCR

0
1
0
1

Considere, nessa traducao, que o endereco atribudo pelo compilador `a variavel A e


zero e a` variavel B e um.
Traduc
ao dos comandos de entrada e sada
Para traducao de um programa em linguagem Simples completo usaremos as seguintes
instrucoes MVS:
Instruc
ao Micro-c
odigo
INPP
s 1
i1
D 0;
FIMP
Finaliza a execucao
AMEM n s s + n
Onde:
INPP - instrucao MVS que serve para colocar a maquina de execucao numa configuracao inicial;
FIMP - instrucao que finaliza a execucao de um programa.
AMEM - instrucao que aloca memoria para as variaveis globais do programa.
Exemplo 6 Considere o seguinte programa Simples:
1
2
3
4
5
6
7

programa r e p e t e
inteiro i j
inicio
i < 1
e n q u a n t o i < 10 f a c a
j < 1
e n q u a n t o j < 10 f a c a


CAPITULO 4. MVS - MAQUINA
VIRTUAL SIMPLES

8
9
10
11
12
13

escreva i + j
j < j + 1
fimenquanto
i < i + 1
fimenquanto
fimprograma

A traducao MVS e:
1
2
3
4
5

L1

6
7
8
9
10
11
12

L3

13
14
15
16
17
18
19
20
21
22
23
24
25
26

L4

27
28
29
30
31
32
33

L2

INPP
AMEM
CRCT
ARZG
NADA
CRVG
CRCT
CMME
DSVF
CRCT
ARZG
NADA
CRVG
CRCT
CMME
DSVF
CRVG
CRVG
SOMA
ESCR
CRVG
CRCT
SOMA
ARZG
DSVS
NADA
CRVG
CRCT
SOMA
ARZG
DSVS
NADA
FIMP

2
1
0
0
10
L2
1
1
1
10
L4
0
1

1
1
1
L3
0
1
0
L1

60

Captulo 5

An
alise Sem
antica e Gera
c
ao de
C
odigo
Nesse captulo estao apresentadas as modificacoes do analisador lexico e analisador
sintatico para possibilitar algumas verificacoes semanticas e a geracao do codigo Simples
para Maquina MVS.

5.1
1
2
3
4
5

Func
oes Utilit
arias

/
E s t r u t u r a s e R o t i n a s U t i l i t a r i a s do Compilador

Por L u i z Eduardo da S i l v a
/

6
7
8
9
10
11

/
L i m i t e s das e s t r u t u r a s
/
#define TAM TSIMB 100 / Tamanho da t a b e l a de s i m b o l o s /
#define TAM PSEMA 100 / Tamanho da p i l h a s e m a n t i c a
/

12
13
14
15
16
17
18
19
20
21
22
23

/
Variaveis globais
/
int TOPO TSIMB
= 0 ; / TOPO da t a b e l a de s i m b o l o s /
int TOPO PSEMA
= 0 ; / TOPO da p i l h a s e m a n t i c a /
int ROTULO
= 0 ; / Proximo numero de r o t u l o /
int CONTA VARS
= 0 ; / Numero de v a r i a v e i s /
int POS SIMB ;
/ Pos . na t a b e l a de s i m b o l o s /
int aux ;
/ v a r i a v e l a u x i l i a r /
int numLinha = 1 ; / numero da l i n h a no programa /
char atomo [ 3 0 ] ;
/ nome de um i d e n t i f . ou numero /

24
25
26
27
28
29
30
31
32
33
34
35
36
37

/
Rotina g e r a l de t r a t a m e n t o de e r r o
/
void ERRO ( char msg , . . . ) {
char formato [ 2 5 5 ] ;
v a l i s t arg ;
v a s t a r t ( arg , msg ) ;
s p r i n t f ( formato , \n%d : , numLinha ) ;
s t r c a t ( formato , msg ) ;
s t r c a t ( formato , \n\n ) ;
p r i n t f ( \nERRO no programa ) ;
v p r i n t f ( formato , a r g ) ;
va end ( a r g ) ;

61

DE CODIGO

CAPITULO 5. ANALISE
SEMANTICA
E GERAC
AO
exit (1) ;

38
39

40
41
42
43
44
45
46
47

/
Tabela de S i m b o l o s
/
struct e l e m t a b s i m b o l o s {
char i d [ 3 0 ] ;
int d e s l o c a ;
} TSIMB [ TAM TSIMB ] , e l e m t a b ;

48
49
50
51
52

/
P i l h a Semantica
/
int PSEMA[TAM PSEMA ] ;

53
54
55
56
57
58
59
60
61
62
63
64
65

/
Funcao que BUSCA um s i m b o l o na t a b e l a de s i m b o l o s .

Retorna 1 s e o s i m b o l o nao e s t a na t a b e l a

Retorna i , onde i e o i n d i c e do s i m b o l o na t a b e l a

s e o s i m b o l o e s t a na t a b e l a
/
int b u s c a s i m b o l o ( char i d e n t )
{
int i = TOPO TSIMB1;
f o r ( ; strcmp (TSIMB [ i ] . id , i d e n t ) && i >= 0 ; i ) ;
return i ;
}

66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86

/
Funcao que INSERE um s i m b o l o na t a b e l a de s i m b o l o s .

Se j a e x i s t e um s i m b o l o com mesmo nome e mesmo n i v e l

uma mensagem de e r r o e a p r e s e n t a d a e o programa e

interrompido .
/
void i n s e r e s i m b o l o ( struct e l e m t a b s i m b o l o s elem )
{
i f (TOPO TSIMB == TAM TSIMB) {
ERRO ( OVERFLOW t a b e l a de s i m b o l o s ) ;
}
else {
POS SIMB = b u s c a s i m b o l o ( elem>i d ) ;
i f (POS SIMB != 1) {
ERRO ( I d e n t i f i c a d o r [% s ] d u p l i c a d o , elem>i d ) ;
}
TSIMB [ TOPO TSIMB ] = elem ;
TOPO TSIMB++;
}
}

87
88
89
90
91
92
93
94
95

/
Funcao de i n s e r c a o de uma v a r i a v e l na t a b e l a de s i m b o l o s
/
void i n s e r e v a r i a v e l ( char i d e n t ) {
s t r c p y ( e l e m t a b . id , i d e n t ) ;
e l e m t a b . d e s l o c a = CONTA VARS;
i n s e r e s i m b o l o (& e l e m t a b ) ;

62

DE CODIGO

CAPITULO 5. ANALISE
SEMANTICA
E GERAC
AO

96

97
98
99
100
101
102
103
104
105
106

/
R o t i n a s para manutencao da PILHA SEMANTICA
/
void empilha ( int n ) {
i f (TOPO PSEMA == TAM PSEMA) {
ERRO ( OVERFLOW P i l h a Semantica ) ;
}
PSEMA[TOPO PSEMA++] = n ;
}

107
108
109
110
111
112
113

int d e s e m p i l h a ( ) {
i f (TOPO PSEMA == 0 ) {
ERRO ( UNDERFLOW P i l h a Semantica ) ;
}
return PSEMA[TOPO PSEMA ] ;
}

5.2
1

Modificac
ao do analisador l
exico

%{

2
3

#include s i n t a t i c o . h

4
5

%}

6
7
8
9
10

identificador
numero
espaco
novalinha

[ azAZ ] ( [ azAZ0 9])


[0 9]+
[ \ t ]+
[\n ]

11
12

%x c o m e n t a r i o

13
14

%%

15
16
17
18

programa
inicio
fimprograma

return T PROGRAMA;
return T INICIO ;
return T FIM ;

leia
escreva

return T LEIA ;
return T ESCREVA ;

se
entao
senao
fimse

return
return
return
return

enquanto
faca
fimenquanto

return T ENQTO;
return T FACA ;
return T FIMENQTO;


div

return
return
return
return

19
20
21
22
23
24
25
26

T SE ;
T ENTAO;
T SENAO ;
T FIMSE ;

27
28
29
30
31
32
33
34
35

T MAIS ;
T MENOS;
T VEZES ;
T DIV ;

63

DE CODIGO

CAPITULO 5. ANALISE
SEMANTICA
E GERAC
AO

36
37
38
39

>
<
=

return T MAIOR ;
return T MENOR;
return T IGUAL ;

e
ou
nao

return T E ;
return T OU ;
return T NAO ;

<
(
)

return T ATRIB ;
return T ABRE ;
return T FECHA ;

inteiro
logico
V
F

return
return
return
return

40
41
42
43
44
45
46
47
48
49
50
51
52

T INTEIRO ;
T LOGICO ;
T V;
T F;

53
54
55
56
57
58
59

{ i d e n t i f i c a d o r } { s t r c p y ( atomo , y y t e x t ) ;
return T IDENTIF ; }
{numero}
{ s t r c p y ( atomo , y y t e x t ) ;
return T NUMERO; }
{ espaco }
/ nao f a z nada /
{ novalinha }
numLinha++;

60
61

// .

/ c o m e n t a r i o de l i n h a /

62
63
64
65
66

/
<comentario > /
<comentario >.
<comentario >\n

BEGIN( c o m e n t a r i o ) ;
BEGIN( INITIAL ) ;
/ nao f a z nada /
numLinha++;

ERRO ( ERRO LEXICO ) ;

67
68
69
70

%%

5.3
1
2
3
4
5

Modificac
ao do analisador sint
atico

A N A L I S A D O R
S I N T A T I C O

Por L u i z Eduardo da S i l v a
JANEIRO2013
/

6
7
8
9
10
11

%{
#include
#include
#include
#include

<s t d i o . h>
<s t r i n g . h>
< s t d l i b . h>
<s t d a r g . h>

12
13
14
15

#include u t i l s . c
#include l e x i c o . c
%}

16
17
18

// Simbolo de p a r t i d a
%s t a r t programa

64

DE CODIGO

CAPITULO 5. ANALISE
SEMANTICA
E GERAC
AO

19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

// S i m b o l o s t e r m i n a i s
%token T PROGRAMA
%token T INICIO
%token T FIM
%token T IDENTIF
%token T LEIA
%token T ESCREVA
%token T ENQTO
%token T FACA
%token T FIMENQTO
%token T SE
%token T ENTAO
%token T SENAO
%token T FIMSE
%token T ATRIB
%token T VEZES
%token T DIV
%token T MAIS
%token T MENOS
%token T MAIOR
%token T MENOR
%token T IGUAL
%token T E
%token T OU
%token T V
%token T F
%token T NUMERO
%token T NAO
%token T ABRE
%token T FECHA
%token T LOGICO
%token T INTEIRO

52
53
54
55
56
57
58

// P r e c e d e n c i a e a s s o c i a t i v i d a d e
%l e f t T E T OU
%l e f t T IGUAL
%l e f t T MAIOR T MENOR
%l e f t T MAIS T MENOS
%l e f t T VEZES T DIV

59
60

%%

61
62
63
64
65
66
67
68
69
70

// Regras de producao
programa
: cabecalho
{ p r i n t f ( \tINPP\n ) ; }
variaveis
T INICIO l i s t a c o m a n d o s
T FIM
{ p r i n t f ( \tFIMP\n ) ; }
;

71
72
73
74

cabecalho
: T PROGRAMA T IDENTIF
;

75
76

variaveis

65

DE CODIGO

CAPITULO 5. ANALISE
SEMANTICA
E GERAC
AO
:
|
;

77
78
79

/ v a z i o /
declaracao variaveis

80
81
82
83
84
85
86
87
88
89
90
91

declaracao variaveis
: declaracao variaveis
tipo
{ CONTA VARS = 0 ; }
lista variaveis
{ p r i n t f ( \tAMEM\ t%d\n , CONTA VARS) ; }
| tipo
{ CONTA VARS = 0 ; }
lista variaveis
{ p r i n t f ( \tAMEM\ t%d\n , CONTA VARS) ; }
;

92
93
94
95
96

tipo
: T LOGICO
| T INTEIRO
;

97
98
99
100
101

lista variaveis
: lista variaveis
T IDENTIF
{ i n s e r e v a r i a v e l ( atomo ) ; CONTA VARS++; }

102
103
104
105

| T IDENTIF
{ i n s e r e v a r i a v e l ( atomo ) ; CONTA VARS++; }
;

106
107
108
109
110

lista comandos
: / v a z i o /
| comando l i s t a c o m a n d o s
;

111
112
113
114
115
116
117

comando
:
|
|
|
;

entrada saida
repeticao
selecao
atribuicao

118
119
120
121
122

entrada saida
: leitura
| escrita
;

123
124
125
126
127
128
129
130
131
132
133
134

leitura
: T LEIA
T IDENTIF
{
POS SIMB = b u s c a s i m b o l o ( atomo ) ;
i f (POS SIMB == 1)
ERRO ( V a r i a v e l [% s ] nao d e c l a r a d a ! ,
atomo ) ;
else {
p r i n t f ( \tLEIA\n ) ;
p r i n t f ( \tARZG\ t%d\n ,

66

DE CODIGO

CAPITULO 5. ANALISE
SEMANTICA
E GERAC
AO
TSIMB [ POS SIMB ] . d e s l o c a ) ;

135

136

137
138

139
140
141
142
143

escrita
: T ESCREVA e x p r e s s a o
{ p r i n t f ( \tESCR\n ) ; }
;

144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164

repeticao
: T ENQTO
{
p r i n t f ( L%d\tNADA\n , ++ROTULO) ;
empilha (ROTULO) ;
}
expressao
T FACA
{
p r i n t f ( \tDSVF\ tL%d\n,++ROTULO) ;
empilha (ROTULO) ;
}
lista comandos
T FIMENQTO
{
aux = d e s e m p i l h a ( ) ;
p r i n t f ( \tDSVS\ tL%d\n , d e s e m p i l h a ( ) ) ;
p r i n t f ( L%d\tNADA\n , aux ) ;
}
;

165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186

selecao
: T SE
expressao
{
p r i n t f ( \tDSVF\ tL%d\n , ++ROTULO) ;
empilha (ROTULO) ;
}
T ENTAO
lista comandos
T SENAO
{
p r i n t f ( \tDSVS\ tL%d\n , ++ROTULO) ;
p r i n t f ( L%d\tNADA\n , d e s e m p i l h a ( ) ) ;
empilha (ROTULO) ;
}
lista comandos
T FIMSE
{
p r i n t f ( L%d\tNADA\n , d e s e m p i l h a ( ) ) ;
}
;

187
188
189
190
191
192

atribuicao
: T IDENTIF
{
POS SIMB = b u s c a s i m b o l o ( atomo ) ;
i f (POS SIMB == 1)

67

DE CODIGO

CAPITULO 5. ANALISE
SEMANTICA
E GERAC
AO
ERRO ( V a r i a v e l [% s ] nao d e c l a r a d a ! ,
atomo ) ;

193
194

else

195

empilha (TSIMB [ POS SIMB ] . d e s l o c a ) ;


}
T ATRIB
expressao
{ p r i n t f ( \tARZG\ t%d\n , d e s e m p i l h a ( ) ) ; }

196
197
198
199
200

201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223

expressao
: e x p r e s s a o T VEZES e x p r e s s a o
{ p r i n t f ( \tMULT\n ) ; }
| e x p r e s s a o T DIV e x p r e s s a o
{ p r i n t f ( \ tDIVI \n ) ; }
| e x p r e s s a o T MAIS e x p r e s s a o
{ p r i n t f ( \tSOMA\n ) ; }
| e x p r e s s a o T MENOS e x p r e s s a o
{ p r i n t f ( \tSUBT\n ) ; }
| e x p r e s s a o T MAIOR e x p r e s s a o
{ p r i n t f ( \tCMMA\n ) ; }
| e x p r e s s a o T MENOR e x p r e s s a o
{ p r i n t f ( \tCMME\n ) ; }
| e x p r e s s a o T IGUAL e x p r e s s a o
{ p r i n t f ( \tCMIG\n ) ; }
| expressao T E expressao
{ p r i n t f ( \tCONJ\n ) ; }
| e x p r e s s a o T OU e x p r e s s a o
{ p r i n t f ( \ tDISJ \n ) ; }
| termo
;

224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246

termo
: T IDENTIF
{
POS SIMB = b u s c a s i m b o l o ( atomo ) ;
i f (POS SIMB == 1)
ERRO ( V a r i a v e l [% s ] nao d e c l a r a d a ! ,
atomo ) ;
else {
p r i n t f ( \tCRVG\ t%d\n ,
TSIMB [ POS SIMB ] . d e s l o c a ) ;
}
}
| T NUMERO
{ p r i n t f ( \tCRCT\ t%s \n , atomo ) ; }
| TV
{ p r i n t f ( \tCRCT\ t 1 \n ) ; }
| TF
{ p r i n t f ( \tCRCT\ t 0 \n ) ; }
| T NAO termo
{ p r i n t f ( \tNEGA\n ) ; }
| T ABRE e x p r e s s a o T FECHA
;

247
248
249
250

%%
/++
|
Corpo p r i n c i p a l do programa COMPILADOR
|

68

DE CODIGO

CAPITULO 5. ANALISE
SEMANTICA
E GERAC
AO

251

++/

252
253
254

yywrap ( ) {
}

255
256
257
258
259

y y e r r o r ( char s )
{
ERRO ( ERRO SINTATICO ) ;
}

260
261
262
263
264

main ( )
{
yyparse ( ) ;
}

5.4
1
2
3
4
5
6
7

Simulador da M
aquina MVS

Simulador da Maquina V i r t u a l S i m p l e s (MVS)

Por L u i z Eduardo da S i l v a
/
#include <s t d i o . h>
#include <s t r i n g . h>
#include < s t d l i b . h>

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

/
Conjunto de i n s t r u c o e s mnemonicas da MVS
/
#define TOTALINST 21
char i n s t [ TOTALINST ] = {
CRVG , / Carrega v a l o r /
CRCT , / Carrega c o n s t a n t e /
SOMA , / Soma /
SUBT , / S u b t r a i /
MULT , / M u l t i p l i c a /
DIVI , / D i v i d e ( d i v i s a o i n t e i r a ) /
CMIG , / Compara s e i g u a l /
CMMA , / Compara s e maior /
CMME , / Compara s e menor /
CONJ , / Conjuncao e l o g i c o /
DISJ , / D i s j u n c a o ou l o g i c o /
NEGA , / Negacao nao l o g i c o /
ARZG , / Armazena na v a r i a v e l /
DSVS , / D e sv i a sempre /
DSVF , / D e sv i a s e f a l s o /
NADA , / Nada /
ESCR , / E s c r e v e /
LEIA , / Le /
INPP , / I n i c i a Programa P r i n c i p a l /
AMEM , / Aloca memoria /
FIMP / Fim do programa /
};

36
37
38
39

enum c o d i n s t {CRVG, CRCT, SOMA, SUBT, MULT, DIVI , CMIG,


CMMA, CMME, CONJ, DISJ , NEGA, ARZG, DSVS, DSVF, NADA, ESCR,
LEIA , INPP , AMEM, FIMP} ;

69

DE CODIGO

CAPITULO 5. ANALISE
SEMANTICA
E GERAC
AO

40
41
42
43
44
45
46
47
48
49

/
R e g i o e s do ambiente de e x e c u c a o da MVS
/
struct prog { int r , i , o ; }
P [ 5 0 0 ] ; / Regiao do Programa /
int
L [ 5 0 ] ; / P o s i c a o dos r o t u l o s /
int
M[ 5 0 0 ] ; / P i l h a M Dados do programa /

50
51
52
53
54
55
56
57

/
R o t i n a s da MVS
/
int b u s c a i n s t r u c a o ( char s ) ;
int c a r r e g a p r o g r a m a ( char s , int nro ) ;
void mostra programa ( int nro ) ;
void e x e c u t a p r o g r a m a ( void ) ;

58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79

/
Funcao p r i n c i p a l .
Carrega o c o d i g o p a s s a d o em l i n h a de comando e e x e c u t a
/
main ( int argc , char argv [ ] ) {
int i , n r o i n s t ;
argc ;
argv++;
i f ( argc < 1) {
p u t s ( \nMVS Maquina V i r t u a l S i m p l e s ) ;
p u t s ( USO: mvs <nomedoarquivo . mvs>\n\n ) ;
exit (0) ;
}
i f ( c a r r e g a p r o g r a m a ( argv [ 0 ] , &n r o i n s t ) )
{
mostra programa ( n r o i n s t ) ;
executa programa ( ) ;
p r i n t f ( Fim do programa . \ n ) ;
}
return 1 ;
}

80
81
82
83
84
85
86
87
88
89
90

/
Funcao que c o d i f i c a as i n s t r u c o e s .
Recebe o nome da i n s t r u c a o e r e t o r n a um numero .
/
int b u s c a i n s t r u c a o ( char s )
{
int i ;
f o r ( i = TOTALINST1; i >= 0 && strcmp ( i n s t [ i ] , s ) ; i ) ;
return i ;
}

91
92
93
94
95
96
97

/
Carrega o programa MVS.
Recebe o nome do a r q u i v o com o programa para MVS e
r e t o r n a o numero de l i n h a s do programa .
/
int c a r r e g a p r o g r a m a ( char s , int nro )

70

DE CODIGO

CAPITULO 5. ANALISE
SEMANTICA
E GERAC
AO

98

{
FILE arq ;
char l i n h a [ 1 0 0 ] , p , s t r [ 6 ] ;
int j ;

99
100
101
102

i f ( ( arq = f o p e n ( s , r ) ) == NULL)
{
p u t s ( \n\ nErro na a b e r t u r a do a r q u i v o \n\n ) ;
return 0 ;
}
nro = 0 ;
while ( ! f e o f ( arq ) )
{
f g e t s ( l i n h a , 1 0 0 , arq ) ;
l i n h a [ s t r l e n ( l i n h a ) 1]= \0 ;
/
Tres t i p o s de i n s t r u c o e s :
1 . Com r o t u l o :
L1 : \tNADA\n
2 . Sem r o t u l o nem argumento :
\tINPP\n
3 . Com argumento :
\tCRCT\ t 4 \n
ou
\tDSVF\ tL1 \n
/
i f ( l i n h a [ 0 ] == L ) / t i p o 1 /
{
p = ( char ) s t r t o k ( l i n h a , \ t ) ;
p++;
P [ nro ] . r = a t o i ( p ) ;
P[ nro ] . i = b u s c a i n s t r u c a o ( NADA ) ;
P [ nro ] . o = 1;
L [ P [ nro ] . r ] = nro ;
}
e l s e / t i p o 2 ou 3 /
{
p = ( char ) s t r t o k ( l i n h a , \ t ) ;
P [ nro ] . r = 1;
P [ nro ] . i = b u s c a i n s t r u c a o ( p ) ;
p = ( char ) s t r t o k (NULL, \ t ) ;
i f ( ! p ) / t i p o 2 /
P [ nro ] . o = 1;
else
/ t i p o 3 /
{
i f ( p == L ) p++;
P [ nro ] . o = a t o i ( p ) ;
}
i f (P [ nro ] . i == TOTALINST1)
{
( nro )++;
break ; / INSTRUCAO FIM /
}
}
( nro )++; // proxima i n s t r u c a o
}
f c l o s e ( arq ) ;
return 1 ;

103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155

71

DE CODIGO

CAPITULO 5. ANALISE
SEMANTICA
E GERAC
AO

156
157
158
159
160
161
162

void mostra programa ( int nro ) {


int i ;
f o r ( i = 0 ; i < nro ; i ++) {
p r i n t f ( %d\ t%s \ t%d\n , P [ i ] . r , i n s t [ P [ i ] . i ] , P [ i ] . o ) ;
}
}

163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213

/
Funcao que e x e c u t a o programa MVS
A p a r t i r do v e t o r P ( programa ) p r e e n c h i d o , e x e c u t a uma
a uma as i n s t r u c o e s do programa .
/
void e x e c u t a p r o g r a m a ( void )
{
int i = 0 , s ;
char numstr [ 6 ] ;
while ( 1 ) {
switch (P [ i ] . i ) {
case CRCT : s++; M[ s ] = P [ i ] . o ; i ++;
break ;
case CRVG : s++; M[ s ] = M[ P [ i ] . o ] ; i ++;
break ;
case ARZG : M[ P [ i ] . o ] = M[ s ] ; s ; i ++;
break ;
case SOMA : M[ s 1] = M[ s 1] + M[ s ] ; s ; i ++;
break ;
case SUBT : M[ s 1] = M[ s 1] M[ s ] ; s ; i ++;
break ;
case MULT : M[ s 1] = M[ s 1] M[ s ] ; s ; i ++;
break ;
case DIVI : M[ s 1] = M[ s 1] / M[ s ] ; s ; i ++;
break ;
case CONJ : i f (M[ s 1] && M[ s ] ) M[ s 1]=1;
e l s e M[ s 1] = 0 ;
s ; i ++;
break ;
case DISJ : i f (M[ s 1] | | M[ s ] ) M[ s 1] = 1 ;
e l s e M[ s 1] = 0 ;
s ; i ++;
break ;
case NEGA : M[ s ] = 1M[ s ] ; i ++;
break ;
case CMME : i f (M[ s 1] < M[ s ] ) M[ s 1] = 1 ;
e l s e M[ s 1] = 0 ;
s ; i ++;
break ;
case CMMA : i f (M[ s 1] > M[ s ] ) M[ s 1] = 1 ;
e l s e M[ s 1] = 0 ;
s ; i ++;
break ;
case CMIG : i f (M[ s 1] == M[ s ] ) M[ s 1] = 1 ;
e l s e M[ s 1] = 0 ;
s ; i ++;
break ;
case DSVS : i = L [ P [ i ] . o ] ;
break ;
case DSVF : i f (M[ s ] == 0 ) i = L [ P [ i ] . o ] ;

72

DE CODIGO

CAPITULO 5. ANALISE
SEMANTICA
E GERAC
AO

214
215

case NADA

216
217

case FIMP
case LEIA

218
219
220
221
222

case ESCR

223
224

case AMEM

225
226

case INPP

227
228

default :

229
230

231

232
233

e l s e i ++; s ;
break ;
: i ++;
break ;
: p r i n t f ( \n\n ) ; return ;
: s++; p r i n t f ( ? ) ;
f g e t s ( numstr , 5 , s t d i n ) ;
M[ s ] = a t o i ( numstr ) ; i ++;
break ;
: p r i n t f ( \ nSaida = %d , M[ s ] ) ; s ; i ++;
break ;
: s = s + P [ i ] . o ; i ++;
break ;
: s = 1; i ++;
break ;
p u t s ( I n s t r u c a o MVS d e s c o n h e c i d a ! ) ;
exit (0) ;

73

Captulo 6

Projeto - Rotinas e Passagem de


Par
ametro
6.1

Instruco
es MVS para tradu
c
ao de rotinas

Instruc
ao
CRVL n
ARZL n

Armazena Local

CREL n

Carrega endereco local

CREG n

Carrega endereco global

CRVI n

Carrega valor indireto

ARMI n

Armazena Indireto

SVCP n

Salva Contador do Programa

ENSP n

Entrada sub-programa

RTSP n

Retorno sub-programa

DMEM n

6.2
1

Descric
ao
Carrega valor local

Desaloca memoria

Modificac
ao da gram
atica para incluir rotinas

programa
: cabecalho
variaveis
subprogramas
T INICIO
lista comandos
;

2
3
4
5

T FIM

6
7

(...)

8
9
10
11
12

Micro-c
odigo
ss+1
M [s] M [d + n]
M [d + n] M [s]
ss1
ss+1
M [s] d + n
ss+1
M [s] n
ss+1
M [s] M [M [d + n]]
M [M [d + n]] M [s]
ss1
ss+1
M [s] i + 2
ss+1
M [s] d
ds+1
d M [s]
i M [s 1]
s s (n + 2)
ssn

subprogramas
: / Nao tem subprogramas /
| lista subprogramas
;

74


CAPITULO 6. PROJETO - ROTINAS E PASSAGEM DE PARAMETRO

13
14
15
16
17
18
19
20

lista subprogramas
: subprograma l i s t a s u b p r o g r a m a s
| subprograma
;
subprograma
: funcao
| procedimento
;

21
22

funcao
: T FUNC t i p o T IDENTIF T ABRE l i s t a p a r a m e t r o s T FECHA
v a r i a v e i s T INICIO l i s t a c o m a n d o s T FIMFUNC
;

23
24
25
26
27
28
29
30
31

;
procedimento
: T PROC T IDENTIF T ABRE l i s t a p a r a m e t r o s T FECHA
v a r i a v e i s T INICIO l i s t a c o m a n d o s T FIMPROC
;

32
33
34
35
36

lista parametros
: / sem p ar ame tr os /
| l i s t a p a r a m e t r o s parametro
;

37
38
39

parametro : forma passagem t i p o T IDENTIF


;

40
41
42
43
44

forma passagem
: T REF
| / Vazio /
;

45
46
47
48

chamada procedimento
: T IDENTIF T ABRE argumentos
;

T FECHA

49
50
51
52
53
54
55
56

chamada funcao
: T IDENTIF T ABRE argumentos T FECHA
;
argumentos
: / nao tem argumentos /
| lista argumentos
;

57
58
59
60
61

lista argumentos
: l i s t a a r g u m e n t o s argumento
| argumento
;

62
63
64
65

argumento
: expressao
;

66
67

( . . . )

68
69
70

comando
: entrada saida

75


CAPITULO 6. PROJETO - ROTINAS E PASSAGEM DE PARAMETRO
|
|
|
|
;

71
72
73
74
75

76

repeticao
selecao
atribuicao
chamada procedimento

76
77

( . . . )

78
79

termo
:
|
|
|
|
|
|
;

80
81
82
83
84
85
86
87

6.3

T IDENTIF
T NUMERO
TV
TF
T NAO termo
T ABRE e x p r e s s a o T FECHA
chamada funcao

Modificac
ao da Tabela de Smbolos

A Figura 6.1 ilustra as informacoes que devem estar disponveis na Tabela de Smbolos,
no incio do bloco da rotina e no incio do corpo principal para um programa exemplo.
As colunas da Tabela de Smbolos sao:
# - identifica a posicao do smbolo na tabela
id - e o nome do identificador, o nome escolhido pelo programador para a entidade
do programa
Esc - escopo da variavel. No caso da linguagem simples os smbolos so podem ter
escopo global (G) ou local (L).
Dsl - deslocamento (ou endereco) e o operando que acompanhara as variaveis na
instrucao CRVG, CRVL. As funcoes tambem tem valor para esse campo.
Rot - rotulo atribudo pelo compilador para a funcao ou procedimento. Essa informacao e necessaria para traducao da instrucao de desvio (DSVS) na chamada do
procedimento ou funcao.
Cat - categoria do smbolo que pode ser: VAR = variavel, PRO = procedimento,
FUN = funcao, PAR = parametro.
Tip - tipo do smbolo (INT = inteiro ou LOG = logico).
Mec - mecanismo de passagem para parametros que pode ser REF = referencia ou
VAL = valor.
Par - lista encadeada dos parametros da rotina, com seus Tipos e Mecanismos
de passagem de parametro. Essa informacao e necessaria para traduzir de forma
correta os parametros na chamada da rotina. Observe que no programa principal
as variaveis locais e parametros das rotinas sao excludos da tabela de smbolos


CAPITULO 6. PROJETO - ROTINAS E PASSAGEM DE PARAMETRO

77

Figura 6.1: Modificacao da Tabela de Smbolos para permitir a traducao de procedimento


e funcao na linguagem Simples


CAPITULO 6. PROJETO - ROTINAS E PASSAGEM DE PARAMETRO

6.4
6.4.1
1
2
3
4
5
6
7
8
9
10

Exemplos de Tradu
c
ao de Procedimentos e Fun
co
es
Teste 1 - Simples

programa t e s t e 1
inteiro x
p r o c muda ( r e f i n t e i r o a )
inicio
a < 7
fimproc
inicio
muda ( x )
escreva x
fimprograma

C
odigo MVS correspondente:
1
2
3
4

L1

5
6
7
8

L0

9
10
11
12
13
14
15

6.4.2
1
2
3
4
5
6
7
8

INPP
AMEM
DSVS
ENSP
CRCT
ARMI
RTSP
NADA
CREG
SVCP
DSVS
CRVG
ESCR
DMEM
FIMP

1
L0
7
3
1
0
L1
0
1

Teste 2 - Simples

programa t e s t e 2
p r o c somatudo ( i n t e i r o a i n t e i r o b i n t e i r o c i n t e i r o d )
inicio
escreva a + b + c + d
fimproc
inicio
somatudo ( 1 0 3 4 8 )
fimprograma

C
odigo MVS correspondente:
1
2
3
4
5
6
7

L1

78

INPP
DSVS
ENSP
CRVL
CRVL
SOMA
CRVL

L0
6
5
4


CAPITULO 6. PROJETO - ROTINAS E PASSAGEM DE PARAMETRO

8
9
10
11
12
13

L0

14
15
16
17
18
19
20

6.4.3
1
2
3
4
5
6
7
8
9
10
11
12
13
14

SOMA
CRVL
SOMA
ESCR
RTSP
NADA
CRCT
CRCT
CRCT
CRCT
SVCP
DSVS
FIMP

4
10
3
4
8
L1

Teste 3 - Simples

programa t e s t e 3
inteiro x
proc r e c u r s i v o ( i n t e i r o n)
inicio
se n > 0
entao e sc re v a n
r e c u r s i v o (n 1)
senao
fimse
fimproc
inicio
leia x
recursivo (x)
fimprograma

C
odigo MVS correspondente:
1
2
3
4

L1

5
6
7
8
9
10
11
12
13
14
15
16
17
18

L2
L3

19
20
21
22

L0

INPP
AMEM
DSVS
ENSP
CRVL
CRCT
CMMA
DSVF
CRVL
ESCR
CRVL
CRCT
SUBT
SVCP
DSVS
DSVS
NADA
NADA
RTSP
NADA
LEIA
ARZG

1
L0
3
0
L2
3
3
1

L1
L3

79


CAPITULO 6. PROJETO - ROTINAS E PASSAGEM DE PARAMETRO
CRVG
SVCP
DSVS
DMEM
FIMP

23
24
25
26
27

6.4.4
1
2
3
4
5
6
7
8
9
10
11
12
13

0
L1
1

Teste 4 - Simples

programa t e s t e 4
inteiro n
func i n t e i r o f a t o r i a l ( i n t e i r o n)
inicio
se n = 0
e n t a o f a t o r i a l < 1
s e n a o f a t o r i a l < n f a t o r i a l ( n 1 )
fimse
fimfunc
inicio
leia n
escreva f a t o r i a l (n)
fimprograma

C
odigo MVS correspondente:
1
2
3
4

L1

5
6
7
8
9
10
11
12

L2

13
14
15
16
17
18
19
20
21
22

L3

23
24
25
26
27
28
29
30
31

L0

INPP
AMEM
DSVS
ENSP
CRVL
CRCT
CMIG
DSVF
CRCT
ARZL
DSVS
NADA
CRVL
AMEM
CRVL
CRCT
SUBT
SVCP
DSVS
MULT
ARZL
NADA
RTSP
NADA
LEIA
ARZG
AMEM
CRVG
SVCP
DSVS
ESCR

1
L0
3
0
L2
1
4
L3
3
1
3
1

L1
4
1

0
1
0
L1

80


CAPITULO 6. PROJETO - ROTINAS E PASSAGEM DE PARAMETRO
DMEM
FIMP

32
33

6.4.5
1
2
3
4
5
6
7
8
9
10
11
12

Teste 5 - Simples

programa t e s t e 5
inteiro x y z
p r o c soma ( i n t e i r o a i n t e i r o b r e f i n t e i r o c )
inicio
c < a + b
fimproc
inicio
leia x
leia y
soma ( x y z )
escreva z
fimprograma

C
odigo MVS correspondente:
1
2
3
4

L1

5
6
7
8
9
10

L0

11
12
13
14
15
16
17
18
19
20
21
22
23

6.4.6
1
2

INPP
AMEM
DSVS
ENSP
CRVL
CRVL
SOMA
ARMI
RTSP
NADA
LEIA
ARZG
LEIA
ARZG
CRVG
CRVG
CREG
SVCP
DSVS
CRVG
ESCR
DMEM
FIMP

3
L0
5
4
3
3

0
1
0
1
2
L1
2
3

Teste 6 - Simples

programa t e s t e 6
inteiro z x

3
4
5
6
7

proc g ( i n t e i r o t )
inteiro y
inicio
y < t t

81


CAPITULO 6. PROJETO - ROTINAS E PASSAGEM DE PARAMETRO

8
9
10

z < z + x + y
escreva z
fimproc

11
12
13
14
15
16
17
18

proc f 1 ( i n t e i r o x i n t e i r o y )
inteiro t
inicio
t < z + x + y
g( t )
z < t
fimproc

19
20
21
22
23
24
25
26

proc h ( i n t e i r o y )
inteiro x
inicio
x < y + 1
f1 (x y)
g(z + x)
fimproc

27
28
29
30
31
32
33
34
35

inicio
z < 1
x < 3
h(x)
g(x)
escreva x
escreva z
fimprograma

C
odigo MVS correspondente:
1
2
3
4

L1

5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

L2

INPP
AMEM
DSVS
ENSP
AMEM
CRVL
CRVL
MULT
ARZL
CRVG
CRVG
SOMA
CRVL
SOMA
ARZG
CRVG
ESCR
DMEM
RTSP
ENSP
AMEM
CRVG
CRVL
SOMA
CRVL
SOMA

2
L0
1
3
3
0
0
1
0
0
0
1
1
1
0
4
3

82


CAPITULO 6. PROJETO - ROTINAS E PASSAGEM DE PARAMETRO

27
28
29
30
31
32
33
34
35

L3

36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

L0

53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68

6.4.7
1
2
3
4
5
6
7
8
9
10
11

ARZL
CRVL
SVCP
DSVS
CRVL
ARZG
DMEM
RTSP
ENSP
AMEM
CRVL
CRCT
SOMA
ARZL
CRVL
CRVL
SVCP
DSVS
CRVG
CRVL
SOMA
SVCP
DSVS
DMEM
RTSP
NADA
CRCT
ARZG
CRCT
ARZG
CRVG
SVCP
DSVS
CRVG
SVCP
DSVS
CRVG
ESCR
CRVG
ESCR
DMEM
FIMP

0
0
L1
0
0
1
2
1
3
1
0
0
3
L2
0
0

L1
1
1
1
0
3
1
1
L3
1
L1
1
0
2

Teste 7 - Simples

programa nome programa


inteiro x y
proc l e ( r e f i n t e i r o a r e f i n t e i r o b)
inicio
leia a
leia b
fimproc
inicio
le (x y)
escreva x + y
fimprograma

83


CAPITULO 6. PROJETO - ROTINAS E PASSAGEM DE PARAMETRO
C
odigo MVS correspondente:
1
2
3
4

L1

5
6
7
8
9
10

L0

11
12
13
14
15
16
17
18
19
20

6.4.8
1
2
3
4
5
6
7
8
9
10
11
12
13

INPP
AMEM
DSVS
ENSP
LEIA
ARMI
LEIA
ARMI
RTSP
NADA
CREG
CREG
SVCP
DSVS
CRVG
CRVG
SOMA
ESCR
DMEM
FIMP

2
L0

4
3
2
0
1
L1
0
1

Teste 8 - Simples

programa nome programa


inteiro x y
p r o c soma ( i n t e i r o a i n t e i r o b )
inteiro s
inicio
s < a + b
escreva s
fimproc
inicio
leia x
leia y
soma ( x y )
fimprograma

C
odigo MVS correspondente:
1
2
3
4

L1

5
6
7
8
9
10
11
12
13
14

L0

INPP
AMEM
DSVS
ENSP
AMEM
CRVL
CRVL
SOMA
ARZL
CRVL
ESCR
DMEM
RTSP
NADA

2
L0
1
4
3
0
0
1
2

84


CAPITULO 6. PROJETO - ROTINAS E PASSAGEM DE PARAMETRO
LEIA
ARZG
LEIA
ARZG
CRVG
CRVG
SVCP
DSVS
DMEM
FIMP

15
16
17
18
19
20
21
22
23
24

6.4.9
1
2
3

0
1
0
1
L1
2

Teste 9 - Simples

programa t s u b p r o g r a m a s
inteiro a b c
l o g i c o f 1 k4 y5

4
5
6
7
8
9
10
11
12
13

proc t e s t ( l o g i c o l o l i n t e i r o a i n t e i r o b)
i n t e i r o a1 a2 a3 a4 a5
inicio
se l o l entao
escreva a
senao
escreva b
fimse
fimproc

14
15
16
17
18
19
20

f u n c i n t e i r o soma ( i n t e i r o a i n t e i r o b )
i n t e i r o a1 a2 a3 a4 a5
i n t e i r o b1 b2 b3 b4 b5
inicio
soma < a + b
fimfunc

21
22
23
24
25
26

p r o c proc soma ( r e f i n t e i r o c i n t e i r o a i n t e i r o b )
inicio
c < a + b
fimproc

27
28
29
30
31

f u n c l o g i c o maior ( i n t e i r o a i n t e i r o b )
inicio
maior < a > b
fimfunc

32
33
34
35
36

inicio
leia a
b < 7

37
38
39

proc soma ( c a b )
escreva c

40
41

e s c r e v a soma ( a b )

42
43

t e s t ( maior ( a b ) a b )

85


CAPITULO 6. PROJETO - ROTINAS E PASSAGEM DE PARAMETRO

44

s e maior ( a b ) e n t a o
escreva 1
senao
escreva 0
fimse

45
46
47
48
49
50
51

fimprograma

C
odigo MVS correspondente:
1
2
3
4

L1

5
6
7
8
9
10
11

L2

12
13
14

L3

15
16
17

L4

18
19
20
21
22
23
24
25

L5

26
27
28
29
30
31

L6

32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

L0

INPP
AMEM
DSVS
ENSP
AMEM
CRVL
DSVF
CRVL
ESCR
DSVS
NADA
CRVL
ESCR
NADA
DMEM
RTSP
ENSP
AMEM
CRVL
CRVL
SOMA
ARZL
DMEM
RTSP
ENSP
CRVL
CRVL
SOMA
ARMI
RTSP
ENSP
CRVL
CRVL
CMMA
ARZL
RTSP
NADA
LEIA
ARZG
CRCT
ARZG
CREG
CRVG
CRVG
SVCP
DSVS

6
L0
5
5
L2
4
L3
3

5
3
10
4
3
5
10
2
4
3
5
3
4
3
5
2

0
7
1
2
0
1
L5

86


CAPITULO 6. PROJETO - ROTINAS E PASSAGEM DE PARAMETRO

47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73

L7

74
75
76

L8

77
78

6.4.10
1
2
3
4
5
6
7
8
9

CRVG
ESCR
AMEM
CRVG
CRVG
SVCP
DSVS
ESCR
AMEM
CRVG
CRVG
SVCP
DSVS
CRVG
CRVG
SVCP
DSVS
AMEM
CRVG
CRVG
SVCP
DSVS
DSVF
CRCT
ESCR
DSVS
NADA
CRCT
ESCR
NADA
DMEM
FIMP

2
1
0
1
L4
1
0
1
L6
0
1
L1
1
0
1
L6
L7
1
L8
0

Teste 10 - Simples

programa nome programa


f u n c i n t e i r o soma ( i n t e i r o a i n t e i r o b )
inicio
soma < a + b
fimfunc
inicio
e s c r e v a soma ( 1 0 2 0 )
e s c r e v a soma ( 5 1 0 0 )
fimprograma

C
odigo MVS correspondente:
1
2
3
4
5
6
7
8

L1

INPP
DSVS
ENSP
CRVL
CRVL
SOMA
ARZL
RTSP

L0
4
3
5
2

87


CAPITULO 6. PROJETO - ROTINAS E PASSAGEM DE PARAMETRO

9
10
11
12
13
14
15
16
17
18
19
20
21
22

L0

NADA
AMEM
CRCT
CRCT
SVCP
DSVS
ESCR
AMEM
CRCT
CRCT
SVCP
DSVS
ESCR
FIMP

1
10
20
L1
1
5
100
L1

88

Vous aimerez peut-être aussi