Exercícios 02
1
aQuestão Considere a gramática abaixo que gera sentenças da linguagem L onde
L = { w | w = 0
m1, m
≥
1 }.
A gramática acima gera sentenças que tenham os N primeiros bits 0 e o último bit é sempre 1.
1 A) Adapte a gramática para que, além das sentenças propostas que já gera, gere também todas as
sentenças com ao menos uma subpalavra “11”. Codifique no programa JFLAP a gramática adaptada e
teste as derivações executadas pelo mesmo para as seguintes sentenças: (a) 0101011000; (b) 000001;
(c) 010101.
Obs. 1: Apenas para ilustrar, note que tal gramática deve gerar, após a adaptação da gramática, entre as
infinitas sentenças da linguagem L, por exemplo, as seguintes sentenças: 11011, 0000011,
011011011, 000001, 111, 100111001, 000111, 01, 000111000, 1010011, 011, etc.
Obs. 2: Apenas para ilustrar, note que tal gramática não deve gerar, após a adaptação da gramática, por
exemplo, 1010, 10100, 0001010001, 101, 010101, 000, 000000101, etc.
2
aQuestão Construa uma gramática regular G sobre o alfabeto
Σ
={0,1} que gera SENTENÇAS da
linguagem L onde as sentenças possuem um número par de bits “1” e um número ímpar de bits “0”,
apresentando, obrigatoriamente, a subpalavra “101”, ou então, as sentenças possuem ao menos uma
subpalavra 0000. Codifique no programa JFLAP a gramática e teste as derivações executadas pelo
mesmo para as seguintes sentenças: (a) 0001010110; (b) 101101101101; (c) 11100001.
OUTRAS QUESTÕES (apenas para exercitar construção de gramática para a prova)
3
aQuestão Construa uma gramática regular G sobre o alfabeto
Σ
={0,1} que gera SENTENÇAS da
linguagem L onde as sentenças possuem um número par de bits “1” e um número par de
bits “0”, terminando, obrigatoriamente, com o sufixo “011”, ou então, sentenças que
possuam ao menos uma subpalavra “111” e uma única vez a subpalavra “01”
4
aQuestão Construa uma gramática regular G sobre o alfabeto
Σ
={0,1} que gera SENTENÇAS da
linguagem L onde as sentenças possuem um número ímpar de bits “1” e um número
ímpar de bits “0”, iniciando, obrigatoriamente, com o prefixo “10011” ou então, sentenças
que não possuam a subpalavra “010” e tenham, uma única vez, a subpalavra “10”
5
aQuestão Construa uma gramática regular G sobre o alfabeto
Σ
={0,1} que gera SENTENÇAS da
linguagem L onde as sentenças possuem um número ímpar de bits “1” e um número
ímpar de bits “0”, apresentando, obrigatoriamente, a subpalavra “10” ou então, sentenças
que possuam a subpalavra “101” e não tenham a subpalavra “00”
Questão 6
DESCRIÇÃO DO PROBLEMA
Construção de um reconhecedor de expressões de Linguagens de livre contexto.
Definição do problema:
♦
Seja a gramática G (V, T, P, S) onde :
V = { S }
T = { + , - , * , / , ( , ) , a , b , c , d , e }
P = S
→
S+S | S-S | S*S | S/S | (S) | a | b | c | d | e
♦
Esta gramática é uma gramática regular ? Porquê ?
♦
Com esta gramática geram-se expressões simples com até 5 variáveis (a,b,c,d,e). Por
exemplo:
(a/c)+((e-d)*(a-b))/e
(a+c)
(d)
b/(c-e)
♦
Implementar um reconhecedor de expressões com base nesta gramática
♦
Uma solução consiste em usar o algoritmo de Cocke-Younger-Kasami. É um
algoritmo lento com complexidade O(n
3). É um algoritmo que pode ser rotulado de
parser bottom-up
.
♦
Para usar este algoritmo a gramática precisa estar “normalizada” na Forma Normal
de Chomsky (FNC)
♦
Uma gramática está na FNC se e somente se todas as regras da gramática estiverem
na forma
A
→
BC ou A
→
α
onde A, B e C
∈
V
e
α
∈
T
♦
Então é preciso transformar a gramática acima para a FNC. Veja abaixo a gramática
já transformada:
♦
Gramática G (V, T, P, S) transformada na FNC :
V = { S, A, B, C, D, E, F, G, H, I, J, K }
T = { + , - , * , / , ( , ) , a , b , c , d , e }
P = (1)
S
→
SG | SH | SI | SJ | EK | a | b | c | d | e
(2)
A
→
+
(3)
B
→
-(4)
C
→
*
(5)
D
→
/
(6)
E
→
(
(7)
F
→
)
(8)
G
→
AS
(9)
H
→
BS
(10)
I
→
CS
(11)
J
→
DS
(12)
K
→
SF
♦
Verifique se a gramática se apresenta na FNC gerando as mesmas sentenças antes de
sua transformação
♦
Agora com a gramática na FNC é possível aplicar o algoritmo C-Y-K para
reconhecimento de sentenças (no caso expressões simples) que a gramática gera.
♦
Exemplo de aplicação do algoritmo CYK:
♦
Seja a gramática G (V, T, P, S) onde:
V = { S, A }
T = { a, b }
P = (1)
S
→
AA | AS | b
(2)
A
→
SA | AS | a
Implementar o algoritmo CYK para a gramática das expressões
Veja o código em JavaScript no anexo
ANEXO – arquivo cyk01.htm
<html>
<head>
<script language="JavaScript" type="text/JavaScript" src="cyk_funcoes.js">
</script>
</head>
<body>
<center><h1>Teste do algoritmo Cocke-Younger-Kasami</h1></center>
<hr>
<Table align="Center" noborder>
<TR>
<TD>Digite a expressão:</TD>
<TD><input type='text' name='txtExpressao' id='txtExpressao' value='' onfocus='this.select();'
maxlength=50 size=50></TD>
</TR>
<TR>
<TD
colspan=2
align="center"><A
href='javascript:
f01_VerificarExpressao()'>Verificar
Expressão</A></TD>
</TR>
</Table>
<HR>
<center>
<div id='divResultado' style="display:block; position:relative; background-color:#eeeeee;">
</div>
</center>
</body>
</html>
ANEXO – arquivo cyk_funcoes.js
//---function f01_VerificarExpressao() {
var vDiv = document.getElementById('divResultado'); var k, m, m1, m2, rCol, sLin, kLin;
var vSentenca, vTamanho;
var vGramatica, vMatriz, vTotRegrasGramatica, vStartSymbol, vMsg, vTexto; var vNaoTermA, vNaoTermB, vNaoTermC, vRK, vRK_SK;
//---> (0) Definição da gramática: Cada regra da gramatica será obrigatoriamente um string de tamanho 2 ou 3 // Isto porquEa gramatica está obrigatoriamente na FNC...
// Exemplo: a regra S -> AA fica armazenada assim: "SAA" // a regra S -> + fica aramazenada assim: "S+" //
// --> Sempre o primeiro caracter refere-se ao vocabuário não-terminal que fica à esquerda da "flecha" da regra... //
vGramatica = new Array(6); // pois esta gramatica possui 6 regras... vGramatica[0] = "SAA"; vGramatica[1] = "SAS"; vGramatica[2] = "Sb"; vGramatica[3] = "ASA"; vGramatica[4] = "AAS"; vGramatica[5] = "Aa"; vTotRegrasGramatica = 6; vStartSymbol = "S";
//---> (1) Pegar o tamanho da sentença a ser avaliada
vSentenca = document.getElementById('txtExpressao').value; vTamanho = vSentenca.length;
//---> (2) Criar a matriz estrutura de dados básica do algoritmo CYK... // Obs.: só iremos usar a "metade" triangular da matriz...
// ... e não usaremos a coluna com índice 0... // ... só a linha com indice 0 para colocar a sentença vMatriz = new Array(vTamanho+1);
for (k = 0; k <= vTamanho; k++) { vMatriz[k] = new Array(vTamanho+1); }
//---> (3) Inicializar esta matriz com todas as casas vazias... for (k = 0; k <= vTamanho; k++) {
for (m = 0; m <= vTamanho; m++) { vMatriz[k][m] = "";
} }
for (k = 1; k <= vTamanho; k++) {
vMatriz[0][k] = vSentenca.substring(k-1,k); }
//---> (4) Etapa 1 do algoritmo CYK
// Obs.: no pseudo-codigo r refere-se à coluna !!!! // s refere-se à linha !!!
for (rCol = 1; rCol <= vTamanho; rCol++) {
//---> Ver todas as regras da gramatica que geram vMatriz[0][r]... for (k = 0; k < vTotRegrasGramatica; k++) {
if (vGramatica[k].length == 2) {
if (vGramatica[k].substring(1,2) == vMatriz[0][rCol]) {
vMatriz[1][rCol] = vMatriz[1][rCol] + vGramatica[k].substring(0,1); }
} } }
//---> (5) Etapa 2 do algoritmo CYK
for (sLin = 2; sLin <= vTamanho; sLin++) {
for (rCol = 1; rCol <= (vTamanho-sLin+1); rCol++) { for (kLin = 1; kLin <= (sLin-1); kLin++) {
//---> Candidatos Vrk e V(r+k)(s-k) (veja pseudo-codigo) vRK = vMatriz[kLin][rCol];
vRK_SK = vMatriz[sLin-kLin][rCol+kLin];
//---> Ver quem faz papel de B e quem faz papel de C (veja pseudo-codigo) for (m1 = 0; m1 < vRK.length; m1++) {
vNaoTermB = vRK.substring(m1,m1+1); for (m2 = 0; m2 < vRK_SK.length; m2++) { vNaoTermC = vRK_SK.substring(m2,m2+1);
//---> Procura as regras da forma A -> BC (no caso com tamanho = 3) for (m = 0; m < vTotRegrasGramatica; m++) {
if (vGramatica[m].length == 3) {
if ( (vGramatica[m].substring(1,2) == vNaoTermB) && (vGramatica[m].substring(2,3) == vNaoTermC) ) { vNaoTermA = vGramatica[m].substring(0,1);
if (vMatriz[sLin][rCol].indexOf(vNaoTermA) < 0) { vMatriz[sLin][rCol] = vMatriz[sLin][rCol] + vNaoTermA; } } } } // end-for m } // end-for m2 } // end-for m1 } // end-for kLin } // end-for kLin } // end-for sLin
//---> (6) Verifica se a sentenca existe... vMsg = "";
if (vTamanho > 0) {
if (vMatriz[vTamanho][1].indexOf(vStartSymbol) >= 0) { vMsg = "Senteça aceita";
else {
vMsg = "Sentença REJEITADA !!!"; }
}
//---> (7) Mostrar o resultado... incluindo a matriz de processamento... vTexto = "";
vTexto = "<table border>";
for (sLin = vTamanho; sLin > 0; sLin--) { vTexto = vTexto + "<tr>";
for (rCol = 1; rCol <= vTamanho-sLin+1; rCol++) {
vTexto = vTexto + "<td>" + vMatriz[sLin][rCol] + "</td>"; }
vTexto = vTexto + "</tr>"; }
vTexto = vTexto + "<tr>";
for (rCol = 1; rCol <= vTamanho; rCol++) {
vTexto = vTexto + "<td>" + vMatriz[0][rCol] + "</td>"; }
vTexto = vTexto + "</tr>"; vTexto = vTexto + "</table>"; vTexto = vTexto + "<p><hr>";
vTexto = vTexto + "<b><fontcolor='#FF0000'>" + vMsg + "</font></b>";
vDiv.innerHTML = vTexto; }