• Nenhum resultado encontrado

Projeto de Linguagens de Programação

N/A
N/A
Protected

Academic year: 2021

Share "Projeto de Linguagens de Programação"

Copied!
45
0
0

Texto

(1)

Projeto de Linguagens de Programação

Aula 4: Analisador Sintático 1 Prof Joaquim Pessôa Filho

(2)

Sumário

1. Estratégias de parsing

2.  Implementação do parsing

3.  Gramáticas livre de contexto

4.  Gramáticas preditivas

5.  Gramáticas ambíguas

(3)

Análise Léxica Análise Sintática Análise Semântica

Geração de código intermediário Otimização de código

Geração de código Síntese

Análise

Programa Fonte

Programa Executável

Compilador Atual

(4)

Analisador sintático

  Analisador sintático ou parser: processo principal do compilador

  Coordena as outras etapas

  Funções

  Verificar a boa formação do programa: quais cadeias pertencem à linguagem

  Sintaxe, gramática

  Construção da árvore sintática do programa: implícita ou explícita

  Tratar erros

  Exemplos

  while ( <exp> ) <comandos>

  id := <exp>

(5)

Parsing

Dada uma gramática livre de contexto G:

Parsing possibilita o reconhecimento de uma cadeia e a determinação de sua estrutura de frase

Considerar gramáticas não-ambíguas.

(6)

Estratégias de Parsing

O que diferencia as estratégias parsing é a

ordem na qual a árvore sintática da cadeia de entrada é construída

  Bottom-up

  Top-down

(7)

Gramática Micro-English (Exemplo)

Sentença ::= Sujeito Verbo Objeto

.

Sujeito ::= I | a Substantivo | the Substantivo Objeto ::= me | a Substantivo | the Substantivo Substantivo ::= cat | mat | rat

Verbo ::= like | is | see | sees

(8)

Sentenças geradas por Micro- English

  the cat sees a rat.

  I like the mat.

  the cat likes me.

  I sees the cat.

Micro-English pode gerar sentenças

gramaticalmente incorretas em Inglês Ex: I sees the cat.

(9)

sees

Estratégia Bottom-up

rat

a .

cat the

Substantivo

(10)

sees

Estratégia Bottom-up

rat

a .

cat the

Substantivo Sujeito

(11)

sees

Estratégia Bottom-up

rat

a .

cat the

Substantivo Sujeito

Verbo

(12)

sees

Estratégia Bottom-up

rat

a .

cat the

Substantivo Sujeito

Verbo Substantivo

(13)

sees

Estratégia Bottom-up

rat

a .

cat the

Substantivo Sujeito

Verbo Substantivo

Objeto

(14)

sees

Estratégia Bottom-up

rat

a .

cat the

Substantivo Sujeito

Verbo Substantivo

Objeto Sentença

(15)

Estratégia Top-Down

sees a rat .

cat the

Sujeito Verbo Objeto

Sentença

.

(16)

Estratégia Top-Down

sees a rat .

cat the

Sujeito Verbo Objeto

Sentença

.

Substantivo

(17)

Estratégia Top-Down

sees a rat .

cat the

Sujeito Verbo Objeto

Sentença

.

Substantivo

(18)

Estratégia Top-Down

sees a rat .

cat the

Sujeito Verbo Objeto

Sentença

.

Substantivo

(19)

Estratégia Top-Down

sees a rat .

cat the

Sujeito Verbo Objeto

Sentença

.

Substantivo Substantivo

(20)

Estratégia Top-Down

sees a rat .

cat the

Sujeito Verbo Objeto

Sentença

Substantivo Substantivo

(21)

Recursive-descent parsing (Exemplo Micro-English)

private void parseNoun ();

// analisa um substantivo (cat, mat ou rat) private void parseVerb ();

// analisa um verbo (like, sees) private void parseSubject ();

// analisa um sujeito (I ou a rat) private void parseObject ();

// analisa um objeto (me ou a rat) private void parseSentence ();

// analisa a sentença

(22)

Recursive-descent parsing

  O método parseSentence delega quase todo o trabalho para os outros métodos, e depois que todos os métodos foram executados,

aceita o “.” (ponto do final da sentença)

(23)

Implementação do parser

  É preciso definir uma classe contendo todos os métodos de parsing

public class Parser{

private TerminalSymbol currentTerminal;

... // Métodos auxiliares ... // Métodos de parsing }

(24)

Implementação do parser

private void accept (TerminalSymbol expectedTerminal)

if(currentTerminal é igual ao expectedTerminal)

...

else

reportar o erro ] }

(25)

Implementação do parser

Métodos de parsing (exemplo):

private void parseSentence () { Sentence

::=

parseSubject(); Subject

parseVerb(); Verb

parseObject(); Object

accept(‘.’); .

}

(26)

Implementação do parser

private void parseSubject () {

if(currentTerminal é igual a ‘I’) Subject ::=

accept(‘I’); I

else |

if(currentTerminal é igual a ‘a’){

accept(‘a’); a

parseNoun (); Noun

}else |

if(currentTerminal é igual a ‘the’){

accept(‘the’); the

parseNoun (); Noun

}else{

Reportar o erro sintático

}

}

(27)

Implementação do parser

private void parseNoun () {

if(currentTerminal é igual a ‘cat’) Noun :: =

accept(‘cat’); cat

else |

if(currentTerminal é igual a ‘mat’){

accept(‘mat’); mat

}else |

if(currentTerminal é igual a ‘rat’){

accept(‘rat’); rat

}else{

Reportar o erro sintático

}

}

(28)

Implementação do parser

O parser é iniciado pelo método:

public void parse () {

currentTerminal = Primeiro terminal da cadeia;

parseSentence();

}

(29)

Observação Importante

