Trabalho prático de Processamento de Linguagem I

13 de Abril do ano 2000

Sandrina Ferreira Maciel

E-mail: A20232@correio.ci.uminho.pt

Ana Cláudia Barbosa de Faria

E-mail: A23163@correio.ci.uminho.pt

Carina das Dores Lopes Duarte

E-mail: A23171@correio.ci.uminho.pt

Resumo:

RELATORIO CORRECTO ( Nota: no relatório anterior houve esquecimento de anexar um ficheiro

Este trabalho surge no âmbito da disciplina de Processamento de Linguagens I, e consiste num processador generico de decumentos estruturados (XML) que valida a boa formação e que guarda a sua informação num grove.


Índice

  1. Introdução
  2. Desenvolvimento
    1. Análise do problema - Primeira Etapa
    2. Análise do problema - Segunda Etapa
    3. Análise do problema - Terceira Etapa
  3. Conclusão
  4. ANEXO

Introdução

O objectivo deste trabalho prático é a criação de um reconhecedor de documentos no formato XML. A sua realização será constituida por três fases.

A primeira fase é constituida por três etapas:

A primeira etapa tem como objectivo a criação de um analisador léxico e outro sintáctico usando, para isso,a ferramenta Lex e yacc para a gramática apresentada.

Na segunda etapa, a finalidade é acrescentar aos analisadores construídos anteriormente a análise semântica, que valide certos requesitos. Nomeadamente, todas as marcas terão de ser abertas e fechadas correctamente, e o documento terá que começar obrigatoriamente por uma marca que só terá de fechar no final do documento.

Na terceira etapa vai-se proceder ao armazenamento da infornação definida nas etapas anteriores.


Desenvolvimento

Análise do problema - Primeira Etapa

Na primeira etapa foi necessário criar um analisador sintáctico (yacc) para reconhecer a seguinte gramática:

Documento --> ElemList '$'

ElemList --> ElemList Elem

| Elem

Elem --> char

| '&' id ';'

| '<' id AttrList '>' ElemList '<' '/' id '>'

| '<' id AttrList '/' '>'

AttrList --> AttrList

| &

Attr --> id '=' valor

Criamos também um analisador léxico (lex) onde o número de marcas abertas tem que ser igual ao número de marcas fechadas, não interessando o seu conteúdo.

Exemplo:

<data> 29/12/90 </epoca> é reconhecido nesta primeira etapa.

Análise do problema - Segunda Etapa

Na segunda etapa criamos um analisador semântico para reconhecer o conteúdo das marcas, deste modo quando se abre uma tag temos de ter cuidado que o conteúdo tem de ser o mesmo. Para além disso temos de ter uma marca a englobar todo o documento.

Exemplos:

< data 29/12/90 </epoca> já não é reconhecido nesta etapa, pois interessa o conteúdo das marcas.

<data> 29/12/90 </data> é reconhecido nesta etapa.

<datas> <data> <dia> 27 <mes> marco </mes> <ano> 2000 </ano> </dia> </data> <data1> <dia> 18 <mes1> agosto </mes1> <ano1> 1999 </ano1> </dia1> </data1> </datas>

Análise do problema - Terceira Etapa

Nesta etapa construimos a seguinte estrutura de dados em C:

typedef struct Anodo { char * nomeId; char * val; struct Anodo * seg; }tcelAtribs,* taptAtribs;

typedef struct Gnodo { char * idElem; union c{ char * txt; struct cel { struct Gnodo * conteudo; taptAtribs atributo; }normal; }cont; struct Gnodo * irmao; }tcelGrove,* taptGrove;

typedef struct abert{ char * abertId; taptAtribs atr; }tcelAbert,* taptAbert;

taptGrove grove;

Criamos algumas funções auxiliares utilizadas no analisador sintáctico e definidas no ficheiro em C, funções a que chamamos "concat1", "concat2", "concat3". A função "concat1" insere um atributo no fim da lista de atributos já existente, cujo tipo é taptAtribs. Na função "concat2" inserimos um caractere a uma sequência de caracteres. Já a função "concat3" inserimos um elemento no fim de uma lista de elementos que é do tipo taptGrove.

Implementamos uma função "ordena" que aceita como parametro a estrutura principal (taptGrove), que tem como objectivo criar uma função suficientemente genérica para gerar o formtato ESIS. Nesta função utilizamos uma função auxiliar (imprime) que escreve no ecran os dois campos, nomeId e val, da estrutura taptAtribs.


Conclusão

Com a realização deste trabalho pensamos ter adquirido uma ideia geral sobre a finalidade desta disciplina, bem como serviu para aplicar os conhecimentos adquiridos nesta. Julgamos ter captado os principais objectivos propostos neste trabalho, tais como construir um analisador léxico e sintáctico (usando as ferramentas lex e yacc, respectivamente), analisador semântico e armazenamento da informação do documento (criando um grove).

Ficamos a perceber a implementação de um processador genérico de documentos estruturados (neste caso, XML) que validará a formação dos documnetos e que guardará a sua informação num grove.


ANEXO

Trabalho em yacc


%{
#include "trabalho1.h"
%}
%start DOCXML
%union {char *valor;
        char car;
        taptGrove grv;
        taptAtribs atri;
        taptAbert abt;
       }
%token <valor>id num str
%token <car>caract
%type <valor>Fecho Valor Txt
%type <grv>Elems Elem DOCXML
%type <atri>Atribs Atrib
%type <abt>Abertura AberturaFecho
%%
DOCXML:Abertura Elems Fecho {$$=(tcelGrove *)malloc(sizeof(tcelGrove));
			     $$->idElem=$1->abertId;
                             $$->cont.normal.atributo=$1->atr;
                             $$->cont.normal.conteudo=$2;
			     $$->irmao=NULL;
			      grove=$$;
                             if (strcmp($1->abertId,$3)!=0)
                                printf("Erro!!\n");
                             else  printf("Documento XML valido.\n");
                             }
     ;
Elems: Elem {$$=$1;
             printf("Elems deriva com Elem\n");}
     |Elems Elem {$$=concat3($1,$2);
                 printf("Elems deriva com Elems Elem\n");}     
     ;
Elem:Txt                   {$$=(tcelGrove *)malloc(sizeof(tcelGrove));
			    $$->idElem="sequencia";
                            $$->cont.txt=$1;
                            $$->irmao=NULL;
                            printf("Elem deriva com Txt\n");}
    |Abertura Elems Fecho {$$=(tcelGrove *)malloc(sizeof(tcelGrove));
			   $$->idElem=$1->abertId;
                           $$->cont.normal.atributo=$1->atr;
                           $$->cont.normal.conteudo=$2;
                           $$->irmao=NULL;
                          if (strcmp($1->abertId,$3)!=0)
                              { printf("Erro!!\n");exit(0);}     
                           else { printf("Documento em  XML e valido.\n");
			   printf("Elem deriva com Abertura Elems Fecho.\n");}
                        }

    |'&' id ';'     {$$=(tcelGrove *)malloc(sizeof(tcelGrove));
		     $$->idElem="entidade";
                     $$->cont.txt=$2;
                     $$->irmao=NULL;
                     printf("A etiqueta foi reconhecida\n");}
    |AberturaFecho   {$$=(tcelGrove *)malloc(sizeof(tcelGrove));
		      $$->idElem=$1->abertId;
                      $$->cont.normal.atributo=$1->atr;
                      $$->cont.normal.conteudo=NULL;
                      $$->irmao=NULL;
                      printf("Elem deriva com AbreturaFecho\n");}
    ;
Txt: caract        {$$=concat2(NULL,$1);
                    printf("Txt deriva com caract\n");}   
    |Txt caract    {$$=concat2($1,$2);
		    printf("Txt deriva com Txt caract\n");}
   ;
Abertura:'<'id Atribs '>' {$$=(tcelAbert*)malloc(sizeof(tcelAbert));
                           $$->abertId=$2;
                           $$->atr=$3;
                           printf("Abertura deriva com < id Atribs >\n");}
    ;  
Fecho:'<''/' id '>'      {$$=$3;
                          printf("Fecho deriva com id\n");}
     ;
AberturaFecho:'<' id Atribs '/''>'{$$->abertId=$2;
                                   $$->atr=$3;
                                   printf("AbF deriva com < id Atribs / >\n");}
	     ;
Atribs:Atribs Atrib   {$$=concat1($1,$2);
                       printf("Atrib e lista de Atribs seguida de Atrib.\n");}
       |         {$$=NULL;
                  printf("Atribs deriva com a producao vazia.\n");}
      ;
Atrib:id '=' Valor {$$=(tcelAtribs *)malloc(sizeof(tcelAtribs));
		    $$->nomeId=$1;
                    $$->val=$3;
                    $$->seg=NULL;
                    printf("Atrib e uma sequencia de id=valor. \n");}
     ;
Valor:id  {$$=$1;
          printf("Valor deriva com identificador.\n");}
     |num {$$=$1;
          printf("Valor deriva com num.\n");}
     |str {$$=$1;
          printf("Valor deriva com string.\n");}
     ;
%%
#include "lex.yy.c"
#include "trabalho1.c"

int yyerror(char *s)
{printf("Texto invalido!%s\n",s);}

main(){
   yyparse();
    ordena(grove);
	}

Trabalho em lex


%{
/*include "y.tab.h"*/
#include <string.h>
#define ERRO -1
%}
%x etiq acaba
%%
"<"                {BEGIN(etiq); return('<');}
"&"                {BEGIN(etiq); return('&');}
\n                 {BEGIN(acaba);}
<acaba><<EOF>>     {yyterminate();}
<acaba>.           {BEGIN(0);yyless(0);return(caract);}
.                  {yylval.car=yytext[0];return(caract);} 
<etiq>">"          {BEGIN(0); return('<');}   
<etiq>";"          {BEGIN(0); return(';');}
<etiq>"/"          {return('/');}
<etiq>"="          {return('=');}
<etiq>[a-zA-Z][a-zA-Z0-9]*     {yylval.valor=strdup(yytext);
                                 return(id);}
<etiq>[0-9]+         {yylval.valor=strdup(yytext);return(num);}
<etiq>\"[^"]*\"      {yylval.valor=strdup(yytext);return(str);}
<etiq>[ \t\n]   ;
<etiq>.              {return (ERRO);}
%%

