Conversão de AFN em AFD
EXEMPLO 1: Dado AFN que corresponde a expressão regular a* converter em AFD
Inicialm Inicialmente ente calculamos calculamos a clausura-e ou fechamento-e fechamento-e do estado 1: Fechamento-e({1}) = {1,2,4} Movimento({1,2,4}, Movimento({1,2,4},a) a) = {3}
Fechamento-e({3}) Fechamento-e({3}) ={2,3,4}
Movimento({2,3,4}, Movimento({2,3,4},a)={3} a)={3}
Fechamento-e({3}) Fechamento-e({3}) ={2,3,4}
EXEMPLO 2: Dado o seguinte AFN AFN converter em AFD
fechamento-e ({1}) = {1,2,6}
Movimento({1,2,6},a) = {3,7}
Fechamento-e({3,7} = {3,4,7,8}
Movimento({3,4,7,8},b) = {5}
Fechamento-e({5}) ={5,8}
EXEMPLO 3: Considere o AFN construído para a expressão regular : letra (letra |digito)* converter para AFD
fechamento-e({1})={1} Movimento({1},a) = {2}
Fechamento-e({2}) = {2,3,4,5,7,10}
Movimento({2,3,4,5,7,10},letra)={6}
Fechamento-e({6})={4,5,6,7,9,10}
Movimento({2,3,4,5,7,10},digito) ={8}
Fechamento-e({8})={4,5,7,8,9,10}
Movimento({4,5,6,7,9,10},letra)={6}
Fechamento-e({6})={4,5,6,7,9,10}
Movimento({4,5,6,7,9,10},digito)={8}
Fechamento-e({8})={4,5,7,8,9,10}
Movimento({4,5,7,8,9,10},letra) ={6}
Fechamento-e({6})={4,5,6,7,9,10}
Movimento({4,5,7,8,9,10},digito) = {8}
Fechamento-e({8})={4,5,7,8,9,10}
EXEMPLO 4: Considera o seguinte AFN construído para a expressão regular: ( a | b)*a
Fechamento({0}) = {0,1,2,4,7} Movimento({0,1,2,4,7},a) ={3,8}
Fechamento({3,8})={1,2,3,4,6,7,8}
Movimento({0,1,2,4,7},b) = {5}
Fechamento({5})={1,2,4,5,6,7}
Movimento({0,1,2,3,4,6,7,8},a)={3,8}
Fechamento({3,8})={1,2,3,4,6,7,8}
Movimento({0,1,2,3,4,6,7,8},b)={5}
Fechamento({5})={1,2,4,5,6,7}
Movimento({1,2,4,5,6,7},a) = {3,8}
Fechamento({3,8})={1,2,3,4,6,7,8}
Movimento({1,2,4,5,6,7},b) = {5}
Fechamento({5}) ={1,2,4,5,6,7}
2. ANALISADOR SINTATICO A função de um analisador sintático é determinar a estrutura sintática de um programa a partir de tokens produzidos pelo analisador léxico e, construir uma arvore de análise gramatical ou uma arvore sintática que represente esta estrutura. O esquema abaixo mostra como o analisador sintático trabalha junto com o analisador léxico.
Envia Program fonte
Analisador sintático
Analisador léxico
Árvore de deriva ão
Tabela de Símbolos
As linguagens de programação possuem construções que não podem ser representadas por gramáticas regulares, por isto utilizam-se gramáticas livres de contexto. De fato, algumas construções não podem ser representadas nem por gramáticas livres de contexto, mas estas construções são poucas e o problema é facilmente solucionado modificando-se a linguagem.
Um analisador sintático faz o reconhecimento de sentenças da linguagem, mas caso haja erros (sentença não reconhecida) o analisador deve reportar o erro e se possível recuperar o seu estado e continuar o reconhecimento. Esta recuperação de estado pode ser bastante difícil, por isto em protótipos de compiladores geralmente não é implementado. Gramáticas livres de contexto (GLC)
Uma gramática livre de contexto é uma especificação para a estrutura sintática de uma linguagem de programação. Esta especificação é muito similar à especificação da estrutura léxica de uma linguagem utilizando expressões regulares, com exceção de que uma GLC contem regras de recursividade. Como exemplo de execução vamos utilizar expressões de aritmética simples com inteiros e operações básicas como soma, subtração e multiplicação. Estas expressões podem ser dadas pelas seguintes regras exp exp op exp op + | - | *
| (exp) | numero
Também pode ser escrita da seguinte forma exp exp op exp exp (exp) exp numero op + op op *
Derivações e linguagem definida pela gramática.
Derivação é o processo através da qual as regras de reproduções são aplicadas para formar uma palavra ou verificar se esta pertence à linguagem. Símbolos não terminais são substituídos por lado direito da produção correspondente. Uma derivação começa com um nome de estrutura simples e termina com uma cadeia e símbolos de token. Em cada etapa de uma derivação é realizada uma substituição utilizando a regra gramatical. Exemplo: A continuação, é mostrado um exemplo de derivação para a expressão aritmética: (34-3)*42, no lado direto aparece as regras utilizadas. (ex. 2) (1) exp exp op exp [ exp exp op exp ] (2) [ exp numero ] exp op numero (3) [ op * ] exp * numero (4) [ exp (exp) ] (exp) * numero (5) [ exp exp op exp ] (exp op exp) * numero (6) [ exp numero ] (exp op numero) * numero (7) [ op - ] (exp - numero) * numero (8) [ exp numero ] (numero - numero) * numero
O conjunto de todas as cadeias de símbolos de tokens obtidos pela derivação de símbolos exp é a linguagem definida pela gramática de expressões. Esta linguagem tem todas as expressões sintaticamente legais. Podemos escrever em forma simbólica como: L(G)={s | exp * s } Onde G representa a gramática de expressões, s representa uma cadeia arbitraria de símbolos de tokens (sentença) e os símbolos representam uma derivação composta de uma seqüência de substituições. O asterisco é utilizado para indicar uma seqüência de passos É importante notar que se conservam as regras gramaticais em BNF (Backus-Naur Form) para concatenação e seleção, mas não tem um equivalente especifico da operação de repetição para * das expressões regulares. Mas uma operação assim não é necessária, já que a repetição pode ser obtida através da recursão. Por exemplo, a regra gramatical; A Aa | a ou A aA | a Geram a linguagem { an | n é um enteiro 1}, equivalente a a+ Por exemplo, a cadeia aaaa pode ser gerada pela primeira regra gramatical com a derivação. A Aa Aaa
Aaaa
aaaa
Uma derivação similar funciona para a segunda regra gramatical. A primeira regra gramática ou seja, A Aa | a, é chamada de recursiva pela esquerda enquanto a segunda regra, ou seja, A aA | a, é chamada de recursiva pela dereita. Arvores de Análise Gramatical
Uma arvore gramatical é uma representação gráfica de uma derivação, dá uma forma explicita a estrutura que origino a sentença. Dada uma GLC a arvore de derivação é obtida da seguinte forma: A raiz da arvore é o símbolo inicial Os vértices interiores são obrigatoriamente não terminais Símbolos terminais e a palavra vazia são as folhas Por exemplo, uma arvore gramatical para a derivação. (ex: 3) exp
exp op exp
numero op exp numero + exp numero + numero
seria:
Se enumerarmos os passos da derivação, podemos associa-os aos nos da arvore. (ex. 4) (1) exp (2) (3) (4)
exp op exp
numero op exp numero + exp numero + numero
Uma derivação proporciona um método para construir uma cadeia particular de terminais a partir de um não-terminal inicial. Mas as derivações não representam apenas a estrutura das cadeias que o constroem. Em geral, existem muitas derivações para a mesma cadeia. Por exemplo, a cadeia acima pode ter outra derivação: (ex. 5) (1) (2)
(3) (4)
exp
exp op exp
exp op numero exp + numero
numero + numero
Podemos observar que uma arvore de analise gramatical pode corresponder em geral a muitas derivações, que no conjunto representam a mesma estrutura básica para a cadeia de terminais analisada gramaticalmente. No entanto podemos diferenciar dois tipos de derivações particulares: uma derivação pela esquerda e derivação pela direita. Uma derivação pela esquerda, é aquela derivação na qual é substituído o não terminal mais para esquerda, como no exemplo (ex. 4), de forma análoga uma derivação pela direita, é aquela derivação na qual é substituído o não terminal mais para direita (ex. 5)
Um outro exemplo de derivação pela direita é foi mostrado no ex. 2, para a cadeia : (numero - numero) * numero
A arvore de derivação correspondente seria:
Usando a derivação pela esquerda podemos gerar a seguinte seqüência de derivação: (1) exp (2) (3) (4) (5) (6) (7) (8)
exp op exp (exp) op exp (exp op exp) op exp (numero op exp) op exp (numero - exp) op exp (numero - numero) op exp (numero - numero) * exp (numero - numero) * numero
[ exp exp op exp ] [ exp (exp) ] [ exp exp op exp ] [exp numero ] [op - ] [ exp numero ] [ op * ] [ exp numero]
Arvore sintático abstrato
É uma representação mais simplificada da arvore de analise gramatical, por exemplo, a expressão (34-3)*42 pode ser representado como:
Onde os nós representam as operações e as folhas os números.