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

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

Um Tradutor Dirigido por Sintaxe Simples

Apresentações semelhantes


Apresentação em tema: "Um Tradutor Dirigido por Sintaxe Simples"— Transcrição da apresentação:

1 Um Tradutor Dirigido por Sintaxe Simples
Apresenta de forma resumida boa parte do assunto que veremos em detalhes no restante do curso Dá uma visão geral do processo de compilação

2 Um compilador simples Objetivo: traduzir expressões infixas em posfixas 9 –  9 5 – 2 + Aplicabilidade: computação baseda em pilha (por exemplo, gerador de código para .NET e JVM)

3 Front-end de um compilador
Programa fonte Analisador léxico tokens Tabela de Símbolos Parser Todos interagem com a tabela de símbolos árvore sintática Ger. de código intermediário Three-address code

4 Definição de uma linguagem
Linguagem = sintaxe + semântica Sintaxe = forma Semântica = significado

5 Definição de uma linguagem
Especificação da sintaxe: gramática livre de contexto, BNF (Backus-Naur Form) Especificação da Semântica: normalmente informal (textual) formal: uso de semântica operacional, denotacional, de ações, etc.

6 Exemplo: if-else if ( expression ) statement else statement

7 Exemplo: if-else if ( expression ) statement else statement
stmt g if ( expr ) stmt else stmt

8 Gramática Livre de Contexto
Um conjunto de tokens, símbolos terminais Um conjunto de símbolos não-terminais Um conjunto de produções, cada produção consiste de um não-terminal, uma seta, e uma sequencia de tokens e/ou não terminais Um não terminal designado como símbolo inicial

9 Exemplo 1 list g list + digit list g list - digit list g digit
digit g 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9

10 Exemplo 1a list g list + digit | list - digit | digit digit g 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 Explicar quais são os terminais e quais os não terminais.

11 Exemplo 2 call g id ( optparams ) optparams g params |  params g params , param | param

12 Derivações Uma gramática deriva strings a partir do seu símbolo inicial e repetidamente substituindo não-terminais pelo corpo de sua produção As sequencias de terminais produzidas desta forma formam a linguagem definida pela gramática Exemplos: 9, 9 - 5, Dar exemplo. Exemplo de function call e parâmetros.

13 Parsing Problema de pegar uma string de terminais e verificar como derivá-la a partir do símbolo inicial da gramática; caso não seja possível, reportar erros de sintaxe. Processo de procurar uma parse-tree para uma dada sequencia de terminais.

14 Parse Trees Mostra graficamente como o símbolo inicial de uma gramática deriva uma string da linguagem. Para uma produção A g XYZ A Note que os nós são símbolos não terminais. X Y Z

15 Parse Trees A raiz é o símbolo inicial Cada folha é um terminal ou 
Cada nó interior é um não-terminal Se A é um não-terminal e X1, X2,...,Xn são labels de filhos deste nó, tem que haver uma produção A g X1 X2 ... Xn Note que os nós são símbolos não terminais.

16 Exemplo 9 – 5 + 2 list list digit digit list digit 9 - 5 + 2

17 Ambiguidade Parse-tree gera uma string, mas uma string pode possuir várias parse-trees, se a gramática for ambígua. Solução: usar sempre gramáticas não-ambíguas, ou gramáticas ambíguas com informações adicionais sobre como resolver ambiguidades.

18 Ambiguidade - Exemplo string g string + string | string - string | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9

19 Exemplo: Duas parse trees
9 – 5 + 2 string string string + string string - string string - string string + string 2 9 9 5 5 2

20 Associatividade de Operadores
+, –, * e / são associativos à esquerda, na maioria das linguagens de programação: 9 – é equivalente a (9-5)+2 Atribuição em C e exponenciação são associativos à direita: a = b = c 2**3**4

21 Associatividade à direita
right g letter = right | letter letter g a | b | … | z

22 Precedência de operadores
9 + 5 * 2 * tem maior precedência do que + Usaremos dois não-terminais para representar os dois níveis de precedência em expressões e um outro para gerar as unidades básicas de expressões.

23 Precedência de operadores
expr g expr + term | expr – term | term term g term * factor | term / factor | factor factor g digit | ( expr ) digit g 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9