Grove


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/******************* concatenar atributos ********************************/


taptAtribs ultimoL(taptAtribs ls)
{ 
  if(ls->seg!=NULL)
    {
      return(ultimoL(ls->seg));
    }
  else {
     return(ls);
  }
}

taptAtribs concat1(taptAtribs ls, taptAtribs n){
  taptAtribs aux;
  if(ls!=NULL){
    aux=(taptAtribs)ultimoL(ls);
    aux->seg=n;}
  else {ls=n;}
  return(ls);
}
		


/**************************** concatenar elementos ********************/ 

	        
taptGrove ultimoElem(taptGrove ls)
{
  if(ls->irmao!=NULL)
    {
      return(ultimoElem(ls->irmao));
    }
  else {
    return(ls);
  }
}


taptGrove concat3(taptGrove ls, taptGrove n)
 { taptGrove aux;
   if(ls!=NULL){
    aux=(taptGrove)ultimoElem(ls);
    aux->irmao=n;}
   else {ls=n;}
  return(ls);
}




/********************** concatenar  um caracter a um texto **************/




char *concat2(char *frase, char c){
  int res,j=0;
  char *nova=NULL;
  if(frase!=NULL){
       res=strlen(frase);
       nova=(char*)malloc(res+2);
       while(j <res)
       {nova[j]=frase[j];
       j++;
       }
     nova[j++]=c;
     nova[j]='\0';}
  else{ res=1;
       nova=(char*)malloc(res+2);
       nova[0]=c;
       nova[1]='\0';
     }
  free(frase);
  return(nova);
		
}



