1 / 69

Revisão Compiladores – AP1

Revisão Compiladores – AP1. Prof. Alexandre Monteiro Baseado em material cedido pelo Prof. Euclides Arcoverde Recife. Contatos. Prof. Guilherme Alexandre Monteiro Reinaldo Apelido: Alexandre Cordel E-mail/ gtalk : alexandrecordel@gmail.com greinaldo@fbv.edu.br

Download Presentation

Revisão Compiladores – AP1

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. Revisão Compiladores – AP1 Prof. AlexandreMonteiro Baseadoem material cedidopelo Prof. EuclidesArcoverde Recife

  2. Contatos • Prof. Guilherme Alexandre Monteiro Reinaldo • Apelido: Alexandre Cordel • E-mail/gtalk: alexandrecordel@gmail.com greinaldo@fbv.edu.br • Site: http://www.alexandrecordel.com.br/fbv • Celular: (81) 9801-1878

  3. Objetivo • O principal objetivo é responder à seguinte pergunta: • Como criar uma linguagem computacional? • Para responder a pergunta, estudaremos: • Como especificar uma linguagem • Como construir um compilador para ela

  4. História das Linguagens

  5. História das Linguagens • Começaram a surgir outras linguagens mais elaboradas • Fortran (1957) • LISP (1959) • COBOL (1960) • BASIC (1964) • C (1972) • etc.

  6. Linguagens de Alto Nível

  7. Linguagens de Alto Nível • O nome “alto nível” tem o sentido de “alto nível de abstração”, pois essas linguagens abstraem detalhes operacionais pouco relevantes • Assim, o programador pode (tenta) focar só no algoritmo • Veremos agora dois exemplos para comparar as linguagens de nível alto e baixo

  8. Exemplo em Baixo Nível • Programa Hello World em assembly x86 DOSSEG .MODEL SMALL .DATA Msgdb "Hello World.",13,10,"$" .CODE Start: mov AX, @DATA mov DS, AX lea DX, Msg mov AH, 9 int 21h mov ah, 4ch int 21h END Start

  9. Exemplo em Alto Nível • Programa Hello World em C #include <stdio.h> intmain() { printf(“Hello World”); return 0; }

  10. Linguagens de Baixo Nível • Características gerais • Dependentes de arquitetura • Oferecem instruções primitivas simples (operações sobre o hardware) • Programas extensos e pouco legíveis • Visam oferecer mais controle sobre o hardware

  11. Linguagens de Alto Nível • Características gerais • Especificadas independentemente de qualquer arquitetura • Oferecem comandos mais intuitivos • Dizem mais “o que” deve ser feito do que “como” deve ser feito • Mais fácil de programar e de ler códigos prontos • Restringem o uso do hardware para evitar bugs • Controle da alocação de memória em Java

  12. Introdução a Compiladores

  13. compilação execução interpretação Compilação x Interpretação • Compilação • Interpretação código fonte código de máquina resultados código fonte resultados

  14. O que é um Compilador? • Um compilador é um programa que lê um programa escrito em uma linguagem (linguagem fonte) e a traduzem um programa equivalente em outra linguagem (linguagem alvo). Aho, Sethi, Ullman. Compilador Programa Fonte Programa Objeto

  15. O que é um Compilador? • Nesse processo de tradução, há duas tarefas básicas a serem executadas por um compilador: • análise, em que o texto de entrada (na linguagem fonte) é examinado, verificado e compreendido • síntese, ou geração de código, em que o texto de saída (na linguagem objeto) é gerado, de forma a corresponder ao texto de entrada

  16. O que é um Compilador? • A fase de análise normalmente se subdivide em análise léxica, análise sintática e análise semântica • É possível representar completamente a sintaxe de uma LP através de uma gramática sensível ao contexto • Mas como não existem algoritmos práticos para tratar essas gramáticas, a preferência recai em usar gramáticas livres de contexto • Deixa-se para a análise semântica a verificação de todos os aspectos da linguagens que não se consegue exprimir de forma simples usando gramáticas livres de contexto

  17. O que é um Compilador? • A implementação de reconhecedores de linguagens regulares (autômatos finitos) é mais simples e mais eficiente do que a implementação de reconhecedores de linguagens livres de contexto (autômatos de pilha) • Nesse caso, é possível usar expressões regulares para descrever a estrutura de componentes básicos das LP, tais como identificadores, palavras reservadas, literais numéricos, operadores e delimitadores, etc. • Essa parte da tarefa de análise (análise léxica) é implementada separadamente, pela simulação de autômatos finitos

  18. O que é um Compilador? • Um dos modelos possíveis para a construção de compiladores faz a separação total entre o front-end, encarregado da fase de análise, e o back-end, encarregado da geração de código, de forma que: • O front-end e back-end se comunicam apenas através de uma representação intermediária • O front-end depende exclusivamente da linguagem fonte • O back-end depende exclusivamente da linguagem objeto

  19. Análise Léxica Análise Sintática Analise Semântica Geração de Código Intermediário Geração de Código Final Etapas da Compilação Front-End (Análise) Back-End (Síntese)

  20. O que é um Compilador? • Um compilador típico consiste de algumas fases onde cada uma passa sua saída para as fases seguintes • As principais fases são: • análise léxica (ou scanner) • análise sintática (ou parser) • análise semântica • otimização • gerador de código • otimização (novamente!)

  21. Fases da Compilação Programa Fonte Analisador Léxico Analisador Sintático e Semântico Manipulador de erros Tabela de Símbolos Gerador de Código Intermediário Otimizador de Código Gerador de código Programa Objeto

  22. Análise Léxica • Também chamada de scanner • Agrupa caracteres em símbolos (ou tokens) • Token: <nome-token, valor-atributo> • Entrada: fluxo de caracteres • Saída: fluxo de símbolos • Símbolos são: • Palavras reservadas, identificadores de variáveis e procedimentos, operadores, pontuação, etc. • Expressões regulares usadas para reconhecimento • Scanner é implementado como uma MEF (Método dos Elementos Finitos) • Lex/Flex (J) são ferramentas para gerar scanners

  23. Análise Léxica • Por exemplo, os caracteres na instrução de atribuição position = initial + rate * 60 • seriam agrupados nos seguintes tokens: • O identificador position • O símbolo de atribuição = • O identificador initial • O símbolo de adição + • O identificador rate • O símbolo de multiplicação * • O número 60 <id, 1> <=> <id, 2> <+> <id, 3> <*> <60>

  24. Análise Sintática • Também chamada de parser • Agrupa símbolos em unidades sintáticas • Ex.: os 3 símbolos A+B podem ser agrupados em uma estrutura chamada de expressão • Expressões depois podem ser agrupados para formar comandos ou outras unidades • Saída: representação de árvore sintática do programa • Gramática livre de contexto é usada para definir a estrutura do programa reconhecida por um parser • Yacc/Bison (J) são ferramentas para gerar parsers

  25. Análise Sintática • Regras sintáticas (1) • Qualquer identificador é uma expressão • Qualquer número é uma expressão • Se expressão1 e expressão2 são expressões, então também são expressões • expressão1+ expressão2 • expressão1* expressão2 • ( expressão1)

  26. Análise Sintática • Regras sintáticas (2) • Se identificador1 é um identificador e expressão2 é uma expressão, então identificador1= expressão2é um comando (statement) • Se expressão1 é uma expressão e statement2 é um comando (statement), entãowhile( expressão1) { statement2 }if( expressão1) { statement2 } são comandos (statements)

  27. Análise Sintática position = initial + rate * 60 comando de atribuição identificador = expressão position expressão expressão + * expressão expressão identificador initial identificador número rate 60

  28. Gerador de Código Intermediário • Usa as estruturas produzidas pelo analisador sintático e verificadas pelo analisador semântico para criar uma sequência de instruções simples (código intermediário) • Está entre a linguagem de alto nível e a linguagem de baixo nível

  29. Gerador de Código Intermediário • Considere que temos um único registrador acumulador • Considere o comando de atribuição x := a + b * c pode ser traduzido em: t1 := b * c t2 := a + t1 x := t2 • Pode-se fazer um gerador de código relativamente simples usando regras como:

  30. Gerador de Código Intermediário

  31. Gerador de Código Intermediário • O comando de atribuição x := a + b * c • Gera o código Load b { t1 := b * c } Mult c Store t1 Load a { t2 := a + t1 } Add t1 Store t2 Load t2 { x := t2 } Store x

  32. Otimizador de Código • Independente da máquina • Melhora o código intermediário de modo que o programa objeto 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

  33. Otimizador de Código Otimizadorpor sub-expressões comuns

  34. Gerador de Código • Produz o código objeto final • Toma decisões com relação à: • Alocação de espaço para os dados do programa; • Seleção da forma de acessá-los • Definição de quais registradores serão usados, etc. • Projetar um gerador de código que produza programas objeto eficientes é uma das tarefas mais difíceis no projeto de um compilador

  35. Gerador de Código • Várias considerações têm que ser feitas: • Há vários tipos de instruções correspondendo a vários tipos de dados e a vários modos de endereçamento • Há instruções de soma específicas, por exemplo para incrementar/decrementar de 1 • Algumas somas não foram especificadas explicitamente • Cálculo de endereço de posições em vetores • Incremento/decremento registrador de topo pilha • Local onde armazenar variáveis • Alocação de registradores

  36. Gerador de Código temp1 = id3 * 60.0id1 = id2 + temp1 MOVF id3, R2MULF #60.0, R2MOVF id2, R1ADDF R2, R1MOVF R1, id1

  37. Tabela de Símbolos • É uma estrutura de dados usada para guardar informações a respeito de todos os nomes usados pelo programa e registrar informações importantes associadas a cada um, tais como seu tipo (inteiro, real, etc.), tamanho, escopo, etc.

  38. Manipulador de Erros • É ativado sempre que for detectado um erro no programa fonte • Deve avisar o programador da ocorrência do erro emitindo uma mensagem, e ajustar-se novamente à informação sendo passada de fase a fase de modo a poder completar o processo de compilação • Mesmo que não seja mais possível gerar código objeto, a análise léxica e sintática deve prosseguir até o fim

  39. Bibliografia • AHO, A., LAM, M. S., SETHI, R., ULLMAN, J. D., Compiladores: princípios, técnicas e ferramentas. Ed. Addison Wesley. 2a Edição, 2008 (Capítulo 1)

  40. Adiantando... • Lexema: sequência de caracteres com significado interligado • Token: classificação dada ao lexema • Geralmente retornado junto com o próprio lexema ou outro atributo, como um ponteiro • Padrão: é uma descrição da forma que os lexemas de um token podem tomar. • Ex. sequência de caracteres que formam palavra-chave como um token.

  41. Exemplos

  42. Especificando Tokens • Geralmente são especificados com expressões regulares • Cada token é associado a uma expressão regular que representa seus lexemas válidos • Padrão que representa várias palavras (dizemos que as palavras “casam” com o padrão)

  43. Especificando Tokens • Expressões Regulares • Formalismo utilizado para definir o conjunto de aceitação de uma linguagem • Principais operadores utilizados pelas ERs

  44. Especificando Tokens • Operadores derivados

  45. Especificando Tokens • Exercícios • Defina expressões para expressar: • Número IP: \d{3}.\d{3} .\d{3} .\d{3} • Números naturais (e inteiros): \d{n} ou [0-9]{n} • Números de telefone (com DDD opcional): \([0-9]{2}\).[0-9]{4}. [0-9]{4} • Horas: [012]\d:[0-5]\d • E-mails: [a-zA-Z0-9\._-]@[A-Za-z]+\\.[A-Za-z]+ • Placa de Carro: [A-Z]{3}-\d{4} • CEP: \d{5}-\d{3} ou \d\d\d\d\d • URLs: - Com http - (http|https)://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?- Sem http - ([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?

  46. Análise Sintática • Alguns autores consideram que a análise sintática envolve tudo que diz respeito à verificação do formato do código fonte • Inclui a análise léxica como subfase • Visão mais coerente, porém o livro texto que usamos tem outra visão...

  47. Análise Sintática • Entenderemos análise sintática como sendo apenas a segunda fase dessa verificação de formato: • “É a fase que analisa os tokens para descobrir a estrutura gramatical do código fonte” • Também chamada “Reconhecimento” (Parsing) • Porém, um nome melhor seria “Análise Gramatical”

  48. Gramáticas • São usadas para organizar os tokens em “frases” de sentido lógico • Definem regras de formação recursivas expressão → CTE_INT | ID | expressão + expressão

  49. Gramáticas • As gramáticas livres de contexto possuem quatro elementos: • Símbolos terminais • Símbolos não-terminais • Símbolo inicial • Produções! ou Regras de Produção!

  50. Gramáticas • Elementos das gramáticas livres de contexto: • Símbolos terminais: • Símbolos assumidos como atômicos, indivisíveis • Em compiladores, são os tokens (int, +, -, /, identificador, valores literais, etc) • Símbolos não-terminais: • Usados para organizar os tokens em “frases” • Representam elementos abstratos do programa (expressões, termos, etc)

More Related