1 / 76

CES-41 COMPILADORES

CES-41 COMPILADORES. Capítulo I Introdução. Capítulo I - Introdução. 1.1 – Compiladores 1.2 – Estrutura de um compilador 1.3 – Interpretadores 1.4 – Automação da construção de compiladores. 1.1 – Compiladores. 1.1.1 – Definição Genericamente falando, compilador é um software que

claire-lamb
Download Presentation

CES-41 COMPILADORES

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. CES-41 COMPILADORES Capítulo I Introdução

  2. Capítulo I - Introdução 1.1 – Compiladores 1.2 – Estrutura de um compilador 1.3 – Interpretadores 1.4 – Automação da construção de compiladores

  3. 1.1 – Compiladores 1.1.1 –Definição • Genericamente falando, compilador é um software que • Lê um programa escrito numa linguagem: a linguagem-fonte (é o programa-fonte) • Traduz em um programa equivalente, escrito noutra linguagem : a linguagem-objeto (é o programa-objeto) • Reporta a presença de erros no programa-fonte

  4. Programa fonte Programa objeto Compilador Esquematicamente: Mensagens de erro

  5. Possíveis linguagens-fontes: • Mais comuns: linguagens tradicionais de programação: Fortran, Pascal, C, Modula-2, C++, Java, etc. • Linguagens especializadas: simulação, computação gráfica, banco de dados, experimentos Possíveis linguagens-objetos: • Mais comuns: linguagem assembly ou linguagem de máquina de vários computadores • Outras linguagens de programação

  6. Exemplos de linguagens de programação como linguagens-objetos: • Transformação de programas sequenciais escritos em C ou Fortran, em programas paralelos escritos em HPF (High Performance Fortran) for (i = 1; i <= n; i++) C[i] = A[i] + B[i] do parallel i = 1, n C[i] = A[i] + B[i] for (i = 1; i <= n; i++) C[i] = A[i] + C[i-1] do parallel i = 1, n C[i] = A[i] + C[i-1]

  7. Tradução de programas realizadores de certos experimentos: • Escritos numa linguagem especializada • Traduzidos (compilados) para uma linguagem de programação como C • Compilados depois por um compilador similar ao de C • Programas em Lex e Yacc são traduzidos para C • Lex e Yaccsão linguagens especializadas para construir componentes de um compilador

  8. Há ainda o “compilador” Assembler: • Linguagem-fonte: Assembly • Linguagem-objeto: linguagem de máquina Enfoque desta disciplina: • A linguagem-fonte é uma linguagem tradicional e a linguagem-objeto é o Assemblyde uma máquina • Para a implementação, a linguagem-fonte é Lex eYacce a linguagem-objeto é C

  9. 1.1.2 –O contexto de um compilador • Além do compilador, outros programas são exigidos para criar um programa executável nalguma máquina

  10. Programa fonte com diretivas de pré-processamento Pré-processador Programa fonte puro Compilador Programa objeto em Assembly Montador Código de máquina com endereçamento deslocado Bibliotecas e outros arquivos com endereçamento deslocado Editor de Ligações Código de máquina executável com endereçamento deslocado Código de máquina executável com endereçamento correto Carregador

  11. a) Pré-processador – realiza várias tarefas antes da compilação: • Inclusão de arquivos ao programa-fonte – Por exemplo, na Linguagem C: • #include <math.h>: inclui protótipos de funções matemáticas pertencentes à biblioteca da linguagem; essas funções já estão em linguagem de máquina • #include “sistemas.c”: inclui arquivo pertencente ao acervo do programador; contém código fonte

  12. Processamento de macros – para abreviar construções longas • Exemplo, em C, com as macros: #define EHPAR(x) (((x)%2)?0:1) #define ERRO(msg) printf (“ERRO: % s/n”, msg) pode-se escrever comandos dos tipos: if (EHPAR(a+b)) --------------; if (valor max) ERRO(“valor muito grande”); O resultado do pré-processamento é: if ((((a+b)%2)?0:1)) ....... ; if (valor > max) printf(“ERRO:%s\n”,“valor muito grande”); O pré-processador substitui a primeira parte do #define pela segunda, realizando inclusive passagem de argumentos

  13. Processamento de extensões de linguagens: • Algumas linguagens são acrescidas de certos artifícios para propósitos específicos de certas aplicações • Exemplos: comandos para manipular banco de dados, para computação gráfica, processamento paralelo, etc. • Muitas linguagens são, na realidade, extensões da Linguagem C • Diretivas iniciadas pelos caracteres “##” são substituídas pelo pré-processador por chamadas de funções, comandos do sistema operacional, etc.

  14. b) Montador (Assembler): • Transforma o código Assembly, produzido pelo compilador, em código de máquina relocável • Exemplo: programa em C para o cálculo do fatorial de um número digitado e seus correspondentes em Assembly e em linguagem de máquina • Supõe-se uma CPU bem simples, com apenas um registrador de propósitos gerais (AC - acumulador) Para fazer C = A + B Sendo A, B e C endereços de memória

  15. C1: CONST 1 C2: CONST 2 #include <stdio.h> void main ( ) { int n, fat, i; scanf (“%d”, &n); fat = 1; i = 2; while (i <= n) { fat = fat * i; i = i + 1; } printf (“%d”, fat); } Primeiramente, reserva de espaço para as constantes 1 e 2

  16. C1: CONST 1 C2: CONST 2 n: CONST 0 fat: CONST 0 i: CONST 0 #include <stdio.h> void main ( ) { int n, fat, i; scanf (“%d”, &n); fat = 1; i = 2; while (i <= n) { fat = fat * i; i = i + 1; } printf (“%d”, fat); } Em seguida, reserva de espaço para as variáveis n, i, fat

  17. C1: CONST 1 C2: CONST 2 n: CONST 0 fat: CONST 0 i: CONST 0 #include <stdio.h> void main ( ) { int n, fat, i; scanf (“%d”, &n); fat = 1; i = 2; while (i <= n) { fat = fat * i; i = i + 1; } printf (“%d”, fat); } Agora a tradução dos comandos

  18. C1: CONST 1 C2: CONST 2 n: CONST 0 fat: CONST 0 i: CONST 0 inic: READ n Rótulo da 1ª instrução executável: inic #include <stdio.h> void main ( ) { int n, fat, i; scanf (“%d”, &n); fat = 1; i = 2; while (i <= n) { fat = fat * i; i = i + 1; } printf (“%d”, fat); } Na realidade, a tradução de scanf é algo mais complexo: É uma chamada de subprograma

  19. C1: CONST 1 C2: CONST 2 n: CONST 0 fat: CONST 0 i: CONST 0 inic: READ n LD C1 ST fat LD C2 ST i Rótulo da 1ª instrução executável: inic #include <stdio.h> void main ( ) { int n, fat, i; scanf (“%d”, &n); fat = 1; i = 2; while (i <= n) { fat = fat * i; i = i + 1; } printf (“%d”, fat); }

  20. C1: CONST 1 C2: CONST 2 n: CONST 0 fat: CONST 0 i: CONST 0 inic: READ n LD C1 ST fat LD C2 ST i loop: SUB n JP escrever JUMP loop Rótulo da 1ª instrução executável: inic #include <stdio.h> void main ( ) { int n, fat, i; scanf (“%d”, &n); fat = 1; i = 2; while (i <= n) { fat = fat * i; i = i + 1; } printf (“%d”, fat); } “escrever” é o rótulo da instrução logo após JUMP

  21. C1: CONST 1 C2: CONST 2 n: CONST 0 fat: CONST 0 i: CONST 0 inic: READ n LD C1 ST fat LD C2 ST i loop: SUB n JP escrever LD fat MULT i ST fat LD i ADD C1 ST i JUMP loop Rótulo da 1ª instrução executável: inic #include <stdio.h> void main ( ) { int n, fat, i; scanf (“%d”, &n); fat = 1; i = 2; while (i <= n) { fat = fat * i; i = i + 1; } printf (“%d”, fat); }

  22. C1: CONST 1 C2: CONST 2 n: CONST 0 fat: CONST 0 i: CONST 0 inic: READ n LD C1 ST fat LD C2 ST i loop: SUB n JP escrever LD fat MULT i ST fat LD i ADD C1 ST i JUMP loop escrever:WRITE fat Rótulo da 1ª instrução executável: inic #include <stdio.h> void main ( ) { int n, fat, i; scanf (“%d”, &n); fat = 1; i = 2; while (i <= n) { fat = fat * i; i = i + 1; } printf (“%d”, fat); } Na realidade, a tradução de printf é algo mais complexo: É uma chamada de subprograma

  23. C1: CONST 1 C2: CONST 2 n: CONST 0 fat: CONST 0 i: CONST 0 inic: READ n LD C1 ST fat LD C2 ST i loop: SUB n JP escrever LD fat MULT i ST fat LD i ADD C1 ST i JUMP loop escrever:WRITE fat STOP END inic Rótulo da 1ª instrução executável: inic #include <stdio.h> void main ( ) { int n, fat, i; scanf (“%d”, &n); fat = 1; i = 2; while (i <= n) { fat = fat * i; i = i + 1; } printf (“%d”, fat); }

  24. C1: CONST 1 C2: CONST 2 n: CONST 0 fat: CONST 0 i: CONST 0 inic: READ n LD C1 ST fat LD C2 ST i loop: SUB n JP escrever LD fat MULT i ST fat LD i ADD C1 ST i JUMP loop escrever:WRITE fat STOP END inic #include <stdio.h> void main ( ) { int n, fat, i; scanf (“%d”, &n); fat = 1; i = 2; while (i <= n) { fat = fat * i; i = i + 1; } printf (“%d”, fat); } Final da compilação Agora vem a montagem

  25. C1: CONST 1 C2: CONST 2 n: CONST 0 fat: CONST 0 i: CONST 0 inic: READ n LD C1 ST fat LD C2 ST i loop: SUB n JP escrever LD fat MULT i ST fat LD i ADD C1 ST i JUMP loop escrever:WRITE fat STOP END inic O Assembler monta uma tabela de rótulos para ajudar a preencher o programa em linguagem de máquina

  26. C1: CONST 1 C2: CONST 2 n: CONST 0 fat: CONST 0 i: CONST 0 inic: READ n LD C1 ST fat LD C2 ST i loop: SUB n JP escrever LD fat MULT i ST fat LD i ADD C1 ST i JUMP loop escrever:WRITE fat STOP END inic

  27. C1: CONST 1 C2: CONST 2 n: CONST 0 fat: CONST 0 i: CONST 0 inic: READ n LD C1 ST fat LD C2 ST i loop: SUB n JP escrever LD fat MULT i ST fat LD i ADD C1 ST i JUMP loop escrever:WRITE fat STOP END inic

  28. C1: CONST 1 C2: CONST 2 n: CONST 0 fat: CONST 0 i: CONST 0 inic: READ n LD C1 ST fat LD C2 ST i loop: SUB n JP escrever LD fat MULT i ST fat LD i ADD C1 ST i JUMP loop escrever:WRITE fat STOP END inic

  29. C1: CONST 1 C2: CONST 2 n: CONST 0 fat: CONST 0 i: CONST 0 inic: READ n LD C1 ST fat LD C2 ST i loop: SUB n JP escrever LD fat MULT i ST fat LD i ADD C1 ST i JUMP loop escrever:WRITE fat STOP END inic

  30. C1: CONST 1 C2: CONST 2 n: CONST 0 fat: CONST 0 i: CONST 0 inic: READ n LD C1 ST fat LD C2 ST i loop: SUB n JP escrever LD fat MULT i ST fat LD i ADD C1 ST i JUMP loop escrever:WRITE fat STOP END inic

  31. C1: CONST 1 C2: CONST 2 n: CONST 0 fat: CONST 0 i: CONST 0 inic: READ n LD C1 ST fat LD C2 ST i loop: SUB n JP escrever LD fat MULT i ST fat LD i ADD C1 ST i JUMP loop escrever:WRITE fat STOP END inic

  32. C1: CONST 1 C2: CONST 2 n: CONST 0 fat: CONST 0 i: CONST 0 inic: READ n LD C1 ST fat LD C2 ST i loop: SUB n JP escrever LD fat MULT i ST fat LD i ADD C1 ST i JUMP loop escrever:WRITE fat STOP END inic

  33. C1: CONST 1 C2: CONST 2 n: CONST 0 fat: CONST 0 i: CONST 0 inic: READ n LD C1 ST fat LD C2 ST i loop: SUB n JP escrever LD fat MULT i ST fat LD i ADD C1 ST i JUMP loop escrever:WRITE fat STOP END inic

  34. C1: CONST 1 C2: CONST 2 n: CONST 0 fat: CONST 0 i: CONST 0 inic: READ n LD C1 ST fat LD C2 ST i loop: SUB n JP escrever LD fat MULT i ST fat LD i ADD C1 ST i JUMP loop escrever:WRITE fat STOP END inic

  35. C1: CONST 1 C2: CONST 2 n: CONST 0 fat: CONST 0 i: CONST 0 inic: READ n LD C1 ST fat LD C2 ST i loop: SUB n JP escrever LD fat MULT i ST fat LD i ADD C1 ST i JUMP loop escrever:WRITE fat STOP END inic Endereço inicial da execução: 5 Essa informação deve acompanhar o programa em linguagem de máquina

  36. O programa em linguagem C é o programa-fonte • O programa gerado pelo Assembler é o programa-objeto • O programa-objeto foi montado a partir do endereço zero da RAM • Esse programa é guardado num arquivo (extensão obj) Endereço inicial da execução: 5

  37. O local para execução é estabelecido pelo sistema operacional do computador • Esse local depende da disponibilidade da RAM • E se o local não for o endereço zero (por exemplo, endereço 3000)? Endereço inicial da execução: 5

  38. Os locais para C1, C2, n, fat e i não são mais 0, 1, 2, 3 e 4, mas sim 3000, 3001, 3002, 3003 e 3004 • Os rótulos inic, loop e escrever mudarão para os endereços 3005, 3010 e 3019 • Então todos os endereços das instruções estarão com um erro (deslocamento de3000 posições) • Isso tem de ser corrigido antes da execução Endereço inicial da execução: 3005

  39. c) Editor de ligações • Antes de corrigir os endereços do programa-objeto, é necessário juntar a ele todos os subprogramas auxiliares pertencentes à biblioteca da linguagem • Exemplos: funções para entrada e saída (scanf, printf, etc.), funções matemáticas (sqr, pow, sqrt, log, sin, cos, etc.) • Esse trabalho de juntar o programa-objeto com tais subprogramas é feito por um software denominado editor de ligações (linkage-editor) • O produto do editor de ligações é um arquivo denominado programa-executável (extensão exe)

  40. d) Carregador • A região de memória onde um programa será alocado para execução só será conhecida quando ele for chamado para isso • Então o endereçamento do arquivo executável precisa ser corrigido, quando sua execução for solicitada • Esse trabalho é feito pelo carregador (loader), que produz a versão final do programa, pronto para rodar

  41. 1.2 – Estrutura de um Compilador 1.2.1 – Componentes de um compilador • O trabalho de compilação é dividido em 2 fases: Fase de análise e fase de síntese • Além disso, existem atividades que fazem parte das duas fases

  42. O processo não precisa ser sequencial

  43. Programa-fonte (caracteres) while (i < n) i = i + j; Analisador léxico while ( i < n ) Sequência de átomos Analisador sintático i = i + j ; Árvore sintática Analisador semântico while i int - - - int - - - n < = Gerador de código intermediário Tabela de símbolos int - - - j Código objeto + i n i load i R1: sub n JZ R2 JP R2 load i add j st i J R1 R2: - - - - - R1: T1 = i < n JF T1 R2 T2 = i + j i = T2 JUMP R1 R2: - - - - - i j R1: T1 = i < n JF T1 R2 i = i + j JUMP R1 R2: - - - - - Otimizador de código intermediário Código intermediário Gerador de código objeto Exemplo

  44. 1.2.2 –A fase de análise • São realizados três tipos de análise: • Análise linear ou léxica • Análise hierárquica ou sintática • Análise semântica

  45. a) Análise léxica • Os caracteres do texto são agrupados em átomos (tokens) • A validade dos átomos é verificada • Os átomos recebem uma classificação

  46. Exemplo: frase da Língua Portuguesa: ajbxswn o homem alto apanhou a laranja madura na laranjeira tdhf

  47. Exemplo: um comando while em Pascal: while num  50 do num := num * 2

  48. b) Análise sintática • Os átomos são agrupados em frases, em estrutura de árvore (árvore sintática) • A validade da posição dos átomos é verificada

  49. Exemplo: frase: o homem alto apanhou a laranja madura na laranjeira

  50. Exemplo: comando while de Pascal: while num  50 do num := num * 2

More Related