24 Exemplo stmt g id = expression ; | if ( expression ) stmt | if ( expression ) stmt else stmt | while ( expression ) stmt | do stmt while ( expression ) ; | { stmt } stmts g stmts stmt | 

25 Tradução dirigida por sintaxe
Tradução dirigida associa regras ou trechos de programa às produções de uma gramática.

26 Exemplo expr g expr1 + term traduza expr1; traduza term; trate + ;

27 Conceito: Atributo Um valor associado a um construtor do programa.
Exemplos: Tipo em uma expressão; Número de instruções geradas; Localização da primeira instrução gerada por um construtor;

28 Conceito: Esquema de tradução (dirigida pela sintaxe)
Notação para associar trechos de programa a produções de uma gramática Os trechos de programa são executados quando a produção é usada durante a análise sintática O resultado da execução desses trechos de programa, na ordem criada pela análise sintática, produz a tradução desejada do programa fonte

29 Notação pós-fixada Se E é uma variável ou constante, sua notação pós-fixada é ela mesma; Se E é uma expressão da forma E1 op E2, então sua notação pós fixada é E1’ E2’ op, onde E1’ e E2’ são as notações pós-fixadas de E1 e E2 respectivamente; Se E é uma expressão com parênteses ( E ), então sua notação pós-fixada é a mesma notação pós-fixada de E1.

30 Exemplo (9-5) 9-(5+2) 9-(5+2)* *

31 Definição dirigida por sintaxe
Definição dirigida por sintaxe associa a cada símbolo um conjunto de atributos; e a cada produção, regras semânticas para computar os valores dos atributos (Gramática de atributos)

32 Definição dirigida por sintaxe
Dada uma string x, construa uma parse tree para ela; Aplique as regras semânticas para avaliar os atributos em cada nó.

33 Exemplo – valores dos atributos nos nós de uma parse tree
expr.t = 95-2+ expr.t = 95- term.t = 2 expr.t = 9 term.t = 5 term.t = 9 9 - 5 + 2

34 Tipos de Atributos Atributos sintetizados: seus valores são obtidos a partir dos filhos de um determinado nó; Podem ser calculados através de uma travessia bottom-up; Atributos herdados: têm seus valores definidos a partir do próprio nó, de seus pais ou seus irmãos.

35 Exemplo – Definição dirigida por sintaxe
Produção Regra semântica expr g expr1 + term expr.t = expr1.t || term.t || ‘+’ expr g expr1 – term expr.t = expr1.t || term.t || ‘-’ expr g term expr.t = term.t term g term.t = ‘0’ term g term.t = ‘1’ … term g term.t = ‘9’

36 Travessias Travessia em profundidade (depth-first)
procedure visit (node N) { for (each child C of N, from left to right) { visit(C); } evaluate semantic rules at node N; }

37 Esquemas de tradução Gramática livre de contexto com fragmentos de programas (ações semânticas) embutidos no lado direito das produções. Semelhante à definição dirigida por sintaxe, mas com a ordem de avaliação das regras semânticas explicitada.

38 Exemplo 1 rest g + term {print (‘+’) } rest1 rest + term {print(‘+’)}

39 Exemplo 2 expr g expr + term { print (‘+’) } expr g expr - term { print (‘-’) } expr g term term g 0 { print (‘0’) } term g 1 { print (‘1’) } … term g 9 { print (‘9’) }

40 Exemplo 2 expr expr term + expr - term 2 term 5 9

41 Ações traduzindo 9=5+2 em 95-2+
expr {print(‘+’)} expr term + {print(‘-’)} {print(‘2’)} expr - term 2 {print(‘5’)} term 5 {print(‘9’)} 9

42 Parsing Processo de determinar como uma string de terminais pode ser gerada por uma gramática Conceitualmente é a construção da parse tree Mas a parse tree pode não ser efetivamente construída durante a compilação.

43 Parsing Para gramáticas livres de contexto sempre é possível construir um parser com complexidade O(n3) para fazer o parsing de n tokens. Na prática, o parsing de linguagens de programação normalmente pode ser feito linearmente. Travessia linear da esquerda para a direita, olhando um token de cada vez.

