Tabela de Símbolos
Tabela de Símbolos • Funções: - Armazenar Armazenar as infor informaçõe maçõess sobre sobre os nomes nomes declarados num programa podendo ser: o o o o o o o
Variávei veis Consta stantes Proc Proceedim dimento entoss Funções Métodos Classes Entre ntre ou outtros o Em algu alguns ns casos casos são são regi registr strado adoss também também inicio inicio e fim de laços, seleções, etc..
Tabela de Símbolos • - Usad Usada, a, pel pelo ana anallisado sadorr sem semâânti ntico, par para verificar se uma variável foi declarada, na verificação de compatibilidade compatibilidade de tipos, entre outras consultas que forem necessárias. - Pode ser usada usada para para armazen armazenar ar os valores valores das das variáveis durante a execução do programa - Utili Utilizad zadoo no ambi ambient entee de deb debug ug
Tabela de Símbolos •
Por ser muito utilizada em consultas, é importante que a estrutura de dados tenha uma performance considerável. Tamb Também ém é necess necessári árioo o cresci crescimen mento to dinâmico de tal estrutura de dados
- Por isso isso uma boa boa escolha escolha é a tabela tabela hashi hashing ng Devem ser guardados quais endereços de memória serão associados as variáveis
- Pode ser utilizada o atributo referência na classe Simbolo para essa utilidade
Tabela de Símbolos Escopo: • Um progra programa ma pode pode ter ter vária váriass tab tabel elas as de símb símbol olos os dando assim o escopo para os símbolos. Alguns exemplos: o Tabela Tabela de de Símbo Símbolos los globais globais (externos (externos)) o Tabela Tabela de Símbo Símbolos los globai globaiss (interno (internoss ao módulo) módulo) o Tabela Tabela de Sím Símbol bolos os de um umaa funçã funçãoo
• Cada Cada funç função ão tem tem a sua sua pró própr pria ia tabe tabela la de sím símbo bolo loss
Tabela de Símbolos Utilizando a Tabela de Símbolos:
- As informações armazenadas para cada símbolo podem variar de acordo com o tipo/uso - Cada entrada na tabela pode ser implementada como um registro contendo campos (nome, tipo, classe, tamanho, escopo, etc.) sobre o símbolo.
- Cria-se a classe Símbolo. - Cria-se a classe Tabela (Tabela de Símbolos). - A interação se dar por ações semânticas inseridas no analisador sintático, na classe principal do compilador.
Tabela de Símbolos • A tabela se símbolos interage com quase todas as fases do compilador: varredura, análise sintática e análise semântica. - Elas podem fornecer identificadores a tabela -O analisador semântico interage com os tipos de dados e outras informações -As fases de otimização e geração de código utilizam a informação da tabela para efetuar escolhas apropriadas
Ex. Tabela de Símbolos
Tabela de Símbolos • Exercício Definir a Estrutura da Tabela da sua linguagem • Apresentar na Próxima Aula em Slide – Considerar Variáveis, funções, Métodos, Classes e Métodos etc... – Escopo para 0 programa principal, 1 funções, Métodos, Classes e Métodos etc..., 2 outras funções, Métodos, Classes e Métodos etc.. Uma Dentro da outra – Linha de declaração, linhas de utilização e
Compilador Preparação • Programa que lê um programa escrito em uma linguagem (fonte) e o traduz para uma outra linguagem (destino), reportando erros quando eles ocorrem.
Linguagens • Linguagem fonte: C, Pascal, Java, Fortran, etc. • Linguagem destino: linguagem de máquina (assembler) de um processador, de uma máquina virtual (e.g. Java ou .NET), ou qualquer outra linguagem (e.g. C).
Processadores de Linguagens: Compilador Programa fonte Compilador Programa destino
Execução de um programa
entrada
Programa destino
saída
Processadores de Linguagens: Interpretador
Programa fonte entrada
Interpretador
saída
Compilador Híbrido Programa fonte Tradutor Programa intermediário entrada
Máquina Virtual
saída
Sistema de processamento de uma linguagem Programa fonte preprocessador Programa fonte modificado compilador Programa em assembler
assembler Código objeto (relocável) Linker / Loader
Bibliotecas / código objeto
Código objeto (executável)
Programas auxiliares do processo de compilação • Preprocessadores: processam macros, incluem de arquivos, suportam compilação condicional e extensão de linguagens. • Assemblers: servem como uma pequena abstração da arquitetura da máquinadestino. São na realidade um tradutor /compilador simples, de dois passos, que gera código relocável.
Programas auxiliares do processo de compilação (cont.) • Carregadores (loaders) e linkeditores (linkers) – Ajustam o código relocável, resolvem referências externas.
Compilação: Análise e Síntese • Análise: quebra o código fonte em suas partes, e cria uma representação intermediária do programa. Verifica erros e constrói tabela de símbolos. • Síntese: Constroi o programa-destino a partir da representação intermediária.
Fases de um compilador stream de caracteres
árvore sintática
Analisador léxico
Ger. de código intermediário
stream de tokens
representação intermediária
Analisador sintático
Otimizador de código
árvore sintática
representação intermediária
Analisador semântico
Gerador de código Código de máquina
Análise: front-end do compilador (até geração de código intermediário) Síntese: back-end do compilador
Análise do programa fonte • Análise léxica – lê a seqüencia de caracteres e a organiza como tokens – sequencias de caracteres com algum significado • Análise sintática – agrupa caracteres ou tokens em uma estrutura hierárquica com algum significado • Análise semântica – verifica se os componentes de um programa se encaixam de forma a ter um significado adequado.
Programas baseados em análise • Editores de programa dirigidos à sintaxe (comuns nos IDEs, como no Eclipse e Visual Studio) • Pretty-printers • Interpretadores
Análise léxica ou Scanning • Lê os caracteres de entrada e agrupa-os em sequencias chamadas lexemas. • Para cada lexema o analisador léxico produz como saída um token da forma que é passado para a fase seguinte.
Exemplo • position = initial + rate * 60
< => < +> <*>
Tabela de Símbolos identificador
tipo
…
1
position
…
2
initial
…
3
rate
…
…
…
…
…
Análise sintática ou parsing • A partir dos tokens cria uma estrutura em árvore (árvore sintática) que representa a estrutura gramatical do programa.
Árvore Sintática • position = initial + rate * 60 =
+ *
60
Análise semântica • Verifica o programa em relação a possíveis erros semânticos e guarda informações adicionais
Exemplo: verificação de tipos A expressão x = x + 3.0
está sintaticamente correta, mas pode estar semanticamente certa ou errada, dependendo do tipo de x.
Análise Semântica =
+
*
inttofloat 60
Código intermediário • Idealmente deve ser fácil de produzir e também de traduzir para a linguagem-destino. • Na prática, se está gerando código para uma máquina abstrata. • Por exemplo, Three-address-code: usa três operandos por instrução, cada um como se fosse um registrador.
Código intermediário - exemplo t1 = inttofloat(60) t2 = id3 * t1 t3 = id2 + t2 id1 = t3
Otimização de código • Realiza transformações no código visando melhorar sua performance em aspectos de tempo de execução, uso de memória, tamanho do código executável etc.
Otimização de código - exemplo t1 = inttofloat(60) t2 = id3 * t1 t3 = id2 + t2 id1 = t3
t2 = id3 * 60.0 id1 = id2 + t2
Geração de código • Realiza a alocação de registradores (se necessária) e a tradução do código intermediário para a linguagem-destino.
Geração de código LDF MULF LDF ADDF STF
R2, R2, R1, R1, id1,
id3 R2, #60.0 id2 R1, R2 R1
Tabela de Símbolos • Estrutura de dados usada para guardar identificadores e informações sobre eles: – alocação de memória, – tipo do identificador, – escopo (onde é válido no programa) – se for um procedimento ou função: número e tipo dos argumentos, forma de passagem dos parâmetros e tipo do resultado.
Tabela de Símbolos identificador
tipo
…
1
position
…
2
initial
…
3
rate
…
…
…
…
…
Organizando fases em passos • Fases: visão lógica de um compilador • Em uma implementação as fases podem ser agrupadas em um ou mais passos • Passos: número de vezes em que se passa pelo mesmo código. • Por exemplo, em um assembler são necessários pelo menos dois passos.
Separação entre front-end e back-end para criação de múltiplos compiladores C Front-end
Pascal
Fortran
Front-end
Front-end
código intermediário Back-end x86
C# Front-end
Separação entre front-end e back-end para criação de múltiplos compiladores Pascal Front-end código intermediário Back-end ARM
Back-end Back-end
Back-end
x86
.NET
MIPS
Separação entre front-end e back-end para criação de múltiplos compiladores C Front-end
Pascal Front-end
Fortran Front-end
C# Front-end
código intermediário Back-end ARM
Back-end Back-end
Back-end
x86
.NET
MIPS
Ferramentas auxiliares para a construção de compiladores • Scanner generators, baseados em expressões regulares. Exemplo: lex • Parser generators, baseados em gramáticas livres de contexto. Exemplo: yacc • Engenhos de tradução dirigida por sintaxe, geram rotinas para navegar na parse tree e gerar código intermediário • Geradores de geradores de código (template matching) • Toolkits de construção de compiladores
Contexto Histórico • Demanda por linguagens de mais alto nível que linguagem de máquina e assembler. • Nos anos 1950, compiladores eram programas notadamente difíceis de se escrever. • Avanço teórico e de técnicas e ferramentas de implementação tornaram possível implementar compiladores muito mais facilmente.
Classificações: Gerações ① Linguagens de máquina ② Linguagens de montagem ( Assembly languages) ③ Fortran, Cobol, Lisp, C, C++, C#, Java
(Linguagens de Proposito Geral) ④ SQL, Postscript ( Domain Specific Languages)
First Program Mark 1 (Computation) 000 CI = S 001 A = A - S 010 A = - S 011 If A < 0, CI = CI + 1 100 CI = CI + S 101 A = A – S 110 S = A 111 HALT
Classificações: Paradigma
Imperativo “como” = programador diz o que vai ser executado Conceito de estado e comandos que mudam o estado = computações que alteram variáveis! C, C++, C#, Java Declarativo “o quê” = Insere Regras, Dados e faz Consultas ML, Haskell, Prolog
Classificações - Evoluções
Von Neumann(1940s): C, Fortran, Pascal (Define variáveis e faz transformações em seus valores em unico programa com chamada de subprogramas, salva apenas os dados, execução local) Orientadas a Objetos(1960s): Simula 67, Smalltalk, C++, C#, Java, Ruby (instânciar objetos e mantê-los ativos, salvando dados e programas=classes, instalação local e execução pode ser distribuida) Scripting Languages(1980s): Awk, JavaScript, Perl, PHP, Python, Ruby, Tcl (regras de execução a serem interpretadas, conceito de execução distribuída)
Fundamentos de Linguagens de Programação
Estático x Dinâmico:
Estático: em tempo de compilação (Cobol, Clipper…..) Dinâmico: em tempo de execução (Basic,…) Java = Estático até o Bytecode e Dinâmico na execução do Bytecode.
Fundamentos de Linguagens de Programação
Ambientes e Estados ambiente
nomes
locais (variáveis)
estado
valores
Fundamentos de Linguagens de Programação
Escopo estático e estrutura de Blocos
Controle de Acesso Explícito
public, private, protected
Fundamentos de Linguagens de Programação • Escopo Dinâmico • Exemplo: macros em C #define a (x+1) int x = 2; void b() {int x = 1; printf(%d\n ”, a); } void c() {printf( “%d\n ”, a); } void main() { b(); c(); }
Fundamentos de Linguagens de Programação • Mecanismos de passagem de parâmetro – – – –
Por valor (call by value ) Por referência (call by reference ) Por nome (call by name ) Por necessidade (call by need )