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

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

©Universidade do Algarve 1 Introdução da Disciplina Compiladores João M. P. Cardoso Universidade do Algarve 8000-117 Faro, Portugal.

Apresentações semelhantes


Apresentação em tema: "©Universidade do Algarve 1 Introdução da Disciplina Compiladores João M. P. Cardoso Universidade do Algarve 8000-117 Faro, Portugal."— Transcrição da apresentação:

1 ©Universidade do Algarve 1 Introdução da Disciplina Compiladores João M. P. Cardoso Universidade do Algarve Faro, Portugal

2 ©Universidade do Algarve 2 O que é um compilador? Software que traduz o texto que representa um programa para código máquina capaz de ser executado pelo computador Contudo, um compilador pode ser muito mais do que isso...

3 ©Universidade do Algarve 3 Importância Papel importante no desenvolvimento de aplicações complexas em tempo útil Muitas das matérias abordadas são utilizadas por outras ferramentas: Tradução de linguagens Interpretação de descrições (ex.: html, postscript, latex, ficheiros word) Procura de palavras ou frases por motores de busca

4 ©Universidade do Algarve 4 Dilema da Programação Assembly é fastidioso, erróneo, pouco produtivo, etc. Embora possa permitir melhor desempenho Desenho de linguagens de alto-nível Como implementar a linguagem? Interpretador Compilador

5 ©Universidade do Algarve 5 Compilador Programa em Linguagem Máquina Código fonte descrito numa linguagem de alto- nível (ex.: C, C++, Pascal, etc.) Compilador Ponto de Origem Ponto de Destino