44 Top-down ou bottom-up parsers
Refere-se à ordem em que os nós da parse tree são criados. Top-down: mais fáceis de escrever “à mão” Bottom-up: suportam uma classe maior de gramáticas e de esquemas de tradução; são frequentemente usados/gerados pelas ferramentas de geração automática de parsers.

45 Exemplo stmt g expr ; | if (expr ) stmt | for ( optexpr ; optexpr ; optexpr ) stmt | other optexpr g expr | 

46 Exemplo for ( ; expr ; expr ) other stmt for ( optexpr ; optexpr ;
expr expr stmt for ( ; expr ; expr ) other

47 Construindo um parser top-down
Para cada nó n, com um não-terminal A, selecione uma das produções de A e construa os filhos de n para os símbolos à direita da produção. Encontre o próximo nó para o qual uma sub-árvore deve ser construída.

48 Construindo um parser top-down
Para algumas gramáticas basta uma única travessia da esquerda para a direita da string de entrada. Token corrente é chamado de lookahead symbol. Exemplo: for ( ; expr ; expr ) other

49 Backtracking A escolha de uma produção pode exigir tentativa-e-erro, voltando para tentar novas alternativas possíveis. Predictive-parsing: parsing em que não ocorre backtracking.

50 Recursive descent parsing
Método de análise sintática top-down em que um conjunto de procedimentos recursivos é usado para processar a entrada. Cada procedimento está associado a um símbolo não-terminal da gramática. Predictive parsing é um caso especial de recursive descent parsing em que o símbolo lookahead determina sem ambiguidades o procedimento a ser chamado para cada não-terminal.

51 Exemplo – predictive parsing
stmt g for ( optexpr ; optexpr ; optexpr ) stmt match (for); match (‘(‘); optexpr (); match (‘;‘); optexpr (); match (‘)‘); stmt ();

52 Exemplo – predictive parsing
void match (terminal t) { if (lookahead == t) lookahead = nextTerminal else report (“syntax error”); }

53 Exemplo – predictive parsing (cont.)
void optexpr( ) { if (lookahead == expr) match (expr) ; }

54 Exemplo – predictive parsing (cont.)
void stmt( ) { switch (lookahead) { case expr: match(expr); match(‘;’); break; case if: match(if); match(‘(‘); match(expr);match(‘)’); stmt(); break; case for: match(for); match(‘(‘); optexpr(); match(‘;‘); optexpr(); match(‘;‘); optexpr(); match(‘)‘); stmt(); break; case other: match(other); break; default: report(“syntax error”); } }

55 Predictive parsing - Problema
Recursão à esquerda leva a loop em predictive parsers: expr g expr + term | term A g Aa | e

56 Predictive parsing - Solução
Reescrever produções tornando-as recursivas à direita: A g Aa | b reescrever para A g bR R g aR |  Exemplo: expressão “baaaa”

57 Sintaxe abstrata x Sintaxe concreta
Sintaxe abstrata: ignora distinções superficiais de forma, irrelevantes para o processo de tradução. list + list - digit 2 list digit 9 5 digit 9 - 5 + 2

58 Sintaxe abstrata x Sintaxe concreta (cont.)
Na árvore sintática abstrata os nós são construções do programa, enquanto que na parse tree os nós são não-terminais. Idealmente as duas árvores devem ser próximas.

59 Reescrevendo a gramática de expressões
expr g expr + term {print (‘+’) } expr g expr - term {print (‘-’) } expr g term term g {print (‘0’) } … term g {print (‘9’) }

60 Reescrevendo a gramática de expressões
A g Aa | Ab | c A g cR R g aR | bR | 

61 Reescrevendo a gramática de expressões (cont.)
A = expr a = + term {print(‘+’)} b = - term {print(‘-’)} c = term ?

62 Reescrevendo a gramática de expressões (cont.)
expr g term rest rest g + term| - term|  term g 0 | …| 9 Alternativas para ações semânticas: rest g - expr {rest.t = ‘-’ || expr.t } rest g - expr {rest.t = expr.t || ‘-’ } Exemplo: 9-5+2 ?

63 Reescrevendo a gramática de expressões (cont.)
expr g term rest rest g + term {print (‘+’) } rest | - term {print (‘-’) } rest |  term g {print (‘0’) } … term g {print (‘9’) }

64 Tradutor em C void expr () { term(); rest(); }

65 Tradutor em C void term () { if (isdigit(lookahead)) { t = lookahead; match(lookahead); print(t); } else report(“syntax error”); }

66 Tradutor em C (cont.) void rest() { if (lookahead == ‘+’) { match(‘+’); term(); print(‘+’); rest(); } else if (lookahead ==‘-’) { match(‘-’); term(); print(‘-’); rest(); } else { }; }

67 Otimizações void rest () { while (true) { if (lookahead == ‘+’) { match(‘+’); term(); print(‘+’); continue; } else if (lookahead ==‘-’) { match(‘-’); term(); print(‘-’); continue; } break; } }

68 Usando um analisador léxico
Facilita o tratamento de lexemas ao invés de caracteres: Tratamento de espaços em branco Tratamento de número maiores que 9 (constantes) Reconhecimento de identificadores e palavras-chave.

69 Estendendo para identificadore e números maiores que 9
expr g expr + term {print (‘+’) } | expr – term {print (‘-’) } | term term g term * factor {print (‘*’) } | term / factor {print (‘/’) } | factor factor g ( expr ) | num {print (num.value) } | id {print (id.lexeme) }

70 Class Token int tag class Token int value class Num string lexeme
class Word

71 Código do analisador léxico
token scan() { char t; while(true) { t = getchar(); if (t == ‘ ’ || t ==‘\t’) { } ; else if (t ==‘\n’) line++; else if (isdigit(t)) { tokenval = t – ‘0’; t = getchar(); while (isdigit(t)) { { tokenval = tokenval * 10 + t – ‘0’; t = getchar(); } ungetc(t,stdin); return token<num,tokenval>; } else …

72 A tabela de símbolos Interface:
insert(s,t) lookup(s) Palavras reservadas: insert(“div”,div) insert(“mod”, mod)

73 Geração de código intermediário
Árvores: e.g. parse trees ou (abstract) syntax trees Representações lineares: e.g. three-address code

74 Construção da Syntax tree
Classes para representar a hierarquia de construções da Linguagem: Statements, IfStatements, WhileStatements; Expressions, BinaryExpressions, etc.

75 class AST class Statement class Expression Expr E; Stmt S; class IfStmt Identifier I; Expr E; class AssignmentStmt Expr E; Stmt; class WhileStmt

76 class AST class Statement class Expression Int IL; class IntLiteral Operator Op; Expr E1, E2; class BinaryExpr Operator Op; Expr E; class UnaryExpr

77 Exemplo stmt g expr ; {stmt.n = new Eval(expr.n); } | if (expr ) stmt {stmt.n = new If(expr.n, stmt.n}

78 Fluxo de controle Desvios condicionais ou incondicionais
o destino pode ser especificado pelo operando da instrução o operando pode especificar um desvio relativo o destino pode ser especificado simbolicamente, através de labels

79 Fluxo de controle - instruções
ifFalse x goto L ifTrue x goto L goto L

80 Fluxo de controle – exemplo 1
class IfStmt extends Stmt { Expr E; Stmt S; public If (Expr x, Stmt y) { E = x; S = y; after = newlabel(); } public void gen() { Expr n = E.rvalue(); emit(“ifFalse ”+n.toString()+“goto ”+after); S.gen() emit(after +”:“); } }

81 Código para calcular expr em x
ifFalse x goto after Código para calcular expr em x ifFalse x goto after Código para stmt1 after

82 L-values e R-values i = 5; i = i + 1;
L-values são locais (endereços), e R-values são valores.

83 Resumo If ( peek == ‘\n’ ) line = line + 1; Lexical Analyser
<if> <(> <id,”peek”> <eq> <const,’\n’> <)> <id,”line”> <assign> <id,”line”> <+> <num,1> <;> Syntax Directed Translator 1: t1 = (int) ‘\n’ 2: ifFalse peek == t1 goto 4 3: line = line + 1 4: if eq assign peek (int) line + line 1 ‘\n’


Carregar ppt "Um Tradutor Dirigido por Sintaxe Simples"

Apresentações semelhantes


Anúncios Google