A apresentação está carregando. Por favor, espere

A apresentação está carregando. Por favor, espere

Teoria e Implementação de Linguagens Computacionais

Apresentações semelhantes


Apresentação em tema: "Teoria e Implementação de Linguagens Computacionais"— Transcrição da apresentação:

1 Teoria e Implementação de Linguagens Computacionais
Revisão 1º EE André Ricardo Schäffer Lopes – Rodrigo Diego Melo Amorim–

2 Níveis de Linguagem Linguagem de máquina Linguagem de alto nível
Linguagem de montagem Assembly language Controle explícito dos endereços de memória para dados e para o próprio programa; Várias instruções de máquina para cada linha de comando da linguagem de alto-nível Linguagem de alto nível suporta • uso de expressões, usando notação semelhante à matemática; •tipos de dados primitivos e compostos; •estruturas de controle como if-then-else, while, for etc.; •declarações de variáveis, tipos, funções, procedimentos etc.; •abstração: o que é feito x como é feito; •encapsulamento (ou abstração de dados): classes, pacotes, módulos (orientação a objetos). Linguagem de montagem: Uso de um programa montador (assembler) Instruções têm relação direta com Linguagem de Máquina

3 Processadores de Linguagens
Manipulam programas expressos em alguma linguagem de programação: Compiladores Interpretadores

4 Tradutores e Compiladores
Linguagem fonte -> Linguagem destino Chinês para inglês Java para C Compilador Ling. de alto nível -> Ling. de baixo nível

5 Interpretadores Programa fonte -> executa imediatamente
Lê, analisa e executa as instruções, uma de cada vez

6 Compiladores x Interpretadores
Tempo de espera pela compilação Execução dos programas com máxima performance, em linguagem de máquina Interpretadores Resultados imediatos Execução (de linguagem de alto nível) até 100 vezes mais lenta que a versão compilada Interpretadores Sem a tradução do programa para código objeto antes da execução

7 Uso de interpretadores
Programador trabalha em modo interativo Quer ver o resultado de uma instrução antes de entrar na próxima Execução de instruções apenas um vez, ou raramente Programas descartáveis Em que a velocidade de execução não é tão importante Inadequado quando o programa vai ser executado em produção, ou executado frequentemente, ou instruções tem formato complicado, difícil de ser analisado.

8 Diagramas Tombstone Programas Máquinas P L M

9 X Diagramas Tombstone Execução Programa P rodando na máquina M P M
sort PPC sort PPC X M PPC x86

10 Diagramas Tombstone Compiladores S L T

11 Diagramas Tombstone Tradução
Um programa fonte P expresso na linguagem S -> um programa objeto expresso na linguagem T, usando um tradutor de S para T executando na máquina M? Um programa fonte P expresso na linguagem S -> um programa objeto expresso na linguagem T, usando um tradutor de S para T executando na máquina M

12 Diagramas Tombstone Tradução P S P T S M T M

13 Diagramas Tombstone Interpretador S L

14 Diagramas Tombstone Interpretação
Um programa P expresso em uma linguagem S, usando um interpretador de S executando na máquina M?

15 Diagramas Tombstone P S S M M

16 Compilação em estágios
sort Java sort C sort x86 Java x86 C C x86 Podemos ter n estágios Por exemplo, usado se vc n tem o compilador de java para x86 x86 x86

17 Cross-Compiler Roda em uma máquina hospedeira, mas gera código para outra máquina Máquina destino débil em memória, compilador ou outras ferramentas

18 Exemplo Cross-Compiler sort Java sort PPC sort PPC Java x86 PPC  PPC

19 Interpretive Compiler
Características de interpretadores e compiladores Simples e rápido de traduzir para ela, e simples e rápida de interpretar Exemplo: Java, no JDK Portabilidade Compila para uma linguagem intermediária, e interpreta esta linguagem

20 Java no JDK Java M JVM  JVM M P JVM P Java P JVM Java M JVM  JVM M M

21 Máquina Real x Abstrata
Projeto de uma nova máquina “Ultima” P Ultima P Ultima Ultima M Ultima Para testes: usar um interpretador M

22 Bootstrapping Compilação de uma linguagem utilizando um compilador dessa mesma linguagem Utilizado para melhorar a eficiência de um compilador Precisa de um compilador escrito em outra linguagem que depois será descartado

23 Bootstrapping - melhorando a eficiência
Ada Mfast Ada Mslow Mfast Ada Mslow M

24 Bootstrapping - melhorando a eficiência
Ada P Mfast P Mfast Ada Mslow Mfast M M

25 Bootstrapping - melhorando a eficiência
Ada Mfast Ada Mfast Ada Mslow Mfast M

26 Especificação de Linguagens
Sintaxe A forma do programa Organização das frases Palavras reservadas Semântica estática (Restrições contextuais) Regras de escopo e regras de tipo Semântica Significado do programa Semântica estática -> Gramáticas de atributos incorporam informações semânticas nas parse trees Determinar que todas as variáveis devem ser declaradas antes de serem referenciadas – O end do subprograma Ada seguido de um nome deve coincidir com o nome do subprograma • Esses dois problemas exemplificam a categoria das regras de linguagem chamada de semântica estática – Leva esse nome pois a análise necessária para verificar essas especificações pode ser feita na Compilação Situações em que a possibilidade de a frase ser bem formada depende do seu contexto Regras de Tipos •Normalmente, valores são classificados em tipos. •Cada operação na linguagem tem uma regra de tipos, que define os tipos esperados para os operandos e o tipo do resultado (se existir). •Qualquer operação utilizando um valor com tipo de errado gera um erro de tipos. Classificação de Linguagens em Relação a Tipos •Estaticamente tipada: todos os erros de tipos podem ser detectados estaticamente, sem executar o programa. •Dinamicamente tipada, se (alguns) erros de tipos só podem ser detectados durante a execução do programa. Regras de escopo •Exemplos: declaração de variáveis, let Ligação estática x Ligação dinâmica •Estática = em tempo de compilação, sem rodar o programa; •Dinâmica: só rodando o programa

27 O processo de Compilação
begin if x = 5 then ... + params output Programa Código Fonte Compilador

28 Árvore sintática abstrata
Fases de Compilação Código fonte Análise Léxica Tokens e Lexemas implementação abstração Árvore sintática abstrata Análise Sintática Análise Semântica As fases estão associadas às três partes da especificação de uma linguagem: sintaxe, restrições contextuais (semântica estática) e semântica. AST decorada Código máquina Geração de Código

29 Análise Léxica (Scanning)
Código fonte -> sequência de tokens Símbolos como identificadores, literais, operadores, palavras-chave, pontuação etc. if (n == 0) { return 1; } else { ... } if LPAR "n" id assign "0" intLit RPAR LCUR return "1" intLit comm RCUR else

30 Análise Sintática int y = 0,k = 0; int x = y+++k;
Agrupa caracteres ou Tokens em uma estrutura hierárquica com algum significado Determina se uma dada cadeia de entrada pertence ou não à linguagem definida por uma gramática int y = 0,k = 0; int x = y+++k; A seguinte construção é válida?

31 Gramáticas – descrevendo Linguagens
Gramáticas Livres de Contexto são utilizadas para descrever linguagens de programação Produções Símbolos terminais Símbolos não-terminais Símbolo inicial

32 Exemplo S → S ; S S → id := E S → print (L) E → id E → num E → E + E
E → (S , E) L → E L → L , E Terminais: id print , + ; := ( ) num Não terminas: S E L Símbolo inicial: S → é utilizado na notação de produções A cadeia seguinte pertence à gramática? a := 7; b := c + (d := 5 + 6, d)

