Resumo:
Este relat´orio corresponde à primeira fase do trabalho da disciplina de Processamento de Linguagens I, que consiste na implementação de um Processador Gen´erico de Documentos Estruturados
O objectivo desta primeira fase é o de implementar uma ferramenta que analise documentos estruturados e construa uma estrutura de dados( Grove ) com toda a informação do mesmo. Esta fase estava dividida em 3 etapas, as quais descreveremos detalhadamente posteriormente.
Nesta etapa era-nos pedido a contrução de uma analisador l´exico e sint´actico, usando as ferramentas LEX + YACC para a seguinte gram´atica:
Documento : ElemList '$'
ElemList : ElemList Elem
| Elem
Elem : char
| '&' id ';'
| '<' id AttrList '>' ElemList '<' '/' id '>'
| '<' id AttrList '/' '>'
AttrList : Attr AttrList
|
Attr : id '=' valor
Fizemos as alterações à gram´atica que achamos necess´arias para tornar o nosso programa mais funcional resultando em:
Documento : ElemList '$'
ElemList : ElemList Elem
|
Elem : Texto
| '&' ID ';'
| '<' ID AttrList Composto
Texto : Texto CHAR
|CHAR
|E
Composto : '>' ElemList '<' '/' ID '>'
| '/' '>'
AttrList : AttrList Attr
|
Attr : ID '=' VALOR
Nesta etapa t´inhamos que fazer algumas validções: - todas as anotações correspondentes a elementos com conteúdo são abertas e fechadas correctamente; - o documento tem que obrigatoriamente começar com a abertura dum elemento (que irá englobar todo o documento).
Para a primeira validação fizemos:
| '<' ID AttrList Composto {if($4 != NULL && strcasecmp($2,$4->id) != 0){
printf("\nIdentificador %s aberto e %s a termina-lo\n",$2,$4->id);
exit(0);}
...
Para a segunda criamos um estado em Lex que apenas aceita que os documentos comecem por uma Tag:
\<{id}\> {yyless(0);BEGIN B;}
Nesta etapa t´inhamos que fazer o armazenamento de toda a informação num grove. Decidimos algumas alterações na estrutura de dados oferecida pelo professor. Criamos apontadores para a ´ultima posição da lista de atributos e para a ´ultima posição do grove, de modo a facilitar a concatenação dos v´arios elementos. Sendo assim ficamos com a seguinte estrutura:
typedef struct Anodo{
char* nome;
char* valor;
struct Anodo* seg;
struct Anodo* ult;
}atributo;
typedef struct Gnodo{
char* id;
union C{
char* texto; /* para nodos _texto */
struct X{ /* para os outros nodos */
struct Gnodo* conteudo;
atributo* atribs;
}normal;
}cont;
struct Gnodo* irmaos;
struct Gnodo* ultimo;
}grove;
Fizemos tb as seguintes funções para percorrer todo o grove e gerar um documento no formato ESIS. Temos tb uma função que retira tamb´em alguns caracteres indesejados antes de inserir no grove(ex. \n, espaços,...).
void percorreaux(atributo *a); void corta_espacos_dir( char *command ); void percorre(grove *g1);
De uma maneira geral fic´amos satisfeitos com a nossa resolução, pois pensamos que cumprimos os objectivos pedidos pelo docente na totalidade.
Apesar de nos termos deparado com algumas dificuldades na parte inicial, com alguma investigação conseguimos ultrapassa-las e construir um trabalho que nos satisfaz plenamente.
Só queriamos pedir desculpa pela simplicidade deste relat´orio mas ela justifica-se por se tratar de um relat´orio interm´edio e não do relat´orio final.
Aguard´amos ansiosamente a segunda fase do trabalho.
char [^\&\<]
id [a-zA-Z][a-zA-Z0-9\-]*
valor \"[^\"]*\"
%x A B C
%%
\<{id}\> {yyless(0);BEGIN B;}
<B>\&\& {printf("%s",yytext);yylval.string=(char*)strdup(yytext);return(E);}
<B>\\\& {printf("%s",yytext);yylval.string=(char*)strdup(yytext);return(
E);}
<B>[\<\&] {printf("%c",*yytext);BEGIN A;return((char)*yytext);}
<A>{id} {printf("%s",yytext);yylval.string=(char *)strdup(yytext);return(ID);}
<A>[\>\;] {printf("%c",*yytext);BEGIN B;return((char)*yytext);}
<A>[\=\/] {printf("%c",*yytext);return((char)*yytext);}
<A>{valor} {yylval.string=(char*)strdup(yytext);printf("%s",yytext);return(VALOR);}
<B><<eof>> {return('$');exit(0);}
<B>{char} {yylval.car=(char)*yytext;printf("%c",*yytext);return(CHAR);}
. {printf("O Documento tem que comecar com uma tag\n");exit(0);}
%%
%{
#include "grove.c"
grove *g;
char *s,c;
%}
%union
{
char car;
char *string;
grove *gr;
atributo *at;
}
%token <car> CHAR
%token <string> ID VALOR E
%type <gr> ElemList Elem Composto
%type <at> Attr AttrList
%type <string> Texto
%start Documento
%%
Documento : ElemList '$' {g = $1;printf("CHEGOU AO FIM\n");}
ElemList : ElemList Elem {//printf("\nElemList Elem\n");
if($1 != NULL && $2 != NULL){
$1->ultimo->irmaos = $2;
$1->ultimo = $2;
$$ = $1;
}else if($2 != NULL){
$$ = $2;
}else{
$$ = $1;
}
}
| {//printf("\nElemList\n");
$$ = NULL;}
Elem : Texto {//printf("\nElem Texto\n");
$$ = (grove *)malloc(sizeof(struct Gnodo));
$$->id = NULL;
$$->cont.texto = (char *)strdup($1);
corta_espacos_dir($$->cont.texto);
$$->irmaos = NULL;
$$->ultimo = $$;
if($$->cont.texto[0] == '\0'){$$ = NULL;}
}
| '&' ID ';' {//printf("\nElemId\n");
$$=(grove *)malloc(sizeof(struct Gnodo));
$$->id=(char *)strdup($2);
$$->cont.normal.conteudo = NULL;
$$->cont.normal.atribs = NULL;
$$->irmaos = NULL;
$$->ultimo = $$;}
| '<' ID AttrList Composto {//printf("\nElemAttCom\n");
if($4 != NULL && strcasecmp($2,$4->id) != 0){
printf("\nIdentificador %s aberto e %s a termina-lo\n",$2,$4->id);
exit(0);
}else{
if($4 == NULL){
$$=(grove *)malloc(sizeof(struct Gnodo));
$$->id=(char *)strdup($2);
$$->cont.normal.conteudo = NULL;
$$->cont.normal.atribs = $3;
$$->irmaos = NULL;
$$->ultimo = $$;
}else{
$4->cont.normal.atribs = $3;
$$ = $4;
}
}
}
Texto : Texto CHAR {//printf("\nTexto Char\n");
s = (char *)strdup("a");
s[0] = $2;
$$ = (char *)strcat($1,s);
//printf("\t%s\n",$$);
}
|CHAR {//printf("\nChar\n");
$$ = (char *)strdup("a");
$$[0] = $1;
//printf("%s\n",$$);
}
|E {
$$ = (char *)strdup($1);
}
Composto : '>' ElemList '<' '/' ID '>' {//printf("\nComp ElemL\n");
$$=(grove *)malloc(sizeof(struct Gnodo));
$$->id=(char *)strdup($5);
$$->cont.normal.conteudo = $2;
$$->cont.normal.atribs = NULL;
$$->irmaos = NULL;
$$->ultimo = $$;}
| '/' '>' {//printf("\nComp \n");
$$=NULL;}
AttrList : AttrList Attr {//printf("\nAttrLAtt\n");
if($1 != NULL){
$1->ult->seg = $2;
$1->ult = $2;
$$ = $1;
}else{
$$ = $2;
}
}
| {//printf("\nAttrNull\n");
$$ = NULL;}
Attr : ID '=' VALOR {//printf("\nAttr Id V\n");
$$ = (atributo *)malloc(sizeof(struct Anodo));
$$->nome = (char *)strdup($1);
$$->valor = (char *)strdup($3);
$$->ult = $$;
$$->seg = NULL;}
%%
#include "lex.yy.c"
grove *g;
void percorreaux(atributo *a){
if(a != NULL){
printf("A %s %s\n",a->nome,a->valor);
percorreaux(a->seg);
}
}
void corta_espacos_dir( char *command )
{
int i, encontrou = 0 ;
i = ( strlen( command ) - 1 ) ;
while( ( i >= 0 ) && ( encontrou == 0 ) )
{
if( ( command[i] != ' ' ) && ( command[i] != '\n' ) && (command[i] != '\t'))
{
command[i + 1] = '\0' ;
encontrou = 1 ;
}
else if( i == 0 )
// Neste caso, o comando e formado apenas por "\s" e
// "\n".
command[i] = '\0' ;
i-- ;
}
}
void percorre(grove *g1){
if(g1 != NULL){
if(g1->id == NULL){
printf("-%s\n",g1->cont.texto);
percorre(g1->irmaos);
}else{
printf("(%s\n",g1->id);
percorre(g1->cont.normal.conteudo);
percorreaux(g1->cont.normal.atribs);
printf(")%s\n",g1->id);
percorre(g1->irmaos);
}
}
}
main(){
yyparse();
printf("\n\n");
percorre(g);
}
yyerror(char *s){
printf("%s\n",s);
}
typedef struct Anodo{
char* nome;
char* valor;
struct Anodo* seg;
struct Anodo* ult;
}atributo;
typedef struct Gnodo{
char* id;
union C{
char* texto; /* para nodos _texto */
struct X{ /* para os outros nodos */
struct Gnodo* conteudo;
atributo* atribs;
}normal;
}cont;
struct Gnodo* irmaos;
struct Gnodo* ultimo;
}grove;