• Nenhum resultado encontrado

Algoritmo de parser GLR

N/A
N/A
Protected

Academic year: 2021

Share "Algoritmo de parser GLR"

Copied!
10
0
0

Texto

(1)

Algoritmo de parser GLR

Denis P. Pinheiro

1 Departamento de Ciˆencia da Computac¸˜ao

Universidade Federal de Minas Gerais (UFMG) Belo Horizonte – MG – Brasil

denis@dcc.ufmg.br

Resumo. Este artigo apresenta o algoritmo de parser GLR criado por [Tomita 1986]. O parser GLR (Generalized LR parser) ´e uma extens˜ao do al-goritmo de parsing LR padr˜ao conhecido na literatura. Este parser ´e utilizado principalmente no processamento de linguagens naturais. N˜ao determinismo ´e utilizado para o tratamento da ambig¨uidade inerente das linguagens naturais. Otimizac¸˜oes sugeridas por Tomita em seu artigo original tamb´em s˜ao apresen-tadas neste trabalho.

1. Introduc¸˜ao

Processamento de linguagens naturais n˜ao ´e um problema trivial. Devido `a ambiguidade inerente das linguagens naturais os algoritmos de parsing normalmente utilizados para porcessamento de linguagens de programac¸˜ao n˜ao s˜ao adequados para o processamento de linguagens naturais.

As linguagens de programac¸˜ao s˜ao estuturalmente muito bem definidas e s˜ao, em sua maioria, n˜ao amb´ıguas (exemplos de excec¸˜ao: C++, Pearl). Existem diversos parsers que s˜ao usados para processamento de LPs, como por exemplo, os parsers LL, LR, LALR, etc. Todos estes parsers s˜ao determin´ısticos (i.e. n˜ao suportam ambig¨udades, nem con-flitos) e reconhecem linguagens definidas por um subconjunto de gram´aticas livres de contexto [Aho et al. 1986].

Devido ao n˜ao determinismo proviniente da ambig¨uidade inerente das linguagens naturais, estes parsers determin´ısticos n˜ao s˜ao utilizados para processamento de lingua-gens naturais. Surge ent˜ao a necessidade de um mecanismo eficiente para o processa-mento de linguagens naturais.

Em 1986, Tomita apresenta um algoritmo eficiente, baseado no parser LR, que reconhece qualquer linguagem livre de contexto(LLC). Este ´e um algoritmo de parsing universal denominado Parser LR Generalizado (Generalized LR Parser) [Tomita 1986].

Neste trabalho, ´e apresentado o algoritmo GLR de parsing usado para reconhec-imento de qualquer LLC. Na pr´oxima sec¸˜ao, ´e feita uma revis˜ao do algoritmo LR de parsing, qual o GLR se mostra uma extens˜ao. Na sec¸˜ao 3 ´e apresentado o algoritmo GLR, com foco para o processo de reconhecimento. Nesta sec¸˜ao, tamb´em s˜ao apresentadas al-gumas otimizac¸˜oes sugeridas pelo pr´oprio Tomita em seu artigo original. Em seguida, na sec¸˜ao 4, ´e apresentada uma breve descric¸˜ao de dois algoritmos universais de parsing bem conhecidos na literatura, o CYK e o Earley. Finalmente, na sec¸˜ao 5 uma conclus˜ao do deste trabalho ´e apresentada.

(2)

2. Parser LR

Um parser LR ´e um analisador sint´aticobottom-upusado para reconhecer linguagens de programac¸˜ao definidas por gram´aticas livres de contexto. A t´ecnica utilizada ´e denomi-nada LR(k)parsing: a entrada ´e processada da esquerda para a direita (Left-rigth) e re-aliza uma derivac¸˜ao mais `a direita (Right derivation) utilizando k s´ımbolos delookahead

para decidir qual ac¸˜ao tomar durante a execuc¸˜ao. Este parser possui algumas vantagens:

• Muitas linguagens de programac¸˜ao podem ser processadas usando alguma

variac¸˜ao de um parser LR(exceto C++ e Perl);

• Parsers LR podem ser implementados eficientemente;

• Durante a leitura da intrada da esquerda para a direita, erros s˜ao detectados t˜ao