33 Derivações S S ; S S ; id := E id := E ; id := E id := num ; id := E
id := num ; id := E + E id := num ; id := E + (S, E) id := num ; id := id + (S, E) id := num ; id := id + (id := E, E) id := num ; id := id + (id := E + E, E) id := num ; id := id + (id := E + E, id) id := num ; id := id + (id := num + E, id) id := num ; id := id + (id := num + num, id) Para determinar se uma cadeia pertence à gramática pode ser utilizado o processo de Derivação

34 Construída conectando cada derivação à sua origem.
Parse tree S S S ; id := E E id := num + E E Construída conectando cada derivação à sua origem. ( S , E ) id id id := E E + E num num Obs. Na prática não é implementada pelos compiladores.

35 Gramática Ambígua A partir dela uma sentença pode dar origem a mais de uma árvore de parsing diferente Indeterminismo Eliminação de ambigüidade Refatoração da gramática

36 Exemplo x := 1 + 2 + 3; S S E E id := id := E + E E + E num E + E num

37 Refatoração S → S ; S S → id := E S → print (L) E → id E → num
E → E + E E → (S , E) L → E L → L , E S → S ; S S → id := E S → print (L) E → id E → num E → E + T E → T E → (S , E) L → E L → L , E

38 Parsers Avaliam uma entrada quanto à sintaxe Podem ser Top-down
Recursive-descent / LL(k) Bottom-up LR(k)

39 Recursive descent parser
Algoritmo baseado em previsões Funções mutuamente recursivas Simples implementação Uma função para cada não-terminal Uma cláusula para cada produção Verifica o primeiro símbolo terminal para decidir qual função usar

40 Exemplo parseA() { accept(‘a’); parseB(); accept(‘c’); parseC(); }
case (d): parseC(); parseB(); case (c): accept(‘c’); } A ::= aBcC B ::= CB | cC C ::= da parseC() { accept(‘d’); accept(‘a’); }

41 Recursive descent parser
Na prática, constrói uma tabela de produções indexadas por não-terminais e terminais a c d A A::= aBcC B B::= CB B::= CA C C::= da A ::= aBcC B ::= CB | CA C ::= da

42 Recursive descent parser
Vantagens Fácil de implementar Fácil de entender Desvantagens Performance deficiente Gramática reconhecida possui restrições Sem recursão à esquerda Deve estar fatorada

43 Recursive descent parser
A ::= aBcC B ::= CB | CA C ::= da A ::= aBcC B ::= CX X ::= B | A C ::= da Gramática LL(k) a c d A A::= aBcC B B::= CX C C::= da X X::=A X::=B

44 Parsers LL(k) Gramáticas SEM entradas duplicadas na tabela são conhecidas como LL(k) LL(1) -> Left-to-right, leftmost-derivation, 1-symbol lookahead Left-to-right – direção na qual os símbolos serão examinados Leftmost-derivation – ordem pela qual os símbolos não-terminais serão expandidos 1-symbol lookahead – não mais que um símbolo será avaliado por vez Também existem LL(2), LL(3),... Toda LL(1) é LL(2), toda LL(2) é LL(3),... LL(k)

45 Recursão à esquerda Gramáticas LL(1) são vulneráveis a entradas duplicadas. Por exemplo, o fragmento a seguir: E → E + T E → T O fato de E aparecer no início do lado direito da produção é a causa do problema. Isso é conhecido como Recursão à Esquerda. Para corrigir, precisamos refatorar a gramática com Recursão à Direita: E → T E´ E´ → +T E´ E´ →

46 Parsers LR(k) Supera as fraquezas de LL(k)
LR(1) -> Left-to-right, rightmost-derivation, 1-symbol lookahead Uso de uma pilha para armazenar símbolos de forma temporária Possui duas operações, shift e reduce shift - move o primeiro símbolo para o topo da pilha reduce - escolhe uma regra da gramática do tipo X→A B C. pop C B A da pilha e push X. Consegue descrever a maioria das linguagens de programação LALR(1) Melhoramento sobre o LR(1) Diminui o tamanho da tabela de parsing

