Análise Sintática Introdução Linguagens e Automatas

Propaganda
17/03/2014
Análise Sintática
Introdução
Renato Ferreira
Linguagens e Automatas
• Linguagens formais são importantes em
Computação
– Especialmente em linguagens de programação
• Linguagens regulares
– A linguagem formal mais fraca
– Adotada na prática
– Muitas aplicações
• Linguagens Livres de Contexto
– Várias outras definições em Linguagens Formais
1
17/03/2014
Linguagens Regulares
• Linguagens que necessitam de contagem
módulo um inteiro fixo
• Intuição: Um autômato finito que roda por
tempo suficiente tem que repetir estados
• Automatos finitos não se lembram quantas
vezes um estado particular foi visitado
Além das Linguagens Regulares
• Muitas linguagens são não regulares
• Strings com parentesis balanceados:
{ (i)i | i ≥ 0}
2
17/03/2014
A funcionalidade de em Parser
• Entrada: sequencia de tokens do analisador
léxico
• Saída: uma árvore de reconhecimento do programa
– Alguns parsers não produzem a árvore…
Exemplo
• COOL
if x = y then 1 else 2 fi
• Entrada do parser
IF ID = ID THEN INT ELSE INT FI
• Saída do parser
IF‐THEN‐ELSE
=
I
D
INT
INT
I
D
3
17/03/2014
Comparação com Análise Léxica
Fase
Entrada
Saída
Analisador léxico
Strings de Caracteres
String de Tokens
Analisador sintático
(Parser)
String de Tokens
Árvore de Reconhecimento
(Parse tree)
O Papel do Analisador Sintático
• Nem todos os strings de tokens são
programas…
– O parser tem que distinguir entre os strings válidos e os inválidos
• Demandas
– Uma linguagem pra descrever strings de tokens
– Um método para distinguir strings válidos de inválidos
4
17/03/2014
Gramáticas Livres de Contexto
• Construções em Linguagens de Programação tem estrutura recursiva
• Uma EXPR é:
– if EXPR then EXPR else EXPR fi
– while EXPR loop EXPR pool
–…
• Gramáticas livres de contexto constituem uma
notação natural para essa estrutura recursiva
Definição
• Uma gramática livre de contexto consiste de:
– Um conjunto de símbolos terminais T
– Um conjunto de símbolos não‐terminais N
– Um símbolo inicial S (S N)
– Um conjunto de produções:
X  Y1Y2 ...Yn
• onde
XN
Yi  T  N   
5
17/03/2014
Exemplos de Gramáticas Livres de Contexto (GLC)
• Um fragmento de COOL:
EXPR if EXPRthen EXPR else EXPR fi
| while EXPRloop EXPR pool
| id
Mais Exemplos de GLCs
• Expressões aritméticas
E  E*E
| EE
| (E)
| id
6
17/03/2014
A linguagem de uma GLC
• As produções são vistas como regras:
X  Y1...Yn
• Significa que X pode ser substituido por Y1…Yn
•
Idéia Chave
1. Inicie com um string que consiste do Símbolo
Inicial “S”
2. Substitua qualquer X não terminal na string pelo lado direito de uma produção qualquer
X  Y1LYn
3. Repita (2) até que não hajam mais símbolos
não terminais na string
7
17/03/2014
Formalizando
• Seja G uma GLC com símbolo inicial S.
• A linguagem definida por G é:
{a1…an | S *a1…an onde todo ai é terminal}
Terminais
• Terminais são assim chamados pois não
existem regras para substituí‐los
• Uma vez gerados, os terminais são
permanentes
• Os terminais são os tokens da linguagem
8
17/03/2014
Exemplos
• Seja L(G) a linguagem da GLC G
– Strings com parentesis balanceados {(i)i|i≥0}
S  (S)
S  ε
Exemplos em COOL
EXPR if EXPRthen EXPR else EXPR fi
| while EXPRloop EXPR pool
| id
id
if id then id elseid fi
whileid loop id pool
if whileid loop id pool then id elseid
if if id then id elseid fi then id elseid fi
9
17/03/2014
Exemplos de Expressões Aritméticas
E  E * E | E  E | (E) | id
id
id  id
(id)
(id) * id
id * id
id * (id)
Observações
• Grande avanço com as GLC, porém:
– Precisamos de mais do que só determinar a validade
• árvore de reconhecimento
– Erros precisam ser tratados
– Precisamos de uma implementação de GLC (bison)
10
17/03/2014
Mais Observações
• Forma da gramática é importante
– Muitas gramáticas produzem a mesma linguagem
– Ferramentas obedecem a gramática
– Ferramentas de expressão regular (flex) são
também sensíveis, porém raramente produzem
problemas na prática
Derivações e Árvores de Reconhecimento
• Um derivação é uma sequencia de produções
• A derivação pode ser representada como uma
árvore
– O símbolo inicial é a raíz da árvore
– Cada produção acrescenta os filhos ao símbolo à
esquerda
11
17/03/2014
Observações sobre Derivações
• Uma parse tree tem:
– Terminais nas folhas
– Não‐terminais nos nós interiores
• Caminhamento inorder das folhas produz o string original
• A árvore representa associatividade, o string não.
Sumarizando
• Não estamos interessados apenas em se a string pertence a L(G)
– A parse tree é necessária
• Uma derivação define uma árvore de reconhecimento
– Mas uma árvore pode ter mais de uma derivações
• Derivações a esquerda e a direita são importantes
na implementação do parser.
12
17/03/2014
Ambiguidade
• Uma gramática é ambigua permite mais de uma árvore de reconhecimento para uma
mesma string
• Problema grave
– Deixa a semântica dos programas mal‐definida
Como lidar com ambiguidade
• Várias estratégias são possíveis
– Não há forma automática
• A mais direta consiste em re‐escrever a gramática de forma inambígua
13
17/03/2014
O problema do ELSE
• Caso clássico em compiladores:
– Linguagens que permitem if com else e sem else.
– Como decidir a qual if o else se refere?
• O else se associa ao then mais próximo.
– Pode se descrever isso na gramática
Ambiguidade
• Não há tecnicas gerais para tratar ambiguidade
• Impossível conversão automática
– Problema indecindível (Problema da Correspondência
de Post)
• Usada com cuidado, simplifica a gramática
– Permite definições mais naturais
– Mecanismos de desambiguação são necesários
14
17/03/2014
Declarações de Precedência e Associatividade
• Ao invés de re‐escrever a gramática
– Use a mesma gramática (mais natural)
– Com algumas declarações de desambiguação
• A maioria das ferramenta possui declarações
de precedência e de associativade para
permitir a desambiguação das gramáticas.
15
Download