LINGUAGENS FORMAIS E AUTÔMATOS O objetivo deste curso é formalizar a idéia de linguagem e definir os tipos de sintaxe e semântica. Para cada sintaxe, analisamos autômatos, ue são abstrações de algoritmos. Dentre as classes de linguagens temos: Regulares Livres de contexto Sensíveis ao contexto Recursivas Recursivamente enumeráveis O curso de Linguagens Formais e Autômatos se ocupa principalmente dos primeiros, enuanto os dois últimos são objetivo de um curso de Computabilidade. Uma linguagem comum é um conjunto de três aspectos: Aspecto léxico Define os símbolos (signos) ue compõe a linguagem. Aspecto Sintático Define regras para símbolos ue indicam ue seüências de símbolos são aceitas. Aspecto Semântico Dá o significado das seüências de símbolos. Nosso curso se concentra nos dois primeiros aspectos, ue são vitais para a construção de compiladores. Podemos definir linguagem como:. Linguagem é um conjunto de sentenças. 2. Sentença sobre um vocabulário é uma seüência finita de símbolos do vocabulário. 3. Vocabulário é um conjunto finito de símbolos. Por enuanto, definimos uma linguagem só definindo seu aspecto léxico. Assim, se ueremos definir uma linguagem para uma calculadora, definimos o alfabeto (vocabulário): = {+, -,, /, NUM} Sentenças sobre esse vocabulário são: W = NUM NUM + NUM W2 = + NUM Uma linguagem é um subconjunto do conjunto das sentenças. Podemos considerar somente: L = { NUM, NUM + NUM, NUM NUM...} A linguagem pode ser definida de forma recursiva: NUM L α β L α + β, α - β, α β, α / β L E NUM E E + E E E - E E E E E E / E Assim também: E E + E E E + E E E + NUM E NUM + NUM NUM NUM + NUM Definimos sobre o conjunto de sentenças a operação de concatenação. Por exemplo:
W = ++ W2 = NUM W W2 = ++NUM Dado um alfabeto (vocabulário), definimos como o conjunto de todas possíveis sentenças, incluindo ε ue representa a sentença vazia. Dessa forma, toda linguagem é: L Definimos também + = /{ ε}, ou seja, o conjunto de todas possíveis sentenças não vazias. No nosso exemplo do vocabulário da calculadora: = { ε, +,, +,, /, +, +, ++, + NUM,,...} Em seguida, vamos definir o ue é uma gramática, uma linguagem gerada por uma gramática. A cada tipo de linguagem (definida pelo seu tipo de gramática) e a cada um dele vamos associar um autômato. Linguagem Regulares Livres de Contexto Sensíveis ao Contexto Sem Restrição Autômato Autômato Finito Autômato com pilha Máuina de Turing Linearmente Limitada Máuina de Turing Definimos uma gramática G como uma 4-tupla G =, N, P, S, onde: = Alfabeto de símbolos terminais. N = Conjunto de símbolos não terminais. P = Conjunto de regras de produção, da forma: α β, αβ, ( N) e α tem ao menos um símbolo de N. S = Símbolo inicial. S N. Para a linguagem ue definimos, uma gramática adeuada seria: = {+, -,, /, NUM}. N = {E} P ={ E NUM, E E + E, E E E, E E E, E E / E} S = E Dada uma gramática, definimos em ( ) N a relação binária em um passo ( G ) como:
w= γ. αγ. 2 ( w G w2) w2= γ. βγ. 2 ( α β) P Onde γ, γ2, α, β ( N). Seja ( G ) o fecho reflexivo de ( G ). Assim definimos a linguagem gerada pela gramática G como L(G) = { w / s w} G Por exemplo, a linguagem composta pelas seüências binárias ε,,,,,,,,,... pode ser gerada pela seguinte gramática: = {,} N = { S} P= { S S, S S, S, S } S = S Assim, LG ( ). Um problema é, dada um alfabeto e uma gramática G, como decidir se uma sentença w pertence ou não à linguagem L(G). Isso normalmente é feito usando autômatos. Analisemos alguns antes de definir formalmente o ue é um autômato sobre ={, }.. O seguinte autômato reconhece todas as sentenças com um número par de zeros: Onde representa um estado e um estado final, ou seja, um ponto em ue o funcionamento da máuina pode parar. 2. Seüências de s e s ue têm um número par de s ou um número ímpar de s. 3. Seüências ue terminam em
4. Seüências ue tem o comprimento múltiplo de 3. 5. O antepenúltimo caractere é. Para organizar o raciocínio, vamos chamar os estados de abc,,, onde a,b,c {x, }, onde x representa ualuer coisa diferente de, seja ou nenhum resultado. Definição: Um autômato finito determinístico é uma 5-upla M = { Q,, δ,, F} onde: Q é o conjunto finito de estados é o alfabeto de entrada Qé o estado inicial F Qé o conjunto de estados finais. No exemplo das linguagens ue terminam em e temos:
= {,} Q= {,, } F = { } 2 2 A função δ : Q Qé dada pela seguinte tabela: 2 2 Definamos recursivamente a função δ : Q Qsobre o conjunto das seüências como: δ(, ε) = δ( a, ω) = δ( δ( a, ), ω), onde a, ω Assim, para o exemplo ue estávamos discutindo: (,) = ( (,),) = (,) = = δδ ( (,),) = δ(,) = = δδ ( (,), ε) = δ( 2, ε) = 2 δ δ δ δ Na prática, δ (, ω ) representa o estado alcançado a partir de pelo caminho ω. Assim, definimos o conjunto de linguagens reconhecidas por M como: T( M) = { ω, δ(, ω) F} Exercícios Fazer um autômato finito ue reconheça i. ω {,}, tal ue termina em ou tem um número par de s. ii. ω {,}, tal ue ω é a representação binária de um número múltiplo de 5. iii. ω {,,2,3,4,5,6,7,8,9,A,B,C,D,E,F,x}, tal ue ω é um inteiro positivo na linguagem C. Por exemplo: 235 inteiro 75 octal x7ff hexadecimal
O problema i tem uma solução com somente 4 estados ue é: : número par de s : número ímpar de s terminando em ix : número ímpar de s terminando em i : número ímpar de s terminando em i
Uma pergunta natural seria ual a gramática reconhecida pelo autômato finito do problema iii, ou seja, ue linguagem descreve os números inteiros da linguagem C? Dando nome aos estados temos: S Z S D ec D D D Z X H H Z O O D ec D ε xx Hex H ex H H ε O ct O O ct O ε Isso nos dá uma receita para a construção de uma gramática ue gera a linguagem reconhecida por um autômato finito. Isso nos dá uma prova construtiva para: Teorema: Dado um autômato finito M = { Q,, δ,, F}, construo um não terminal N para cada e considero a gramática G =, N, P, S, onde N = { N / Q} e ~ ~ P= { N an / δ(, a) = } { N ε / F}. Assim, nestas condições L(G) = T(M). Classificação das gramáticas Gramática Regular Dizemos ue uma gramática é regular uando todos os elementos de P são da forma: A a A ab A ε para A e A,B N Gramática Livre de Contexto Dizemos ue uma gramática é livre de contexto se todas as regras são da forma: A ω, com A N e ω ( N ) Gramática Sensível ao Contexto Dizemos ue uma gramática é sensível ao contexto uando todos os elementos de P são da forma: ω ω, com ω, ω ( N ) e 2 2 ω ω 2 Note ue, por essa definição, Regulares são Livres de contexto, mas não são necessariamente sensíveis ao Contexto, pois elas podem ter a regra A ε, onde = A > ε =. Para corrigir esse defeito, redefinimos gramática sensível ao contexto como gramáticas cujas sentenças têm a forma: ω ω2, ω ω2 ou S ε, onde S é um símbolo não terminal, ue não aparece do lado direito de nenhuma regra. Isso permite ue linguagens sensíveis ao contexto tenham a sentença vazia.
Dizemos ue uma linguagem L é regular (respectivamente sensível ao contexto, livre de contexto) se existe uma gramática regular (respectivamente sensível ao contexto, livre de contexto) tal ue L = L(G), ou seja, L é a linguagem gerada pela gramática. Quando passamos para linguagens, passamos a ter inclusões. O diagrama da direita é chamado hieraruia de Chomsky. Dois fatos interessantes: nem toda gramática livre de contexto é sensível ao contexto, mas toda linguagem livre de contexto é sensível ao contexto. Isso acontece pois, dada uma gramática G livre de contexto mas com alguma regra do tipo A ε, ou seja, ue não seja sensível ao contexto, então, como provaremos mais tarde, existe uma gramática ~ G livre de contexto e sensível ao contexto tal ue: L(G) = L( ~ G ) Assim, provaremos ue toda linguagem livre de contexto é sensível ao contexto. Isso será feito mais tarde. Outro fato interessante: nem todas as linguagens podem ser descritas por gramáticas. Provemos isso. Dado um alfabeto finito, o conjunto das possíveis sentenças é um conjunto infinito e enumerável. Uma linguagem L é um subconjunto de, logo o conjunto das possíveis linguagens é o conjunto das partes de, ou seja, o conjunto de todos os subconjuntos de. Mas esse é um conjunto não enumerável (Prova diagonal de Cantor). Como toda gramática pode ser definida por uma cadeia finita de caracteres, o conjunto das possíveis gramáticas é enumerável. Assim, existem linguagens ue não podem ser descritas por gramáticas. Queremos resolver o problema da análise sintática, isto é, dada uma gramática G e uma sentença ω determinar se ω L(G) e, em caso afirmativo, saber ual a derivação. Vimos ue, dado um autômato finito podemos construir uma gramática G regular tal ue L(G) é a linguagem reconhecida pelo autômato. Será ue vale a recíproca? Ou seja, dada uma gramática G, existe um autômato finito cuja linguagem reconhecida por ele é L(G)? Considere a linguagem L(G), formada pelas seüências em {,} ue terminam em ou. Temos ue a gramática pode ser dada por:
S S S S S S A A Tentando aplicar o algoritmo para transformar autômatos em linguagens, chegamos a: Isso não é um autômato finito, pois a função de transição δ não está bem determinada. Assim, o ue temos é um autômato finito não determinístico. Outro exemplo de autômato finito não determinístico é o seguinte, ue reconhece todas as cadeias com um número ímpar de s ou um número ímpar e s. Para ue um autômato finito não determinístico reconheça uma sentença, deve existir um caminho ue leve ao estado final partindo do estado inicial. Vejamos nos exemplos: i. Seüências ue terminam em. ii. Seüências cujo antepenúltimo caractere é.
iii. Seüências ue terminam em ou têm um número par de s. Outra maneira é tomar Assim, se temos dois autômatos finitos não determinísticos, podemos criar um autômato ue reconheça a linguagem de um ou de outro, ue pode ser gerado por: Onde o novo estado inicial se liga aos estados dos dois autômatos da mesma forma ue os estados iniciais dos autômatos e 2 se ligavam Assim, se temos autômatos M e M 2 com m e m 2 estados, respectivamente, um autômato finito não determinístico ue reconhece M ou M 2 tem no máximo m+ m2 + estados, enuanto um autômato
finito determinístico deveria ter no máximo m m2 estados. Assim, a cota superior é menor para autômatos finitos não determinísticos. A definição formal de autômato finito não determinístico é uma 5 upla M = { Q,, δ,, F} onde: Q é o conjunto finito de estados é o alfabeto de entrada δ : Q P( Q) : Função de transição Qé o estado inicial F Qé o conjunto de estados finais. Note ue o AFND (Autômato Finito Não Determinístico) é bastante semelhante ao determinístico, porém um estado e um símbolo a levam, não a um estado, mas a um conjunto de estados. Dessa forma, definimos a linguagem reconhecida por um AFND M = { Q,, δ,, F} como: T( M) = { ω / δ(, ω) F } Onde δ : Q P( Q) é definido recursivamente como: δ(, ε) = { } δ ( a, ω) = δ( r, ω) r δ (, a) Por exemplo, para o AFND ao lado calculamos:` δ(,) = δ(,) δ(,) = δ(, ε) δ(, ε) { } { } = { } 2 =, 2 2