Você está na página 1de 77

Compiladores

Unidade 3 Analisador Sinttico Prof.: Henrique Santos

Introduo

Introduo

Anlise Sinttica ou Parser o processo de analisar uma sequncia de entrada para determinar sua estrutura gramatical segundo uma determinada gramtica formal.
Normalmente a entrada uma sequncia de Tokens vindas do Analisador Lxico.

Introduo - Esquema
Obter prximo token programa Analisador Analisador fonte Sinttico Lxico token Tabela de smbolos

Estrutura Gramatical
Toda linguagem de programao possui regras que descrevem a estrutura sinttica de programas escritos corretamente; A sintaxe de programas pode ser descrita atravs de Gramticas Livres de Contexto.

Gramticas Livres de Contexto podem ser implementadas atravs de Autmatos de Pilha.

Gramticas

As gramticas oferecem vantagens aos projetistas das linguagens de programao e de compiladores:


Nos permite construir analisadores sintticos que determinam se um programa fonte est bem formado; Especifica a linguagem de forma precisa e fcil de entender; Revela ambigidades e construes difceis;

Gramticas
Oferece uma estrutura linguagem de programao para a traduo de programas fonte em programas objeto corretos; Para novas construes que devem ser adicionadas a uma linguagem de programao, sua adio mais fcil quando a implementao existente for baseada na descrio atravs de gramtica.

rvore de Anlise Sinttica

A partir da gramtica da linguagem, rvores de sintaxe so construdas para verificar se os tokens podem ser produzidos:
Analisadores sintticos descendentes (top-down); Analisadores sintticos ascendentes (bottom-up).

An. Ascendente e Descendente


Seja a gramtica:
EE+T|T TT*F|F F (E) | id | num

Descendente:
E E+T T+T id+T id+T*F id+F*F id+id*F id+id*id

Ascendente:
id+id*id F+id*id T+id*id E+id*id E+F*id E+T*id E+T*F E+T E

rvore Gramatical
montante := deposito + taxa_juros * 60
Analisador lxico id1 := id2 + id3 * num Analisador sinttico

:=
id1 id2 + * id3

num

Tratamento de Erros

Erros de Sintaxe

A maioria dos tratamentos erros est centrada na fase de anlise sinttica:


A maioria dos erros de natureza sinttica - tokens obtidos do analisador lxico desobedecem as regras de sintaxe da linguagem; Os mtodos de deteco de erros dos analisadores sintticos esto mais precisos;

Erros de Sintaxe

Objetivos do tratador de erros:


Reportar a presena de erros de forma clara; Recuperar de erros de forma rpida para ser capaz de detectar erros seguintes; No deve reduzir significativamente o processo de compilao para programas corretos.

A maioria dos erros encontrados em programas so simples e existem mtodos eficientes que geralmente so suficientes.

Erros de Sintaxe

Em alguns casos, um erro pode ter acontecido muito antes da posio em que ele foi descoberto: mais difcil deduzir a natureza do erro; Em alguns casos, o tratamento de erros deve adivinhar o que o programador tinha em mente ao escrever o programa. Alguns mtodos de parsing - detectam um erro o mais cedo possvel

Erros de Sintaxe

Erros mais comuns encontrados em programas Pascal:


60% dos programas so semanticamente e sintaticamente corretos; 80% dos programas com erros possuem apenas 1 erro, 13% possuem 2 erros.

Erros de Sintaxe

Classificao dos erros:


60% pontuao; 20% operadores e operandos; 15% palavras-chave; 5% outros.

Erro mais difcil de ser reparado - begin ou end faltando.

Erros de Sintaxe

Como reportar a presena de erros?

Como o analisador sinttico deve recuperar de erros?


Existem vrias estratgias, mas nenhum mtodo predomina; No adequado parar a compilao aps encontrar um erro, pois devem existir mais erros no programa; Geralmente se escolhe uma forma de recuperao tal que o compilador possa continuar o trabalho.