logo quanto verificado que um prefixo n˜ao pertence `a linguagem definida pela gram´atica.

Parsers LR s˜ao dif´ıceis de serem desenvolvidos `a m˜ao. Para minimizar este esforc¸o, existem diversos geradores de parsers (i.e. Yacc, JavaCup, JavaCC etc.) que, dada uma gram´atica LR, gera automaticamente um parser LR. Se a gram´atica especifi-cada tiver ambig¨uidades ou outros tipos de conflitos, o gerador pode detectar e informar o usu´ario da sua ocorrˆencia.

O algoritmo de parser LR utiliza de uma tabela de parser que, dependendo da forma como foi constru´ıda, atribui ao parser o t´ıtulo de Parser SLR (Simple LR), LALR (LookAhead LR) ou Canˆonico (respectivamente, utilizando uma tabela de parser SLR, LALR ou LR Canˆonica). Estes tipos de parsers podem lidar com um grande n´umero de gram´aticas; parsers LALR podem lidar com mais gram´aticas que os SLR; e parsers Canˆonicos podem lidar com mais gram´aticas que parsers LALR. O gerador de parser mais conhecido, Yacc (e sua vers˜ao para Java: JavaCup), gera parsers LALR. Na pr´oxima sec¸˜ao ser´a apresentado em detalhes o algoritmo de parser LR.

2.1. Algoritmo

Um parser LR ´e constitu´ıdo de uma entrada, uma sa´ıda, uma pilha e uma tabela deparsing

que tem duas partes: action egoto. Este parser est´a representado esquematicamente na Figura 1.

O parser lˆe um s´ımbolo de cada vez da entrada. A pilha ´e usada para manter uma palavra da forma s0X1s1X2s2. . . Xmsm, onde sm ´e o topo da pilha. Cada Xi ´e um

s´ımbolo da gram´atica (terminal ou n˜ao terminal) e cada si um estado. Dados um s´ımbolo

de entrada e um estado no topo da pilha, o parser indexa a tabela de parsing e determina a ac¸˜ao a ser relizada:shift oureduce.

A tabela de parsing consiste de duas partes, uma func¸˜ao de ac¸˜ao action e uma func¸˜ao de deslocamentogoto. A tabela de ac¸˜ao ´e indexada pelo estado no topo da pilha,

sm, e pelo s´ımbolo de entrada, ai. O valor de action[sm, ai] pode assumir os seguintes

valores:

shift s (shift), onde s ´e um estado;

reduceuma regra da gram´atica da forma A → β;

• aceita (acc); e • erro.

(3)

Figure 1. Representac¸ ˜ao esquem ´atica de um Parser LR

A func¸˜ao goto toma um estado e um s´ımbolo da gram´atica como argumentos e produz um estado como resultado. A tabela de parsing pode ser vista como a func¸˜ao de transic¸˜ao de um autˆomato de pilha determin´ıstico (APD), onde a func¸˜ao action deter-mina as ac¸˜oes sobre a pilha, o que empilhar e o que desempilhar a cada transic¸˜ao, e a func¸˜ao goto determina o pr´oximo estado da transic¸˜ao. O estado inicial do APD ´e o estado inicialmente colocado no topo da pilha do parser LR.

Uma configurac¸˜ao do parser LR ´e um par onde o primeiro elemento ´e o conte´udo da pilha e o segundo ´e a entrada ainda n˜ao processada:

(s0X1s1X2s2. . . Xmsm, aiai+1. . . an$)

A pr´oxima transic¸˜ao do parser ´e determinada pelo s´ımbolo de entrada corrente, ai,

pelo estado no topo da pilha, sm, e pelo valor da entrada na tabela de parsing action, dada

por action[sm, ai]. O resultado pode ser de quatro tipos:

1. Se action[sm, ai] = shif t s, o parser executa uma operac¸˜ao de shif t, obtendo a

seguinte configurac¸˜ao:

(s0X1s1X2s2. . . Xmsmais, ai+1. . . an$)

Neste ponto o parser moveu (shif t) o s´ımbolo de entrada ai e o pr´oximo estado,

dado por goto[sm, ai], para a pilha. Assim, ai+1se torna o s´ımbolo de entrada;

2. Se action[sm, ai] = reduce A → β, ent˜ao o parser executa uma reduc¸˜ao (reduce)

obtendo a seguinte configurac¸˜ao:

(s0X1s1X2s2. . . Xm−rsm−rAs, ai. . . an$)

onde s = goto[sm−r, A] e r ´e o comprimento de β(o lado direito da regra).

Primeiro ´e desempilhado 2r s´ımbolos da pilha (r estados e r s´ımbolos gra-maticais). Ent˜ao, o parser empilha o lado esquerdo da regra, A, e o valor de

goto[sm−r, A] na pilha. Os s´ımbolos gramaticais desempilhados sempre s˜ao iguais

ao lado direito da regra, ou seja, β = Xm−r+1. . . Xm. Neste ponto, pode-se gerar

(4)

3. Se action[sm, ai] == acc, processamento finalizado com sucesso.

4. Se action[sm, ai] == error, o parser descobriu um erro e pode chamar uma rotina

recuperac¸˜ao de erro.

O algoritmo de parser LR ´e apresentado na Listagem a seguir: Algorithm 1 Algoritmo do Parser LR

Entrada: uma palavra w e uma tabela de parsing LR com as func¸˜oes action e goto para a gram´atica G.

Sa´ıda: Se w pertence a L(G), um processamento ´e feito com sucesso, caso contr´ario, um erro ´e indicado.

1: empilha s0(estado inicial)

2: w$ ´e definido como entrada;

3: ip aponta para o primeiro s´ımbolo de w$; 4: loop

5: Seja s o estado no topo da pilha e a o s´ımbolo apontado por ip; 6: if action[s, a] = shif ts0 then

7: empilhe a e s0 no topo da pilha;

8: fac¸a ip apontar para o pr´oximo s´ımbolo da entrada; 9: else if action[s, a] = reduceA → β then

10: Desempilhe 2|β| s´ımbolos da pilha; 11: Seja s0o estado no topo da pilha;

12: Empilhe A e goto[s0, A] no topo da pilha;

13: Gere uma sa´ıda (i.e. a regra A → β); 14: else if action[s, a] = acc then

15: return 16: else 17: error(); 18: end if 19: end loop 2.2. Exemplo Pr´atico

A Figura 2 apresenta a tabela de parsing LR1 incluindo as func¸˜oes action e goto para a

seguinte gram´atica n˜ao amb´ıgua para express˜oes aritm´eticas com os operadores bin´arios + e ∗: (1) E → E + T (2) E → T (3) T → T ∗ F (4) T → F (5) F → (E) (6) F → id

Os c´odigos para as ac¸˜oes s˜ao:

1Neste trabalho n˜ao ser´a mostrado como construir a tabela de parsing LR, mas uma boa referˆencia ´e

(5)

Figure 2. Tabela de Parsing LR

1. si:shift e empilhe o estado i;

2. rj: reducepela regra numerada por j;

3. acc: aceite; 4. branco: erro;

A Figura 3 apresenta a seq¨uˆencia de configurac¸˜oes do parser durante o processa-mento da entrada id * id + id. Por exemplo, na linha (1) o parser est´a no estado 0 e id como o primeiro s´ımbolo de entrada. O valor de action[0, id] = s5 (Figura 2). Assim, na linha (2) o parser empilha o token id e o estado 5, e o s´ımbolo id ´e removido da entrada.

Na seq¨uˆencia, ∗ se torna o s´ımbolo de entrada, e a ac¸˜ao para o estado 5 e para a entrada ∗ ´e reduzir a regra F → id. Ent˜ao, dois s´ımbolos s˜ao desenpilhados (um s´ımbolo de estado e um s´ımbolo da gram´atica). O estado 0 se torna o topo da pilha. Temos agora a configurac¸˜ao na linha (3). As configurac¸˜oes seguintes s˜ao obtidas de maneira similar.

Figure 3. Execuc¸ ˜ao do parser LR para a entrada id * id + id

Na pr´oxima sec¸˜ao ´e apresentada uma extens˜ao deste algoritmo: o parser GLR. Este ´e denominado um parser universal, pois reconhece o conjunto de todas as Linguagens Livres de Contexto.

(6)

3. Parser GLR

Os algoritmos de parsing LR foram desenvolvidos originalmente para linguagens de programac¸˜ao. Um parser LR utiliza um algoritmo determin´ıstico guiado por uma tabela de parser que indica a pr´oxima ac¸˜ao a ser executada. Uma tabela de parsing pode ser obtida automaticamente a partir de uma gram´atica livre de contexto utilizando um algo-ritmo apresentado por [DeRemer 1971].

Um algoritmo de parser LR ´e um dos mais eficiente algoritmos de parsing. Ele ´e totalmente determin´ıstico e n˜ao realiza backtracking e nenhum tipo de busca. Por´em, n˜ao podemos adotar este parser para linguagens naturais, porque ele somente ´e aplicado a um subconjunto de GLCs denominadas gram´aticas LR. De fato, qualquer gram´atica que descreva uma linguagem natural n˜ao ´e LR. Se uma gram´atica ´e n˜ao LR, ent˜ao sua tabela de parsing ter´a m´ultiplas entradas; uma ou mais entradas da tabela de parsing ter´a m´ultiplas entradas [Shieber 1983].

Exemplificando, a Figura 4 apresenta a tabela de parsing com entradas m´ultiplas obtida da seguinte gram´atica amb´ıgua de express˜oes aritm´eticas:

(1) E → E + E (2) E → E ∗ E (3) E → id

Figure 4. Tabela de parsing com entradas m ´ultiplas (conflito shift-reduce)

Como pode ser observado, a tabela de ac¸˜oes possui quatro m´ultiplas entradas: duas na linha 5 e mais duas na linha 6, ambas nas colunas rotuladas com os terminais ∗ e +. A ambiguidade ocorre porque existem duas ´arvores de derivac¸˜ao mais a esquerda (DME) ou mais a direita (DMD) para a entrada id + id * id [Vieira 2006].

Por causa das m´ultiplas entradas na tabela de parsing, um algoritmo LR deter-min´ıstico n˜ao ´e o mais adequado para realizar o parsing, pois algum tipo de n˜ao determin-ismo ´e necess´ario.

3.1. Algoritmo

A id´eia do algoritmo ´e processar m´ultiplas entradas n˜ao deterministicamente. ´E adotado um pseudo-paralelismo (busca em largura) e ´e mantida uma lista de pilhas (Stack List). O pseudo-paralelismo ocorre da seguinte forma.

(7)

Um n´umero de processadores operam em paralelo. Cada processador tem uma pilha e comporta-se basicamente como o algoritmo LR padr˜ao. Quando um processo encontra m´ultiplas entradas, este ´e dividido em v´arios processos (um para cada entrada), replicando a pilha em cada novo processo e adicionando-as na lista de pilhas. Quando um processo encontra um erro, este processo termina e sua pilha ´e removida da lista de pilha. Todos os processos s˜ao sincronizados; eles realizam uma operac¸˜ao de shift

ao mesmo tempo, ent˜ao os processos processam a mesma palavra de entrada ao mesmo tempo. Assim, se um processo encontra uma operac¸˜ao de shift, ele espera at´e que todos os processo encontrem uma operac¸˜ao de shift possivelmente diferente.

A figura 5 apresenta a lista pilha (Stack List) logo depois de realizar a operac¸˜ao deshift do ´ultimo id da entrada “id + id * id” usando a tabela de parsing da figura 4 e a gram´atica de express˜oes aritm´eticas amb´ıgua. Por conveniˆencia, uma pilha ´e apresentada por v´ertices e arestas, onde v´ertices circulares representam estados e os retamgulares, s´ımbolos da gram´atica. A distˆancia entre os v´ertices n˜ao tem nenhum significado especial, somente ajuda o leitor a ter um melhor entendimento do estado das pilhas. Cada pilha ´e como uma pilha no algoritmo LR. O lado direito representa o topo da pilha, enquanto o lado esquerdo o fundo da pilha.

Figure 5. Lista de pilhas ap ´os o shift do ´ultimo id em id + id * id.

A desvantagem deste m´etodo que utiliza lista de pilhas ´e que n˜ao existem nenhuma interconex˜ao entre as pilhas (processos) e n˜ao existe nenhuma forma de um processo uti-lizar um processamento realizado por outro processo. O n´umero de pilhas na lista de pil-has cresce exponencialmente com o n´umero de ambig¨uidades encontradas, mas tamb´em pode reduzir ao passo que um processo encontra um erro e termina. Observa-se tamb´em na figura 5 que o processamento das duas pilhas a partir do estado 4 ´e realizado da mesma forma nos dois processos. Assim, esta redundˆancia de processamento pode ser evitado com a otimizac¸˜ao apresentada na seguinte sec¸˜ao.

Tomita, em seu artigo original [Tomita 1986], apresentou duas otimizac¸˜oes na manipulac¸˜ao da lista de pilhas e gerenciamento dos processos melhoram a eficiˆencia do algoritmo de parsing GLR. Estas otimizac¸˜oes s˜ao apresentadas nas sec¸˜oes que se seguem. 3.2. Primeira Otimizac¸˜ao

Se dois processos est˜ao no mesmo estado, ou seja, se suas pilhas tˆem o mesmo n´umero de estado no topo (no v´ertice mais a direita da pilha), os processos se comportaram da mesma maneira at´e que os estados s˜ao desempilhados atrav´es de uma operac¸˜ao de reduc¸˜ao. Para evitar esta processamento redundante, os processos s˜ao unificados atrav´es da combinac¸˜ao

(8)

das suas pilhas. Ent˜ao, se dois ou mais processos tˆem o mesmo estado no topo da pilha, os v´ertices que representam estes estados e est˜ao mais a direita, s˜ao unificados.

Estas pilhas ent˜ao s˜ao representadas como uma ´arvore, onde o v´ertice no topo cor-responde a raiz da ´arvore. Assim, uma pilha toma a forma de uma ´arvore (tree-structured stack). Quando um v´ertice no topo da pilha representa uma raiz e ´e desempilhada, a pilha na forma de ´arvore ´e dividida no n´umero de pilhas original. Em geral, o sistema mant´em diversas pilhas na forma de ´arvore em paralelo, ent˜ao a lista de pilha toma a forma de uma

floresta.

Figure 6. Uma pilha na forma de ´arvore.

A figura 6 apresenta a pilha na forma de ´arvore obtida ap´os oshift do ´ultimo id na express˜ao id + id * id. Ao contr´ario do exemplo anterior, a palavra de entrada id ser´a processada somente uma vez.

Embora o n´umero de computac¸˜ao seja significantemente reduzido com esta t´ecnica de combinac¸˜ao de pilhas, o n´umero de folhas de uma pilha na forma de ´arvore cresce exponencialmente com o n´umero de ambig¨uidades encontradas. Na pr´oxima sec¸˜ao ´e descrita uma segunda otimizac¸˜ao em que as pilhas s˜ao representadas como um grafo direcionado ac´ıclico para evitar tal ineficiˆencia.

3.3. Segunda Otimizac¸˜ao

No momento em que uma ambig¨uidade ´e encontrada, toda uma pilha ´e copiada para o(s) novo(s) processo(s) criado(s). No entanto, n˜ao ´e ncess´ario copiar a pilha inteira, pois ap´os diferentes operac¸˜oes realizadas em paralelo na pilha em forma de ´arvore, uma porc¸˜ao do fundo da pilha pode permacecer a mesma. Ent˜ao, somente uma porc¸˜ao da pilha deve ser replicada. Quando uma pilha ´e replicada desta forma, a pilha ´e representada como uma ´arvore, onde o fundo da pilha corresponde `a raiz desta ´arvore.

Com esta segunda otimizac¸˜ao combinada com a primeira otimizac¸˜ao apresentada na ´ultima sec¸˜ao, as pilhas s˜ao representadas como um grafo direcionado ac´ıclico. Na figura 7 apresenta a pilha na forma de grafo para o mesmo exemplo dado.

Pode-se mostrar que o algoritmo GLR utilizando pilhas estruturadas na forma de um grafo n˜ao porcessa nenhuma parte de uma sentenc¸a mais de uma vez da mesma maneira. Se dois processos processaram alguma parte da sentenc¸a da mesma maneira, eles est˜ao no mesmo estado. Logo, eles ser˜ao combinados em um ´unico processo.

Portanto, o eficiente algoritmo de parser GLR apresentado ´e uma extens˜ao do algoritmo de parsing LR padr˜ao e reconhece todas as linguagens livres de contexto, o que lhe d´a o t´ıtulo deParser Universal.

(9)

Figure 7. Uma pilha na forma de grafo.

4. Trabalhos Relacionados

Outros algoritmos de universais parsing s˜ao bem conhecidos na literatura. Os mais con-hecidos s˜ao o algoritmo CYK [Cocke 1969, Younger 1967, Kasami 1965] e o apresentado por [Earley 1970]. Ambos os algoritmos s˜ao baseados em programac¸˜ao dinˆamica.

O algoritmo CYK reconhece linguagens definidas por gram´aticas livre de contexto (GLC) na forma normal de chomsky (FNC). Desde que qualquer GLC pode ser convertida sem dificuldades na FNC, o algoritmo CYK pode ser utilizado para reconhecer qualquer linguagem livre de contexto (LLC).

O algoritmo de parsing de Earley ´e usado principalmente para processar lingua-gens naturais. O algoritmo executa em tempo cubico no caso geral e, quadr´atico, para gram´aticas n˜ao amb´ıguas. O algoritmo se mostra mais eficiente quando as regras da gram´atica s˜ao escritas com recurs˜ao a esquerda.

5. Conclus˜ao

As linguagens naturais necessitam de um mecanismo que suporta o n˜ao determinismo proveniente da ambig¨uidade inerente das pr´oprias LNs. Os parser de LP n˜ao s˜ao ad-equados para processamento de LNs por que eles s˜ao algoritmos determin´ısticos e s˜ao suportam ambig¨uidades. Os algoritmos universais de parsers mostram-se mais adequados ao processamento de linguagens naturais.

Este trabalho apresenta o parser universal GLR, desenvolvido como uma extens˜ao do algoritmo de parsing LR. Com as otimizac¸˜oes apresentadas, o algoritmo se mostra eficiente para o processamento de linguagens naturais (LNs).

(10)

References

Aho, A. V., Sthi, R., and Ullman, J. D. (1986). Compilers: Principles, Techniques, and

Tools. Addison-Wesley.

Cocke, J. (1969). Programming languages and their compilers: Preliminary notes. Courant Institute of Mathematical Sciences, New York University.

DeRemer, F. L. (1971). Simple lr(k) grammars. In Communications ACM, volume 14(7), pages 453–460.

Earley, J. (1970). An efficient context-free parsing algorithm. Commun. ACM, 13(2):94– 102.

Kasami, T. (1965). An efficient recognition and syntax-analysis algorithm for context-free languages. In Scientific report AFCRL-65-758, Bedford, MA. Air Force Cambridge Research Lab.

Shieber, S. M. (1983). Sentence disambiguation by a shift-reduce parsing technique. In

Proceedings of the 21st annual meeting on Association for Computational Linguistics,

pages 113–118, Morristown, NJ, USA. Association for Computational Linguistics. Tomita, M. (1986). Efficient Parsing for Natural Language: A Fast Algorithm for

Practi-cal Systems. Kluwer Academic Publishers, Norwell, MA, USA.

Vieira, N. J. (2006). Introduc¸˜ao aos Fundamentos da COmputac¸˜ao: Linguagens e

M´aquinas. Pioneira Thomson Learnig, Brasil.

Younger, D. H. (1967). Recognition and parsing of context-free languages in time n3. In

Referências

Documentos relacionados

Para disciplinar o processo de desenvolvimento, a Engenharia de Usabilidade, também conceituada e descrita neste capítulo, descreve os métodos estruturados, a

O objetivo do curso foi oportunizar aos participantes, um contato direto com as plantas nativas do Cerrado para identificação de espécies com potencial

Ninguém quer essa vida assim não Zambi.. Eu não quero as crianças

Podem treinar tropas (fornecidas pelo cliente) ou levá-las para combate. Geralmente, organizam-se de forma ad-hoc, que respondem a solicitações de Estados; 2)

 Direito recebe informações de outros subsistemas sociais  Processa segundo a sua linguagem interna..  Envia informações para os

Essa versão não altera nenhuma anterior Este medicamento é indicado quando se tem dificuldade para expectorar e há muita secreção densa e viscosa, tais como: bronquite crônica e

ITIL, biblioteca de infraestrutura de tecnologia da informação, é um framework que surgiu na década de mil novecentos e oitenta pela necessidade do governo

Os trabalhadores têm consciência de que as condições de suas atividades profissionais estão mudando e que somente uma formação contínua irá capacitá-los para