6 ©Universidade do Algarve 6 Ponto de Origem Linguagem imperativa (e.g., C/C++, Java, Pascal, etc.) Estado Variáveis escalares Variáveis do tipo array Registos Atributos de objectos (linguagens orientadas por objectos) Computação Expressões (aritméticas, lógicas, etc.) Enunciados de atribuição Fluxo de controlo (if, switch, etc.) Procedimentos (métodos nas linguagens orientadas por objectos) Int sum(int A[], int N) { Int i, sum = 0; For(i=0; i

7 ©Universidade do Algarve 7 Ponto de Destino Linguagem máquina que descreve o programa com base no ISA (Instruction-Set Architecture) do processador Estado Memória Registos (de estado, de propósito geral, etc.) Computação Instruções do ISA (MIPS): Lw $3, 100($2) Add $3, $2, $1 Bne $2, $3, label … Sum: Addi $t0, $0, 0 Addi $v0, $0, 0 Loop: beq $t0, $a1, End Add $t1, $t0, $t0 Add $t1, $t1, $t1 Add $t1, $t1, $a0 Lw $t2, 0($t1) Add $v0, $v0, $t2 Addi $t0, $t0, 1 J Loop End: jr $ra

8 ©Universidade do Algarve 8 Tópicos Estudo das etapas de um compilador Implementação de algumas dessas etapas Aulas práticas serão vocacionadas para implementação e realização de alguns exercícios Construção de um compilador/interpretador simples

9 ©Universidade do Algarve 9 Docentes João M. P. Cardoso Gab. 2.65

10 ©Universidade do Algarve 10 Conteúdo Programático Aulas Teóricas Introdução Análise lexical Análise Sintáctica Análise Semântica Tradução para código intermédio Geração de código final Optimização de código Tópicos avançados

11 ©Universidade do Algarve 11 Conteúdo Programático Aulas Teórico-Práticas Programação de várias etapas de um compilador (vamos utilizar Java) Exercícios de papel e lápis sobre determinados aspectos Trabalhos para Casa Exercícios levantados nas aulas teóricas Realização dos trabalhos para avaliação

12 ©Universidade do Algarve 12 Avaliação Exame (40 %) + Trabalhos (60%) (1) Exame de Época Normal de Recurso Para obter aprovação: Nota da equação (1) >= 9,5 valores, mas Nota do exame >= 6,5 e Nota dos trabalhos >= 10

13 ©Universidade do Algarve 13 Bibliografia Andrew W. Appel. Modern Compiler Implementation in Java, Cambridge University Press, Alfred V. Aho, Ravi Sethi, Jeffery D. Ullman. Compiler - Principles, Techniques, and Tools, Addison-Wesley, [existe uma tradução brasileira] Dick Grune, Henri E. Bal, Ceriel J. H. Jacobs, and Koen G. Langendoen, Modern Compiler Design, John Wiley & Sons, Ltd, [existe uma tradução brasileira] Rui Gustavo Crespo. Processadores de Linguagens. IST Press Com tópicos mais avançados: Steven S. Muchnick. Advanced Compiler Design and Implementation, Morgan Kaufmann Publishers, 1997.

14 ©Universidade do Algarve 14 Boa sorte! POR EXEMPLO, TENHO QUE SABER COMO FUNCIONA UM COMPILADOR. E DEPOIS? DEPOIS? DEPOIS ESTAMOS PRONTOS PARA CONSTRUIR UM COMPILADOR! Página Web da disciplina: Lista de correio electrónico https://imap.ualg.pt/wws/info/fct-compiladores Para subscrever:

15 ©Universidade do Algarve 15 Do alto-nível ao assembly Compiladores João M. P. Cardoso

16 ©Universidade do Algarve 16 Viagem Como são implementadas as estruturas computacionais em assembly? Revisão dos conceitos relacionados com a programação em assembly para o MIPS R3000 (ver disciplina de Arquitectura de Computadores) Fizemos o papel de um compilador. Agora vamos aprender, entre outras coisas, a fazer um compilador.

17 ©Universidade do Algarve 17 Do alto-nível ao assembly Alvo: MIPS R3000 Int sum(int A[], int N) { Int i, sum = 0; For(i=0; i

18 ©Universidade do Algarve 18 Do alto-nível ao assembly Variáveis globais: Armazenadas na memória Para cada uso de uma variável global o compilador tem de gerar instruções load/store int a, b, c;... fun(...) {... } Memória a b c

19 ©Universidade do Algarve 19 Variáveis Globais Int a, b, c; void fun() { c = a + b; }.data 0x a:.space4 b:.space4 c:.space4.text fun:… la$t1, a lw$t1, 0($t1) la$t2, b lw$t2, 0($t2) add$t3, $t2, $t1 la$t4, c sw$t3, 0($t4) … 0x x x Alocação de memória Memória a b c

20 ©Universidade do Algarve 20 Do alto-nível ao assembly Conceito de chamada a procedimentos Cada procedimento tem estados Variáveis locais Endereço de retorno Estado é guardado na área de memória designada por pilha de chamadas (é utilizado um registo para apontar para a posição actual da pilha) Pilha de chamadas A pilha de chamadas encontra-se no topo da memória A pilha cresce para baixo void fun() { int a, b, c;... c = a + b;... } Memória c b a Registos $sp

21 ©Universidade do Algarve 21 Variáveis Locais Exemplo: void fun() { int a, b, c;... c = a + b;... } fun:addi$sp, $sp, -12 … lw$t1, 0($sp) lw$t2, 4($sp) add$t3, $t2, $t1 sw$t3, 8($sp) … addi$sp, $sp, 12 jr $ra Memória c b a $sp Reserva espaço na pilha liberta espaço na pilha Load a Load b store c a + b

22 ©Universidade do Algarve 22 Variáveis Locais Acesso aos registos internos do processador é muito mais rápido Mas os registos internos são em número limitado E por isso nem todas as variáveis locais podem ser armazenadas nesses registos No passado a atribuição de registos internos do processador a variáveis locais era feita pelo programador: A linguagem C tem uma palavra reservada para orientar o compilador: register (e.g., register int c;) Hoje os compiladores são muito mais eficientes Essa atribuição é lhe inteiramente delegada

23 ©Universidade do Algarve 23 Variáveis Locais Utilização de registos internos void fun() { int a, b, c;... c = a + b;... } fun:… add$t3, $t2, $t1 … jr $ra Ficheiro de Registos $t1 $t2 $t3 a b c

24 ©Universidade do Algarve 24 Do alto-nível ao assembly Implementar Registos Registos contêm vários campos Cada estrutura é armazenada em posições contíguas de memória typedef struct { int x, y, z; } foo; foo *p; Memória z y x p

25 ©Universidade do Algarve 25 Do alto-nível ao assembly Exemplo com estrutura local: typedef struct { int x, y, z; } foo; fun() { foo *p; p->x = p->y + p->z; } fun:addi$sp, $sp, -16 … lw$t1, 0($sp) addi$t1, $t1, 8 lw$t2, 0($t1) lw$t1, 0($sp) addi$t1, $t1, 12 lw$t3, 0($t1) add$t3, $t2, $t3 lw$t1, 0($sp) addi$t1, $t1, 4 sw$t3, 0($t1) … addi$sp, $sp, 16 jr $ra Reserva espaço na pilha liberta espaço na pilha Endereço de p Load p->y Load p->z p->y + p->z store em p->x Memória z y x p address p->y address p->z address p->x Endereço de p

26 ©Universidade do Algarve 26 Do alto-nível ao assembly Exemplo com estrutura local (optimizado): typedef struct { int x, y, z; } foo; fun() { foo *p; p->x = p->y + p->z; } fun:addi$sp, $sp, -16 … lw$t2, 8($sp) lw$t3, 12($sp) add$t3, $t2, $t3 sw$t3, 4($sp) … addi$sp, $sp, 16 … Reserva espaço na pilha liberta espaço na pilha Load p->y Load p->z p->y + p->z store em p->x Memória z y x p

27 ©Universidade do Algarve 27 Do alto-nível ao assembly Compiladores João M. P. Cardoso

28 ©Universidade do Algarve 28 Alinhamento, empacotamento e enchimento Requisitos de alinhamento: Inteiros tipo int (4 bytes) a começar em endereços com os 2 LSBs == 00 Inteiros tipo short (2 bytes) a começar em endereços com o LSB == 0 Alinhamento requer: Enchimento entre campos para assegurar o alinhamento Empacotamento de campos para assegurar a utilização de memória

29 ©Universidade do Algarve 29 Alinhamento typedef struct { int w; char x; int y; char z; } foo; foo *p; Memória z y x p w y x, z p w Organização ingénua Organização Empacotada (poupa 4 bytes) livre ocupado 32 bits

30 ©Universidade do Algarve 30 Arrays Afectação de posições de memória para os elementos do array Elementos são armazenados contiguamente Memória a[0] int a[4]; a[1] a[2] a[3] Memória a[1] short a[4]; a[0] a[3]a[2] 32 bits

31 ©Universidade do Algarve 31 Arrays Utilizando registos do processador para armazenar as variáveis i e j:.data A:.space 16.text Proc: … la $t0, A addi$t2, $0, 4 mult$t1, $t2 mflo$t2 add$t3, $t2, $t0 lw$t4, 0($t3) … int a[4]; proc() { int i, j; … i = a[j]; … } Endereço de a[j] = endereço de a[0] + (4 × j) = a + (4 × j)

32 ©Universidade do Algarve 32 Expressões a = b * c + d – e; a em $t4; b em $t0; c em $t1; d em $t2; e em $t3 … mult$t0, $t1 mflo$t4 sub$t5, $t2, $t3 add$t4, $t4, $t5 … mult$t0, $t1 mflo$t4 add$t4, $t4, $t2 sub$t4, $t4, $t3 …

33 ©Universidade do Algarve 33 Estruturas condicionais If(a == 1) b = 2; a em $t0; b em $t1 If(a == 1) b = 2; else b = 1; a em $t0; b em $t1 … addi$t2, $0, 1 bne$t2, $t0, skip_if addi$t1, $0, 2 Skip_if:… … addi$t2, $0, 1 bne$t2, $t0, else addi$t1, $0, 2 jskip_if Else:addi$t1, $0, 1 Skip_if:…

34 ©Universidade do Algarve 34 Estruturas condicionais Branch-delay O processador executa sempre a instrução a seguir a uma instrução de salto (quer o salto seja realizado ou não) Quando não é possível deslocar uma instrução para depois da instrução de salto, tem de se introduzir uma instrução nop If(a == 1) b = 2; C = a+1; a em $t0; b em $t1 … addi$t2, $0, 1 bne$t2, $t0, skip_if addi$t3, $t0, 1 addi$t1, $0, 2 Skip_if:…

35 ©Universidade do Algarve 35 Ciclos Transformar o fluxo de controlo (while, for, do while, etc.) em saltos Int sum(int A[], int N) { Int i, sum = 0; For(i=0; i

36 ©Universidade do Algarve 36 Ciclos Optimizações Manter i e endereço de a[i] em registos Determinar endereço de a[0] antes do corpo do ciclo, e incrementar de 4 (no caso de serem acessos a palavras de 32 bits) no corpo do ciclo Caso o ciclo execute pelo menos uma iteração (N > 0) passar salto do ciclo para o fim do corpo

37 ©Universidade do Algarve 37 Ciclos Código após as optimizações Int sum(int A[], int N) { Int i, sum = 0; For(i=0; i

38 ©Universidade do Algarve 38 Procedimentos Protocolo entre os procedimentos que invocam e os procedimentos invocados Dependente do processador No MIPS: Procedimento espera argumentos nos registos $a0-$a3 Coloca valores a retornar nos registos $v0-$v1 Outras formas de passagem de parâmetros utilizam a pilha de chamadas (por exemplo, sempre que o número de argumentos ultrapassa o número de registos para utilizar como argumentos)

39 ©Universidade do Algarve 39 Sumário Quais as responsabilidades do compilador? Esconder do programador conceitos baixo-nível da máquina Produzir rapidamente código eficiente Afectar variáveis a registos locais ou posições de memória Cálculo de expressões com constantes Manter funcionalidade inicial Geração de instruções de forma a suportar as chamadas aos procedimentos utilizadas no programa Optimizações

40 ©Universidade do Algarve 40 Anatomia de um Compilador Compiladores João M. P. Cardoso

41 ©Universidade do Algarve 41 Viagem Do texto que representa o programa até ao código máquina Duas fases: Análise Reconhecimento dos enunciados no código fonte e armazenamento em estruturas internas Síntese Geração do código assembly a partir das estruturas internas

42 ©Universidade do Algarve 42 Análise Lexical Lexical Analyzer (Scanner) Cadeia de Tokens Programa (cadeia de caracteres)

43 ©Universidade do Algarve 43 Análise Lexical /* uma expressão simples */ y = b*x +c; // atribui a y ID(y) EQ ID(b) TIMES ID(x) PLUS ID(c) SEMICOLON EOF Lexical Analyzer (Scanner)

44 ©Universidade do Algarve 44 Análise Lexical /* exemplo Int sum(int A[], int N) { Int i, 5sum = 0; For(i=0; i

45 ©Universidade do Algarve 45 Análise Sintáctica Syntax Analyzer (Parser) Árvore sintáctica Syntax Analyzer (Parser) Lexical Analyzer (Scanner) Cadeia de Tokens Programa (cadeia de caracteres)

46 ©Universidade do Algarve 46 Análise Sintáctica b x * = y y = b*x + c + c Árvore Sintáctica (concreta)

47 ©Universidade do Algarve 47 Análise Sintáctica bx y = + * c Árvore Sintáctica (abstracta): AST y = b*x + c

48 ©Universidade do Algarve 48 Análise Sintáctica Tratamento de erros Int sum(int A[], int N)) { Int i, sum = 0; For(i=0; i

49 ©Universidade do Algarve 49 Análise Semântica Semantic Analyzer Syntax Analyzer (Parser) Árvore sintáctica Syntax Analyzer (Parser) Lexical Analyzer (Scanner) Cadeia de Tokens Programa (cadeia de caracteres) Representação intermédia tmp1 = b*x; tmp2 = tmp1 + c;

50 ©Universidade do Algarve 50 Análise Semântica Tratamento de erros boolean sum(int A[], int N) { Int i, sum; For(i=0; i

51 ©Universidade do Algarve 51 Optimização de código Code Optimizer Representação intermédia optimizada Representação intermédia Semantic Analyzer Syntax Analyzer (Parser) Árvore sintáctica Syntax Analyzer (Parser) Lexical Analyzer (Scanner) Cadeia de Tokens Programa (cadeia de caracteres)

52 ©Universidade do Algarve 52 Geração de código assembly Code Generator Código Assembly Code Generator Code Optimizer Representação intermédia optimizada Representação intermédia Semantic Analyzer Syntax Analyzer (Parser) Árvore sintáctica Syntax Analyzer (Parser) Lexical Analyzer (Scanner) Cadeia de Tokens Programa (cadeia de caracteres) mult $t4, $t1,$t2; Add $t4, $t4, $t3;

53 ©Universidade do Algarve 53 TPC Apresente os resultados de cada etapa de compilação para a expressão: y = a*x*x+b*x+c;

54 ©Universidade do Algarve 54 Análise Lexical Compiladores João M. P. Cardoso

55 ©Universidade do Algarve 55 Linguagens Formais Linguagem natural Ambígua problema no processamento das linguagens dependência do contexto permite mensagens mais curtas Linguagem (artificial) formal Obedece a regras apresentadas rigorosamente através do recurso a formalismos apropriados Regras garantem a não ambiguidade da linguagem

56 ©Universidade do Algarve 56 Linguagens formais e definição da linguagem Necessidade de definir precisamente uma linguagem Estrutura por camadas na definição da linguagem Começar por um conjunto de símbolos da linguagem Estrutura lexical - identifica palavras na linguagem (cada palavra é uma sequência de símbolos) Estrutura Sintáctica - identifica frases na linguagem (cada frase é uma sequência de palavras) Semântica – significado do programa (especifica que resultados deverão ser obtidos para as entradas)

57 ©Universidade do Algarve 57 Especificação Formal de Linguagens Expressões regulares (método generativo) Existem casos que não se podem descrever por expressões regulares Autómatos finitos (método por reconhecimento) Não deterministas (NFAs) Deterministas (DFAs) Implementam qualquer expressão regular

58 ©Universidade do Algarve 58 Especificação de Estruturas Lexicais utilizando Expressões regulares Dado um vocabulário/alfabeto = conjunto de símbolos Expressões regulares são construídas com: - string vazia Qualquer símbolo do alfabeto r 1 r 2 – expressão regular r 1 seguida de r 2 (sequência): concatenação (às vezes utiliza- se o.) r 1 | r 2 – expressão regular r 1 ou r 2 (selecção) r* - sequência iterativa ou selecção | r | rr | … Parêntesis para indicar precedências Prioridade: *,., |

59 ©Universidade do Algarve 59 Expressões regulares Reescrever a expressão regular até se obter apenas uma sequência de letras (string) Exemplo (0 | 1)*.(0 | 1)* (0 | 1)(0 | 1)*.(0 | 1)* 1(0 | 1)*.(0 | 1)* 1.(0 | 1)* 1.(0 | 1)(0 | 1)* 1.(0 | 1) 1.0 Regras gerais 1) r 1 | r 2 r 1 2) r 1 | r 2 r 2 3) r* rr* 4) r*

60 ©Universidade do Algarve 60 Não determinismo na geração Diferente aplicação de regras pode conduzir a resultados finais diferentes Exemplo 1 (0 | 1)*.(0 | 1)* (0 | 1)(0 | 1)*.(0 | 1)* 1(0 | 1)*.(0 | 1)* 1.(0 | 1)* 1.(0 | 1)(0 | 1)* 1.(0 | 1) 1.0 Exemplo 2 (0 | 1)*.(0 | 1)* (0 | 1)(0 | 1)*.(0 | 1)* 0(0 | 1)*.(0 | 1)* 0.(0 | 1)* 0.(0 | 1)(0 | 1)* 0.(0 | 1) 0.1

61 ©Universidade do Algarve 61 Linguagem gerada por expressões regulares Conjunto de todas as strings geradas pela expressão regular é uma linguagem de expressões regulares Em geral, uma linguagem pode ser infinita String na linguagem é chamada de token

62 ©Universidade do Algarve 62 Linguagens e Expressões Regulares Exemplos: = {0, 1,. } (0 | 1)*.(0 | 1)* - números binários de vírgula flutuante (00)* - strings de zeros com comprimento par (1*01*01*)* - strings com um número par de zeros = {a, b, c, 0, 1, 2 } (a | b | c)(a | b | c | 0 | 1 | 2)* - identificadores alfanuméricos (0|1|2)* - números ternários

63 ©Universidade do Algarve 63 Expressões Regulares Outras construções: r + - uma ou mais ocorrências de r: r | rr | rrr... Equivalente a: r.r * r ? – zero ou uma ocorrência de r: (r | ) [ ] – classes de símbolos: [ac] o mesmo que: (a | c) [a-c] o mesmo que: (a | b | c)

64 ©Universidade do Algarve 64 Expressões Regulares Especifique a linguagem de Inteiros Especifique a linguagem de identificadores (uma letra seguida de sequências de letras e algarismos) Enumere propriedades algébricas das expressões regulares Dê exemplos de linguagens que não podem ser especificadas por expressões regulares

65 ©Universidade do Algarve 65 Análise Lexical Compiladores João M. P. Cardoso

66 ©Universidade do Algarve 66 Especificação Formal de Linguagens Expressões regulares (método generativo) Existem casos que não se podem descrever por expressões regulares Autómatos finitos (método por reconhecimento) Não deterministas (NFAs) Deterministas (DFAs) Implementam qualquer expressão regular

67 ©Universidade do Algarve 67 Autómatos Finitos Conjunto de estados 1 estado de Entrada 1 ou mais estados terminais (ou estados de aceitação) Alfabeto de símbolos: (inclui o símbolo de string de tamanho zero: ) Transições entre estados despoletadas pela ocorrência de um determinado símbolo do alfabeto Transições rotuladas com símbolos

68 ©Universidade do Algarve 68 Autómatos Finitos Exemplo Estado de início Estado de aceitação (0 | 1)*.(0 | 1)*

69 ©Universidade do Algarve 69 Aceitação de string pelo autómato Reconhecimento através da execução do autómato Começar com o estado de início e com o primeiro símbolo da string Guardar estado corrente e o símbolo corrente da string Em cada passo, fazer corresponder símbolo corrente com a transição rotulada com esse símbolo Continuar até ao fim da string ou até que a correspondência falhe Se o estado final é estado de aceitação, então o autómato aceita a string Linguagem do autómato é constituída pelo conjunto de strings que ele aceita

70 ©Universidade do Algarve 70 Exemplo 11.0 Símbolo corrente Estado de início Estado de aceitação

71 ©Universidade do Algarve 71 Exemplo 11.0 Símbolo corrente Estado de início Estado de aceitação

72 ©Universidade do Algarve 72 Exemplo 11.0 Símbolo corrente Estado de início Estado de aceitação

73 ©Universidade do Algarve 73 Exemplo 11.0 Símbolo corrente Estado de início Estado de aceitação

74 ©Universidade do Algarve 74 Exemplo 11.0 Símbolo corrente Estado de início Estado de aceitação

75 ©Universidade do Algarve 75 Exemplo 11.0 Símbolo corrente String aceite! Estado de início Estado de aceitação

76 ©Universidade do Algarve 76 Autómatos Finitos NFA: Autómato Finito não Determinista De um determinado estado, a mesma ocorrência pode conduzir a estados distintos DFA O mesmo que NFA com a seguinte ressalva: De um determinado estado, a ocorrência de um símbolo não pode ter mais do que um laço, e por isso não pode levar a estados diferentes.

77 ©Universidade do Algarve 77 NFA vs DFA DFA Sem transições No máximo uma transição de cada estado para cada símbolo NFA – nenhuma destas restrições a a a b OK NOT OK

78 ©Universidade do Algarve 78 Autómatos Finitos Autómatos Finitos Deterministas (DFAs) Implementações mais rápidas do que para os NFAs, mas Maior complexidade do autómato

79 ©Universidade do Algarve 79 Generativo vs Reconhecimento Expressões regulares são um mecanismo para gerar as Strings da linguagem Autómatos são um mecanismo para reconhecer se uma String específica pertence à linguagem Abordagem standard Usar expressões regulares aquando da definição da linguagem Tradução automática para autómatos para a implementação da analisador lexical

80 ©Universidade do Algarve 80 Análise Lexical Compiladores João M. P. Cardoso

81 ©Universidade do Algarve 81 Da Expressão Regular ao Autómato Tradução da Expressão Regular para um Autómato Implementação do Autómato

82 ©Universidade do Algarve 82 Da Expressão Regular ao Autómato Construção por indução estrutural Dada uma expressão regular r arbitrária, Assumir que podemos convertê-la para um autómato com Um estado início Um estado de aceitação Mostrar como converter todas as construções de expressões regulares para produzir um autómato com Um estado de início Um estado de aceitação

83 ©Universidade do Algarve 83 Construtores Básicos a a

84 ©Universidade do Algarve 84 Sequência r1.r2 r1r1 r2r2

85 ©Universidade do Algarve 85 Selecção r1 | r2 r1r1 r2r2

86 ©Universidade do Algarve 86 Asterisco de Kleene r* r

87 ©Universidade do Algarve 87 Regras de Conversão r1r1 r2r2 r1.r2 r1r1 r2r2 r1 | r2 r r* a a

88 ©Universidade do Algarve 88 Conversão A conversão de uma expressão regular para um autómato baseada nas regras apresentadas produz um NFA Nós queremos ter um DFA para facilitar o algoritmo de reconhecimento Pode-se converter do NFA para o DFA o DFA pode ser exponencialmente maior do que o NFA Teoricamente um NFA com N estados pode originar um DFA com 2 N -1 estados A optimização do DFA resultante envolveria eliminação de estados equivalentes

89 ©Universidade do Algarve 89 Conversão NFA para DFA O DFA tem um estado para cada subconjunto de estados no NFA O estado início do DFA corresponde ao conjunto de estados alcançáveis seguindo as transições do estado início no NFA Um estado do DFA é de aceitação se um estado de aceitação do NFA está no conjunto de estados agrupados Para determinar a transição despoletada pelo símbolo a de um dado estado D do DFA Colocar S como conjunto vazio Encontrar o conjunto N de estados D no NFA Para todos os estados do NFA em N Determinar o conjunto de estados N em que o NFA pode estar depois de reconhecer a Actualizar S com a união de S com N Se S não é vazio, há uma transição para a de D para o estado no DFA que tem o conjunto de estados S do NFA Caso contrário, não há nenhuma transição a de D

90 ©Universidade do Algarve 90 NFA para DFA Exemplo: (0 | 1)*.(0|1)* ,2,3,4,8 5,7,2,3,4,8 6,7,2,3,4,8 9,10,11,12,16 13,15,10,11,12,16 14,15,10,11,12,

91 ©Universidade do Algarve 91 Estrutura Lexical nas Linguagens Cada linguagem tem várias categorias de palavras. Numa linguagem de programação: Palavras chave (if, while) Operações aritméticas (+, -, *, /) Números inteiros (1, 2, 45, 67) Números em vírgula flutuante (1.0,.2, 3.337) Identificadores (abc, i, j, ab345) Tipicamente tem-se uma categoria lexical para cada palavra chave e/ou categoria Cada categoria lexical é definida por expressões regulares

92 ©Universidade do Algarve 92 Exemplo de Categorias Lexicais (exemplo) Palavra_chave_if = if Palavra_chave_while = while Operador = +|-|*|/ Inteiro = [0-9] [0-9]* Float = [0-9]*. [0-9]* Identificador = [a-z]([a-z]|[0-9])* Na análise sintáctica vamos utilizar estas categorias

93 ©Universidade do Algarve 93 Análise Lexical Compiladores João M. P. Cardoso

94 ©Universidade do Algarve 94 Da Expressão Regular ao Analisador Lexical Tradução da Expressão Regular para um NFA Do NFA para o DFA Implementação em software do DFA

95 ©Universidade do Algarve 95 Interpretador do DFA State = DFA initial state; inputChar = getchar(); While(inputChar) { State = trans(State, inputChar]); inputChar = getchar(); } If(State é um estado de aceitação) realizar acção relativa ao estado State (reconheceu String) Else realizar outra acção Algoritmo do Interpretador

96 ©Universidade do Algarve 96 NFA para DFA Exemplo: (0 | 1)*.(0|1)* ,2,3,4,8 5,7,2,3,4,8 6,7,2,3,4,8 9,10,11,12,16 13,15,10,11,12,16 14,15,10,11,12,

97 ©Universidade do Algarve 97 DFA Tabela de transição de estados (adicionamos o estado 0 – estado morto - para as transições não apresentadas) Esta do Actu al Próximo Estado

98 ©Universidade do Algarve 98 Implementação do DFA Implementar a tabela de transições de estados com um array bidimensional Esta do Actu al Próximo Estado

99 ©Universidade do Algarve 99 Implementação do DFA O array fornecerá uma indexação por número de estado e símbolo Supondo a possibilidade de 256 símbolos: int Edge[NumStates][256] (NumStates = 7) Esta do Actu al Próximo Estado

100 ©Universidade do Algarve 100 Implementação do DFA int Edge[NumStates][256] = { /* */ /* estado 0 */ {..., 0, 0, 0,..., 0,..., 0,...}, /* estado 1 */ {..., 3, 2, 0,..., 0,..., 4,...}, /* estado 2 */ {..., 3, 2, 0,..., 0,..., 4,...}, /* estado 3 */ {..., 3, 2, 0,..., 0,..., 4,...}, /* estado 4 */ {..., 6, 5, 0,..., 0,..., 0,...}, /* estado 5 */ {..., 6, 5, 0,..., 0,..., 0,...}, /* estado 6 */ {..., 6, 5, 0,..., 0,..., 0,...} } Exemplo: Edge[3][(int).] 4 Esta do Actu al Próximo Estado

101 ©Universidade do Algarve 101 Implementação do DFA Um array unidimensional traduz o número de estado no número da acção a realizar: // estado int final[NumStates] = {0, 0, 0, 0, 1, 1, 1} Exemplo: final[3] 3 (logo deve ser realizada a acção 3) Esta do Actu al Próximo Estado

102 ©Universidade do Algarve 102 Implementação do DFA State = 1; // estado inicial do DFA inputChar = input.read(); While(inputChar) { State = edge[State][inputChar]; inputChar = input.read(); } If(final[State] == 1) realizar acção (reconheceu String) Else realizar outra acção Programação do Interpretador

103 ©Universidade do Algarve 103 Optimizações na implementação do DFA Representação da tabela de transições por um array bidimensional pode não ser eficiente em termos de espaço de memória Mapeamento indirecto: int Edge[NumStates][4] = { /* estado 0 */ {0, 0, 0, 0}, /* estado 1 */ {3, 2, 4, 0}, /* estado 2 */ {3, 2, 4, 0}, /* estado 3 */ {3, 2, 4, 0}, /* estado 4 */ {6, 5, 0, 0}, /* estado 5 */ {6, 5, 0, 0}, /* estado 6 */ {6, 5, 0, 0} } /* */ Int map[256] = {..., 0, 1, 3, 3,... 3,... 2,...} Exemplo: Edge[3][(int).] é feito assim: Edge[3][map[(int).]]

104 ©Universidade do Algarve 104 Optimizações na implementação do DFA Para o exemplo apresentado: Permitiu passar de um array com (1792) elementos para um array com 256 e outro array com 7 4 (28) elementos De 1792 para 284 elementos Existem outras formas de optimização...

105 ©Universidade do Algarve 105 Análise Sintáctica Compiladores João M. P. Cardoso

106 ©Universidade do Algarve 106 Sintaxe em Linguagens de Programação Linguagens regulares deficientes para especificar a sintaxe das linguagens de programação Porquê? Construções com sintaxe encadeada (a+(b-c))*(d-(x-(y-z))) if (x < y) if (y < z) a = 5 else a = 6 else a = 7 Linguagens regulares não têm o estado requerido para modelar encadeamento Nenhuma expressão regular para especificar linguagens com expressões com parêntesis

107 ©Universidade do Algarve 107 Solução Gramáticas independentes do contexto Reconhecimento realizado por autómatos finitos equipados com uma pilha

108 ©Universidade do Algarve 108 Gramáticas Notação de Backus Naur Form (BNF) para especificar a gramática Símbolos terminais: letras maiúsculas (por vezes a negrito) e Símbolos não-terminais: iniciados por uma letra maiúscula Ou, símbolos não-terminais delimitados por Numa produção (derivação) os lados esquerdo e direito são separados pelo símbolo ou ::= Ex.: Expr Term OP Term Produções alternativas (p 1, p 2, p 3,..., p n ) são representadas por p 1 | p 2 | p 3 |...| p n Ex.: Literal BINARIO | OCTAL | INT | FLOAT Se o lado direito de uma produção não contém nenhum símbolo, então escreve-se Ex.: Palavra

109 ©Universidade do Algarve 109 Gramáticas EBNF, ou BNF estendido Inclui { } para representar 0 ou mais repetições de símbolos e [ ] para representar elementos opcionais

110 ©Universidade do Algarve 110 Gramáticas (independentes do contexto) Conjunto de símbolos terminais { OP, INT, OPEN, CLOSE } Cada símbolo terminal definido por expressões regulares Conjunto de símbolos não-terminais { Start, Expr } Conjunto de produções Um único símbolo não-terminal no lado esquerdo da produção (LHS) Sequência de símbolos terminais e não-terminais no lado direito da produção (RHS) OP = + | - | * | / INT = [0-9] [0-9]* OPEN = ( CLOSE = ) Start Expr Expr Expr OP Expr Expr INT Expr OPEN Expr CLOSE

111 ©Universidade do Algarve 111 Jogo da produção/derivação Dada a frase corrente Começar pelo símbolo não-terminal Start Repetir até não haver símbolos não-terminais Seleccionar um símbolo não-terminal Seleccionar uma produção com símbolos não-terminais em LHS Substituir símbolo não-terminal com o RHS da produção Substituir a expressão regular com as Strings correspondentes String gerada está na linguagem Nota: selecções diferentes produzem Strings diferentes

112 ©Universidade do Algarve 112 Produção/Derivação Start Expr Expr OP Expr OPEN Expr CLOSE OP Expr OPEN Expr OP Expr CLOSE OP Expr OPEN INT OP Expr CLOSE OP Expr OPEN INT OP Expr CLOSE OP INT OPEN INT OP INT CLOSE OP INT ( ) + 1 OP = +|-|*|/ INT = [0-9] [0-9]* OPEN = ( CLOSE = ) 1) Start Expr 2) Expr Expr OP Expr 3) Expr INT 4) Expr OPEN Expr CLOSE

113 ©Universidade do Algarve 113 Análise Sintáctica Compiladores João M. P. Cardoso

114 ©Universidade do Algarve 114 Árvore Sintáctica Nós internos: símbolos não-terminais Folhas: símbolos terminais Laços: De símbolos não-terminais do LHS da produção A nós do RHS da produção Captura a derivação da frase (String)

115 ©Universidade do Algarve 115 Árvore Sintáctica para (2-1)+1 Start Expr OP + OPEN ( CLOSE ) Expr INT 1 OP - Expr INT 2 Expr INT 1

116 ©Universidade do Algarve 116 Ambiguidade numa Gramática Múltiplas derivações (como consequência: múltiplas árvores sintácticas) para a mesma String Derivação e árvore sintáctica reflecte usualmente a semântica do programa Ambiguidade na gramática reflecte muitas das vezes ambiguidades na semântica da linguagem (considerada indesejável)

117 ©Universidade do Algarve 117 Exemplo de ambiguidade Duas árvores sintácticas para Start Expr OP + Expr OP - INT 2 INT 1 INT 1 Start Expr OP - Expr OP + INT 1 INT 1 INT 2 Árvore correspondente a (2-1)+1 Árvore correspondente a 2-(1+1)

118 ©Universidade do Algarve 118 Eliminação de ambiguidade Solução: modificar gramática Faz todos os operadores com associação à esquerda Gramática Original Start Expr Expr Expr OP Expr Expr INT Expr OPEN Expr CLOSE Gramática Modificada Start Expr Expr Expr OP INT Expr INT Expr OPEN Expr CLOSE

119 ©Universidade do Algarve 119 Árvore sintáctica para a gramática Apenas uma árvore sintáctica para: Start Expr OP + ExprOP - INT 2 INT 1 INT 1 Start Expr OP - Expr OP + INT 1 INT 1 INT 2 Árvore sintáctica válida Árvore sintáctica inválida

120 ©Universidade do Algarve 120 Violação de prioridade Todos os operadores associam à esquerda Viola prioridade de * sobre + 2-3*4 associa como (2- 3)*4 Start Expr OP * ExprOP - INT 2 INT 3 INT 4 Árvore sintáctica para 2-3*4

121 ©Universidade do Algarve 121 Resolver prioridade Gramática Original OP = + | - | * | / INT = [0-9] [0-9]* OPEN = ( CLOSE = ) Start Expr Expr Expr OP INT Expr INT Expr OPEN Expr CLOSE Gramática Modificada OP1 = + | - OP2 = * | / INT = [0-9] [0-9]* OPEN = ( CLOSE = ) Start Expr Expr Expr OP1 Term Expr Term Expr OPEN Expr CLOSE Term Term OP2 INT Term INT

122 ©Universidade do Algarve 122 Modificação nas Árvores Sintácticas Start Expr OP * ExprOP - INT 2 INT 3 INT 4 Velha Árvore sintáctica para 2-3*4 Start Expr OP1 - Term INT 2 Nova Árvore sintáctica para 2-3*4 Term OP2 * INT 3 INT 4

123 ©Universidade do Algarve 123 Ideia Geral Agrupar operadores por níveis de prioridade * e / estão no nível de topo + e – estão no nível a seguir Símbolo não-terminal para cada nível de prioridade Term é não-terminal para * e / Expr é não-terminal para + e - Pode-se fazer associatividade dos operadores à esquerda ou à direita em cada nível Generalizar para níveis arbitrários de prioridades

124 ©Universidade do Algarve 124 Exercícios (TPC) Especificar utilizando a representação BNF gramáticas correspondentes às expressões regulares: [0-9]+ e [0- 9]* Dada a gramática: NUM = [0-9]+ ID = [A-Za-Z][0-9A-Za-z]* Expr Expr + Term | Expr – Term | Term Term Term * Factor | Term / Factor | Factor Factor Primary ^ Factor | Primary Primary -Primary | Element Element ( Expr ) | NUM | ID Quais as árvores sintácticas para: 5-2*3 y^3

125 ©Universidade do Algarve 125 Análise Sintáctica Compiladores João M. P. Cardoso

126 ©Universidade do Algarve 126 Manuseando estruturas if-then- else Start Stat Stat IF Expr THEN Stat ELSE Stat Stat IF Expr THEN Stat Stat...

127 ©Universidade do Algarve 127 Árvore Sintáctica Considere o enunciado: if e 1 then if e 2 then s 1 else s 2

128 ©Universidade do Algarve 128 Árvore Sintáctica Duas Árvores Sintácticas Stat IF Expr Stat IF ExprStat ELSE e1 e2 Stat s1s2 IF Expr Stat IF ExprStat ELSE e2 e1 Stat s1 s2 Qual é a correcta? THEN

129 ©Universidade do Algarve 129 Leituras alternativas Gramática ambígua Árvore sintáctica 1 if e 1 if e 2 s 1 else s 2 Árvore sintáctica 2 if e 1 if e 2 s 1 else s 2

130 ©Universidade do Algarve 130 Gramática modificada Goal Stat Stat WithElse Stat LastElse WithElse IF Expr THEN WithElse ELSE WithElse WithElse... LastElse IF Expr THEN Stat LastElse IF Expr THEN WithElse ELSE LastElse

131 ©Universidade do Algarve 131 Gramática modificada Ideia básica: controlar quando um IF sem ELSE pode ocorrer No nível de topo do enunciado Ou como último numa sequência de enunciados if then else if then...

132 ©Universidade do Algarve 132 Analisador Sintáctico Converte programas numa árvore sintáctica Pode ser programado do zero! Ou construído automaticamente por um gerador de parsers Aceitam uma gramática como entrada Produzem um analisador sintáctico como resultado Problema prático A Árvore Sintáctica para a gramática modificada é complicada Gostaríamos de começar com uma árvore sintáctica mais intuitiva

133 ©Universidade do Algarve 133 Solução Sintaxe Abstracta versus Concreta Sintaxe abstracta corresponde ao meio intuitivo de pensar a estrutura do programa Omite detalhes como palavras-chave supérfluas que estão lá para tornar a linguagem ambígua Sintaxe abstracta pode ser ambígua Sintaxe Concreta corresponde à gramática completa para utilizada para analisar sintacticamente a linguagem Os analisadores sintácticos são muitas das vezes escritos para produzirem Árvores Sintácticas Abstractas (ASTs)

134 ©Universidade do Algarve 134 ASTs (Árvores Sintácticas Abstractas) Começar com uma gramática intuitiva mas ambígua Modificar a gramática para a tornar não- ambígua Árvores sintácticas concretas Menos intuitivas Converter as árvores sintácticas concretas em ASTs Correspondem à gramática intuitiva para a linguagem Mais simples de manipular pelo programa

135 ©Universidade do Algarve 135 Exemplo Gramática intuitiva mas ambígua OP = * | / | + | - INT = [0-9] [0-9]* Start Expr Expr Expr OP Expr Expr INT Gramática não-ambígua OP1 = + | - OP2 = * | / INT = [0-9] [0-9]* OPEN = ( CLOSE = ) Start Expr Expr Expr OP1 Term Expr Term Term OPEN Expr CLOSE Term Term OP2 INT Term INT

136 ©Universidade do Algarve 136 Exemplo Start Expr OP2 - INT 3 Árvore sintáctica concreta para (2-3)*4 Term OP1 * INT 4 Term OPENCLOSE Term INT 2 Term Start Expr OP * Expr OP - INT 2 Expr INT 4 Expr INT 3 Árvore sintáctica abstracta para (2-3)*4 Utiliza gramática intuitiva Elimina terminais supérfluos OPEN, CLOSE, etc.

137 ©Universidade do Algarve 137 Exemplo Start Expr OP * OP - INT 2 INT 4 INT 3 AST para (2-3)*4 Ainda mais simplificada Árvore sintáctica abstracta para (2-3)*4 Start Expr OP * Expr OP - INT 2 Expr INT 4 Expr INT 3

138 ©Universidade do Algarve 138 Sumário Níveis da estrutura lexicais e sintácticos Lexicais – expressões regulares e autómatos Sintácticos – gramáticas Ambiguidades na gramática Gramáticas modificadas Árvores Sintácticas Abstractas (ASTs) Papel generativo versus papel reconhecedor Generativo mais conveniente para especificação Reconhecedor requerido na implementação

139 ©Universidade do Algarve 139 Análise Sintáctica Compiladores João M. P. Cardoso

140 ©Universidade do Algarve 140 Vocabulário gramatical Derivação à esquerda (Leftmost) Expandir sempre o símbolo não terminal mais à esquerda que resta Derivação à direita (Rightmost) Expandir sempre o símbolo não terminal mais à direita que resta Aplicar primeiro a produção aqui NT 1 T 1 T 2 T 3 NT 2 NT 3 E só depois aos outros símbolos não-terminais

141 ©Universidade do Algarve 141 Ponto Inicial Assumir que a análise lexical produziu uma sequência de tokens (símbolos terminais) Cada token tem um tipo e um valor Tipos correspondem a símbolos terminais Valores correspondem ao conteúdo do token lido Exemplo INT(549) – token que identifica um inteiro de valor lido 549 IF – palavra chave if sem necessidade de valor OP(+) – operador com valor +

142 ©Universidade do Algarve 142 Abordagem Básica Começar pelo símbolo Start ou pela primeira produção Construir uma derivação leftmost Se o símbolo leftmost é não-terminal, seleccionar uma produção e aplicá-la Se o símbolo leftmost é terminal, fazer corresponder com a entrada Se todos os terminais foram correspondidos, foi encontrada uma derivação que aceita a String! Chave: encontrar as produções correctas para os símbolos não-terminais

143 ©Universidade do Algarve 143 Gramática do Exemplo INT = [0-9]+ Start Expr Expr Expr + Term Expr Expr - Term Expr Term Term Term * INT Term Term / INT Term INT Conjunto de tokens (símbolos terminais): { +, -, *, /, INT }

144 ©Universidade do Algarve 144 Analisador Sintáctico para a gramática exemplo Start Árvore Sintáctica Posição corrente na árvore sintáctica Forma sentencial Entrada que falta 2-2*2 Start

145 ©Universidade do Algarve 145 Analisador Sintáctico para a gramática exemplo Start Árvore Sintáctica Forma sentencial Entrada que falta 2-2*2 Expr Posição corrente na árvore sintáctica Expr Produção Aplicada Start Expr

146 ©Universidade do Algarve 146 Analisador Sintáctico para a gramática exemplo Start Árvore Sintáctica Forma sentencial Entrada a faltar 2-2*2 Expr - Term Expr Produção Aplicada Expr Expr - Term Term Expr-

147 ©Universidade do Algarve 147 Analisador Sintáctico para a gramática exemplo Start Árvore Sintáctica Forma sentencial Entrada que falta 2-2*2 Term - Term Expr Produção Aplicada Expr Term Term Expr- Term

148 ©Universidade do Algarve 148 Analisador Sintáctico para a gramática exemplo Start Árvore Sintáctica Forma sentencial Entrada que falta 2-2*2 INT - Term Expr Produção Aplicada Term INT Term Expr- INT Term

149 ©Universidade do Algarve 149 Analisador Sintáctico para a gramática exemplo Start Árvore Sintáctica Forma sentencial Entrada que falta 2-2*2 2 - Term Expr Term Expr- INT 2 Term Token corresponde!

150 ©Universidade do Algarve 150 Analisador Sintáctico para a gramática exemplo Start Árvore Sintáctica Forma sentencial Entrada que falta -2*2 2 - Term Expr Term Expr- INT 2 Term Token corresponde!

151 ©Universidade do Algarve 151 Analisador Sintáctico para a gramática exemplo Start Árvore Sintáctica Forma sentencial Entrada que falta 2*2 2 - Term Expr Term Expr- INT 2 Term

152 ©Universidade do Algarve 152 Analisador Sintáctico para a gramática exemplo Start Árvore Sintáctica Forma sentencial Entrada que falta 2*2 2 – Term*INT Expr Term Expr- INT 2 Term INT * Produção Aplicada Term Term * INT

153 ©Universidade do Algarve 153 Analisador Sintáctico para a gramática exemplo Start Árvore Sintáctica Forma sentencial Entrada que falta 2*2 2 – INT*INT Expr Term Expr- INT 2 Term INT * Produção Aplicada Term INT INT

154 ©Universidade do Algarve 154 Analisador Sintáctico para a gramática exemplo Start Árvore Sintáctica Forma sentencial Entrada que falta 2*2 2 – 2*INT Expr Term Expr- INT 2 Term INT * INT 2 Token corresponde!

155 ©Universidade do Algarve 155 Analisador Sintáctico para a gramática exemplo Start Árvore Sintáctica Forma sentencial Entrada que falta *2 2 – 2*INT Expr Term Expr- INT 2 Term INT * INT 2 Token corresponde!

156 ©Universidade do Algarve 156 Analisador Sintáctico para a gramática exemplo Start Árvore Sintáctica Forma sentencial Entrada que falta 2 2 – 2*INT Expr Term Expr- INT 2 Term INT * INT 2

157 ©Universidade do Algarve 157 Analisador Sintáctico para a gramática exemplo Start Árvore Sintáctica Forma sentencial Entrada que falta 2 2 – 2*2 Expr Term Expr- INT 2 Term INT 2 * Token corresponde!

158 ©Universidade do Algarve 158 Analisador Sintáctico para a gramática exemplo Start Árvore Sintáctica Forma sentencial Entrada que falta 2 – 2*2 Expr Term Expr- INT 2 Term INT 2 * Análise sintáctica terminou

159 ©Universidade do Algarve 159 Sumário Três acções (mecanismos) Aplicar produção para expandir o símbolo não-terminal corrente na árvore sintáctica Casar o símbolo terminal corrente Aceitar a análise sintáctica como correcta Qual a produção a utilizar por cada símbolo não-terminal? Uma abordagem: Backtracking Tenta uma alternativa Quando for claro que a alternativa falhou tentar outra alternativa

160 ©Universidade do Algarve 160 Analisador Sintáctico Preditivo Alternativa ao backtracking Muito útil para linguagens de programação, que podem ser desenhadas para facilitar a análise Ideia básica Ver à frente na sequência de tokens Decisão de qual a produção a aplicar baseada nos tokens seguintes Utilizaremos a profundidade de um token no mecanismo de ver à frente

161 ©Universidade do Algarve 161 Gramática Exemplo Start Expr Expr Term Expr Expr + Term Expr Expr - Term Expr Expr Term INT Term Term * INT Term Term / INT Term Term INT = [0-9]+ Conjunto de tokens (símbolos terminais): { +, -, *, /, INT }

162 ©Universidade do Algarve 162 Pontos de Escolha Assumir que Term é a posição corrente na árvore sintáctica 3 produções diferentes a aplicar Term * INT Term Term / INT Term Term Utilizar o próximo token para decidir Se o próximo token for *, aplicar Term * Int Term Se o próximo token for /, aplicar Term / Int Term De outro modo, aplicar Term

163 ©Universidade do Algarve 163 Múltiplas Produções com o mesmo prefixo no RHS Gramática Exemplo Nt IF THEN Nt IF THEN ELSE Assumir que Nt é a posição corrente na árvore sintáctica e IF é o próximo token Qual a produção a aplicar?

164 ©Universidade do Algarve 164 Solução: factorizar a gramática à esquerda Nova gramática factoriza o prefixo comum numa única produção Nt IF THEN Nt Nt ELSE Nt Nenhuma escolha quando o próximo token é um IF Todas as alternativas foram unificadas numa única produção

165 ©Universidade do Algarve 165 Símbolos não-terminais E as produções com símbolos não- terminais? Nt Nt 1 1 Nt Nt 2 2 Tem de se escolher com base nos primeiros terminais possíveis que Nt 1 e Nt 2 podem gerar E se Nt 1 ou Nt 2 podem gerar ? Tem de se escolher com base em 1 e 2

166 ©Universidade do Algarve 166 Análise Sintáctica Compiladores João M. P. Cardoso

167 ©Universidade do Algarve 167 Analisador sintáctico descendente A recursividade à esquerda pode levar a ciclos infinitos! Exemplo de produção: Term Term*Num Passos potenciais na análise: Term Num * Term Num * Term Num *

168 ©Universidade do Algarve 168 Analisador sintáctico descendente A recursividade à esquerda pode levar a ciclos infinitos! Solução: modificar gramática de modo a eliminar recursividade à esquerda

169 ©Universidade do Algarve 169 Eliminar recursividade à esquerda Começar com produções da forma A A A Sequências, de símbolos terminais e não-terminais que não começam com A Repetição da aplicação: A A forma a árvore sintáctica seguinte: A A A

170 ©Universidade do Algarve 170 Eliminar recursividade à esquerda Produções de substituição A A A R R é um novo símbolo não-terminal A R R R A A A R R R Árvore inicial Nova Árvore

171 ©Universidade do Algarve 171 Gramática do Exemplo INT = [0-9]+ Start Expr Expr Expr + Term Expr Expr - Term Expr Term Term Term * INT Term Term / INT Term INT Conjunto de tokens (símbolos terminais): { +, -, *, /, INT }

172 ©Universidade do Algarve 172 Gramática Modificada Pedaço da gramática original Term Term * INT Term Term / INT Term INT Pedaço da gramática modificada Term INT Term Term * INT Term Term / INT Term Term

173 ©Universidade do Algarve 173 Gramática Modificada Start Expr Expr Term Expr Expr + Term Expr Expr - Term Expr Expr Term INT Term Term * INT Term Term / INT Term Term INT = [0-9]+ Start Expr Expr Expr + Term Expr Expr - Term Expr Term Term Term * INT Term Term / INT Term INT

174 ©Universidade do Algarve 174 Comparando as Árvores Sintácticas Term INT* Term INT * Term INTTerm INT* Term INT* Term Gramática originalGramática modificada

175 ©Universidade do Algarve 175 Eliminar Recursividade à esquerda Necessária na análise sintáctica preditiva Modifica o algoritmo de procura no espaço de produções Elimina recursividade directa infinita Contudo: gramática modificada é menos intuitiva Requer mais transformações para se atingir AST desejada

176 ©Universidade do Algarve 176 Requer +transformações para se alcançar AST desejada Árvore Sintáctica para: 2*3*4 Construir AST durante a derivação! Term INT 2 Term INT 3 * Term INT 4 * Term Term INT 3 * Term INT 4 * INT 2 Árvore Sintáctica Concreta AST desejada

177 ©Universidade do Algarve 177 Sumário Analisador sintáctico descendente Utilizar Lookahead para evitar Backtracking Modificar gramática para evitar necessidade de inspecção de tokens muito à frente (lookahead): factorização Modificar gramática para evitar ciclos infinitos Como implementar o analisador sintáctico descendente?

178 ©Universidade do Algarve 178 Análise Sintáctica Compiladores João M. P. Cardoso

179 ©Universidade do Algarve 179 Gramática Modificada Pedaço da gramática original Term Term * INT Term Term / INT Term INT Pedaço da gramática modificada Term INT Term Term * INT Term Term / INT Term Term

180 ©Universidade do Algarve 180 Analisador Sintáctico Construído Manualmente Um procedimento por símbolo não-terminal Esse procedimento examina o símbolo corrente de entrada Chama recursivamente procedimentos para RHS da produção escolhida Os procedimentos retornam verdadeiro se a análise sintáctica foi bem sucedida e retornam falso em caso contrário

181 ©Universidade do Algarve 181 Exemplo Procedimento para o símbolo não- terminal Term: Term() { if (token == INT) { token = NextToken(); return TermPrime(); } else return false; } Produções para o símbolo não-terminal Term: Term INT Term A função NextToken() avança um token na sequência de tokens gerada pela análise lexical e retorna o token nessa posição.

182 ©Universidade do Algarve 182 Exemplo Procedimento para o símbolo não-terminal Term: TermPrime() { if((token == *) || (token == /)) { token = NextToken(); if (token == INT) { token = NextToken(); return TermPrime(); } else return false; } else return true; }

183 ©Universidade do Algarve 183 Exemplo Pseudo-código para a parte do programa responsável pela análise sintáctica:... token = NextToken(); Term();...

184 ©Universidade do Algarve 184 Construção da Árvore Sintáctica Cada procedimento retorna a secção da árvore sintáctica para a parte da String que analisou Utilizar excepções para tornar clara a estrutura do código (outra forma será utilizar uma função de erro) Em geral, podemos ajustar o algoritmo de análise sintáctica para satisfazer objectivos diferentes Tipicamente, produz AST em vez de árvore sintáctica concreta

185 ©Universidade do Algarve 185 Construção da Árvore Sintáctica para o exemplo Com geração de excepções: Term() { if (token == INT) { oldToken = token; token = NextToken(); node = TermPrime(); if (node == NULL) return oldToken; else return new TermNode(oldToken, node); } else throw SyntaxError; }

186 ©Universidade do Algarve 186 Construção da Árvore Sintáctica para o exemplo Com geração de excepções: TermPrime() { if ((token == *) || (token == /)) { first = token; next = NextToken(); if (next == INT) { token = NextToken(); return new TermPrimeNode(first, next, TermPrime()); } else throw SyntaxError; } else return NULL; }

187 ©Universidade do Algarve 187 Construção da Árvore Sintáctica para o exemplo Sem geração de excepções Term() { if (token == INT) { oldToken = token; token = NextToken(); node = TermPrime(); if (node == NULL) return oldToken; else return new TermNode(oldToken, node); } else error(); } TermPrime() { if ((token == *) || (token == /)) { first = token; next = NextToken(); if (next == INT) { token = NextToken(); return new TermPrimeNode(first, next, TermPrime()); } else error(); } else return NULL; }

188 ©Universidade do Algarve 188 Árvore Sintáctica para 2*3*4 Term INT 2 Term INT 3 * Term INT 4 * Term Term INT 3 * Term INT 4 * INT 2 Árvore Sintáctica Concreta AST desejada

189 ©Universidade do Algarve 189 Análise Sintáctica Compiladores João M. P. Cardoso

190 ©Universidade do Algarve 190 Geração Directa da AST TermPrime constrói uma árvore incompleta Falta leftmost child Retorna a raiz e o nó incompleto (root, incomplete) = TermPrime() Chamada com token: * Tokens que faltam: 3 * 4 Term INT 3 * Term INT 4 * root incomplete Falta parte esquerda que será construída pelo procedimento de chamada

191 ©Universidade do Algarve 191 Código para Term Term() { if (token == INT) { leftmostInt = token; token = NextToken(); (root, incomplete) = TermPrime(); if (root == NULL) return leftmostInt; incomplete.leftChild = leftmostInt; return root; } else throw SyntaxError; } INT 2 token 2*3*4 Entrada

192 ©Universidade do Algarve 192 Código para Term INT 2 token 2*3*4 Entrada Term() { if (token == INT) { leftmostInt = token; token = NextToken(); (root, incomplete) = TermPrime(); if (root == NULL) return leftmostInt; incomplete.leftChild = leftmostInt; return root; } else throw SyntaxError; }

193 ©Universidade do Algarve 193 Código para Term INT 2 leftmostInt 2*3*4 Entrada Term() { if (token == INT) { leftmostInt = token; token = NextToken(); (root, incomplete) = TermPrime(); if (root == NULL) return leftmostInt; incomplete.leftChild = leftmostInt; return root; } else throw SyntaxError; }

194 ©Universidade do Algarve 194 Código para Term Term INT 3 * Term INT 4 * INT 2 root incomplete leftmostInt 2*3*4 Entrada Term() { if (token == INT) { leftmostInt = token; token = NextToken(); (root, incomplete) = TermPrime(); if (root == NULL) return leftmostInt; incomplete.leftChild = leftmostInt; return root; } else throw SyntaxError; }

195 ©Universidade do Algarve 195 Código para Term Term INT 3 * Term INT 4 * INT 2 root incomplete leftmostInt 2*3*4 Entrada Term() { if (token == INT) { leftmostInt = token; token = NextToken(); (root, incomplete) = TermPrime(); if (root == NULL) return leftmostInt; incomplete.leftChild = leftmostInt; return root; } else throw SyntaxError; }

196 ©Universidade do Algarve 196 Código para Term Term INT 3 * Term INT 4 * INT 2 root incomplete leftmostInt 2*3*4 Entrada Term() { if (token == INT) { leftmostInt = token; token = NextToken(); (root, incomplete) = TermPrime(); if (root == NULL) return leftmostInt; incomplete.leftChild = leftmostInt; return root; } else throw SyntaxError; }

197 ©Universidade do Algarve 197 Código para TermPrime TermPrime() { if((token == *) || (token == /)) { op = token; next = NextToken(); if (next == INT) { token = NextToken(); (root, incomplete) = TermPrime(); if (root == NULL) { root = new ExprNode(NULL, op, next); return(root, root); } else { newChild = new ExprNode(NULL, op, next); incomplete.leftChild = newChild; return(root, newChild); } } else throw SyntaxError; } else return(NULL,NULL); } Filho da esquerda a ser colocado pelo procedimento de chamada

198 ©Universidade do Algarve 198 Sumário Analisador sintáctico descendente (Top-Down Parser) Utilizar Lookahead para evitar Backtracking O parser é um conjunto de procedimentos mutuamente recursivos

199 ©Universidade do Algarve 199 Terminologia Muitas técnicas de análise sintáctica diferentes Cada uma pode manusear algum conjunto de CFGs (gramáticas independentes do contexto) Categorização das técnicas ()

200 ©Universidade do Algarve 200 Terminologia Muitas técnicas de análise sintáctica diferentes Cada uma pode manusear algum conjunto de CFGs (gramáticas independentes do contexto) Categorização das técnicas L – análise da esq. para a drt. R - análise da drt. para a esq. ()

201 ©Universidade do Algarve 201 Terminologia Muitas técnicas de análise sintáctica diferentes Cada uma pode manusear algum conjunto de CFGs (gramáticas independentes do contexto) Categorização das técnicas L – derivação pela esquerda R – derivação pela direita ()

202 ©Universidade do Algarve 202 Terminologia Muitas técnicas de análise sintáctica diferentes Cada uma pode manusear algum conjunto de CFGs (gramáticas independentes do contexto) Categorização das técnicas Número de lookahead ()

203 ©Universidade do Algarve 203 Terminologia Muitas técnicas de análise sintáctica diferentes Cada uma pode manusear algum conjunto de CFGs (gramáticas independentes do contexto) Categorização das técnicas Exemplos: LL(0), LR(1) Até agora: LL(1) Nas próximas aulas Análises LR(k) ( ) LLk

204 ©Universidade do Algarve 204 Terminologia LL(k) Descendente (top-down), preditiva Constrói derivação pela esquerda (leftmost) de cima para baixo LR(k) Ascendente (bottom-up), shift-reduce Constrói derivação pela direita (rightmost) de baixo para cima

205 ©Universidade do Algarve 205 Análise Sintáctica Compiladores João M. P. Cardoso

206 ©Universidade do Algarve 206 Analisador Sintáctico Ascendente Mecanismo Central Autómato Pushdown, que implementa Parser Shift-reduce

207 ©Universidade do Algarve 207 Autómato Push-Down Constituído por Pilha Pushdown (pode conter terminais e não- terminais) Controlo por um autómato de estados finitos Pode realizar uma de três acções: Shift: Desloca símbolo corrente da entrada para a pilha Reduce: Se o(s) símbolo(s) no topo da pilha casa(m) RHS de alguma das produções da gramática Pop (retirar) esses símbolos da pilha Push não-terminal do LHS para a pilha Aceita a entrada como pertencendo à linguagem

208 ©Universidade do Algarve 208 *(+num) Expr Expr Op Expr Expr (Expr) Expr - Expr Expr num Op + Op - Op * Pilha String de entrada Exemplo: Parser Shift-Reduce

209 ©Universidade do Algarve 209 *(+num) Expr Expr Op Expr Expr (Expr) Expr - Expr Expr num Op + Op - Op * Exemplo: Parser Shift-Reduce

210 ©Universidade do Algarve 210 SHIFT *(+num) Expr Expr Op Expr Expr (Expr) Expr - Expr Expr num Op + Op - Op * Exemplo: Parser Shift-Reduce

211 ©Universidade do Algarve 211 SHIFT *(+num) Expr Expr Op Expr Expr (Expr) Expr - Expr Expr num Op + Op - Op * Exemplo: Parser Shift-Reduce

212 ©Universidade do Algarve 212 *(+num) Expr Expr Op Expr Expr (Expr) Expr - Expr Expr num Op + Op - Op * REDUCE Exemplo: Parser Shift-Reduce

213 ©Universidade do Algarve 213 *(+num) Expr Expr Op Expr Expr (Expr) Expr - Expr Expr num Op + Op - Op * REDUCE Expr Exemplo: Parser Shift-Reduce

214 ©Universidade do Algarve 214 *(+num) Expr Expr Op Expr Expr (Expr) Expr - Expr Expr num Op + Op - Op * Expr SHIFT Exemplo: Parser Shift-Reduce

215 ©Universidade do Algarve 215 (+num) Expr Expr Op Expr Expr (Expr) Expr - Expr Expr num Op + Op - Op * Expr SHIFT * Exemplo: Parser Shift-Reduce

216 ©Universidade do Algarve 216 (+num) Expr Expr Op Expr Expr (Expr) Expr - Expr Expr num Op + Op - Op * Expr Op REDUCE * Exemplo: Parser Shift-Reduce

217 ©Universidade do Algarve 217 (+num) Expr Expr Op Expr Expr (Expr) Expr - Expr Expr num Op + Op - Op * Expr Op * SHIFT Exemplo: Parser Shift-Reduce

218 ©Universidade do Algarve 218 +num) Expr Expr Op Expr Expr (Expr) Expr - Expr Expr num Op + Op - Op * Expr Op * SHIFT ( Exemplo: Parser Shift-Reduce

219 ©Universidade do Algarve 219 +num) Expr Expr Op Expr Expr (Expr) Expr - Expr Expr num Op + Op - Op * Expr Op * SHIFT ( Exemplo: Parser Shift-Reduce

220 ©Universidade do Algarve 220 +num) Expr Expr Op Expr Expr (Expr) Expr - Expr Expr num Op + Op - Op * Expr Op * SHIFT ( num Exemplo: Parser Shift-Reduce

221 ©Universidade do Algarve 221 +num) Expr Expr Op Expr Expr (Expr) Expr - Expr Expr num Op + Op - Op * Expr Op * SHIFT ( num REDUCE Expr Exemplo: Parser Shift-Reduce

222 ©Universidade do Algarve 222 +num) Expr Expr Op Expr Expr (Expr) Expr - Expr Expr num Op + Op - Op * Expr Op * SHIFT ( num Expr Exemplo: Parser Shift-Reduce

223 ©Universidade do Algarve 223 num) Expr Expr Op Expr Expr (Expr) Expr - Expr Expr num Op + Op - Op * Expr Op * SHIFT ( num Expr + Exemplo: Parser Shift-Reduce

224 ©Universidade do Algarve 224 num) Expr Expr Op Expr Expr (Expr) Expr - Expr Expr num Op + Op - Op * Expr Op * SHIFT ( num Expr Op REDUCE + Exemplo: Parser Shift-Reduce

225 ©Universidade do Algarve 225 num) Expr Expr Op Expr Expr (Expr) Expr - Expr Expr num Op + Op - Op * Expr Op * SHIFT ( num Expr Op + Exemplo: Parser Shift-Reduce

226 ©Universidade do Algarve 226 ) num Expr Expr Op Expr Expr (Expr) Expr - Expr Expr num Op + Op - Op * Expr Op * SHIFT ( num Expr num Op + Exemplo: Parser Shift-Reduce

227 ©Universidade do Algarve 227 ) num Expr Expr Op Expr Expr (Expr) Expr - Expr Expr num Op + Op - Op * Expr Op * SHIFT ( num Expr Op + Expr REDUCE num Exemplo: Parser Shift-Reduce

228 ©Universidade do Algarve 228 ) num Expr Expr Op Expr Expr (Expr) Expr - Expr Expr num Op + Op - Op * Expr Op * SHIFT ( num+ REDUCE num Expr Op Expr Exemplo: Parser Shift-Reduce

229 ©Universidade do Algarve 229 ) num Expr Expr Op Expr Expr (Expr) Expr - Expr Expr num Op + Op - Op * Expr Op * SHIFT ( num Expr Op + Expr num Expr Exemplo: Parser Shift-Reduce

230 ©Universidade do Algarve 230 num Expr Expr Op Expr Expr (Expr) Expr - Expr Expr num Op + Op - Op * Expr Op * SHIFT ( num Expr Op + Expr num Expr ) Exemplo: Parser Shift-Reduce

231 ©Universidade do Algarve 231 REDUCE num Expr Expr Op Expr Expr (Expr) Expr - Expr Expr num Op + Op - Op * Expr Op * ( num Expr Op + Expr num Expr ) Exemplo: Parser Shift-Reduce

232 ©Universidade do Algarve 232 REDUCE num Expr Expr Op Expr Expr (Expr) Expr - Expr Expr num Op + Op - Op * Expr Op * ( num Expr Op + Expr num Expr ) Exemplo: Parser Shift-Reduce

233 ©Universidade do Algarve 233 ACCEPT! num Expr Expr Op Expr Expr (Expr) Expr - Expr Expr num Op + Op - Op * Expr Op * ( num Expr Op + Expr num Expr ) Exemplo: Parser Shift-Reduce

234 ©Universidade do Algarve 234 Conflitos que podem Ocorrer Conflito Reduce/Reduce O topo da pilha pode casar com RHS de produções múltiplas Qual a produção a utilizar na redução? Conflito Shift/Reduce Pilha pode casar com RHS da produção Mas esse pode não ser o casamento correcto Pode ser necessário deslocar a entrada e encontrar mais tarde uma redução diferente

235 ©Universidade do Algarve 235 Expr Expr Op Expr Expr (Expr) Expr - Expr Expr num Op + Op - Op * Conflitos Gramática Original Nova Gramática Expr Expr Op Expr Expr Expr - Expr Expr (Expr) Expr Expr - Expr num Op + Op - Op *

236 ©Universidade do Algarve 236 -num Conflitos Expr Expr Op Expr Expr Expr - Expr Expr (Expr) Expr Expr - Expr num Op + Op - Op *

237 ©Universidade do Algarve 237 -num SHIFT Conflitos Expr Expr Op Expr Expr Expr - Expr Expr (Expr) Expr Expr - Expr num Op + Op - Op *

238 ©Universidade do Algarve 238 -num SHIFT num Conflitos Expr Expr Op Expr Expr Expr - Expr Expr (Expr) Expr Expr - Expr num Op + Op - Op *

239 ©Universidade do Algarve 239 -num SHIFT Expr REDUCE num Conflitos Expr Expr Op Expr Expr Expr - Expr Expr (Expr) Expr Expr - Expr num Op + Op - Op *

240 ©Universidade do Algarve 240 -num SHIFT Expr num Conflitos Expr Expr Op Expr Expr Expr - Expr Expr (Expr) Expr Expr - Expr num Op + Op - Op *

241 ©Universidade do Algarve 241 num SHIFT Expr num - Conflitos Expr Expr Op Expr Expr Expr - Expr Expr (Expr) Expr Expr - Expr num Op + Op - Op *

242 ©Universidade do Algarve 242 num Expr num - Opções: Reduce Shift Conflito shift/reduce/reduce Expr Expr Op Expr Expr Expr - Expr Expr (Expr) Expr Expr - Expr num Op + Op - Op *

243 ©Universidade do Algarve 243 num Expr num - REDUCE Conflito shift/reduce/reduce Expr Expr Op Expr Expr Expr - Expr Expr (Expr) Expr Expr - Expr num Op + Op - Op * O que acontece ao escolher- se: Reduce

244 ©Universidade do Algarve 244 num Expr num- SHIFT Expr Conflito shift/reduce/reduce Expr Expr Op Expr Expr Expr - Expr Expr (Expr) Expr Expr - Expr num Op + Op - Op * O que acontece ao escolher- se: Reduce

245 ©Universidade do Algarve 245 Expr num- SHIFT Expr num Conflito shift/reduce/reduce Expr Expr Op Expr Expr Expr - Expr Expr (Expr) Expr Expr - Expr num Op + Op - Op * O que acontece ao escolher- se: Reduce

246 ©Universidade do Algarve 246 Expr num- Expr Expr Op Expr Expr Expr - Expr Expr (Expr) Expr Expr - Expr num Op + Op - Op * O que acontece ao escolher- se: Reduce REDUCE Expr num Conflito shift/reduce/reduce

247 ©Universidade do Algarve 247 Expr num- FAILS! Expr num Expr Expr Op Expr Expr Expr - Expr Expr (Expr) Expr Expr - Expr num Op + Op - Op * O que acontece ao escolher- se: Reduce Conflito shift/reduce/reduce

248 ©Universidade do Algarve 248 num Expr num - Qualquer uma destas opções resulta: Reduce Shift Conflito shift/reduce/reduce Expr Expr Op Expr Expr Expr - Expr Expr (Expr) Expr Expr - Expr num Op + Op - Op *

249 ©Universidade do Algarve 249 num Expr num - O que acontece ao escolher-se: Reduce Conflito shift/reduce/reduce Expr Expr Op Expr Expr Expr - Expr Expr (Expr) Expr Expr - Expr num Op + Op - Op *

250 ©Universidade do Algarve 250 num Expr num Op - REDUCE Conflito shift/reduce/reduce O que acontece ao escolher-se: Reduce Expr Expr Op Expr Expr Expr - Expr Expr (Expr) Expr Expr - Expr num Op + Op - Op *

251 ©Universidade do Algarve 251 Expr num Op - SHIFT num O que acontece ao escolher-se: Reduce Expr Expr Op Expr Expr Expr - Expr Expr (Expr) Expr Expr - Expr num Op + Op - Op * Conflito shift/reduce/reduce

252 ©Universidade do Algarve 252 Expr num Op - REDUCE Expr num O que acontece ao escolher-se: Reduce Expr Expr Op Expr Expr Expr - Expr Expr (Expr) Expr Expr - Expr num Op + Op - Op * Conflito shift/reduce/reduce

253 ©Universidade do Algarve 253 Expr num Op - REDUCE Expr num Expr Conflito shift/reduce/reduce O que acontece ao escolher-se: Reduce Expr Expr Op Expr Expr Expr - Expr Expr (Expr) Expr Expr - Expr num Op + Op - Op *

254 ©Universidade do Algarve 254 Expr num Op - ACCEPT Expr num Expr Conflito shift/reduce/reduce O que acontece ao escolher-se: Reduce Expr Expr Op Expr Expr Expr - Expr Expr (Expr) Expr Expr - Expr num Op + Op - Op *

255 ©Universidade do Algarve 255 num Expr num - SHIFT Conflitos O que acontece ao escolher-se: Shift Expr Expr Op Expr Expr Expr - Expr Expr (Expr) Expr Expr - Expr num Op + Op - Op *

256 ©Universidade do Algarve 256 Expr num - SHIFT num O que acontece ao escolher-se: Shift Expr Expr Op Expr Expr Expr - Expr Expr (Expr) Expr Expr - Expr num Op + Op - Op * Conflitos

257 ©Universidade do Algarve 257 Expr num - REDUCE Expr num Conflitos O que acontece ao escolher-se: Shift Expr Expr Op Expr Expr Expr - Expr Expr (Expr) Expr Expr - Expr num Op + Op - Op *

258 ©Universidade do Algarve 258 Expr num- REDUCE Expr num Expr Conflitos O que acontece ao escolher-se: Shift Expr Expr Op Expr Expr Expr - Expr Expr (Expr) Expr Expr - Expr num Op + Op - Op *

259 ©Universidade do Algarve 259 Expr num- ACCEPT Expr num Expr Conflitos O que acontece ao escolher-se: Shift Expr Expr Op Expr Expr Expr - Expr Expr (Expr) Expr Expr - Expr num Op + Op - Op *

260 ©Universidade do Algarve 260 num Expr num - Este conflito Shift/Reduce reflecte ambiguidade na gramática Conflito Shift/Reduce/Reduce Expr Expr Op Expr Expr Expr - Expr Expr (Expr) Expr Expr - Expr num Op + Op - Op *

261 ©Universidade do Algarve 261 num Expr num - Eliminar alterando a gramática Conflito Shift/Reduce/Reduce Este conflito Shift/Reduce reflecte ambiguidade na gramática Expr Expr Op Expr Expr Expr - Expr Expr (Expr) Expr Expr - Expr num Op + Op - Op *

262 ©Universidade do Algarve 262 Conflito Shift/Reduce/Reduce num Expr num - Expr Expr Op Expr Expr Expr - Expr Expr (Expr) Expr Expr - Expr num Op + Op - Op * Este conflito Shift/Reduce pode ser eliminado com Lookahead de um símbolo

263 ©Universidade do Algarve 263 Análise Sintáctica Compiladores João M. P. Cardoso

264 ©Universidade do Algarve 264 Construção de um Parser Vamos construir sem lookahead Decisões chave Shift ou Reduce Qual a produção a reduzir? Ideia básica Construir um DFA para controlar acções de shift e de reduce O mesmo que, converter gramática por autómato de pilha (pushdown automaton) Codificar controlo de estados finitos numa tabela de parse

265 ©Universidade do Algarve 265 Estados do Parser Sequência de Tokens na entrada ($ para sinalizar o fim da entrada) Estado corrente do autómato de estados finitos Duas Pilhas Pilha de Estados (implementa autómato de estados finitos) Pilha de Símbolos (terminais da entrada e não-terminais das reduções)

266 ©Universidade do Algarve 266 Integração de controlo dos estados finitos Acções Coloca símbolos e estados na pilha Reduzir de acordo com uma dada produção Aceitar Erro Acção seleccionada é uma função de Símbolo corrente na entrada Estado corrente do controlo de estados finitos Cada acção especifica o próximo estado Implementar o controlo utilizando a tabela do parser

267 ©Universidade do Algarve 267 Implementa controlo dos estados finitos Em cada estado, ver Tabela[topo da pilha de estados][símbolo na entrada] Em seguida, realizar acção Tabela do Parser

268 ©Universidade do Algarve 268 Exemplo de Tabela do Parser S X $(1) X (X)(2) X ( )(3) GramáticaEntrada Pilha de Estados Pilha de Símbolos (()) X s0

269 ©Universidade do Algarve 269 Shift para sn Coloca o token na entrada na pilha de símbolos Coloca sn na pilha de estados Avança para o próximo símbolo na entrada Tabela do Parser

270 ©Universidade do Algarve 270 Reduce (n) Retira itens das duas pilhas quantas vezes quantos os símbolos no RHS da regra n Coloca LHS da regra n na pilha de símbolos Ver Tabela[topo da pilha de estados][topo da pilha de símbolos] Coloca esse estado (na parte goto da tabela) na pilha de estados Tabela do Parser

271 ©Universidade do Algarve 271 Aceitar Parar a análise e reportar sucesso Erro Parar a análise e reportar erro Tabela do Parser

272 ©Universidade do Algarve 272 S X $(1) X (X)(2) X ( )(3) (())$ s0 Tabela do Parser em acção GramáticaEntrada Pilha de Estados Pilha de Símbolos

273 ©Universidade do Algarve 273 S X $(1) X (X)(2) X ( )(3) (())$ s0 Tabela do Parser em acção GramáticaEntrada Pilha de Estados Pilha de Símbolos

274 ©Universidade do Algarve 274 S X $(1) X (X)(2) X ( )(3) ())$ s0 ( s2 Tabela do Parser em acção GramáticaEntrada Pilha de Estados Pilha de Símbolos

275 ©Universidade do Algarve 275 S X $(1) X (X)(2) X ( )(3) ())$ s0 ( s2 Tabela do Parser em acção GramáticaEntrada Pilha de Estados Pilha de Símbolos

276 ©Universidade do Algarve 276 S X $(1) X (X)(2) X ( )(3) ))$ s0 ( s2 ( Tabela do Parser em acção GramáticaEntrada Pilha de Estados Pilha de Símbolos

277 ©Universidade do Algarve 277 S X $(1) X (X)(2) X ( )(3) ))$ s0 ( s2 ( Tabela do Parser em acção GramáticaEntrada Pilha de Estados Pilha de Símbolos

278 ©Universidade do Algarve 278 S X $(1) X (X)(2) X ( )(3) )$ s0 ( s2 ( s5 ) Tabela do Parser em acção GramáticaEntrada Pilha de Estados Pilha de Símbolos

279 ©Universidade do Algarve 279 )$ s0 ( s2 ( s5 ) S X $(1) X (X)(2) X ( )(3) Tabela do Parser em acção GramáticaEntrada Pilha de Estados Pilha de Símbolos

280 ©Universidade do Algarve 280 )$ s0 ( s2 ( s5 ) S X $(1) X (X)(2) X ( )(3) Passo 1: pop das pilhas GramáticaEntrada Pilha de Estados Pilha de Símbolos

281 ©Universidade do Algarve 281 S X $(1) X (X)(2) X ( )(3) )$ s0 ( s2 Passo 1: pop das pilhas GramáticaEntrada Pilha de Estados Pilha de Símbolos

282 ©Universidade do Algarve 282 S X $(1) X (X)(2) X ( )(3) )$ s0 ( s2 Passo 2: push não-terminal GramáticaEntrada Pilha de Estados Pilha de Símbolos

283 ©Universidade do Algarve 283 S X $(1) X (X)(2) X ( )(3) )$ s0 ( s2 X Passo 2: push não-terminal GramáticaEntrada Pilha de Estados Pilha de Símbolos

284 ©Universidade do Algarve 284 S X $(1) X (X)(2) X ( )(3) )$ s0 ( s2 X Passo 3: usar Goto, push novo estado GramáticaEntrada Pilha de Estados Pilha de Símbolos

285 ©Universidade do Algarve 285 S X $(1) X (X)(2) X ( )(3) )$ s0 ( s2 X s3 Passo 3: usar Goto, push novo estado GramáticaEntrada Pilha de Estados Pilha de Símbolos

286 ©Universidade do Algarve 286 S X $(1) X (X)(2) X ( )(3) )$ s0 ( s2 X s3 Tabela do Parser em acção GramáticaEntrada Pilha de Estados Pilha de Símbolos

287 ©Universidade do Algarve 287 S X $(1) X (X)(2) X ( )(3) s0 ( s2 X s3 s4 ) Tabela do Parser em acção GramáticaEntrada Pilha de Estados Pilha de Símbolos $

288 ©Universidade do Algarve 288 S X $(1) X (X)(2) X ( )(3) $ s0 ( s2 X s3 s4 ) Tabela do Parser em acção GramáticaEntrada Pilha de Estados Pilha de Símbolos

289 ©Universidade do Algarve 289 S X $(1) X (X)(2) X ( )(3) s0 ( s2 X s3 s4 ) Passo 1: pop pilhas GramáticaEntrada Pilha de Estados Pilha de Símbolos $

290 ©Universidade do Algarve 290 S X $(1) X (X)(2) X ( )(3) s0 Passo 1: pop pilhas GramáticaEntrada Pilha de Estados Pilha de Símbolos $

291 ©Universidade do Algarve 291 S X $(1) X (X)(2) X ( )(3) s0 Passo 2: push não-terminal GramáticaEntrada Pilha de Estados Pilha de Símbolos $

292 ©Universidade do Algarve 292 S X $(1) X (X)(2) X ( )(3) s0 X Passo 2: push não-terminal GramáticaEntrada Pilha de Estados Pilha de Símbolos $

293 ©Universidade do Algarve 293 S X $(1) X (X)(2) X ( )(3) s0 X Passo 3: usar Goto, push novo estado GramáticaEntrada Pilha de Estados Pilha de Símbolos $

294 ©Universidade do Algarve 294 S X $(1) X (X)(2) X ( )(3) s0 X s1 Passo 3: usar Goto, push novo estado GramáticaEntrada Pilha de Estados Pilha de Símbolos $

295 ©Universidade do Algarve 295 S X $(1) X (X)(2) X ( )(3) s0 S s1 Aceitar a String! GramáticaEntrada Pilha de Estados Pilha de Símbolos $

296 ©Universidade do Algarve 296 Análise Sintáctica Compiladores João M. P. Cardoso

297 ©Universidade do Algarve 297 Construção do Parser Sintetizar um DFA Captura todos os estados possíveis em que o parser pode estar Transições de estados para terminais e não- terminais Utilizar o DFA para criar a tabela sintáctica

298 ©Universidade do Algarve 298 Exemplo Gramática S X $ (1) X (X) (2) X ( ) (3) X ( X ) Aqui? Ou aqui? Estados do DFA baseados nos itens Temos de capturar o que foi já percorrido numa produção

299 ©Universidade do Algarve 299 Exemplo Gramática S X $ (1) X (X) (2) X ( ) (3) X ( X ) Estados do DFA baseados nos itens Temos de capturar o que foi já percorrido numa produção Produção X (X) gera 4 itens: X (X )

300 ©Universidade do Algarve 300 Exemplo Gramática S X $ (1) X (X) (2) X ( ) (3) Estados do DFA baseados nos itens Temos de capturar o que foi já percorrido numa produção Itens para todas as produções da Gramática: S X $ X (X) X ( )

301 ©Universidade do Algarve 301 Ideia por trás dos itens Estados correspondem a conjuntos de itens Se um estado contém um item: A c O parser espera uma eventual redução utilizando a produção: A c O parser já analisou Espera que a entrada possa conter c, seguido de Se um estado contém um item: A O parser já analisou Reduzirá utilizando: A Se um estado contém um item: S $ e a entrada está vazia O parser aceita a entrada

302 ©Universidade do Algarve 302 Relação entre itens e acções Se o estado corrente contém o item: A c e o símbolo corrente na entrada é c O parser desloca c para a pilha de símbolos O próximo estado conterá A c Se o estado corrente contém o item: A Reduzirá utilizando: A Se o estado corrente contém o item: S $ e a entrada está vazia O parser aceita a entrada

303 ©Universidade do Algarve 303 Closure() de um conjunto de itens Closure (fechamento) encontra todos os itens no mesmo estado Algoritmo de ponto-fixo para Closure(I) Cada item em I é também um item em Closure(I) Se A B está em Closure(I) e B é um item, então adicionar B a Closure(I) Repetir até que não haja adição de novos itens a Closure(I)

304 ©Universidade do Algarve 304 Closure( {X ( X )} ) Itens S X $ X (X) X ( ) X ( X) X ( ) Exemplos de Closure() S X $ X ( X ) X ( ) Closure( {S X $})

305 ©Universidade do Algarve 305 Goto() de um conjunto de itens Goto encontra o novo estado depois de ter consumido um símbolo da gramática no presente estado Algoritmo para Goto(I, X) em que I é um conjunto de itens e X um símbolo terminal ou não-terminal da gramática Goto(I, X) = Closure( { A X | A X em I } ) dá-nos o novo conjunto obtido pelo movimento do ponto sobre X

306 ©Universidade do Algarve 306 Goto( {X ( X)}, X ) X (X ) Itens S X $ X (X) X ( ) Exemplos de Goto() Goto ( {X (X)}, ( ) X ( X) X ( )

307 ©Universidade do Algarve 307 Começar com o item: S $ Caso não exista adicionar a primeira produção com término $ Criar o primeiro estado como sendo Closure({ Goal S $}) Escolher um estado I Para cada item A X em I determinar Goto(I, X) se Goto(I, X) não está no estado, criar um novo estado Adicionar um laço X do estado I ao estado Goto(I, X) Repetir até que não haja mais modificações possíveis Construir os estados do DFA

308 ©Universidade do Algarve 308 Construir o Parser Construir o DFA DFA para a gramática: Construir a tabela do parser utilizando o DFA S X$ X (X) X ( ) s0 S X $ s1 X X ( X) X ( ) X (X) X ( ) s2 ( X (X ) X s3 ( X ( ) ) s5 X (X) ) s4

309 ©Universidade do Algarve 309 Criação da tabela sintáctica Para cada estado Transição para outro estado utilizando um símbolo terminal é um deslocamento para esse estado (shift to sn) Transição para outro estado utilizando um símbolo não-terminal é um goto para esse estado (goto sn) Se existir um item A no estado fazer uma redução com essa produção para todos os terminais (reduce k) Se existir um item S X $ no estado então colocar acção de aceitação para o terminal $

310 ©Universidade do Algarve 310 S X$ X (X) X ( ) s0 S X $ s1 X X ( X) X ( ) X (X) X ( ) s2 ( X (X ) X s3 ( X ( ) ) s5 X (X) ) s4 Criação da tabela sintáctica

311 ©Universidade do Algarve 311 Problemas que podem ocorrer Nenhum lookahead Vulnerável a conflitos desnecessários Conflitos Shift/Reduce (pode reduzir demasiado cedo em alguns casos) Conflitos Reduce/Reduce Solução: Lookahead Apenas para reduções – reduzir apenas quando o próximo símbolo pode ocorrer depois de não- terminal da produção Lookahead sistemático, divisão de estados baseada no próximo símbolo, acção é sempre uma função do próximo símbolo Pode ser generalizado para ver à frente múltiplos símbolos

312 ©Universidade do Algarve 312 Análise Sintáctica Compiladores João M. P. Cardoso

313 ©Universidade do Algarve 313 Definições: Conjuntos First() e Follow() Conjunto First( ) Conjunto de símbolos terminais situados mais à esquerda em todas as possíveis árvores de derivação de T First( ) se T pode aparecer como primeiro símbolo numa derivação começando em Começar pelo conceito de NT derivando : NT implica que NT deriva NT NT 1... NT n e se todos os NT i (1 i n) derivam implica que NT deriva Notação T é terminal, NT é não- terminal, S é terminal ou não-terminal, e α e representam sequências de terminais e/ou não terminais

314 ©Universidade do Algarve 314 Definições: Regras para First() 1) T First(T) 2) First(S) First(S ) 3) NT deriva implica: First( ) First(NT ) 4) NT S implica: First(S ) First(NT) Notação T é terminal, NT é não- terminal, S é terminal ou não-terminal, e α e representam sequências de terminais e/ou não terminais