Indicar a linha onde aconteceu o erro indicando o lugar em que o erro foi detectado e emitir uma mensagem clara: ponto e vrgula ausente.

Gramtica: Backus-Naur Estendida (EBNF)

Gramtica BNF

A Forma Backus-Naur uma notao para escrever Gramtica Livres de Contexto.


Bastante usada para descrever sintaxes de linguagens de programao.

Como toda gramtica, descreve a estrutura hierrquica de vrias construes da linguagem.

Definio de Gramtica BNF

Consiste de 4 partes: Um Smbolo Inicial (Start Symbol) Um conjunto de Tokens Um conjunto de Smbolos Noterminais Um conjunto de Produes (ou Regras)

Estrutura BNF
Smbolo inicial <prog> -> program id() <vars> begin <cmds> end. <vars> -> var <dec-list> <dec-list> -> <dec><dec-list> | <dec> <dec> -> <lista-ids> : <tipo>;

Uma produo

Smbolos no-terminais

<lista-ids> -> id | id , <lista-ids> <tipo> -> integer|real|

Smbolos terminais (Tokens)

Definio de Gramtica BNF

Consiste de 4 partes: Um Smbolo Inicial (Start Symbol) Um conjunto de Smbolos terminais (Tokens) Um conjunto de Smbolos Noterminais Um conjunto de Produes (ou Regras)

Smbolo Inicial

O Smbolo inicial trata-se de um noterminal particular que forma a raiz da rvore de Anlise Sinttica para a gramtica. Por conveno, trata-se sempre do primeiro smbolo da Gramtica

Smbolos Terminais (Tokens)


Os Tokens so as menores unidades possveis de uma sintaxe. O Token pode definir um tipo lgico da unidade, neste caso, o Lexema representa a escrita literal. Tokens so atmicos Ou seja, no so tratados como sendo compostos por partes menores.

Smbolos No-Terminais

Smbolos No-Terminais representam grandes pedaos da gramtica So Strings envolvidas por < e > como no exemplo <tipo>. No so Strings que ocorrem literalmente no texto do programa. A gramtica informa como eles podem ser expandidos em Tokens.

Produes

As produes so as regras construtoras da rvore Cada uma tem um lado-esquerdo, o separador (::= ou ), e um lado direito.
O lado Esquerdo apenas um No-Terminal O lado Direito composto por uma sequncia de um ou mais Tokens ou NoTerminais.

A produo mostra uma forma de construir a rvore


Ele permite que o No-terminal da esquerda possa ter os elementos da direita, como seus filhos na rvore sinttica.

EBNF

Trs extenses BNF

Parte opcional de uma produo: delimitado por colchetes

<cmd-if> ::= if <exp> then <cmds> [else <cmds>] ;

EBNF

Parte pode ser repetida indefinidamente ou omitida completamente: delimitada por chaves
Permite que listas sejam construdas com uma nica regra, em vez de usar recurso e duas regras

<lista-ids> ::= id { , id } <bloco-cmds> ::= begin {<cmd>} end

EBNF

Mltipla escolha: delimitado por parnteses e com o uso do operador OU (|).

<cmd-for> ::= for id := <exp> ( to | downto ) <exp> do (<cmd> | <bloco-cmds>)

Derivao Esquerda

Derivao

Existem vrias formas de ver o processo como uma gramtica deriva uma linguagem;
rvores de sintaxe e derivaes

As derivaes oferecem uma descrio precisa da construo de uma rvore de sintaxe de forma top-down; Na derivao, uma produo tratada como uma regra de substituio em que um no terminal da esquerda substitudo pelo string do lado direito da produo;

Exemplo de Derivao

Seja a gramtica:
E E + E | E * E | ( E ) | - E | id

A derivao de -(id) a partir de E :


E - E - (E) - (id)

A derivao fornece uma prova de como uma instncia particular gerada a partir da gramtica Em E - (id), dizemos que E deriva - (id)