O parser visto não constrói explicitamente a árvore sintática, mas determina a estrutura de frase da cadeia de entrada

(30)

Gramáticas livre de contexto

  Uma sintáxe para programas de uma-linha

S → S; S S → id := E S → print (L) E → id

E → num E → E + E E → (S, E) L → E

L → L, E

(31)

Exemplo

  Uma sentença na linguagem desta gramática é

id := num; id := id + (id := num + num, id)

onde o texto fonte (antes da análise léxica) pode ter sido

a : = 7; b : = c + (d : = 5 + 6, d)

(32)

Derivações

  Começando no ponto inicial:

S S ; S

S ; id := E

id := E; id := E id := num ; id := E

id := num ; id := E + E id := num ; id := E + (S, E) id := num ; id := id + (S, E)

id := num ; id := id + (id := E, E)

id := num ; id := id + (id := E + E, E) id := num ; id := id + (id := E + E, id ) id := num ; id := id + (id := num + E, id) id := num ; id := id + (id := num + num, id)

(33)

Árvores de Parse

(34)

Gramáticas ambíguas

  Considerando a gramática:

E → id E → num E → E * E E → E / E E → E + E E → E − E E → (E)

(35)

Gramáticas ambíguas

  Uma gramática é ambígua se ela pode

derivar uma sentença com duas árvores de parse diferentes

(36)

Gramáticas ambíguas

  Exemplo: 1-2-3 e 1+2*3

(37)

Gramáticas ambíguas

  Analisando agora a gramática:

E → E + T E → E − T E → T

T → T * F T → T / F T → F

F → id F → num F → (E)

id * num + num * id / num – id

(38)

Marcador de fim de arquivo

  Parsers deve não somente ler símbolos terminais, tais como +, −, num, e outros, mas também o

marcador de fim de arquivo ($).

S → E $ E → E + T E → E − T E → T

T → T * F T → T / F T → F F → id F → num F → (E)

(39)

Parsing preditivo

  Algumas gramáticas são fáceis para analisar gramaticalmente usando um algoritmo simples conhecido como descendente recursivo.

  Na essência, cada produção gramatical torna-se uma clausula de uma função recursiva.

S → if E then S else S S → begin S L

S → print E L → end

L → ; S L

E → num = num

(40)

Parsing preditivo

  Um parser descendente recursivo para essa

linguagem tem uma função para cada não-terminal e uma cláusula para cada produção.

final int IF=1, THEN=2, ELSE=3, BEGIN=4, END=5, PRINT=6, SEMI=7, NUM=8, EQ=9;

int tok = getToken();

void advance() {tok=getToken();}

void eat(int t) {

if (tok==t) advance();

else error();

}

(41)

Parsing preditivo

void S() {switch(tok) {

case IF: eat(IF); E(); eat(THEN); S();

eat(ELSE); S(); break;

case BEGIN: eat(BEGIN); S(); L(); break;

case PRINT: eat(PRINT); E(); break;

default: error();

}}

void L() {switch(tok) {

case END: eat(END); break;

case SEMI: eat(SEMI); S(); L(); break;

default: error();

}}

void E() { eat(NUM); eat(EQ); eat(NUM); }

(42)

Considerando a gramática

S → E $ E → E + T E → E − T E → T

T → T * F T → T / F T → F

F → id F → num F → (E)

(43)

Parsing preditivo

void S() { E(); eat(EOF); } void E() {switch (tok) {

case ?: E(); eat(PLUS); T(); break;

case ?: E(); eat(MINUS); T(); break;

case ?: T(); break;

default: error();

}}

void T() {switch (tok) {

case ?: T(); eat(TIMES); F(); break;

case ?: T(); eat(DIV); F(); break;

case ?: F(); break;

default: error();

}}

(44)

Exercícios

1.  Traduza cada dessas expressões regulares numa gramática livre de contexto:

1.  ( (xy*x) | (yx*y) )?

2.  ( (0 | 1)+ "." (0 | 1)* ) | ( (0 | 1)* "." (0 | 1)+ )

(45)

Exercícios

2. Escreva uma gramática não-ambígua para cada linguagem seguinte:

1.  Palíndromes sobre o alfabeto {a, b}.

2.  Strings como a expressão regular a*b* e tem mais a's que b's.

3.  Parênteses e colchetes balanceados. Exemplo:

([[](()[()][])])

4.  Blocos de comandos em C onde os pontos-e- vírgulas terminam os comandos:

{ expression; { expression; expression; } expression; }

Referências

Documentos relacionados

Convencionam as partes que, exclusivamente para os empregados que mantêm contrato de trabalho com a mesma empresa ou, empresa do mesmo grupo econômico há mais de 10 (dez) anos e

Convencionam as partes que, exclusivamente para os empregados que mantêm contrato de trabalho com a mesma empresa ou, empresa do mesmo grupo econômico há mais de 10 (dez) anos e

Assim, a casa favorece as relações e a convivência entre (1) gerações de uma mesma família, entre (2) pessoas de famílias diferentes e que são afins na casa em que escolheram

1964: Managing for Results (“Administrando para Obter Resultados”, ed. Thomson Pio- neira). Neste livro, que complementa The Practice of Management, Drucker explica por que é

‘ O crime de insubmissão previsto no artigo 183 do CPM (‘deixar de apresentar-se o convocado à incorporação, dentro do prazo que lhe foi marcado ...’) aplica-se apenas aos

Gári Veiga Glass, Secretaria Municipal de Saúde de Pelotas, RS/Brasil Genivalda Cândido da Silva, Universidade Federal da Bahia, BA/Brasil Giovani Vilmar Comerlatto, Instituto

[r]

Fatores de risco para câncer de tireóide estavam presentes em quatro pacientes (tabela 1): uma adolescente estava em tratamento para doença de Graves e três pacientes