315 ©Universidade do Algarve 315 Definições: Exemplo First() First(Term)? Gramática Term * INT Term Term / INT Term Term Solução First(Term) = {*,/} First(* INT Term) = {*} First(/ INT Term) = {/} First(*) = {*} First(/) = {/}

316 ©Universidade do Algarve 316 Definições: Conjunto First() Se duas ou mais produções diferentes para o mesmo símbolo não-terminal têm conjuntos First com símbolos terminais comuns então: A gramática não pode ser analisada com um parser preditivo LL(1) sem retrocesso Exemplo: S X $ X a X a b First(X a) = { a } First(X a b) = { a } Qual a produção a escolher quando perante o símbolo terminal a?

317 ©Universidade do Algarve 317 Definições: Conjunto Follow() Para o símbolo não-terminal A, Follow(A) é o conjunto dos primeiros terminais que podem vir depois de A em alguma derivação Regras para Follow() $ Follow(S), em que S é o símbolo início Se A B é uma produção então First( ) Follow(B) Se A B é uma produção então Follow(A) Follow(B) Se A B é uma produção e deriva então Follow(A) Follow(B)

318 ©Universidade do Algarve 318 Definições: Algoritmo para Follow() for all nonterminals NT Follow(NT) = {} Follow(S) = {$} while Follow sets keep changing for all productions A B Follow(B) = Follow(B) First( ) if ( derives ) Follow(B) = Follow(B) Follow(A) for all productions A B Follow(B) = Follow(B) Follow(A)

319 ©Universidade do Algarve 319 Definições: Exemplo Follow() Gramáticas exemplo: S X $ X a X a b Follow(S) = { $ } Follow(X) = { $ } S X $ X ( X ) X Follow(S) = { $ } Follow(X) = { ), $ }

320 ©Universidade do Algarve 320 Parser com Lookahead apenas nas reduções Designa-se por parser Simple LR: SLR(1) ou simplesmente SLR Se um estado contiver: A Reduzir de A apenas se o próximo símbolo na entrada pode seguir (follow) A em alguma derivação Gramática exemplo: S X $ (1) X a (2) X a b (3)

321 ©Universidade do Algarve 321 Parser sem Lookahead: LR(0) S X $ X a X a b S X $ X a X a b s0 s3 s1 s2 X a b reduce(2) ou shift to s2

322 ©Universidade do Algarve 322 Tabela sintáctica com apenas lookahead nas reduções Para cada estado Transição para outro estado utilizando um símbolo terminal é um deslocamento para esse estado (shift to sn) (como anteriormente) Transição para outro estado utilizando um símbolo não-terminal é um goto para esse estado (goto sn) (como anteriormente) Se existir um item: X no estado, fazer uma redução com essa produção sempre que o símbolo corrente (T) na entrada possa seguir (follow) X em alguma derivação Elimina acções de redução inúteis