Derivao

Em cada passo da derivao, existem duas escolhas a fazer


Qual smbolo no terminal substituir Qual alternativa usar para substituir o no terminal E - E - (E) -(E + E) - (E+ id ) - (id + id)

Para entender como os analisadores sintticos trabalham, devemos considerar derivaes em que sempre o smbolo no terminal mais esquerda em qualquer forma sentencial substitudo

Derivao Esquerda
Consiste em uma tcnica para construo da rvore de Anlise Sinttica. A cada vez deve-se expandir sempre o primeiro No-terminal mais a esquerda. Importante porque todo projeto de Compilador Top-Down segue esta forma de construo da rvore.

Exemplo de Gramtica
<prog> begin <lista_instr> end <lista_instr> <instr> | <instr> ; <lista_instr> <instr> <var> := <expr> <var> identificador <expr> <expr> + <expr> | <expr> - <expr> | <var> | numero

Derivao Esquerda
<prog> begin <lista_instr> end begin <instr>; <lista_instr> end begin <var> := <expr>; <lista_instr> end begin A := <expr>; <lista_instr> end begin A := <expr> + <expr>; <lista_instr> end begin A := 2 + <expr>; <lista_instr> end begin A := 2 + <var>; <lista_instr> end begin A := 2 + B; <lista_instr> end begin A := 2 + B; <instr> end begin A := 2 + B; <var> := <expr> end begin A := 2 + B; C := <expr> end begin A := 2 + B; C := <var> end begin A := 2 + B; C := B end

rvore de Sintaxe

As folhas de uma rvore de sintaxe da esquerda para a direita formam a produo da rvore, que a string gerada ou derivada pelo smbolo no terminal da raiz da rvore; Toda rvore impe uma ordem natural da esquerda para a direita Outra definio de uma linguagem gerada por uma gramtica o conjunto de strings que podem ser gerados por uma rvore de sintaxe.
Se um nodo a est a esquerda de um nodo b, ento os filhos de a tambm esto

rvores de Sintaxe
E -> E+E | E*E | (E) | -E | id
E E E E ) ( E E ) E

E
E

E +

rvores de Sintaxe
E E

E
E ) E

E
E ) E id

E + id

E + id

Gramticas Ambguas

Gramticas Ambguas

Uma gramtica ambgua se a partir dela uma sentena pode dar origem a duas rvores sintticas Uma gramtica ambgua traz problemas na implementao de um compilador Eliminao de ambigidade quase sempre possvel
Transformaes na gramtica Definir regras para torn-las no ambguas.

Regras para Eliminao

Em alguns casos, uma gramtica ambgua no precisa ser reescrita para eliminar sua ambigidade
<cmd> if <exp> then <cmd> | if <exp> then <cmd> else <cmd> | outro

A string abaixo possui duas rvores de sintaxe if E1 then if E2 then C1 else C2 A regra geral que a gramtica deve seguir casar cada else com o then mais prximo

Transformao de Ling.

Em outros casos, preciso transformar a gramtica Exemplo clssico: gramtica para expresses aritmticas
E ::= id | E '*' E | E +' E | '-' E |'(' E ')'

Transf. Ling: Exemplo


a + b * c
E E + E E E *

*
E +

c
E

a
E

Transformao de Ling.

Soluo: Transformar a gramtica


* e / com maior precedncia que + ou Operadores associativos a esquerda

E ::= id | E '*' E | E +' E | '-' E |'(' E ')'

E ::= E '+' T | T T ::= T '*' F | F F ::= id |'(' E ')' |-' E

Recurso Esquerda

Recurso Esquerda

Uma gramtica recursiva esquerda se ela possui um no terminal A tal que A A para alguma string :
<exp> <exp> + <termo>

possvel que um analisador sinttico entre em loop infinito quando ele utiliza derivaes de uma gramtica recursiva esquerda.

Exemplo Recurso Esq.


Considere a produo
A Ab | c