47 Parsing LR - de Gramáticas Ambíguas
Gramáticas ambíguas ocasionam conflitos em parsers LR Shift-reduce conflict O parser não consegue decidir se empilha o próximo símbolo da entrada, ou se reduz para uma regra já disponível Reduce-reduce conflict O parser pode realizar uma redução para duas regras distintas

48 Parsing LR - de Gramáticas Ambíguas
Dangling-else if a then { if b then s1 } else s2 ? if a then if b then s1 else s2 Caso clássico: dangling-else if a then { if b then s1 else s2 }

49 Parsing LR - de Gramáticas Ambíguas
Solução: Transformar a gramática Introdução dos conceitos de matched e unmatched S ::= 'if' E 'then' S 'else' S S ::= 'if' E 'then' S S ::= ... S ::= M | U M ::= 'if' E 'then' M 'else' M | ... U ::= 'if' E 'then' S | 'if' E 'then' M 'else' U

50 Análise Semântica (Contextual)
Verifica se o programa está de acordo com as restrições contextuais da linguagem fonte Em uma linguagem com tipos estáticos e ligação estática: Verifica regras de escopo Verifica regras de tipos Duas fases: Identificação Verificação Identificação: ocorrências de nomes x definições Verificação: aplica regras de tipos para cada expressão, inferindo os tipos, e depois compara com os tipos esperados, etc.

51 Identificação Faz a ligação entre uso de nomes e sua definição
Tabela de identificação (tabela de símbolos), com nome e atributos de cada identificador Cada definição tem o seu escopo – parte do programa sobre a qual ela tem efeito Delimitado por um bloco

52 Estrutura de blocos de um programa
Monolítica: O único bloco é o programa inteiro Declarações estão em um escopo global Regras de escopo: Nenhum identificador pode ser declarado mais de uma vez Nenhum identificador pode ser usado sem ter sido definido Define a organização da tabela de símbolos Monolítica : Basic, Cobol;

53 Estrutura de blocos de um programa
Plana O programa pode ser particionado em vários blocos disjuntos Dois níveis de escopo: Escopo local: ocorrências de identificadores declarados localmente são restritos a um bloco em particular Outras declarações têm escopo global Fortran;

54 Estrutura de blocos de um programa
Aninhada Blocos podem ser aninhados um dentro do outro Vários níveis de escopo: Declarações no nível mais externo têm escopo global (nível 1) Declarações dentro de um bloco interno são locais ao bloco Cada bloco está dentro de outro bloco, com um nível a mais Pascal, Ada, C, Java

55 Passos Travessia do programa fonte
Um compilador de um passo atravessa o programa uma única vez Um compilador de múltiplos passos faz várias travessias O projeto de um compilador é diretamente relacionado ao número de passos

56 Compilação em múltiplos passos
Módulo principal (driver) Chama cada um dos passos Driver do Compilador chama cada um dos passos, responsáveis pela análise sintática, análise contextual e geração de código. Analisador Sintático Analisador Contextual Gerador de Código

57 Compilação em passo único
Analisador sintático Realiza/chama as atividades à medida que lê e reconhece o programa Driver do Compilador Analisador sintático vai realizando/chamando as atividades de análise contextual e geração de código, à medida que lê e reconhece o programa Analisador Sintático Analisador Contextual Gerador de Código

58 Pontos relevantes no Projeto de um Compilador
Velocidade – possível vantagem para um passo Espaço – possível vantagem para um passo (dados x programa) Modularidade – vantagem de múltiplos passos Flexibilidade – vantagem de múltiplos passos Transformações/otimizações de programas – vantagem de múltiplos passos Características da linguagem fonte podem inviabilizar o uso de um passo único – se a linguagem permite o uso de uma função antes da sua definição, por exemplo.


Carregar ppt "Teoria e Implementação de Linguagens Computacionais"

Apresentações semelhantes


Anúncios Google