323 ©Universidade do Algarve 323 Nova tabela sintáctica Reduce(2) implica redução com a regra: X a Como Follow(X) = {$} b nunca segue X nas derivações: resolver conflito shift/reduce com shift

324 ©Universidade do Algarve 324 S X $ X a X a b S X $ X a X a b s0 s3 s1 s2 X a b b nunca segue X nas derivações: resolver conflito shift/reduce com shift Nova tabela sintáctica b Follow(X) a Follow(X)

325 ©Universidade do Algarve 325 Lookahead mais genérico Itens contêm informação lookahead potencial, resultando em mais estados no controlo de estados finitos Item da forma: [A X c] diz Próximo símbolo na entrada é c Parser já consumiu, espera analisar X, e depois reduzir utilizando: A X Em adição ao estado corrente na tabela sintáctica, todas as acções do parser são função dos símbolos de lookahead

326 ©Universidade do Algarve 326 Sumário Geradores de Parsers – dada uma gramática, produz um parser Técnica de análise sintáctica ascendente Construir automaticamente um autómato de pilha (pushdown automata) Obter um parser shift-reduce Controlo de estados finitos + pilha Implementação baseada em tabela Conflitos: Shift/Reduce, Reduce/Reduce Uso de lookahead para eliminar conflitos Parser SLR(1) (elimina acções de redução inúteis) Parser LR(k) (uso de lookahead genérico)