void imprime(taptAtribs at)
{
  if (at!=NULL)
    {printf(" %s %s\n",at->nomeId,at->val);
    imprime(at->seg);
    }
}

void ordena (taptGrove grove)
{
if(grove!=NULL)
  {if ((strcmp(grove->idElem,"sequencia")!=0) && (strcmp(grove->idElem,"entidade")!=0))
    {printf("( %s\n",grove->idElem);
    imprime(grove->cont.normal.atributo);
    ordena(grove->cont.normal.conteudo);
    printf(") %s\n",grove->idElem);
    }
  else {printf(" -->  %s\n",grove->cont.txt);}
  ordena(grove->irmao);
  }
}

EXEMPLOS DE EXECUCAO


Exemplo 1

<texto>
<data> um de abril do ano dois mil</data>
<corpo> E o dia das mentiras </corpo>
<fecho> E para nao esquecer
</texto>

EXECUCAO

Atribs deriva com a producao vazia.
Abertura deriva com < id Atribs >
Txt deriva com caract
Elem deriva com Txt
Elems deriva com Elem
Atribs deriva com a producao vazia.
Abertura deriva com < id Atribs >
Txt deriva com caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Elem deriva com Txt
Elems deriva com Elem
Fecho deriva com id
Documento em  XML e valido.
Elem deriva com Abertura Elems Fecho.
Elems deriva com Elems Elem
Txt deriva com caract
Elem deriva com Txt
Elems deriva com Elems Elem
Atribs deriva com a producao vazia.
Abertura deriva com < id Atribs >
Txt deriva com caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Elem deriva com Txt
Elems deriva com Elem
Fecho deriva com id
Documento em  XML e valido.
Elem deriva com Abertura Elems Fecho.
Elems deriva com Elems Elem
Txt deriva com caract
Elem deriva com Txt
Elems deriva com Elems Elem
Atribs deriva com a producao vazia.
Abertura deriva com < id Atribs >
Txt deriva com caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Elem deriva com Txt
Elems deriva com Elem
Fecho deriva com id
Erro!!

//Obs: Este exemplo e invalido, porque propositadamente nao foi fechada uma marca, logo o reconhecedor da "ERRO" e consequetemente nao e gerado o ESIS. //




Exemplo 2


