Compiladores  
Aula 07 Analise Semântica e Geração de  
Código Intermediário  
Edirlei Soares de Lima  
<edirlei.lima@universidadeeuropeia.pt>  
Processo de Compilação  
unidades léxicas  
Analisador  
Léxico  
Analisador  
Sintático  
Programa-fonte  
parse trees  
(opcional)  
Gerador de Código  
Intermediário e  
Analisador  
Tabela de Símbolos  
Otimização  
Semântico  
código  
intermediário  
linguagem de máquina  
Programa Objeto  
Gerador de Código  
Processo de Compilação  
O Gerador de Código Intermediário produz um programa em  
uma linguagem intermediaria entre o programa-fonte e saída  
final do compilador.  
As linguagens intermediarias se parecem muito com linguagens de  
montagem (e muitas vezes são linguagens de montagem (assembly)).  
Linguagem Assembly  
Assembly é uma linguagem legível por humanos para o código  
de máquina de uma arquitetura de computador específica.  
Instruções executam operações simples:  
Operações aritméticas/lógicas;  
Transferência de dados;  
Controle do fluxo de execução (desvios, chamadas de função).  
Tipos de dados básicos:  
Valores inteiros (1,2,4,8 bytes);  
Endereços de memória;  
Valores em ponto flutuante.  
Software Windows  
NASM:  
https://www.nasm.us/pub/nasm/releasebuilds/2.14.03rc2/win32/nas  
m-2.14.03rc2-win32.zip  
GCC (MinGW):  
https://sourceforge.net/projects/mingw/files/latest/download  
Exemplo de Programa Assembly  
SECTION .data  
formatout: db "%d", 10, 0  
variavel1: dd 0  
Dados Globais  
SECTION .text  
global _main  
Código do Programa  
extern _printf  
_
main :  
mov eax, 2  
mov ebx, 4  
add eax, ebx  
mov dword [variavel1], eax  
push dword[variavel1]  
push formatout  
call _printf  
Compilar:  
nasm -f win32 code.asm  
gcc code.obj -o code.exe  
add esp, 8  
mov eax, 0  
ret  
Assembly Tamanhos de Dados  
Diretiva  
db  
Proposito  
Define Byte  
Espaço  
Allocates 1 byte  
dw  
Define Word  
Allocates 2 bytes  
Allocates 4 bytes  
Allocates 8 bytes  
Allocates 10 bytes  
dd  
Define Doubleword  
Define Quadword  
Define Ten Bytes  
dq  
dt  
Assembly Registradores  
Assembly Movimentação de Dados  
mov <op1> <op2>: copia os dados de op2 para op1.  
Movimentos de registrador para registrador são possíveis, mas os  
movimentos diretos de memória para memória não são.  
É necessário primeiro carregar o conteúdo em um registrador e depois  
move-lo para a memória.  
Exemplos:  
mov eax, 2  
mov ebx, 4  
add eax, ebx  
mov dword [variavel1], eax  
Assembly Movimentação de Dados  
push <op>: coloca op na parte superior da pilha de  
memória.  
pop <op>: remove 4 bytes da parte superior da pilha e os  
armazena em op (registrador ou memória).  
Exemplo:  
push dword[variavel1]  
push formatout  
call _printf  
add esp, 8  
Assembly Operações Aritméticas Inteiras  
add <op1> <op2>: soma op1 e op2 e armazena o resultado  
em op1.  
sub <op1> <op2>: subtrai op1 e op2 e armazena o resultado  
em op1.  
imul <op1> <op2>: multiplica op1 por op2 e armazena o  
resultado em op1.  
idiv <op>: divide o conteúdo do registrador eax por op e  
armazena o resultado em eax.  
Assembly Usando Funções C Externas  
Função printf:  
SECTION .data  
formatout: db "%d", 10, 0  
variavel1: dd 0  
SECTION .text  
global _main  
extern _printf  
_
main :  
mov eax, 2  
mov ebx, 4  
add eax, ebx  
mov dword [variavel1], eax  
push dword[variavel1]  
push formatout  
call _printf  
add esp, 8  
mov eax, 0  
ret  
Geração de Código Intermediário  
(Implementação)  
..  
.
void GenerateCode(Node * ast)  
{
int i = 0;  
if (ast == NULL)  
return;  
while (ast->children[i] != NULL)  
{
GenerateCode(ast->children[i]);  
i++;  
}
if ((ast->type == ADD_OP) || (ast->type == SUB_OP) ||  
(
ast->type == DIV_OP) || (ast->type == MULT_OP)){  
if ((ast->children[0]->type == INT_LIT) &&  
ast->children[1]->type == INT_LIT)){  
(
printf("mov eax, %s\n", ast->children[0]->info);  
printf("mov ebx, %s\n", ast->children[1]->info);  
}
.
..  
Geração de Código Intermediário  
Implementação)  
(
Entrada:  
int test;  
test = (45 + 100)/2;  
print(test);  
Exercício 01  
1
) Continue a implementação do gerador de código intermediário  
para dar suporte a geração de código para declaração e  
utilização de variáveis float.  
Atenção: add, sub, idiv e imul são operações para números inteiros.  
Na internet existem documentos e exemplos de códigos ilustrando  
como utilizar números float em Assembly.  
Algumas referências:  
https://www.csee.umbc.edu/courses/undergraduate/313/spring05/burt_katz/lecture  
s/Lect12/floatingpoint.html  
https://www.nasm.us/doc/nasmdoc3.html  
Leitura Complementar  
Aho, A. V., Lam, M. S., Jeffrey, R. S.  
Compiladores: Princípios, Técnicas e  
Ferramentas. 2ª edição, Pearson, 2007.  
ISBN: 978-8588639249.  
Capítulo 6: Intermediate-Code Generation