Aplicaes repetidas da primeira regra constroem bs direita de A, terminando eventualmente com um c esquerda
Construmos a string da direita para esquerda.

Exemplo Recurso Esq.


A A A

A A A c b b ... b b b ...

Eliminando Recurso Esq.

Dadas produes da forma:


A A1 | A2 | ... | An | 1 | 2 | ... | n

Troque as produes A por:

A 1A | 2A | ... | nA A 1A | 2A | ... | nA|

Eliminando Recurso Esq.


Aplicando esta regra para:
A Ab | c

Produz:
A cA A bA |

Eliminando Recurso Esq


A A A

A
... A A

...

Recurso Indireta Esq.


O procedimento anterior elimina as recurses diretas mas no elimina a recurso envolvendo derivaes em um ou mais passos; Por exemplo, considere a gramtica:
S Aa | b A Ac | Sd

O no-terminal S recursivo esquerda porque S Aa Sda, mas no imediatamente recursivo;

Recurso Indireta Esq

Processo para Eliminao:


Gramtica Inicial S AA | a A SS | b

1 passo (substituio) S AA | a A AAS | aS | b 2 passo (eliminar recursividade direta) S AA | a A aSA | bA A ASA |

Gramticas LL(1)

Anlise Sinttica Descendente

Para implementar um Analisador Sinttico Descendente mais facilmente, a gramtica deve ser bem escrita. Alm de no serem recursivas esquerda, as gramticas devem obedecer duas restries:
O lado direito das produes devem comear por terminais; Para um no terminal qualquer, no devem existir duas regras que comecem com um mesmo terminal.

Gramticas LL(1)

As gramticas que:
No so recursivas esquerda; Para um mesmo no terminal, no existem regras cujo lado direito comecem com o mesmo terminal .

so chamadas gramticas LL(1)


Left to right, Leftmost derivation; 1 nico smbolo a frente para determinar qual regra aplicar.

Dispondo de uma gramtica LL(1), podese fazer ASD preditivo de forma mais eficiente.

Fatorao Esquerda

Transformao que elimina regras que comecem com o mesmo prefixo


Adiamos a deciso de qual regra usar at que tenhamos visto o suficiente da entrada para podermos fazer a escolha.

Fatorao Esquerda

Regra:
para cada no terminal A, achar o maior prefixo comum a duas ou mais alternativas; se h um prefixo em comum, ento substituir a produo A 1 | ... | n | (em que representa as alternativas que no comeam por ) por A A| A 1|...|n

Fatorao Esquerda

Exemplo
<atribuio> id = <exp> ; <funo> id ( <lista-exp> ) ;

Ao encontrarmos o id na entrada, no podemos imediatamente decidir qual produo escolher.


uma atribuio ou uma chamada de funo/procedimento?

Fatorao Esquerda

Fatorando: <atrib_fun> id (<atrib>|<func>) <atrib> = <exp>; <func> ( <lista-exp> ) ;

Fatorao Esquerda

Exemplo 2
<if> ::= if <e> then <c> <if-else> ::= if <e> then <c> else <c>

Ao encontrarmos o if na entrada, no podemos imediatamente decidir qual produo escolher. Fatorando:

<if> if <e> then <c> ( else <c> | ) <if> if <e> then <c> [ else <c> ]

Analisador Sinttico Top-Down Preditivo

Anlise Sinttica Top-Down

A construo top-down de uma rvore de sintaxe a partir de uma seqncia de tokens de entrada feita comeando pela raiz, rotulada pelo smbolo inicial, e repetidamente executando os seguintes passos:
No nodo n rotulado pelo no terminal A, selecione uma das produes de A e construa filhos para o nodo n para cada smbolo do lado direito da produo; Encontre o prximo nodo onde uma subrvore pode ser construda.

Anlise Sinttica Top-Down

Seja a gramtica:
<tipo> <tipo-simples> | id | array [ <tipo_simples> ] of <tipo> <tipo_simples> integer | char | num ponto-ponto num

