Trabalho Prático de Processamento de Linguagens I

Universidade do Minho 10/04/00

Mário Miguel Azevedo Cerqueira - 24854

E-mail: oMaildoMario@portugalmail.pt

Jorge Miguel Alves Semblano - 22667

E-mail: semblas@yahoo.com

Paulo André Fonseca M Coelho - 16984

E-mail: a16984@ci.uminho.pt

Resumo:

Este trabalho surge no âmbito da disciplina de Processamento de Linguagens I, e consiste na implementação de um processador de documentos estruturados e este relatório refere-se á primeira fase desse trabalho, fase esta que consiste na análise léxica e sintática de um documento XML. Depois verificou-se se o documento é válido ou não, criou-se um grove contendo a informação desse documento, e desenvolveu-se funções para a sua travessia.


Índice

  1. Introdução
  2. Análise léxica
  3. Análise sintática
  4. Anexo I

Introdução

Contido numa importante area das ciências da computação, o processamento de linguagens, este trabalho consistiu em desenvolver um analisador léxico ( lex ) e um analisador sintático ( yacc ), no yacc fizemos as acções semânticas para inserir a informação no grove, este desenvolvido num módulo em C.


Análise léxica

Após uma análise da gramática foram detectados os seguintes simbolos terminais não variáveis e os seguintes terminais variáveis: valor, identificador, texto. Para conseguirmos desenvolver a análise léxica tivemos de introduzir "start conditions" devido a certos conflitos que surgiram entre os identificadores e o texto. Abaixo está um excerto dessa análise:

%%

[ \n\t]+ ;

[/=] { return (*yytext); }

> { BEGIN(CHR); return (*yytext); }

<CHR>[^<&]+ { yylval.texto=(char*) strdup(yytext);

return (CHAR); }

<CHR>& { BEGIN(IDCAR); return('&'); }

<CHR>< { BEGIN(0); return('<'); }

<IDCAR>{IDENT} { yylval.id=(char*) strdup(yytext);

return(ID); }

<IDCAR>; { BEGIN(CHR); return(';'); }

{IDENT} { yylval.id=(char*) strdup(yytext); return (ID); }

{VAL} { yylval.valor=(char*) strdup(yytext); return (VALOR); }

. { return (*yytext); }

%%


Análise sintática

A gramática utilizada na análise sintática foi a que foi apresentada, dado não ter dado qualquer conflito. Para sabermos a informação do analisador léxico tivemos de declarar tokens para os simbolos terminais que atribui um código (número) ao simbolo. Mas para os terminais sobre os quais necessitamos de tirar informação para armazenar no grove temos de definir os tipos dos tokens, bem como passar os valores através do yylval no lex

%token ID VALOR CHAR

%union {

char* id;

char* texto;

char* valor;

atributo* atr;

grove* grv;

}

%type <id> ID

%type <texto> CHAR

%type <valor> VALOR

%type <atr> Attr

%type <atr> AttrList

%type <grv> Elem

%type <grv> ElemList

%type <grv> DOC_XML

Acções semânticas

Para validar a utilização das tags ( nome da tag que abre = nome da tag que fecha ) utilizamos uma stack em C, e á medida que abria uma tag inseria-se na stack (push) e quando uma tag fechava comparavamos essa tag com a que estava no topo da stack e se fossem iguais faziamos um pop da stack. Um outro tipo de implementação seria compararmos o $2 com o $9. Optamos por esta implementação por stack para posteriormente implementar outro tipo de funcionalidades para controlo de erros e por qualquer altera,ção da gramática.

GROVE

Para este item foi adoptada a estrutura disponibilizada nas aulas. Esta implementação está sujeita a posteriores alterações como por exemplo a indexação dos nodos do grove através de uma tabela de hash para melhorar a procura, outra optimização poderá ser guardar no campo informação um apontador para um ficheiro em vez de guardar o texto todo em memória..

typedef struct Anodo {

char *nome;

char *valor;

struct Anodo* seg;

} atributo;

typedef union C {

char *texto;

struct X {

struct Gnodo *conteudo;

atributo *atribs;

} normal;

} conteudos;

typedef struct Gnodo {

char *id;

conteudos cont;

struct Gnodo *irmaos;

} grove;

#define ATRBS(n) n->cont.normal.atribs

#define MANOS(n) n->irmaos

#define CONT(n) n->cont

#define NEXTCONT(n) n->cont.normal.conteudo

#define IDG(n) n->id

char* getTexto(grove* g);

atributo* criaAtributo( char* nome, char* valor );

atributo* insLista( atributo* lista, atributo* nodo );

grove* criaGnodo( char* id, conteudos c, grove* manos );

grove* insMano(grove* g, grove *n);

conteudos criaConteudoNormal(atributo* atrs, grove* g);

int show(grove* g);

int showAtribs(atributo* atrs);


Anexo I

Analisador Sintático

%{

#include "grove.c"

%}

%token ID VALOR CHAR

%union {

char* id;

char* texto;

char* valor;

atributo* atr;

grove* grv;

}

%type <id> ID

%type <texto> CHAR

%type <valor> VALOR

%type <atr> Attr

%type <atr> AttrList

%type <grv> Elem

%type <grv> ElemList

%start DOC_XML

%%

DOC_XML : '<' ID AttrList '>' {push(&stck,$2);} ElemList '<' '/' ID '>'

{verif_tag($9); show($6);

if (valido==1) printf("\nDocumento XML Valido!!\n");exit(0);}

;

ElemList : ElemList Elem {$$ = insMano($1, $2);}

| Elem {$$ = insMano(NULL, $1);}

;

Elem : CHAR { $$ = NULL; }

| '&' ID ';' { $$ = NULL; }

| '<' ID AttrList '>' {push(&stck,$2);} ElemList '<' '/' ID '>'

{verif_tag($9); $$ = criaGnodo($2, criaConteudoNormal($3, $6), NULL);}

| '<' ID AttrList '/' '>' { $$ = NULL; }

;

AttrList : Attr AttrList {$$ = insLista($2, $1);}

| {$$ = NULL;}

;

Attr : ID '=' VALOR {$$ = criaAtributo($1, $3);} ;

%%

#include <stdio.h>

#include "stack.c"

stack stck;

int valido = 1;

void main(void)

{

init(&stck);

yyparse();

}

void verif_tag(char* tag) {

char *st = strdup (top(&stck));

if ( st!=NULL)

{

if ( strcmp( tag, st)!=0 )

{

printf(">%d<Erro no documento, esperava-se #%s# e nao #%s#>\n",

line(),st,tag);

valido = 0;

}

pop(&stck);

}

}

yyerror(char *s)

{

printf(">%d<ERRO: nao esperado #%s#>: %s\n",line(), texto(), s);

}


Agradecimentos: Bibliografia: