Resumo:
Esta é a primeira fase do trabalho semestral da cadeira de Processamento de Linguagens I. Nesta fase tivemos que implementar um conversor de XML para ESIS.
A realização deste projecto foi proposta em três fases. A primeira fase consistia na implementação dum conversor de documentos XML para documentos ESIS. Foram utilizadas as ferramentas flex e bison, para a concepção do motor que executa a analise sintatica dos documentos XML.
Dada a gramática que define o problema, ou seja, a da linguagem XML, tivemos que fazer a sua análise léxica. Esta análise teve que ser contextualizada para que fosse possivel diferenciar o texto que se encontra dentro e fora das tags. Recorremos portanto a "start conditions" (condições de contexto) para poder fazer uma análise correcta do texto de entrada. Para isto utilizamos apenas dois estados, um que define a zona do texto que se encontra no interior de uma tag (definido respectivamente por <texto>) e outro para o texto exterior. O texto cru (aquele que se encontra entre um abrir tag e fechar tag) teve que ser acumulado numa variavel do tipo char * para posteriormente ser retornado para o bison e constituir uma celula basica do grove. Em relação á análise sintática poucas alterações foram introduzidas. Apenas tivemos que converter da forma BNF para o formato do bison (YACC). Incluimos algumas novas produções para garantir o perfeito funcionamento da aplicação, como por exemplo, a capacidade de ter linhas em branco antes e depois do documento XML, poder ter tags vazias de informação, etc...
A análise semântica é assegurada por uma estrutura de dados do tipo stack, que permite a detecção de tags cruzadas, bem como a garantia de que todas as tags que são abertas são mais tarde fechadas: exemplo de tags cruzadas: <a> <b> </a> </b>
Na criação do grove utilizamos um modulo de listas (LibList-v1.2) para acumular os irmãos dos nodos. Aproveitamos a recusividade implícita do bison, e recorremos a algumas primitivas que nos permitiam ir criando o grove. Estas primitivas permitem criar um nodo para cada tipo de token que podemos encontrar.
TAttribute createAttributeNode(char *ident, char *value);
Produçao : Attr: IDENT '=' VALUE
TGroveNode createTextNode(char *text);
Produçao : Elem: TEXT
TGroveNode createSpecialCharNode(char *specialchar);
Produçao : Elem: SPECIALCHAR
TGroveNode createComplexTagNode(char *ident, TAttributeList attr);
Produçao : Elem: TagOpen ElemList TagClose
Produçao : Elem: TagOpen TagClose
TGroveNode createSimpleTagNode(char *ident, TAttributeList attr);
Produçao 5: Elem: '<' IDENT AttrList '/' '>'
A travessia do grove permite-nos gerar o documento ESIS.
Estrutura de dados utilizada para armazenar o grove:
typedef struct _TAttribute_ { char *ident; char *value; } TAttribute, *TAttributePtr;
typedef struct _TGroveSimpleNode_ { char *ident; TAttributeList attributes; } TGroveSimpleNode;
typedef struct _TGroveComplexNode_ { char *ident; TGrove child; TAttributeList attributes; } TGroveComplexNode;
typedef union _TGroveContent_ { char *text; char *specialchar; TGroveSimpleNode simpletag; TGroveComplexNode complextag; } TGroveContent;
typedef struct _TGroveNode_ { int type; // TEXT, SPECIALCHAR, COMPLEXTAG, SIMPLETAG TGroveContent content; } TGroveNode, *TGroveNodePtr;Figura:
Figura:
Figura:
Figura:
Figura:
Tentamos a todo o custo ter um bom sistema de mensagens de erro, para que seja simples ao utilizador descubrir a linha e o tipo de erro que o seu texto contem.
Tentamos tambem garantir que todos os casos possíveis fossem aceites como válidos: exemplo de uma tag válida :
<a atr = " atributo">
Procuramos garantir a aceitação de documentos que contenham erros do tipo linhas em branco antes e depois do documento, aspas nao terminadas, etc...
Nesta primeira fase pouco se pode concluir, no entanto e' uma das mais importantes do projecto. É nesta fase que construimos o motor que irá suportar toda a funcionalidade do programa final. Deve portanto ser consistente, pois um erro cometido poderá prejudicar a totalidade do projecto.