Commit 1b90b6f9 authored by Eduardo de Santana Medeiros Alexandre's avatar Eduardo de Santana Medeiros Alexandre
Browse files

tradutor

parent 36ec2130
......@@ -187,6 +187,8 @@ Antes de propor esta atividade a seus alunos, que tal tentar elaborar um
algoritmo que formalize sua solução. Descreva testes a serem efetuados e
instruções para descrever as decisões a serem tomadas.
[[sec_linguagem_programacao]]
=== Linguagem de Programação
......@@ -263,7 +265,7 @@ nível necessárias para o algoritmo, um programa, conhecido como *((tradutor))*
acionado para converter programas escritos na linguagem de alto nível, em
programas com linguagem de máquina.footnote[Este software será estudado mais adiante na <<sec_tradutor_interpretador>>.]
==== Paradigmas de Programação
=== Paradigmas de Programação
(((Paradigmas de Programação)))
......@@ -403,18 +405,7 @@ alto nível, como é o caso do Pascal ou do C, e a linguagem alvo for uma
linguagem de máquina numérica ou uma representação simbólica desta
linguagem (linguagem de montagem), o tradutor é chamado de compilador.
// FIXME ajustar proximo parágrafo. fig_processo_traducao
////
Podemos observa na <<fig_processo_traducao>> todos os passos necessários para que um
algoritmo expresso em uma linguagem de programação possa ser carregado em
memória para ser executado por um computador. Cada fase possui um conjunto de
entradas e saídas de seu processamento. Estas fases e seus respectivos
softwares envolvidos são descritas nas seções seguintes.
////
Podemos observa na <<fig_processo_traducao>> o processo de *((tradução))* e *((ligação))* de códigos
Podemos observar na <<fig_processo_traducao>> o processo de *((tradução))* e *((ligação))* de códigos
fonte, escrito em linguagens de programação, em um código binário executável. Nesta seção vamos
abordar apenas o processo de tradução (montagem ou compilação), o processo de ligação será visto depois.
......@@ -439,7 +430,7 @@ digraph automata_0 {
node [style=filled,color=white];
style=filled;
color=lightgrey;
code_assembly [label="Linguagem de Baixo Nível\n(Assembly)"];
code_assembly [label="Linguagem de Baixo Nível\n(Linguagem de montagem)"];
code_c [label="Linguagem de Alto Nível\n(Ex: C, Pascal, ...)"];
}
......@@ -452,6 +443,8 @@ digraph automata_0 {
compilador [label="Compilador"];
}
code_gerado [label="Código traduzido\n(Linguagem de montagem)"];
subgraph clusterCodigoObjeto {
label = "Código Objeto\n(binário)";
node [style=filled,color=white];
......@@ -462,15 +455,14 @@ digraph automata_0 {
}
ligador [label="Ligador",shape="doubleoctagon"];
programa [label="Código Binário\nExecutável", shape="component"];
code_assembly -> montador -> objeto1;
code_c -> compilador -> objeto2;
programa [label="Código Binário\nExecutável", shape="component", fillcolor="grey", style="filled"];
objeto1->ligador;
objeto2->ligador;
code_assembly -> montador -> objeto1 [color="forestgreen", style="bold"];
code_c -> compilador -> code_gerado -> montador -> objeto2 [color="blue", style="bold"];
ligador-> programa;
objeto1->ligador [color="red", style="bold"];
objeto2->ligador [color="red", style="bold"];
ligador-> programa [color="red", style="bold"];
{rank=source; code_c code_assembly }
{rank=same; montador compilador}
......@@ -480,6 +472,7 @@ digraph automata_0 {
}
----
==== Processo de Montagem
(((Montador)))
......@@ -492,7 +485,10 @@ linguagem de montagem para seus correspondentes em linguagem de máquina.
No processo de montagem, a instrução abaixo poderia ser traduzida no código
binário presente na <<fig_exemplo_instrucao>>.
STORE [0xF3], regC
.Instrução em Assembly
....
STORE [0xF3], regC
....
////
Isto
......@@ -500,86 +496,6 @@ Isto
pode ser traduzido em vários comandos em linguagem de máquina.
////
===== Características dos softwares montadores
// TODO Repensar. Muitos termos técnicos. Detalhes que são mencionados e não
// são explicados. Talvez simplesmente indicar uma fonte onde
// o aluno possa encontrar estas informações, caso deseje.
Embora a montagem seja um processo simples, é tedioso e passível de erros
quando feito manualmente. Montadores comerciais têm ao menos as seguintes
características:
* Permitem ao programador especificar posição de valores de dados e programas
durante a execução;
* Permitem que o programador de início realize valores de dados na memória
antes da execução do programa;
* Implementam mnemônicos em linguagem de montagem para todas as instruções
da máquina e modos de endereçamento, e traduzem comandos em linguagem de
montagem válidos, nos seus equivalentes em linguagem de máquina;
* Permitem o uso de rótulos simbólicos para representar endereços e
constantes;
* Incluem um mecanismo que permite que variáveis sejam definidas em um
programa em linguagem de montagem e usadas em outros programas separadamente;
* Possibilitam a expansão de macros, ou seja, rotinas (semelhantes às funções
em linguagem de alto nível) que podem ser definidas uma vez e então
instanciadas quantas vezes necessário.
===== Por que usar uma Linguagem de Montagem?
// TODO Repensar onde colocar esta seção, me parece não essencial.
// Ela atrapalha o racionício que está sendo construído na seção.
Programar em uma linguagem de montagem não é fácil. Além da dificuldade, o
desenvolvimento de um programa na linguagem de montagem consome mais tempo do
que seu desenvolvimento em uma linguagem de alto nível. A depuração e
manutenção dos programas em linguagem de montagem são mais complicados.
Nessas condições, por que alguém escolheria programar em uma linguagem de
montagem?
Existem duas razões que justificam esta opção: performance e acesso aos recursos
da máquina. Um expert na linguagem de montagem pode produzir um código menor
e muito mais eficiente do que o gerado por um programador usando linguagem de
alto nível.
Em segundo lugar, certos procedimentos precisam ter acesso total ao hardware.
Por exemplo, se a máquina alvo tiver um bit para expressar o overflow de
operações aritméticas, um programa em linguagem de montagem pode testar
diretamente este bit, coisa que um programa em Java não pode fazer. Além
disso, um programa em linguagem de montagem pode executar qualquer uma das
instruções do conjunto de instruções da máquina alvo.
===== Montadores de dois passos
// TODO Repensar onde colocar esta seção, me parece não essencial.
// Ela atrapalha o racionício que está sendo construído na seção.
A maioria dos montadores leem textos do programa em linguagem de montagem duas
vezes, e são chamados de ``montadores de dois passos''. O primeiro passo
serve para determinar o endereço de todos os itens de dados e instruções de
máquina, e selecionar quais instruções devem ser geradas para cada
instrução em linguagem de montagem (mais ainda não gerá-las).
Os endereços dos itens de dados e instruções são determinados por meio do
uso de um contador de programa para a montagem, chamado contador de
localização. O contador de localização gerencia o endereço da instrução
executada e dos itens de dados durante a montagem, que geralmente é
inicializada com `0` (zero). No início do primeiro passo, é incrementado de
acordo com o tamanho de cada instrução.
Durante este passo, o montador também efetua quaisquer operações
aritméticas em tempo de montagem, e insere as definições de todos os
rótulos de funções e variáveis e as constantes, em uma tabela chamada
Tabela de Símbolos.
A razão principal para exigir uma segunda passagem é permitir que símbolos
sejam usados no programa antes de serem definidos. Após a primeira passagem, o
montador terá identificado todos os símbolos e os colocado na Tabela de
Símbolos, já durante a segunda passagem, gerará código de máquina,
inserindo os identificadores dos símbolos que agora são conhecidos.
==== Processo de Compilação
(((Compilação)))
......@@ -590,43 +506,46 @@ mapeamento direto de um para um entre os comandos em linguagem de montagem e os
equivalentes em código binário, o processo de compilação de linguagens é
muito mais complexo.
===== Passos da compilação
===== Tarefas da compilação
Considere o comando simples abaixo:
Para compreender as tarefas do processo de compilação considere o comando de uma linguagem de alto nível a seguir:
a = b + 4;
O compilador tem que resolver um número grande de tarefas na conversão deste
comando em um ou mais comandos em linguagem de montagem:
Diferente do processo de montagem, os comandos de alto nível não possuem um correspondente
único em linguagem de máquina, portanto o comando mencionado precisará ser traduzidos em várias
instruções de baixo nível.
O processo de compilação envolverá as seguintes etapas:
. Reduzir o texto do programa para símbolos básicos da linguagem, como
identificadores tais como `a` e `b`, demarcações como o valor constante 4 e
delimitadores do programa tais como `=` e `+`. Esta parte da compilação é
chamada de ((análise léxica)).
chamada de *((análise léxica))*.
. Decodificar os símbolos para reconhecer a estrutura do programa. No comando
usado acima, por exemplo, um programa chamado parser deve reconhecer o comando
como sendo uma atribuição de valores da forma:
usado acima, por exemplo, um programa chamado *((parser))* deve reconhecer o comando
como sendo uma 'atribuição' de valores da forma:
+
----------------
<Identificador> “=” <Expressão>
<Identificador> "=" <Expressão>
----------------
+
onde `<Expressão>` é decodificado na forma:
+
----------------
<Identificador> “+” <Constante>
<Identificador> "+" <Constante>
----------------
+
Essa tarefa é chamada de ((análise sintática)).
Essa tarefa é chamada de *((análise sintática))*.
. Análise de nomes: associar os nomes A e B com variáveis do programa, e
associá-los também a posições de memória específicas onde essas variáveis
. Análise de nomes: associar os nomes `a` e `b` com variáveis do programa, e
associá-los também a *posições de memória* específicas onde essas variáveis
serão armazenadas durante a execução.
. Análise de tipos: determinar os tipos de todos os dados. No caso anterior,
as variáveis A e B e a constante 4 seriam reconhecidas como sendo do tipo int
em algumas linguagens. As análises de nome e tipo são também conhecidas como ((análise semântica)):
as variáveis `a` e `b` e a constante `4` seriam reconhecidas como sendo do tipo `int`
em algumas linguagens. As análises de nome e tipo são também conhecidas como *((análise semântica))*:
determina o significado dos componentes do programa.
. Mapeamento de ações e geração de código: associar comandos do programa
......@@ -635,47 +554,62 @@ sequência em linguagem de montagem poderia ser:
+
.Comando de atribuição
--------------------------
ld[B], %r0, %r1 // Carrege variável B em um registrador.
ld[b], %r0, %r1 // Carregue variável b em um registrador.
add %r1, 4, %r2 // Calcule o valor da expressão.
st %r2, %r0, [A] // Faça a atribuição na variável A.
st %r2, %r0, [a] // Faça a atribuição na variável a.
--------------------------
. Existem passos adicionais que o compilador deve tomar, tais como, alocar
variáveis a registradores, usar registradores e, quando o programador desejar,
otimizar o programa. O otimizador de código (independente de máquina) é um
// FIXME Os códigos em assembly não estão uniformes durante o livro.
. Existem etapas adicionais que o compilador deve tomar, tais como, alocar
variáveis a registradores, usar registradores e otimizar o código gerado.
[NOTE]
.Otimizador de código
====
O otimizador de código é um módulo opcional nos compiladores e pode ser
acionado pelo desenvolvedor na etapa de compilação. A otimização irá
proporcionar gerar códigos mais eficientes.
////
O otimizador de código (independente de máquina) é um
módulo opcional (presente na grande maioria dos compiladores) que objetiva
melhorar o código intermediário de modo que o programa objeto produzido ao
fim da compilação seja menor (ocupe menos espaço de memória) e/ou mais
rápido (tenha tempo de execução menor). A saída do otimizador de código é
um novo ((código intermediário)).
////
====
// XXX Acho que eles não irão entender código intermediário.
// Talvez explicar otimizador com o resultado obtido
==== Ligação e Carregamento
=== Ligação
A maioria dos programas é composto de mais de um procedimento. Os compiladores
e os montadores geralmente traduzem um procedimento de cada vez, colocando a
saída da tradução em disco. Antes que o programa possa rodar, todos os seus
saída da tradução em disco. Antes que o programa possa ser executado, todos os seus
procedimentos precisam ser localizados e ligados uns aos outros de maneira a
formarem um único código.
===== Ligação
A função do ((ligador)) é coletar procedimentos traduzidos separadamente e
ligá-los uns aos outros para que eles possam executar como uma unidade chamada
programa binário executável.
código binário executável (o programa).
Se o compilador ou o montador lesse um conjunto de procedimentos fonte e
produzisse diretamente um programa em linguagem de máquina pronto para ser
executado, bastaria que um único comando fonte fosse alterado para que todos
os procedimentos fonte tivessem que ser novamente traduzidos.
Usando a técnica do módulo objeto separado, o único procedimento a ser
Usando a técnica do código objeto separado, o único procedimento a ser
novamente traduzido seria aquele modificado. Havendo a necessidade de realizar
apenas a etapa de ligação dos módulos separados novamente, sendo esta tarefa
apenas a etapa de ligação dos códigos separados novamente, sendo esta tarefa
mais rápida que a tradução.
===== Carregamento
=== Carregamento
O ((carregador)) é um programa que coloca um módulo de carregamento na memória
principal. Conceitualmente, a tarefa do carregador não é difícil. Ele deve
......@@ -708,9 +642,12 @@ geralmente usa uma das seguintes estratégias para a execução do programa: exe
o código fonte diretamente ou traduzir o código fonte em alguma eficiente
representação intermediária e depois executar este código.
Para isso, certos tipos de tradutores transformam uma linguagem fonte em uma
linguagem simplificada, chamada de código intermediário, que pode ser
diretamente executado por um programa chamado interpretador. Nós podemos
diretamente ``executado'' por um programa chamado interpretador. Nós podemos
imaginar o código intermediário como uma linguagem de máquina de um
computador abstrato projetado para executar o código fonte.
......@@ -724,6 +661,91 @@ apenas executa a ação dentro de um contexto fixo, anteriormente determinado
pela compilação. Este tempo no processo de análise é conhecido como
"overhead interpretativa".
=== Conteúdos complementares
==== Características dos softwares montadores
// TODO Repensar. Muitos termos técnicos. Detalhes que são mencionados e não
// são explicados. Talvez simplesmente indicar uma fonte onde
// o aluno possa encontrar estas informações, caso deseje.
Embora a montagem seja um processo simples, é tedioso e passível de erros
quando feito manualmente. Montadores comerciais têm ao menos as seguintes
características:
* Permitem ao programador especificar posição de valores de dados e programas
durante a execução;
* Permitem que o programador de início realize valores de dados na memória
antes da execução do programa;
* Implementam mnemônicos em linguagem de montagem para todas as instruções
da máquina e modos de endereçamento, e traduzem comandos em linguagem de
montagem válidos, nos seus equivalentes em linguagem de máquina;
* Permitem o uso de rótulos simbólicos para representar endereços e
constantes;
* Incluem um mecanismo que permite que variáveis sejam definidas em um
programa em linguagem de montagem e usadas em outros programas separadamente;
* Possibilitam a expansão de macros, ou seja, rotinas (semelhantes às funções
em linguagem de alto nível) que podem ser definidas uma vez e então
instanciadas quantas vezes necessário.
==== Montadores de dois passos
// TODO Repensar onde colocar esta seção, me parece não essencial.
// Ela atrapalha o racionício que está sendo construído na seção.
A maioria dos montadores leem textos do programa em linguagem de montagem duas
vezes, e são chamados de ``montadores de dois passos''. O primeiro passo
serve para determinar o endereço de todos os itens de dados e instruções de
máquina, e selecionar quais instruções devem ser geradas para cada
instrução em linguagem de montagem (mais ainda não gerá-las).
Os endereços dos itens de dados e instruções são determinados por meio do
uso de um contador de programa para a montagem, chamado contador de
localização. O contador de localização gerencia o endereço da instrução
executada e dos itens de dados durante a montagem, que geralmente é
inicializada com `0` (zero). No início do primeiro passo, é incrementado de
acordo com o tamanho de cada instrução.
Durante este passo, o montador também efetua quaisquer operações
aritméticas em tempo de montagem, e insere as definições de todos os
rótulos de funções e variáveis e as constantes, em uma tabela chamada
Tabela de Símbolos.
A razão principal para exigir uma segunda passagem é permitir que símbolos
sejam usados no programa antes de serem definidos. Após a primeira passagem, o
montador terá identificado todos os símbolos e os colocado na Tabela de
Símbolos, já durante a segunda passagem, gerará código de máquina,
inserindo os identificadores dos símbolos que agora são conhecidos.
==== Por que usar uma Linguagem de Montagem?
// TODO Repensar onde colocar esta seção, me parece não essencial.
// Ela atrapalha o racionício que está sendo construído na seção.
Programar em uma linguagem de montagem não é fácil. Além da dificuldade, o
desenvolvimento de um programa na linguagem de montagem consome mais tempo do
que seu desenvolvimento em uma linguagem de alto nível. A depuração e
manutenção dos programas em linguagem de montagem são mais complicados.
// XXX Depuração? Será que eles vão entender?
Nessas condições, por que alguém escolheria programar em uma linguagem de
montagem?
Existem duas razões que justificam esta opção: performance e acesso aos recursos
da máquina. Um expert na linguagem de montagem pode produzir um código menor
e muito mais eficiente do que o gerado por um programador usando linguagem de
alto nível.
Em segundo lugar, certos procedimentos precisam ter acesso total ao hardware.
Por exemplo, se a máquina alvo tiver um bit para expressar o overflow de
operações aritméticas, um programa em linguagem de montagem pode testar
diretamente este bit, coisa que um programa em Java não pode fazer. Além
disso, um programa em linguagem de montagem pode executar qualquer uma das
instruções do conjunto de instruções da máquina alvo.
=== Prática
Em <<pratica_compilacao>> é possível encontrar uma prática para compreender
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment