Este relatório apresenta um protótipo de ferramenta de apoio à revisão de árvores sintáticas dentro do projeto Floresta Sintá(c)tica, que tem como objetivo criar um "treebank" publicamente disponível para a língua portuguesa, ou seja, um conjunto de itens sintaticamente analisados, que permita que todos os interessados na análise do português possam utilizá-lo tendo em conta diferentes objetivos.
O protótipo apresentado é constituído por um conjunto de funções desenvolvidas em Emacs Lisp.
Antes de começar a editar uma árvore, recomenda-se que o usuário execute a macro "highlight-changes-mode", ou simplesmente o seu atalho, definido pela tecla F12. Esta macro faz parte da biblioteca interna do Emacs, e sua funcionalidade consiste em facilitar a indentificação das modificações impostas a um arquivo. Uma vez ativa, todos os pontos do texto que são alterados ficam marcados com uma formatação diferente. No caso do protótipo, as modificações ficam assinaladas em vermelho. Este recurso permite que o usuário indentifique rapidamente os deslocamentos que estão sendo efetuados.
Utilizando-se das macros "highlight-changes-next-change" (ctrl-seta para a direita), o usuário movimenta o cursor para ponto da primeira modificação abaixo da posição em que ele se encontra, se houver, e "highlight-changes-previous-change" (ctrl-seta para a esquerda), o usuário movimenta o cursor para ponto da primeira modificação acima da posição em que ele se encontra, se houver.
Para deslocar um token, o usuário deve posicionar o cursor na linha correspondente e executar a macro apropriada. Se o token selecionado for um nó não-terminal, todos os seus descendentes também sofrerão as modificações impostas pela macro.
Foram criadas 4 macros de deslocamento:
Exemplo 1: subir nível da vírgula (sinal de pontuação).
====P<:num('1948' M S) 1948 ==, =P:v-fin('declarar' PS 3S IND) declarou =ACC:icl ==P:v-inf('estar' V INF) estar ==SC:ap ===H:adj('pronto' F S) pronta ===A<:pp ====H:prp('para') para ====P<:icl =====P:v-inf('defender' V INF) defender =====ACC:np ======>N:art('o' M P) os ======>N:pron-det('seu' M P) seus =======H:n('direito' M P) direitos =====ADVL:pp ======H:prp('em') em ======P<:n('tribunal' M S) tribunal ===, CO:conj-c('e') e CJT:fcl
Após a execução da macro, a ferramenta indentifica que "===," não é um nó não-terminal, e que "=====P<:n(M S) tribunal" é uma palavra. Logo, não será necessário uma troca de posição entre estes tokens, obtendo-se o seguinte resultado:
====P<:num('1948' M S) 1948 ==, =P:v-fin('declarar' PS 3S IND) declarou =ACC:icl ==P:v-inf('estar' V INF) estar ==SC:ap ===H:adj('pronto' F S) pronta ===A<:pp ====H:prp('para') para ====P<:icl =====P:v-inf('defender' V INF) defender =====ACC:np ======>N:art('o' M P) os ======>N:pron-det('seu' M P) seus =======H:n('direito' M P) direitos =====ADVL:pp ======H:prp('em') em ======P<:n('tribunal' M S) tribunal ==, CO:conj-c('e') e CJT:fcl
Exemplo 2: subir o nível de um nó não-terminal "D" sem sua eliminação - todos os seus descendentes também serão modificados, conforme ilustra esquematicamente a Figura 1.
Antes | Depois |
![]() | ![]() |
Após verificar todos os nós a serem deslocados, a ferramenta pergunta se o nó não-terminal selecionado "D" deve ser eliminado. Neste caso, a resposta é negativa. Se a resposta fosse positiva, todos os seus descendentes ficariam dominados imediatamente por "C" (exemplo 3).
Subir o nível de ADVL:pp
STA:fcl P:v-fin('invocar' PS/MQP 3P IND) Invocaram- ACC:pron-pers('se' M/F S/P) se SUBJ:np =>N:art('a' F P) as =H:n('evidência' F P) evidências =N<:fcl ==ACC:pron-indp('que' F P) que ==SUBJ:np ===>N:art('o' M S) o ===H:n('ministério' M S) ministério ==P:v-fin('apresentar' PS 3S IND) apresentou ==ADVL:pp ===H:prp('para') para ===P<:np ====>N:art('a' F S) a ====H:n('resolução' F S) resolução ====N<:pp =====H:prp('de') de =====>N:art('o' M S) o =====H:n('caso' M S) caso .
Após o deslocamento temos:
STA:fcl P:v-fin('invocar' PS/MQP 3P IND) Invocaram- ACC:pron-pers('se' M/F S/P) se SUBJ:np =>N:art('a' F P) as =H:n('evidência' F P) evidências =N<:fcl ==ACC:pron-indp('que' F P) que ==SUBJ:np ===>N:art('o' M S) o ===H:n('ministério' M S) ministério ==P:v-fin('apresentar' PS 3S IND) apresentou ADVL:pp =H:prp('para') para =P<:np ==>N:art('a' F S) a ==H:n('resolução' F S) resolução ==N<:pp ===H:prp('de') de ===>N:art('o' M S) o ===H:n('caso' M S) caso .
Exemplo 3: subir o nível de um nó não-terminal "D" com sua eliminação - serão modificados os níveis de todos os seus descendentes, conforme ilustra esquematicamente a Figura 2.
Antes | Depois |
![]() | ![]() |
Neste exemplo, após identificar todos os nós a serem deslocados, a ferramenta pergunta ao usuário se o nó selecionado "D" deve ser eliminado. Neste caso a resposta é positiva - todos os seus descendentes ficarão dominados imediatamente por "C".
Como exemplo, pode-se subir o nível de CJT:fcl, com sua eliminação.
STA:cu CJT:fcl =SUBJ:np ==>N:art('o' M S) O ==H:n('Governo' M S) Governo =P:v-fin('inaugurar' PS 3S IND) inaugurou =ACC:n('ponte' F P) pontes =CO:conj-c('e' ) e =SUBJ:n('estrada' F P) estradas =, CO:conj-c('mas' ) mas CJT:fcl ="«
Após o deslocamento temos:
STA:cu SUBJ:np =>N:art('o' M S) O =H:n('Governo' M S) Governo P:v-fin('inaugurar' PS 3S IND) inaugurou ACC:n('ponte' F P) pontes CO:conj-c('e' ) e SUBJ:n('estrada' F P) estradas , CO:conj-c('mas' ) mas CJT:fcl ="«
Exemplo 4: Subir o nível de uma palavra ("a") sem eliminar o nó não-terminal a que ela pertence ("C"). A palavra "a" deixará de ser dominada imediatamente pelo nó não-terminal "C" para ser dominada imediatamente pelo nó não-terminal "B", conforme ilustra a figura 3.
Antes | Depois |
![]() | ![]() |
Como exemplo, vamos imaginar que o usuário deseja subir o nível de "=ADVL:adv('ainda') ainda", e que o "ADVL:adv" é dependente da oração infinitiva cujo predicado é "fazer". A análise seria:
A1 STA:fcl P:v-fin('conseguir'PR 1S IND) Consigo ACC:icl =ADVL:adv('ainda') ainda =P:v-inf('fazer') fazer =ACC:np ==>N:art('o' M S) o ==H:n('pino' M S) pino .
A revisão leva a trocar a posição de =ADVL:adv pela de ACC:icl, subindo um nível:
A1 STA:fcl P:v-fin('conseguir'PR 1S IND) Consigo ADVL:adv('ainda') ainda ACC:icl =P:v-inf('fazer') fazer =ACC:np ==>N:art('o' M S) o ==H:n('pino' M S) pino .
Após identificar o tipo do nó selecionado (terminal ou não-terminal), a ferramenta pergunta ao usuário se o deslocamento deve ser feito para uma ramificação à direita ou para uma ramificação à esquerda. Ou seja, se o nó em questão deverá ficar dependente do nó à sua direita ou do nó à sua esquerda. Além disso, esta macro permite que o usuário aumente a indentação do nó selecionado através da inserção de um novo nó não-terminal (construção de um novo constituinte).
Exemplo 5: Descer o nível de um nó não-terminal ("D") com a inserção de um novo nó não-terminal ("X"). A Figura 4 ilustra este deslocamento.
Antes | Depois |
![]() | ![]() |
Nota-se que a árvore produzida após este deslocamento fica momentaneamente "incorreta", pois as opções lingüísticas das ferramentas do projeto VISL não permitem a existência de um nó não-terminal com um único descendente. Espera-se, então, que o usuário execute um novo deslocamento (exemplo 6). Como exemplo, imaginemos que o usuário quer introduzir um nó antes de H:cu, cuja designação será H:np.
STA:fcl SUBJ:np =>N:art('a' F S) A =H:n('pianista' F S) pianista P:v-fin('interpretar' FUT 3S IND) interpretará ACC:np =H:cu ==CJT:np ===>N:art('o' M S) o ====H:n('concerto' M S) concerto ==CO:conj-c('e') e ==CJT:np ===>N:art('a' F S) a ===H:n('sinfonia' F S) sinfonia =N<:np ==H:n('número' M S) número ==N<:num('1' M S) 1 =N<:pp ==H:prp('de') de ==P<:prop('Chopin' M S) Chopin
Após a execução da macro, obteremos o seguinte resultado:
STA:fcl SUBJ:np =>N:art('a' F S) A =H:n('pianista' F S) pianista P:v-fin('interpretar' FUT 3S IND) interpretará ACC:np =H:np ==H:cu ===CJT:np ====>N:art('o' M S) o =====H:n('concerto' M S) concerto ===CO:conj-c('e') e ===CJT:np ====>N:art('a' F S) a ====H:n('sinfonia' F S) sinfonia =N<:np ==H:n('número' M S) número ==N<:num('1' M S) 1 =N<:pp ==H:prp('de') de ==P<:prop('Chopin' M S) Chopin
Exemplo 6: Descer nível de um nó não-terminal ("E"), deslocando-o para a esquerda. A Figura 5 ilustra este deslocamento.
Antes | Depois |
![]() | ![]() |
STA:fcl SUBJ:np =>N:art('a' F S) A =H:n('pianista' F S) pianista P:v-fin('interpretar' FUT 3S IND) interpretará ACC:np =H:np ==H:cu ===CJT:np ====>N:art('o' M S) o =====H:n('concerto' M S) concerto ===CO:conj-c('e') e ===CJT:np ====>N:art('a' F S) a ====H:n('sinfonia' F S) sinfonia =N<:np ==H:n('número' M S) número ==N<:num('1' M S) 1 =N<:pp ==H:prp('de') de ==P<:prop('Chopin' M S) Chopin
Após a execução da macro, obteremos o seguinte resultado:
STA:fcl SUBJ:np =>N:art('a' F S) A =H:n('pianista' F S) pianista P:v-fin('interpretar' FUT 3S IND) interpretará ACC:np =H:np ==H:cu ===CJT:np ====>N:art('o' M S) o =====H:n('concerto' M S) concerto ===CO:conj-c('e') e ===CJT:np ====>N:art('a' F S) a ====H:n('sinfonia' F S) sinfonia ====N<:np =====H:n('número' M S) número =====N<:num('1' M S) 1 =N<:pp ==H:prp('de') de ==P<:prop('Chopin' M S) Chopin
Exemplo 7: Descer nível de um nó terminal ("b"), deslocando-o para a direita. A Figura 6 ilustra este deslocamento.
Antes | Depois |
![]() | ![]() |
O exemplo seguinte baixa o nível do advérbio ainda ligando-o à oração infinitiva seguinte (à direita):
STA:fcl SUBJ:np =>N:art('a' F S) A =H:np('Câmara_Municipal' F S) Câmara_Municipal =N<:pp ==H:prp('de') de ==P<:prop('Lisboa' F S) Lisboa P:v-fin('afirmar' P 3S IND) afirma ADVL:adv('ainda') ainda ACC:cu =CJT:icl ==ADVL:adv('não) não ==P:vp ===AUX:v-inf('ter') ter ===AUX:v-pcp('ser') sido ===MV:v-pcp('levantar' M S) levantado ==ACC:pron-det('nenhum' M S) nenhum =CO:conj-c('mas') mas =CJT:fcl ==SUB:conj-s('que') que ==SUBJ:adv('tal') tal ==P:vp ===AUX:v-fin('vir' FUT 3S IND) virá ===PRT-AUX<:prp('a') a ===MV:v-inf('acontecer') acontecer ==ADVL:pp('a_breve_trecho') a_breve_trecho .
Após a execução (duas vezes) da macro, obteremos o seguinte resultado:
STA:fcl SUBJ:np =>N:art('a' F S) A =H:np('Câmara_Municipal' F S) Câmara_Municipal =N<:pp ==H:prp('de') de ==P<:prop('Lisboa' F S) Lisboa P:v-fin('afirmar' P 3S IND) afirma ACC:cu =CJT:icl ==ADVL:adv('ainda') ainda ==ADVL:adv('não) não ==P:vp ===AUX:v-inf('ter') ter ===AUX:v-pcp('ser') sido ===MV:v-pcp('levantar' M S) levantado ==ACC:pron-det('nenhum' M S) nenhum =CO:conj-c('mas') mas =CJT:fcl ==SUB:conj-s('que') que ==SUBJ:adv('tal') tal ==P:vp ===AUX:v-fin('vir' FUT 3S IND) virá ===PRT-AUX<:prp('a') a ===MV:v-inf('acontecer') acontecer ==ADVL:pp('a_breve_trecho') a_breve_trecho .
Esta macro não se preocupa em verificar se estão sendo deslocados nós terminais ou não-terminais. Apenas, retira do início de cada linha selecionada um sinal-de-igual, se houver.
Exemplo 8: subir o nível de todos os tokens selecionados.
STA:fcl SUBJ:np =>N:art('o' M S) O =H:n('procurador' M S) procurador P:vp =AUX:v-fin('ser' PS 3S IND) foi =MV:v-pcp('nomear' M S) nomeado PIV:pp =H:prp('para') para =P<:icl ==P:v-inf('acompanhar') acompanhar ==ACC:np ===>N:art('a' F S) a ===H:n('investigação' F S) investigação ===N<:pp ====H:prp('em') em ====P<:np =====>N:art('o' M S) o =====H:n('sentido' M S) sentido =====N<:pp ======H:prp('de') de ======P<:icl =======P:v-inf('promover') promover =======ACC:np ========>N:art('um' F S) uma ========H:n('acareação' F S) acareação ========N<:pp =========H:prp('entre') entre =========P<:np ==========>N:art('o' M P) os ==========>N:num('7' M P) 7 ==========H:n('indivíduo' M P) indivíduos .
Após a execução da macro, temos:
STA:fcl SUBJ:np =>N:art('o' M S) O =H:n('procurador' M S) procurador P:vp =AUX:v-fin('ser' PS 3S IND) foi =MV:v-pcp('nomear' M S) nomeado PIV:pp =H:prp('para') para =P<:icl ==P:v-inf('acompanhar') acompanhar ==ACC:np ===>N:art('a' F S) a ===H:n('investigação' F S) investigação ADVL:pp =H:prp('em') em =P<:np ==>N:art('o' M S) o ==H:n('sentido' M S) sentido ==N<:pp ===H:prp('de') de ===P<:icl ====P:v-inf('promover') promover ====ACC:np =====>N:art('um' F S) uma =====H:n('acareação' F S) acareação =====N<:pp ======H:prp('entre') entre ======P<:np =======>N:art('o' M P) os =======>N:num('7' M P) 7 =======H:n('indivíduo' M P) indivíduos .
Esta macro também não se preocupa em verificar o "tipo" dos nós que estão sendo deslocados. Apenas, acrescenta ao início de cada linha selecionada um sinal-de-igual.
Exemplo 9: descer duas vezes o nível de todos os tokens selecionados.
=P<:np ==>N:art('o' <-sam> M S) o ==H:n('contrato' M S) contrato ==N<:pp ===H:prp('com') com ===P<:prop('Teerão' M S) Teerão , N<:fcl =SUBJ:np ==>N:pron-det('cujo'M S) cujo ==H:n('montante' M S) montante =ADVL:adv('não') não =P:vp ==AUX:v-fin('ser' PS 3S IND) foi ==P:v-pcp('especificar' M S) especificado =,
Após a execução da macro, temos:
=P<:np ==>N:art('o' <-sam> M S) o ==H:n('contrato' M S) contrato ===N<:pp ====H:prp('com') com ====P<:prop('Teerão' M S) Teerão ==, ==N<:fcl ===SUBJ:np ====>N:pron-det('cujo'M S) cujo ====H:n('montante' M S) montante ===ADVL:adv('não') não ===P:vp ====AUX:v-fin('ser' PS 3S IND) foi ====P:v-pcp('especificar' M S) especificado =,
Durante a fase de testes do protótipo, verificou-se que algumas tarefas eram constantemente executadas, e para se chegar ao resultado desejado com as macros apresentadas acima, o usuário tem que responder 2 ou 3 perguntas. Então, foram criadas 3 especializações.
Para exemplificar a utilização do protótipo, utilizaremos um exemplo preparado por Susana Afonso, em Maio de 2001. (Desde essa altura, convém indicar, já se sistematizou X:cu para ?:cu e CJT:fcl para CJT:?, assim como as aspas foram regularizadas, optando-se pela sua colocação imediatamente antes do nó terminal.)
Observe a seguinte frase, retirada do corpus CETEMPúblico:
SOURCE: CETEMPúblico n=65 sec=pol sem=95b C65-3 O Governo inaugurou pontes e estradas, mas «não foi capaz de inaugurar» uma Lei de Bases do Ordenamento do Território. STA:cu CJT:fcl =SUBJ:np ==>N:art('o' M S) O ==H:n('Governo'M S) Governo =P:v-fin('inaugurar' PS 3S IND) inaugurou =ACC:n('ponte' F P) pontes =CO:conj-c('e' ) e =SUBJ:n('estrada' F P) estradas =, CO:conj-c('mas' ) mas CJT:fcl ="« =ADVL:adv('não') não =P:v-fin('ser' PS 3S IND) foi =SC:ap ==H:adj('capaz' F S) capaz ==A<:pp ===H:prp('de') de ===P<:icl ====P:v-inf('inaugurar') inaugurar ===="» ====ACC:np =====>N:art('um' F S) uma =====H:prop('Lei_de_Bases_do_Ordenamento_do_Território' F S) Lei_de_Bases_do_Ordenamento_do_Território.
A Figura 7 ilustra a mesma frase, porém sendo editada em uma janela do Emacs já com as macros do protótipo ativas em sua memória.
Vamos imaginar que o usuário queira alterar o nome do nó não-terminal STA:cu para STA:fcl (manualmente) e eliminar o nó não-terminal CJT:fcl. Para isto, após alterar o nome, o usuário deve posicionar o cursor em CJT:fcl e executar a macro diminui-indentação, que verifica que o nó selecionado é do tipo não-terminal, e pergunta ao usuário se ele deseja a sua eliminação. Neste caso, a resposta será positiva, obtendo-se a estrutura apresentada pela Figura 8.
Em seguinda, o usuário deseja introduzir um novo nó não-terminal antes de P:v-fin, cuja designação será X:cu e outro nó não-terminal (CJT:fcl) imediatamente a seguir. Para este deslocamento, ele deve executar 2 vezes a macro aumenta-indentação ou executar, também duas vezes, a macro baixa-nível-com-inserção. Vale lembrar que na segunda opção, o usuário apenas terá que informar o nome do novo nó, não sendo necessário responder a pergunta de inserção ou não-inserção do mesmo. A árvore resultante encontra-se ilustrada pela Figura 9.
Neste momento, ele verifica que precisa introduzir nó antes de ACC:n (ACC:cu) e substituir ACC:n, por CJT:n (manualmente) e aumentar nível de CO:conj-c e de SUBJ:n (cujo nome será alterado manualmente para CJT), conforme ilustra a Figura 10. Para este deslocamento, ele terá que primeiramente executar a macro aumenta-indentação, reponder positivamente pela inserção de um novo nó e informar o nome do mesmo. Em seguinda, manualmente, modificar o nome de ACC:n. E, então, executar a macro aumenta-indentação, respondendo negativamente quanto à inserção de um novo nó, para cada nó terminal que se deseja deslocar. Melhor ainda, se ao invés de executar tantos passos, o usuário selecionar estes dois nós e executar a macro aumenta-indentação-selecionado. Em qualquer caso, o resultado será o mesmo (Figura 10)
E, em seguida, repara que o nível do nó ACC:cu tem de ser aumentado (Figura 11 - aumenta-indentação).
Finalmente, aumentar o nível da vírgula, CO:conj-c e CJT:fcl (Figura 12 - aumenta-indentação-selecionado.
Para instalar o protótipo, o usuário deve seguir os seguintes passos:
Algumas das funcionalidades que podem ser incorporadas ao protótipo apresentado são:
Além dos recursos de deslocamento apresentados, foram criadas macros que modificam o ambiente de edição do Emacs para que ele fique semelhante a editores baseados em Windows - funções de teclado (início e fim de linha, seleção de texto, deleção de caracteres e palavras) e funções de mouse. Isto permite que usuários não acostumados com este editor, possam trabalhar com mais facilidade.
A ferramenta foi testada e utilizada por Susana Afonso, Eckhard Bick e Raquel Marchi, que ajudaram na indentificação dos problemas, bem como fizeram muitas propostas construtivas quanto a funcionalidades ausentes e redundantes nas versões preliminares do protótipo.