Seja a entrada:

Fonte

array [1 .. 10] of integer Tokens array [num ponto-ponto num] of integer

Anlise Sinttica Top-Down


A) tipo B)
tipo of tipo

array [ tipo_simples] C) tipo

D)

tipo

array [tipo_simples ] of tipo num ponto ponto num

array [tipo_simples] of tipo


num ponto ponto num tipo_simples

E)

integer

Anlise Sinttica Top-Down


O Token atual reconhecido retornado pelo analisador lxico; O objetivo do analisador sinttico construir o restante da rvore de sintaxe de tal modo que a string gerada pela rvore case com a string de entrada; Quando os filhos de um nodo so construdos, passamos a considerar o filho mais esquerda;

Analisador Sint. Preditivo

Um analisador sinttico descendente recursivo um mtodo top-down de anlise sinttica em que uma srie de chamadas recursivas so aplicadas quando se processa a string de entrada:
Um procedimento associado a cada no terminal da gramtica.

Analisador Sint. Preditivo

A seqncia de procedimentos que so executados ao se processar a string de entrada definem implicitamente uma rvore de sintaxe para a string de entrada; Cada no terminal encontrado gera uma chamada a um procedimento para trat-lo; Cada terminal da entrada casado com o terminal do lado direito da produo; O atributo token quem guia a escolha sobre qual produo deve ser usada;

Implementao

Seja a gramtica:
<tipo> <tipo-simples> | id | array [ <tipo_simples> ] of <tipo> <tipo_simples> integer | char | num ponto-ponto num

O analisador sinttico preditivo para esta gramtica pode ser implementado conforme os prximos passos:

Pseudo-Cdigo
procedimento parse() Token <- AnLex.obterProxToken(); tipo(); //Smbolo Inicial da Gram. procedimento casaToken(Esperado) Se Token = Esperado Token<- AnLex.obterProxToken(); Seno Erro Sinttico; Imprime Esperado:+Esperado; Fim Se

Pseudo-Cdigo
procedimento tipo_simples() Se Token = INTEGER casaToken(INTEGER); Seno Se Token = CHAR casaToken(CHAR); Seno Se Token = NUM casaToken(NUM); casaToken(PONTO-PONTO); casaToken(NUM); Seno Erro Sinttico; Fim Se

Pseudo-Cdigo
procedimento tipo() Se Token = INTEGER ou CHAR ou NUM tipo_simples(); Seno Se Token = ID casaToken(ID); Seno Se Token = ARRAY casaToken(ARRAY); casaToken(ABRE_COLCHETES); tipo_simples(); casaToken(FECHA_COLCHETES); casaToken(OF); tipo(); Seno Erro Sinttico;

Conjunto Primeiro

Conjunto Primeiro

O analisador sinttico preditivo confia na informao sobre quais os primeiros smbolos podem ser gerados pelo lado direito da produo Definimos PRIMEIRO () o conjunto de tokens que aparecem como os primeiros smbolos de uma ou mais strings de :

PRIMEIRO (tipo_simples) = { integer, char, num } PRIMEIRO (array [ tipo_simples ] of tipo) = {array} PRIMEIRO (tipo) = {integer, char, num, id, array}

Conjunto Primeiro

O conjunto PRIMEIRO deve ser considerado se existem duas produes AeA


O analisador sinttico preditivo requer que PRIMEIRO () e PRIMEIRO () sejam disjuntos; O prximo token lido usado para decidir qual produo usar; Se o proximo token estiver em PRIMEIRO (), ento A usada.

Conjunto Primeiro

As construes de controle de fluxo na maioria das linguagens de programao, com suas palavras chave distintas, podem ser analisadas pelo analisador sinttico preditivo: <cmd>::= if <exp> then <cmd> [else <cmd>]
| while <exp> do <cmd> | begin <cmds_opcs> end

As palavras reservadas if, while e begin nos informam qual alternativa a nica correta.