327 ©Universidade do Algarve 327 Ideia básica para LR(1) Dividir estados em LR(0) DFA baseado em lookahead Acção de reduzir é baseada no item e no lookahead

328 ©Universidade do Algarve 328 Itens LR(1) Itens mantêm informação em relação a: Produção Posição right-hand-side (o ponto) Símbolo lookahead Item LR(1) é da forma [A T] A é uma produção O ponto em A denota a posição T é um símbolo terminal ou o marcador de término ($) Item [A T] significa O parser já analisou Se analisa e o próximo símbolo é T então o parser deve reduzir com A

329 ©Universidade do Algarve 329 Gramática S X $ X (X) X Símbolos terminais ( ) Marcador de término $ Itens LR(1) [ S X $) ] [ S X $( ] [ S X $$ ] [ S X $ ) ] [ S X $ ( ] [ S X $ $] [ X ( X )) ] [ X ( X )( ] [ X ( X )$ ] [ X ( X ) ) ] [ X ( X ) ( ] [ X ( X ) $ ] [ X ( X ) ] [ X ( X ) ( ] [ X ( X ) $ ] [ X ( X ) ) ] [ X ( X ) ( ] [ X ( X ) $ ] [ X ) ] [ X ( ] [ X $ ] Itens LR(1): exemplo

330 ©Universidade do Algarve 330 Criação do parser LR(1) É necessário definir funções Closure() e Goto() para itens LR(1) Necessário algoritmo para criar DFA Necessário algoritmo para criar a tabela do parser

331 ©Universidade do Algarve 331 Closure para LR(1) Closure(I) repeat for all items [A X c] in I for any production X for any d First( c) I = I { [X d] } until I does not change return I

332 ©Universidade do Algarve 332 Goto para LR(1) Goto(I, X) J = { } for any item [A X c] in I J = J {[A X c]} return Closure(J)

333 ©Universidade do Algarve 333 Construção do DFA LR(1) Começar com o item: [Start S $ ?] ? É irrelevante porque nunca deslocaremos $ Determinar o fechamento (closure) do item e formar o estado Seleccionar um estado I for each item [A X c] in I find Goto(I, X) if Goto(I, X) is not already a state, make one Add an edge X from state I to Goto(I, X) state Repetir até que não haja mais adições

334 ©Universidade do Algarve 334 Criação da tabela do parser Para cada estado no DFA LR(1) Transição para outro estado usando um símbolo terminal é um deslocamento para esse estado (shift to sn) Transição para outro estado usando um símbolo não-terminal é um goto para esse estado (goto sn) Se existir um item [A a] num estado, reduzir para o símbolo de entrada a com a produção A (reduce k)

335 ©Universidade do Algarve 335 Parser Look-Ahead LR(1) ou LALR(1) Motivação Parser LR(1) tem um número elevado de estados Método simples para eliminar estados Se dois estados LR(1) são idênticos excepto no símbolo lookahead dos itens então juntar estados Resultado é um DFA LALR(1) Tipicamente tem muito menos estados do que LR(1) Pode ter mais conflitos reduce/reduce

336 ©Universidade do Algarve 336 Classificação de Gramáticas Dada uma determinada gramática, determinar se pode ter como analisador: LL(0), LL(1), LL(2),..., LL(k)? LR(0), LR(1), LR(2),..., LR(k)? SLR(1)?

337 ©Universidade do Algarve 337 Classificar uma gramática como LL(1) Como verificar se uma gramática é LL(1)? Se a tabela sintáctica não tiver mais do que uma produção em cada célula Tabela sintáctica do analisador preditivo Uma linha por cada não-terminal Uma coluna por cada Terminal Colocar produção X na linha X, coluna T, para cada T First( ) Se pode derivar então colocar produção X na linha X, coluna T, para cada T Follow(X)

338 ©Universidade do Algarve 338 Classificar uma gramática como LL(1) Colocar produção X na linha X, coluna T, para cada T First( ) Se pode derivar então colocar produção X na linha X, coluna T, para cada T Follow(X) Gramática: Z d Z X Y Z Y Y c X Y X a Não- terminais Terminais dca Z Y X

339 ©Universidade do Algarve 339 Classificar uma gramática como LL(1) Gramática: Z d Z X Y Z Y Y c X Y X a Não- terminais Terminais dca Z Z X Y Z Z d Z X Y Z Y Y Y Y c Y X X Y X a Como verificar se uma gramática é LL(1)? Se a tabela sintáctica não tiver mais do que uma produção em cada célula A gramática não é LL(1)

340 ©Universidade do Algarve 340 Classificação de Gramáticas Uma gramática diz-se: LR(0) se existir uma tabela sintáctica LR(0) sem conflitos (reduce/reduce, ou shift/reduce) SLR(1) se existir uma tabela sintáctica SLR(1) sem conflitos (reduce/reduce, ou shift/reduce) LR(k) se existir uma tabela sintáctica LR(k) sem conflitos (reduce/reduce, ou shift/reduce) LL(k) se puder ser analisada por um analisador sintáctico preditivo com lookahead=k …

341 ©Universidade do Algarve 341 Classificação de Gramáticas G0G0 regular LR(0) SLR(1) LALR(1) LR(1) LR(k) unambiguous Context free G1G1 G2G2 G3G3 G4G4 G5G5 G6G6 G7G7 LL(0) LL(1) LL(k)

342 ©Universidade do Algarve 342 Geradores de Parsers Geram C, Lex & Yacc flex e bison Geram Java: JLex e CUP JavaCC: html Lista com mais geradores de parsers

343 ©Universidade do Algarve 343 Análise Semântica e Representação Intermédia Compiladores João M. P. Cardoso

344 ©Universidade do Algarve 344 Localização actual nas etapas de compilação Lexical Analyzer (Scanner) Syntax Analyzer (Parser) Token Stream Parse Tree Program (character stream) Semantic Analyzer Intermediate Code Generator Intermediate Representation + Symbol Table

345 ©Universidade do Algarve 345 O que é a semântica de um programa? Sintaxe Como o programa é constituído Representação textual ou estrutura Semântica Qual é o significado do programa?

346 ©Universidade do Algarve 346 Qual o motivo da análise semântica? Certifica-se de que o programa está de acordo com as definições da linguagem de programação Reportar, sempre que haja erros semânticos, mensagens de erro que sejam úteis para o utilizador Não é preciso muito trabalho adicional se for incorporada durante a criação da representação intermédia

347 ©Universidade do Algarve 347 Erros na Análise Semântica boolean sum(int A[], int N) { Int i, sum; For(i=0; i

348 ©Universidade do Algarve 348 Objectivo das representações intermédias do programa Permitir análises e transformações Optimizações Estruturar tradução para código máquina Sequência de passos Árvore Sintáctica Representação Intermédia de nível alto Representação Intermédia de nível baixo Código Máquina Análise Semântica Intermediate Representation (IR)

349 ©Universidade do Algarve 349 Representação Intermédia de Nível Alto Preserva o fluxo de controlo estruturado Útil para optimizações ao nível do ciclo Desenrolamento de ciclos, Fusão de ciclos, etc. Preserva estrutura ao nível dos objectos Útil para optimizações em programas orientados por objectos

350 ©Universidade do Algarve 350 Representação Intermédia de Nível Baixo Passa do modelo de dados abstracto para o espaço planar de endereçamento Elimina o fluxo de controlo estruturado Útil para tarefas de compilação de nível baixo Afectação de registos Selecção de instruções

351 ©Universidade do Algarve 351 Alternativas Há muitas alternativas possíveis Árvores de instruções e de expressões Grafos direccionados acíclicos (DAGs) Código de 3 endereços (C3E) E muitas outras... Mais ou menos especificas à própria linguagem Estas lições apresentam uma possibilidade de árvores de instruções e de expressões (mais tarde falaremos também de código de 3 endereços)

352 ©Universidade do Algarve 352 Tarefas de Compilação Determina formato das estruturas na memória Determinar formato de arrays e de objectos na memória Determinar formato da pilha de chamadas na memória Gerar código para ler valores parâmetros, elementos de arrays, campos de objectos para avaliar expressões e computar valores novos para escrever valores para estruturas de controlo Enumera funções e cria a tabela de funções Invocação de funções acede à entrada correspondente na tabela de funções Gera código para funções variáveis locais, e acesso a parâmetros Invocações de funções

353 ©Universidade do Algarve 353 Tabelas de símbolos (symbol tables) Conceito chave na compilação enquanto a declaração de tipos, variáveis e funções são processadas vamos atribuir significados a esses identificadores utilizando tabelas de símbolos Compiladores utilizam tabelas de símbolos para produzirem Layout das estruturas na memória Tabelas de funções Código para aceder a campos, variáveis locais, parâmetros, etc.

354 ©Universidade do Algarve 354 Tabelas de Símbolos Durante a tradução de árvores sintácticas para representação intermédia Tabelas de símbolos mapeiam identificadores (strings) em descritores (informação acerca dos identificadores) Operação básica: Lookup Dada uma string, encontrar o seu descritor Implementação típica: Hash Table (contentor associativo) Exemplo Dado o nome de uma variável, encontrar descritor Descritor local, descritor de parâmetro, descritor global

355 ©Universidade do Algarve 355 Exemplo void add(int x, int[] v, int N) { int i; i = 0; while (i < N) { v[i] = v[i]+x; i = i+1; } x i Função add v N descritor para parâmetro x descritor para parâmetro v descritor para parâmetro N descritor para variável local i

356 ©Universidade do Algarve 356 Exemplo void add(int x, int[] v, int N) { int i; i = 0; while (i < N) { v[i] = v[i]+x; i = i+1; } x i Função add Código da função v N descritor para parâmetro x descritor para parâmetro v descritor para parâmetro N descritor para variável local i descritor para retorno

357 ©Universidade do Algarve 357 Exemplo void add(int x, int[] v, int N) { int i; i = 0; while (i < N) { v[i] = v[i]+x; i = i+1; } x i add Código da função v N descritor para parâmetro x descritor para parâmetro v descritor para parâmetro N descritor para variável local i descritor para retorno

358 ©Universidade do Algarve 358 Hierarquia em tabelas de símbolos Alcance/Escopo (scope) O mesmo nome para uma variável pode ter significados diferentes em locais diferentes É necessária uma tabela de símbolos por cada escopo A hierarquia deriva de Encadeamento de escopos Hierarquia na tabela de símbolos reflecte esta hierarquia Lookup atravessa de modo ascendente a hierarquia até que o descritor seja encontrado

359 ©Universidade do Algarve 359 Lookup i num exemplo i descritor para a variável local i x descritor para parâmetro x v descritor para a variável global v TS para as variáveis globais TS para os parâmetros da função TS para as variáveis locais da função

360 ©Universidade do Algarve 360 Lookup I num exemplo v[i] = v[i]+x; 1º vai procurar na TS das variáveis locais e só se não encontrar é que sobe na hierarquia das TS i descritor para a variável local i x descritor para parâmetro x v descritor para a variável global v

361 ©Universidade do Algarve 361 Análise Semântica e Representação Intermédia Compiladores João M. P. Cardoso

362 ©Universidade do Algarve 362 Descritores O que contêm? Informação utilizada para geração de código e análise semântica Descritores locais - nome, tipo, offset na pilha Descritores de funções assinatura (tipo do valor retornado, e parâmetros) Referência à tabela de símbolos local Referência ao código para a função

363 ©Universidade do Algarve 363 Parâmetros, Local, e Descritores de Tipos Parâmetros, Local referem a descritores de tipo Descritor de tipo base: int, boolean, etc. Descritor de tipo de array, que contém referência ao descritor de tipo para os elementos do array Descritor de estrutura, etc.

364 ©Universidade do Algarve 364 Exemplo: Tabela de Símbolos para Tipos boolean Descritor de boolean int Descritor de int int [] Descritor de array boolean [] Descritor de array vector [] Descritor de array Descritor de estrutura para vector

365 ©Universidade do Algarve 365 Descritores de funções Contêm referência para o código da função Contêm referência para a tabela de símbolos local (para as variáveis locais da função) Na hierarquia de tabelas de símbolos, a TS para os parâmetros é mãe da TS para as variáveis locais

366 ©Universidade do Algarve 366 Descritor de função para add v i Descritor de variável local TS de variáveis locais x TS para parâmetros Descritor de parâmetro Código para a função add Descritor de função para add N Descritor de parâmetro

367 ©Universidade do Algarve 367 O que é uma árvore sintáctica? Árvore sintáctica guarda resultados da análise sintáctica Nós externos são terminais/tokens Nós internos são não-terminais

368 ©Universidade do Algarve 368 Árvores abstractas versus concretas Relembrar modificações à gramática Factorização à esquerda, eliminação de ambiguidade, precedências dos operadores Modificações levam a uma árvore que não reflecte uma interpretação do programa intuitiva e clara Pode ser mais conveniente trabalhar com a AST (pode ser vista como a árvore sintáctica representativa da gramática sem as modificações modificações)

369 ©Universidade do Algarve 369 Construções alternativas para Representações Intermédias Construir a árvore sintáctica concreta, traduzir para AST, traduzir para representação intermédia Construir a árvore sintáctica abstracta, traduzir para representação intermédia Incluir a construção da representação intermédia durante a análise sintáctica Elimina a construção intermédia da árvore sintáctica – melhora performance do compilador Menos código a escrever

370 ©Universidade do Algarve 370 Tabela de Símbolos Dada uma árvore sintáctica (abstracta ou concreta) Atravessar recursivamente a árvore Construir a tabela de símbolos enquanto a travessia da árvore decorre

371 ©Universidade do Algarve 371 Escopos aninhados Várias formas de aninhamento TS das funções aninhadas na TS dos globais TS de locais aninhada dentro da TS da função Aninhamento resolve ambiguidade em possíveis conflitos Mesmo nome utilizado para uma variável global e uma variável local Nome refere uma variável local dentro da função

372 ©Universidade do Algarve 372 Escopos aninhados de código TS podem ter profundidade arbitrária com base no aninhamento do código: boolean x; int foo(int x) { double x = 5.0; { float x = 10.0; { int x = 1;... x...}... x... }... x... } Nota: Conflitos de nomes com aninhamento podem reflectir erros no programa. Os compiladores geram mensagens de aviso em presença de conflitos deste tipo.

373 ©Universidade do Algarve 373 Representação de código em nível alto Ideia básica Movimento em direcção à linguagem assembly Preservar a estrutura de nível alto Formato de objectos Fluxo de controlo estruturado Distinção entre parâmetros, variáveis locais, e campos Abstracção de nível alto da linguagem assembly Nós load e store Acesso a armazenamento local abstracto, parâmetros e campos, e não posições de memória directamente

374 ©Universidade do Algarve 374 Representação de expressões Árvores de expressões representam as expressões Nós internos – operações como: +, -, etc. Folhas – Nós Load representam acesso a variáveis Nós Load ldl para acesso a variáveis locais – descritor de locais ldp para acessos a parâmetros – descritor de parâmetros lda para acesso a arrays Árvore da expressão para o valor Árvore de expressão para o índice Para acesso a atributos de uma classe ou campos de estruturas...

375 ©Universidade do Algarve 375 Exemplo x e y são variáveis locais x*x + y*y + ldl Descritor de local para x Na tabela de símbolos locais * ldl * Descritor de local para x Na tabela de símbolos locais

376 ©Universidade do Algarve 376 Exemplo v é uma array passado como argumento da função add i é uma variável local x é um argumento da função v[i]+x lda + ldp Descritor local para I na tabela de símbolos locais da função add ldl ldp Descritor de parâmetro para v na tabela de símbolos de parâmetros da função add Descritor de parâmetro para x na tabela de símbolos de parâmetros da função add

377 ©Universidade do Algarve 377 Representação de enunciados de atribuição Nós Store stl para stores em variáveis locais Descritor local Árvore da expressão para o valor a guardar sta para stores em elementos de arrays Árvore da expressão para o array Árvore da expressão para o índice Árvore da expressão para o valor a guardar Para stores em atributos de classes ou campos de estruturas...

378 ©Universidade do Algarve 378 v[i]=v[i]+x; lda + ldp Descritor do parâmetro para v na tabela de símbolos dos parâmetros da função add Descritor local para I na tabela de símbolos locais da função add Descritor do parâmetro para x na tabela de símbolos dos parâmetros da função add ldl sta ldlldp Exemplo

379 ©Universidade do Algarve 379 Orientação Representações intermédias Movimento em direcção à linguagem máquina Suporte para análises do programa e acções de transformação IR (intermediate representation) de nível alto Preserva estruturas de objectos e de arrays Tabelas de símbolos Descritores

380 ©Universidade do Algarve 380 Análise Semântica e Representação Intermédia Compiladores João M. P. Cardoso

381 ©Universidade do Algarve 381 Representação do fluxo de controlo Nós de enunciados Nó if Árvore de expressão para a condição Nó para o corpo do then e nó para o corpo do else Nó while Árvore de expressão para a condição Nó para o corpo Nó return Árvore de expressão para o valor/expressão de retorno

382 ©Universidade do Algarve 382 Exemplo while (i < N) v[i] = v[i]+x; Descritor de locais para i ldl Descritor de parâmetros para v Descritor de parâmetros para x while < ldp lda + ldp ldl sta ldl ldp

383 ©Universidade do Algarve 383 Exemplo while (i < N) v[i] = v[i]+x; Ldl i while < Ldp v lda + Ldp x Ldl i sta Ldl i Ldp v Notação abreviada

384 ©Universidade do Algarve 384 Das árvores sintácticas até à IR Atravessar recursivamente a árvore sintáctica Construir representação de modo ascendente (Bottom-Up) Ver identificador da variável na tabela de símbolos Construir nós Load para aceder a variáveis Construir expressões a partir dos nós de Load e dos nós de operações Construir nós Store para enunciados de atribuição Colocar nós while, if, return para as construções de controlo

385 ©Universidade do Algarve 385 Sumário Representação Intermédia de alto nível Objectivo: representar o programa de um modo intuitivo para suporte de futuras tarefas de compilação Representação dos dados do programa Tabelas de Símbolos Organização hierárquica Representação da computação Árvores de expressões Vários tipos de nós store e load Fluxo de controlo estruturado

386 ©Universidade do Algarve 386 Análise semântica: Erros Assumimos a inexistência de problemas durante a construção da IR Contudo, é necessário fazer muitas verificações durante a tradução Chamadas de Análise Semântica Realização da análise semântica ao nível da árvore sintáctica Para que os erros sejam informativos/claros é necessário que os nós da árvore sejam anotados com as posições no programa

387 ©Universidade do Algarve 387 Objectivo da análise semântica Assegurar que o programa obedece a um conjunto de verificações de sanidade Todas as variáveis usadas foram definidas Tipos são usados correctamente Chamadas a funções têm o número correcto e tipos de parâmetros e do valor retornado Verificação aquando da construção da IR

388 ©Universidade do Algarve 388 Descritores para identificadores Quando se constrói o descritor de uma variável local, parâmetro, etc. temos Nome do tipo Nome da variável O que é a verificação? Verificar se o nome do tipo identifica um tipo válido lookup nome na tabela de símbolos dos tipos Se não estiver lá, falha na análise semântica

389 ©Universidade do Algarve 389 Tabela de símbolos local Quando se constrói a tabela de símbolos local temos uma lista de descritores locais Fazer a verificação a quê? Nomes de variáveis em duplicado Quando se faz a verificação? Quando se insere o descritor na tabela de símbolos local Similar para os parâmetros, para a TS global, etc.

390 ©Universidade do Algarve 390 Verificação para loads, stores, etc. O que tem o compilador? Nome da variável. O que faz? Lookup nome da variável: Se estiver na tabela de símbolos local, referencia descritor local Se estiver na tabela de símbolos dos parâmetros, referencia descritor do parâmetro Se estiver na tabela de símbolos global, referencia descritor global Se não for encontrado um descritor: erro semântico (a variável não foi declarada...)

391 ©Universidade do Algarve 391 Verificação para a Instrução de Load para arrays O que tem o compilador? Nome da variável Expressão de indexação no array O que faz? Lookup nome da variável (se não estiver: erro semântico) Verifica tipo da expressão (se não for inteiro: erro semântico)

392 ©Universidade do Algarve 392 Operação de adição O que tem o compilador? 2 expressões O que pode estar errado? Expressões têm o tipo errado Têm de ser os dois inteiros (por exemplo) Por isso o compilador faz a verificação do tipo das expressões Instruções load guardam o tipo da variável acedida Operações guardam o tipo da expressão produzida Assim, é apenas necessário verificar tipos, e caso falhe dá erro semântico

393 ©Universidade do Algarve 393 Inferência de tipos para operações de adição Algumas linguagens deixam adicionar floats, ints, doubles Quais são os problemas? Tipo do resultado da operação Conversão dos operandos da operação Regras standard podem ser usualmente aplicadas Se adição de um int e de um float converter o int para float, adicionar os floats, e o resultado é um float. Se adição de um float e de um double converter o float para double, adicionar os doubles, e o resultado é um double.

394 ©Universidade do Algarve 394 Regras para a adição Princípio básico: Hierarquia de tipos de números (int, depois float, depois double) Todas as conversões forçadas são feitas de modo ascendente na hierarquia Ex: int para float; float para double; Resultado tem o tipo do operando no nível mais elevado da hierarquia int + float é float, int + double é double, float + double é double

395 ©Universidade do Algarve 395 Inferência de tipos Inferir tipos sem declaração explicita de tipos A adição é um caso muito restrito de inferência de tipos Tópico importante em investigação recente de linguagens de programação Quantas declarações de tipos se podem omitir? Ligado ao polimorfismo

396 ©Universidade do Algarve 396 Instrução Store O que tem o compilador? Nome da variável expressão O que faz? Lookup nome da variável (se não estiver: erro semântico) Verifica tipo da variável com o tipo da expressão Se o tipo da variável não for compatível com o tipo da expressão, erro semântico

397 ©Universidade do Algarve 397 Instrução Store para arrays O que tem o compilador? Nome da variável, expressão de indexação expressão O que faz? Lookup nome da variável (se não estiver: erro semântico) Verifica se o tipo da expressão de indexação é inteiro Verifica tipo da variável em relação ao tipo da expressão Se o tipo da variável não for compatível com o tipo da expressão: erro semântico

398 ©Universidade do Algarve 398 Invocação de funções O que tem o compilador? Nome da função, parâmetros Verificações: Nome da função é identificado na tabela de funções do programa Tipos dos parâmetros casam com tipos dos parâmetros da declaração da função

399 ©Universidade do Algarve 399 Sumário de verificações semânticas Realizar a verificação semântica durante a construção do IR Muitas verificações são para certificar que se constrói uma IR correcta Outras verificações correspondem a verificações simples de sanidade Cada linguagem de programação tem uma lista que deve ser verificada Pode reportar muitos erros potenciais durante a compilação

400 ©Universidade do Algarve 400 Análise Semântica e Representação Intermédia Compiladores João M. P. Cardoso

401 ©Universidade do Algarve 401 Conversão para a IR de nível baixo Converte fluxo de controlo estruturado em fluxo de controlo baseado em saltos (não estruturado) Saltos condicionais e incondicionais Converte modelo de memória estruturado em modelo de memória planar Endereçamento planar para variáveis Endereçamento planar para Arrays Continua independente da linguagem máquina, mas: Movimento para muito próximo da máquina; para um modelo standard da máquina (espaço de endereçamento planar, saltos)

402 ©Universidade do Algarve 402 Representação do Programa Control Flow Graph (CFG): grafo de fluxo de controlo Nós do CFG são nós de instruções stl, sta, cbr, ldl, lda, ldp são nós de instruções +, <,... são nós de expressões Laços no CFG representam o fluxo de controlo Forks em instruções de salto condicional Representam dois ou mais caminhos possíveis Merges quando o controlo pode alcançar um ponto por caminhos múltiplos Um nó de entrada (entry) e um nó de saída (exit)

403 ©Universidade do Algarve 403 ldl i < lda + ldp x ldl i sta ldl i ldp v ldp N cbr entry exit while (i < N) v[i] = v[i]+x; Laços de fluxo de controlo Laços entre Instruções e expressões Exemplo: CFG

404 ©Universidade do Algarve 404 if (x < y) { a = 0; } else { a = 1; } entry ldl xldl y < cbr stl a 0stl a 1 exit Exemplo: CFG

405 ©Universidade do Algarve 405 Modelo de Memória da Máquina Alvo Uma memória planar Composta por palavras Endereçável ao byte Nós modelam instruções Load e Store ld addr,offset – resultado é o conteúdo de memória no local: addr+offset st addr, offset, valor – escreve valor no local: addr+offset Substituir nós: lda e ldl por nós ld Substituir nós: sta e stl por nós st Stack Código Heap Arrays locais (alguns parâmetros)

406 ©Universidade do Algarve 406 ld 4ld 8 ld 4 ** + + ldl Descritor local para x (4) * ldl * Descritor local para y (8) Exemplo: sp ld address offset MEM[address+offset] No caso de offset=4 relativo ao sp (MEM[$sp+offset]): x*x+y*y ld 4 sp

407 ©Universidade do Algarve 407 Parâmetros Muitas máquinas têm convenções nas chamadas Primeiro parâmetro no registo 5, segundo parâmetro no registo 6,... ver $a0, $a1, … do MIPS As convenções variam com a máquina Vamos assumir que cada parâmetro é uma palavra Vamos endereçar os parâmetros pelo número ldp

408 ©Universidade do Algarve 408 Acesso a elementos de um Array Assumir que a variável aponta para o primeiro elemento do array Elementos do array em posições contíguas Qual é o endereço: v[5]? v é um array de inteiros: assumir inteiros de 4 bytes (endereço em v) + (5*4) Determinar endereço Base do Array + (index * element size)

409 ©Universidade do Algarve 409 Exemplo: v[5]+x lda + ldp Descritor de parâmetro v (2) Descritor de parâmetro de x (1) 5 ldp ldp 2 * 54 + ld 0 + ldp 1 Conversão de nós lda para nós ld Determinar endereço Base + (index * element size) ld do endereço Offset de ld é 0

410 ©Universidade do Algarve 410 Variáveis Locais Assumir que são alocadas na pilha de chamadas Endereçamento realizado usando offsets a partir do apontador da pilha Relembrar: pilha cresce para baixo e por isso os offsets são positivos Símbolo especial sp contém apontador para a pilha

411 ©Universidade do Algarve 411 Acções na invocação de funções (relembrar) Invocadora Definir parâmetros de acordo com a convenção de invocações Definir endereço de retorno utilizando a convenção de invocações Saltar para a função invocada Invocada Alocar stack frame = deslocar para baixo o apontador da pilha (sp) computar Definir o valor de retorno de acordo com a convenção de invocações Libertar stack frame = deslocar para cima o apontador da pilha (sp) Retornar para a função invocadora

412 ©Universidade do Algarve 412 Gestão da Pilha (relembrar) Determinar tamanho da stack frame Alocar quando se entra na função Libertar imediatamente antes do retorno da função Guarda todas as variáveis locais Mais espaço para parâmetros (quando estes ultrapassam em número o número de registos convencionados como argumentos de funções) Assume que todas as variáveis locais e os parâmetros têm o comprimento de uma palavra Determinar offsets das variáveis locais e dos parâmetros Computar offsets das variáveis locais e dos parâmetros Guardados nas tabelas de símbolos de locais e de parâmetros Continua a usar nós ldp para aceder aos parâmetros

413 ©Universidade do Algarve 413 Eliminação de nós ldl Uso de offsets na tabela de símbolos locais e sp Substituir nós ldl por nós ld Exemplo de offsets para locais e parâmetros i descritor da variável local i (0) Outras TS (variáveis globais, por exemplo) TS de variáveis locais x TS de parâmetros Descritor do parâmetro x (0) Código para a função add Descritor da função add v Descritor do parâmetro v (1) N Descritor do parâmetro N (2)

414 ©Universidade do Algarve 414 Exemplo: v[i]+x lda + ldp Descritor de parâmetro para v (1) Descritor de parâmetro para x (0) ldp ldp 1* 4 + ld 0 + ldp 0 Descritor de local para i (0) ldl sp ld 0

415 ©Universidade do Algarve 415 Nós Enter e Exit para a função add void add(int x, int[] v, int N) { int i;... } Qual o espaço na pilha para a função add? 4 bytes (espaço para i) Assumindo palavras de 4 bytes Assumindo parâmetros da função em registos usados para passar argumentos Nós enter e exit são anotados com o valor do espaço na pilha necessário para a função enter 4 exit 4....

416 ©Universidade do Algarve 416 ldp 1 * 4 + ld 0 + ldp 0 sp ld 0 ldp 1* 4 + sp ld 0 st 0 sp ld 0 < Exemplo cbr st 0 sp ld sp st 0 sp 0 enter 4 exit 4 ldp 2

417 ©Universidade do Algarve 417 Sumário da IR de nível baixo Acessos a arrays traduzidos para nós ld ou st Endereço é o endereço base do array (apontador) + (index * element size) Acessos locais traduzidos para nós ld ou st Endereço em sp, offset é o offset local Acesso a parâmetros traduzidos para: Instruções lpd – especificar número de parâmetro Nós Enter e Exit de uma função identificam tamanho da pilha utilizado

418 ©Universidade do Algarve 418 Sumário Tradução de árvores sintácticas para IR de nível alto Preserva o fluxo de controlo estruturado Representação eficiente para análise de nível alto e optimizações Tradução de IR de nível alto para IR de nível baixo Espaço de endereçamento planar Remoção da estrutura do fluxo de controlo, substituição por saltos condicionais Movimento em direcção à máquina alvo

419 ©Universidade do Algarve 419 Geração de Código Final Compiladores João M. P. Cardoso

420 ©Universidade do Algarve 420 Problema Dada a representação intermédia de baixo nível como gerar o código assembly? Não optimizado: Variáveis locais e parâmetros todos afectados a posições relativas e distintas na pilha Optimizado: Partilha de posições relativas da pilha por uma ou mais variáveis Utilização de registos do banco de registos do uP para armazenar variáveis...

421 ©Universidade do Algarve 421 Geração de código final Code Generator Código Assembly Code Generator Code Optimizer Representação intermédia optimizada Representação intermédia Semantic Analyzer Syntax Analyzer (Parser) Árvore sintáctica Syntax Analyzer (Parser) Lexical Analyzer (Scanner) Cadeia de Tokens Programa (cadeia de caracteres)

422 ©Universidade do Algarve 422 Geração de código final Y2=a*x*x+b*x+c; Ldl x * + + ldl c stl y2 Ldl x * Ldl a Ldl x * Ldl b IR de alto nível

423 ©Universidade do Algarve 423 Geração de código final Y2=a*x*x+b*x+c; Variáveis: A B X C y2 Ldl x * + + ldl c stl y2 Ldl x * Ldl a Ldl x * Ldl b IR de alto nível

424 ©Universidade do Algarve 424 Geração de código final Y2=a*x*x+b*x+c; Variáveis (posição relativa a $sp) A: 0 B: 4 X: 8 C: 12 Y2: 16 Ld 8 * + + ld 12 st 16 Ld 8 * Ld 0 Ld 8 * Ld 4 IR de baixo nível sp

425 ©Universidade do Algarve 425 Geração de código final Y2=a*x*x+b*x+c; Começar nas folhas: lw $t0, 4($sp) Ld 8 * + + ld 12 st 16 Ld 8 * Ld 0 Ld 8 * Ld 4 IR de baixo nível sp

426 ©Universidade do Algarve 426 Geração de código final Y2=a*x*x+b*x+c; lw $t0, 4($sp) lw $t1, 8($sp) Ld 8 * + + ld 12 st 16 Ld 8 * Ld 0 Ld 8 * Ld 4 IR de baixo nível sp

427 ©Universidade do Algarve 427 Geração de código final Y2=a*x*x+b*x+c; lw $t0, 4($sp) lw $t1, 8($sp) mult $t2, $t1, $t0 Ld 8 * + + ld 12 st 16 Ld 8 * Ld 0 Ld 8 * Ld 4 IR de baixo nível sp

428 ©Universidade do Algarve 428 Geração de código final Y2=a*x*x+b*x+c; lw $t0, 4($sp) lw $t1, 8($sp) mult $t2, $t1, $t0 lw $t3, 8($sp) Ld 8 * + + ld 12 st 16 Ld 8 * Ld 0 Ld 8 * Ld 4 IR de baixo nível sp

429 ©Universidade do Algarve 429 Geração de código final Y2=a*x*x+b*x+c; lw $t0, 4($sp) lw $t1, 8($sp) mult $t2, $t1, $t0 lw $t3, 8($sp) lw $t4, 8($sp) Ld 8 * + + ld 12 st 16 Ld 8 * Ld 0 Ld 8 * Ld 4 IR de baixo nível sp

430 ©Universidade do Algarve 430 Geração de código final Y2=a*x*x+b*x+c; lw $t0, 4($sp) lw $t1, 8($sp) mult $t2, $t1, $t0 lw $t3, 8($sp) lw $t4, 8($sp) mult $t5, $t3, $t4 Ld 8 * + + ld 12 st 16 Ld 8 * Ld 0 Ld 8 * Ld 4 IR de baixo nível sp

431 ©Universidade do Algarve 431 Geração de código final Y2=a*x*x+b*x+c; lw $t0, 4($sp) lw $t1, 8($sp) mult $t2, $t1, $t0 lw $t3, 8($sp) lw $t4, 8($sp) mult $t5, $t3, $t4 lw $t6, 0($sp) Ld 8 * + + ld 12 st 16 Ld 8 * Ld 0 Ld 8 * Ld 4 IR de baixo nível sp

432 ©Universidade do Algarve 432 Geração de código final Y2=a*x*x+b*x+c; lw $t0, 4($sp) lw $t1, 8($sp) mult $t2, $t1, $t0 lw $t3, 8($sp) lw $t4, 8($sp) mult $t5, $t3, $t4 lw $t6, 0($sp) mult $t7, $t5, $t6 Ld 8 * + + ld 12 st 16 Ld 8 * Ld 0 Ld 8 * Ld 4 IR de baixo nível sp

433 ©Universidade do Algarve 433 Geração de código final Y2=a*x*x+b*x+c; lw $t0, 4($sp) lw $t1, 8($sp) mult $t2, $t1, $t0 lw $t3, 8($sp) lw $t4, 8($sp) mult $t5, $t3, $t4 lw $t6, 0($sp) mult $t7, $t5, $t6 Add $t8, $t7, $t2 Ld 8 * + + ld 12 st 16 Ld 8 * Ld 0 Ld 8 * Ld 4 IR de baixo nível sp

434 ©Universidade do Algarve 434 Geração de código final Y2=a*x*x+b*x+c; lw $t0, 4($sp) lw $t1, 8($sp) mult $t2, $t1, $t0 lw $t3, 8($sp) lw $t4, 8($sp) mult $t5, $t3, $t4 lw $t6, 0($sp) mult $t7, $t5, $t6 Add $t8, $t7, $t2 lw $t9, 12($sp) Ld 8 * + + ld 12 st 16 Ld 8 * Ld 0 Ld 8 * Ld 4 IR de baixo nível sp

435 ©Universidade do Algarve 435 Geração de código final Y2=a*x*x+b*x+c; lw $t0, 4($sp) lw $t1, 8($sp) mult $t2, $t1, $t0 lw $t3, 8($sp) lw $t4, 8($sp) mult $t5, $t3, $t4 lw $t6, 0($sp) mult $t7, $t5, $t6 Add $t8, $t7, $t2 lw $t9, 12($sp) Add $t10, $t8, $t9 Ld 8 * + + ld 12 st 16 Ld 8 * Ld 0 Ld 8 * Ld 4 IR de baixo nível sp

436 ©Universidade do Algarve 436 Geração de código final Y2=a*x*x+b*x+c; lw $t0, 4($sp) lw $t1, 8($sp) mult $t2, $t1, $t0 lw $t3, 8($sp) lw $t4, 8($sp) mult $t5, $t3, $t4 lw $t6, 0($sp) mult $t7, $t5, $t6 Add $t8, $t7, $t2 lw $t9, 12($sp) Add $t10, $t8, $t9 Sw $t10, 16($sp) Ld 8 * + + ld 12 st 16 Ld 8 * Ld 0 Ld 8 * Ld 4 IR de baixo nível sp

437 ©Universidade do Algarve 437 Geração de código final Y2=a*x*x+b*x+c; lw $t0, 4($sp) lw $t1, 8($sp) mult $t2, $t1, $t0 lw $t3, 8($sp) lw $t4, 8($sp) mult $t5, $t3, $t4 lw $t6, 0($sp) mult $t7, $t5, $t6 add $t8, $t7, $t2 lw $t9, 12($sp) add $t10, $t8, $t9 sw $t10, 16($sp) Ld 8 * + + ld 12 st 16 Ld 8 * Ld 0 Ld 8 * Ld 4 IR de baixo nível sp 11 registos $t para armazenar valores intermédios! (MIPS tem 10 registos $t)

438 ©Universidade do Algarve 438 Geração de código final Y2=a*x*x+b*x+c; Solução utilizando menos registos para armazenar resultados intermédios? Ld 8 * + + ld 12 st 16 Ld 8 * Ld 0 Ld 8 * Ld 4 IR de baixo nível sp

439 ©Universidade do Algarve 439 Geração de código final Y2=a*x*x+b*x+c; lw $t0, 4($sp) lw $t1, 8($sp) mult $t?, $t1, $t0 Resultado pode ser armazenado em $t1 ou em $t0 Ld 8 * + + ld 12 st 16 Ld 8 * Ld 0 Ld 8 * Ld 4 IR de baixo nível sp

440 ©Universidade do Algarve 440 Geração de código final Y2=a*x*x+b*x+c; lw $t0, 4($sp) lw $t1, 8($sp) mult $t0, $t1, $t0 … Ld 8 * + + ld 12 st 16 Ld 8 * Ld 0 Ld 8 * Ld 4 IR de baixo nível sp

441 ©Universidade do Algarve 441 Geração de código final Y2=a*x*x+b*x+c; lw $t0, 4($sp) lw $t1, 8($sp) mult $t0, $t1, $t0 lw $t1, 8($sp) lw $t2, 8($sp) mult $t1, $t1, $t2 lw $t2, 0($sp) mult $t1, $t1, $t2 add $t0, $t1, $t0 lw $t1, 12($sp) add $t0, $t0, $t1 sw $t0, 16($sp) Ld 8 * + + ld 12 st 16 Ld 8 * Ld 0 Ld 8 * Ld 4 IR de baixo nível sp 3 registos $t para armazenar valores intermédios

442 ©Universidade do Algarve 442 Não optimizado Acessos à pilha requerem mais ciclos do que acessos a registos internos Utilização da pilha para todas as variáveis requer mais instruções

443 ©Universidade do Algarve 443 Geração de código Utilização de esqueletos (templates) para geração de código assembly para Estruturas If-then ou if-then-else Loops

444 ©Universidade do Algarve 444 Geração de código if (test) true_body else false_body boper …, lab_true jlab_end lab_true: lab_end:

445 ©Universidade do Algarve 445 Geração de código while (test) body lab_cont: boper …, lab_body jlab_end lab_body: jlab_cont lab_end: Esqueleto optimizado: lab_cont: boper …, lab_end jlab_cont lab_end:

446 ©Universidade do Algarve 446 Linhas mestras para o gerador de código Descer o nível de abstracção devagar: Utilizar várias etapas Mesmo que apenas se faça uma coisa por cada etapa Mais fácil de depurar, mais fácil de lidar com o problema Manter o nível de abstracção consistente IR deve manter a semântica correcta sempre! Pode ser necessário realizar optimizações entre etapas Utilizar assertions (assertividades) deliberadamente Utilizar uma assertion para verificar um pressuposto Ajudam a encontrar bugs!

447 ©Universidade do Algarve 447 Linhas mestras para o gerador de código Começar com geração simples, mesmo que naïf Ok gerar: 0 + 1*x + 0*y A biblioteca de runtime é nossa amiga! Não tentes gerar código assembly quando existem rotinas na biblioteca com a mesma funcionalidade Exemplo: malloc

448 ©Universidade do Algarve 448 Linhas mestras para o gerador de código Lembrar que as optimizações vêm depois O optimizador realiza as optimizações Pensar o que o optimizador necessita e estruturar o código de acordo com isso Exemplo: alocação de registos, simplificações algébricas, propagação de constantes Utilizar uma boa infra-estrutura de teste Teste regressivo Se um programa cria um bug adicioná-lo ao teste suite Utilizar makefiles: para executar o compilador sobre o teste suite e verificar automaticamente se os resultados estão correctos (pode implicar a utilização de um simulador da arquitectura) Ver teste na Engenharia de Software

449 ©Universidade do Algarve 449 Optimizações Compiladores João M. P. Cardoso

450 ©Universidade do Algarve 450 Alocação de registos Atribuir o maior número de variáveis a registos Utilizar cada registo para armazenar o maior número possível de variáveis (registos são poucos...) Tempo de vida de variáveis Uma das optimizações com maior impacto (tamanho do código e desempenho)

451 ©Universidade do Algarve 451 Tempo de Vida de Variáveis Duração numa sequência de instruções entre a definição de uma variável e o seu uso A = b*c; D=b*b+e; E=A+D; Tempo de vida de A

452 ©Universidade do Algarve 452 Tempo de Vida de Variáveis Y2=a*x*x+b*x+c lw $t0, 4($sp) lw $t1, 8($sp) mult $t2, $t1, $t0 lw $t3, 8($sp) lw $t4, 8($sp) mult $t5, $t3, $t4 lw $t6, 0($sp) mult $t7, $t5, $t6 add $t8, $t7, $t2 lw $t9, 12($sp) add $t10, $t8, $t9 sw $t10, 16($sp) $t0$t1$t2$t3$t4$t5$t6$t7$t8$t9$t10

453 ©Universidade do Algarve 453 Tempo de Vida de Variáveis Y2=a*x*x+b*x+c lw $t0, 4($sp) lw $t1, 8($sp) mult $t2, $t1, $t0 lw $t3, 8($sp) lw $t4, 8($sp) mult $t5, $t3, $t4 lw $t6, 0($sp) mult $t7, $t5, $t6 add $t8, $t7, $t2 lw $t9, 12($sp) add $t10, $t8, $t9 sw $t10, 16($sp) $t0$t1$t2$t3$t4$t5$t6$t7$t8$t9$t10 3 registos

454 ©Universidade do Algarve 454 Y2=a*x*x+b*x+c lw $t0, 4($sp) lw $t1, 8($sp) mult $t2, $t1, $t0 lw $t3, 8($sp) lw $t4, 8($sp) mult $t5, $t3, $t4 lw $t6, 0($sp) mult $t7, $t5, $t6 add $t8, $t7, $t2 lw $t9, 12($sp) add $t10, $t8, $t9 sw $t10, 16($sp) Afectação de registos a variáveis $t0$t1$t2$t3$t4$t5$t6$t7$t8$t9$t10

455 ©Universidade do Algarve 455 Y2=a*x*x+b*x+c lw $t0, 4($sp) lw $t1, 8($sp) mult $t2, $t1, $t0 lw $t3, 8($sp) lw $t4, 8($sp) mult $t5, $t3, $t4 lw $t6, 0($sp) mult $t7, $t5, $t6 add $t8, $t7, $t2 lw $t9, 12($sp) add $t10, $t8, $t9 sw $t10, 16($sp) Afectação de registos a variáveis $t0$t1$t2$t3$t4$t5$t6$t7$t8$t9$t10 4 registos

456 ©Universidade do Algarve 456 Afectação de registos a variáveis Determinar tempo de vida das variáveis Afectar um registo a uma ou mais variáveis Como? Por exemplo: Coloração de grafos (problema NP-complexo) Heurísticas: Algoritmo left-edge

457 ©Universidade do Algarve 457 Afectação de registos a variáveis Algoritmo Left-edge (utilizado no exemplo em que se obteve 3 registos) Ordenar segmentos (intervalos) pelo valor do tempo de início Começar pelo primeiro segmento e tentar adicionar segmentos pela ordem sempre que não haja sobreposição Quando não for possível adicionar mais segmentos, voltar ao passo anterior considerando o segmento seguinte Número de registos = número de colunas com segmentos

458 ©Universidade do Algarve 458 Afectação de registos a variáveis Algoritmo Left-edge LEFT_EDGE(I) { Sort elements of I in a list L in ascending order of li ; c = 0; while (some interval has not been colored ) do { S = ; r = 0; while ( s L such that ls > r) do { s = First element in the list L with ls > r ; S = S { s } ; r = rs ; Delete s from L; } c = c +1; Label elements of S with color c; }

459 ©Universidade do Algarve 459 Afectação de registos a variáveis Coloração de grafos Determinar tempo de vida das variáveis Construir grafo de interferências* (existe interferência quando duas variáveis têm tempos de vida com sobreposição) Laços representam interferência Nós representam variáveis Determinar o número mínimo de cores do grafo (pode ser utilizado o algoritmo left-edge) Cada cor corresponde a um registo (número de registos = número de cores) * Também chamado de grafo de conflitos

460 ©Universidade do Algarve 460 Afectação de registos a variáveis Tempo de vida das variáveis lw $t0, 4($sp) lw $t1, 8($sp) mult $t2, $t1, $t0 lw $t3, 8($sp) lw $t4, 8($sp) mult $t5, $t3, $t4 lw $t6, 0($sp) mult $t7, $t5, $t6 add $t8, $t7, $t2 lw $t9, 12($sp) add $t10, $t8, $t9 sw $t10, 16($sp) $t0$t1$t2$t3$t4$t5$t6$t7$t8$t9$t10

461 ©Universidade do Algarve 461 Afectação de registos a variáveis Grafo de interferências lw $t0, 4($sp) lw $t1, 8($sp) mult $t2, $t1, $t0 lw $t3, 8($sp) lw $t4, 8($sp) mult $t5, $t3, $t4 lw $t6, 0($sp) mult $t7, $t5, $t6 add $t8, $t7, $t2 lw $t9, 12($sp) add $t10, $t8, $t9 sw $t10, 16($sp) $t0$t1$t2$t3$t4$t5$t6$t7$t8$t9$t10 $t0$t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10

462 ©Universidade do Algarve 462 Afectação de registos a variáveis Grafo de interferências Interferência (laço) entre duas variáveis (nós) indica que não podem ser armazenadas no mesmo registo v0v1 v2 v3 v4 v5 v6 v7 v8 v9 v10

463 ©Universidade do Algarve 463 Afectação de registos a variáveis Grafo de interferências Depois de colorido: Número de cores indica o número de registos necessário v0v1 v2 v3 v4 v5 v6 v7 v8 v9 v10

464 ©Universidade do Algarve 464 Afectação de registos a variáveis: exercício Considerando o código ao lado, determine o número de registos necessário para armazenar as variáveis utilizando o algoritmo left_edge (y2 é a única variável utilizada posteriormente) T1=x*x; T2=a*t1; T3=b*x; T4=t3+c; T5=t4+t2; Y2=t5;

465 ©Universidade do Algarve 465 Afectação de registos a variáveis Na presença de estruturas condicionais Problema mais complicado Resolução similar

466 ©Universidade do Algarve 466 Optimizações Existem muitas outras optimizações Loop unrolling (existe uma série de optimizações ao nível de loops) propagação de constantes redução de força (strength reduction) avaliação de expressões com constantes eliminação de sub-expressões comuns, substituição por escalares (scalar replacement) eliminação de acessos a memória redundantes eliminação de código morto movimento de código

467 ©Universidade do Algarve 467 Fim! Disponível para orientar alunos interessados em realizar projectos sobre estes temas No ensino de certos tópicos: utilizando, por exemplo, Java Applets Na criação de infra-estruturas para apoio à leccionação Em tópicos avançados relacionados com investigação


Carregar ppt "©Universidade do Algarve 1 Introdução da Disciplina Compiladores João M. P. Cardoso Universidade do Algarve 8000-117 Faro, Portugal."