<datas>
<data> <dia> 27 <mes> marco </mes> <ano> 2000 </ano> </dia> </data>
<data1> <dia1> 18 <mes1> agosto </mes1> <ano1> 1999 </ano1> </dia1> </data1>
</datas>

EXECUCAO

Atribs deriva com a producao vazia.
Abertura deriva com <id Atribs >
Txt deriva com caract
Elem deriva com Txt
Elems deriva com Elem
Atribs deriva com a producao vazia.
Abertura deriva com <id Atribs >
Txt deriva com caract
Elem deriva com Txt
Elems deriva com Elem
Atribs deriva com a producao vazia.
Abertura deriva com <id Atribs >
Txt deriva com caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Elem deriva com Txt
Elems deriva com Elem
Atribs deriva com a producao vazia.
Abertura deriva com <id Atribs >
Txt deriva com caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Elem deriva com Txt
Elems deriva com Elem
Fecho deriva com id
Documento em  XML e valido.
Elem deriva com Abertura Elems Fecho.
Elems deriva com Elems Elem
Txt deriva com caract
Elem deriva com Txt
Elems deriva com Elems Elem
Atribs deriva com a producao vazia.
Abertura deriva com <id Atribs >
Txt deriva com caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Elem deriva com Txt
Elems deriva com Elem
Fecho deriva com id
Documento em  XML e valido.
Elem deriva com Abertura Elems Fecho.
Elems deriva com Elems Elem
Txt deriva com caract
Elem deriva com Txt
Elems deriva com Elems Elem
Fecho deriva com id
Documento em  XML e valido.
Elem deriva com Abertura Elems Fecho.
Elems deriva com Elems Elem
Txt deriva com caract
Elem deriva com Txt
Elems deriva com Elems Elem
Fecho deriva com id
Documento em  XML e valido.
Elem deriva com Abertura Elems Fecho.
Elems deriva com Elems Elem
Txt deriva com caract
Elem deriva com Txt
Elems deriva com Elems Elem
Atribs deriva com a producao vazia.
Abertura deriva com <id Atribs >
Txt deriva com caract
Elem deriva com Txt
Elems deriva com Elem
Atribs deriva com a producao vazia.
Abertura deriva com <id Atribs >
Txt deriva com caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Elem deriva com Txt
Elems deriva com Elem
Atribs deriva com a producao vazia.
Abertura deriva com <id Atribs >
Txt deriva com caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Elem deriva com Txt
Elems deriva com Elem
Fecho deriva com id
Documento em  XML e valido.
Elem deriva com Abertura Elems Fecho.
Elems deriva com Elems Elem
Txt deriva com caract
Elem deriva com Txt
Elems deriva com Elems Elem
Atribs deriva com a producao vazia.
Abertura deriva com <id Atribs >
Txt deriva com caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Txt deriva com Txt caract
Elem deriva com Txt
Elems deriva com Elem
Fecho deriva com id
Documento em  XML e valido.
Elem deriva com Abertura Elems Fecho.
Elems deriva com Elems Elem
Txt deriva com caract
Elem deriva com Txt
Elems deriva com Elems Elem
Fecho deriva com id
Documento em  XML e valido.
Elem deriva com Abertura Elems Fecho.
Elems deriva com Elems Elem
Txt deriva com caract
Elem deriva com Txt
Elems deriva com Elems Elem
Fecho deriva com id
Documento em  XML e valido.
Elem deriva com Abertura Elems Fecho.
Elems deriva com Elems Elem
Txt deriva com caract
Elem deriva com Txt
Elems deriva com Elems Elem
Fecho deriva com id
Documento XML valido.
( datas
 -->  (
( data
 -->   
( dia
 -->   27 
( mes
 -->   marco 
) mes
 -->   
( ano
 -->   2000 
) ano
 -->   
) dia
 -->   
) data
 -->  
( data1
 -->   
( dia1
 -->   18 
( mes1
 -->   agosto 
) mes1
 -->   
( ano1
 -->   1999 
) ano1
 -->   
) dia1
 -->   
) data1
 -->  
) datas

//Obs: Este exemplo e valido e consequentemente e construido o respectivo ESIS.
//

// So mostramos neste relatorio estes dois exemplos de execucao por acharmos serem suficientes para demonstrarem o fucionamento do nosso reconhecedor. 



Agradecimentos:

Em primeiro lugar temos que agradecer aos professor Pedro Rangel Henriques que nos ajudou imenso, tirando-nos algumas dúvidas sobre como implementar este conversor e ajudando-nos a resolver alguns erros que foram surgindo durante a execução do programa. Gostariamos igualmente de agradecer ao professor José Carlos Ramalho. Finalmente, gostariamos de agradecer aos nossos colegas que nos foram exclarecendo algunas dúvidas.

Bibliografia: