Processador de Documentos estruturados XML (Etapa 2)

Abril de 2000

Carlos Miguel Marques Barroso

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

Sérgio Mauro Serrenho

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

Rui Jorge Torre Lameiro

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

Resumo:


Índice

  1. Introducao
  2. Codigo Fonte
    1. tokenizer.lex
    2. grammar.y
    3. makefile
    4. main.c

Introducao

O objectivo desta fase do trabalho e o de implementar um processador de documentos estruturados XML que depois de validar o documento guarda a informacao numa estrutura de dados.

Esta fase e constituida por tres etapas:

ETAPA 1

O objectivo desta etapa e o de construir um analisador lexico (usando para tal a ferramenta lex) e um analisador sintactico (usando para tal a ferramenta yacc).

ETAPA 2

Nesta segunda etapa foram implementadas no analisador validacoes que obrigam o documento a comecar e acabar com a TAG DOC e a que todas as TAGS sejam abertas e fechadas correctamente.

ETAPA 3

Esta etapa nao sera apresentada neste relatorio devido a acontec imentos imprevistos. No caso de alguns devido ao CeNPL2000 noutr o caso devido a uma intervencao cirurgica com um tempo de repous o algo demorado.

Esta etapa sera entregue posteriormente, juntamente com a 2 fase.


Codigo Fonte

tokenizer.lex


%{
#include <glib.h>
#include <string.h>
#include "y.tab.h"

GString	*strtxt;

%}

%option yylineno

%s TAG TXT

ID	[a-zA-Z][a-zA-Z\-\_0-9]*
Value	\".+\"
TID	\&{ID}\;

%%

\<		{
			if (strtxt) {
				yylval.g_string = strtxt;
				strtxt = NULL;
				unput ('<');
				return(TEXT);
			} else {
				BEGIN(TAG);
				return(*yytext);
			}
		}

<TAG>\>		{
			BEGIN(TXT);
			return(*yytext);
		}

<TAG>{ID}	{
			yylval.string = (char *) strdup(yytext);
			return(ID);
		}

<TAG>\/		{
			return(*yytext);
		}

<TAG>=		{
			return(*yytext);
		}

<TAG>{Value}	{
			BEGIN(TAG);
			yylval.string = (char *) strdup(yytext);
			return(VALUE);
		}

<TAG>[\ \t\n]*	;

<TAG>.		{
			return(ERROR);
		}

<TXT>[^\<\&]{1,255} {
			if (!strtxt) strtxt = g_string_new("");
			strtxt = g_string_append(strtxt, yytext);
		}

<TXT>\&		{
			if (!strtxt) strtxt = g_string_new("");
			strtxt = g_string_append(strtxt, yytext);
		}

<TXT>{TID}	{
			yylval.string = (char *) strdup(yytext);
			return(TID);
		}

<<EOF>>		{
			return(0);
		}

.		{
			return(ERROR);
		}




%%

int yywrap() {
	return(1);
}
        

grammar.y


%{
#include <glib.h>
#include <string.h>
#include <stdio.h>

#define	SYN_ERROR	"Syntax Error"
#define SEM_ERROR	"Semantic Error"

extern int	yylineno;

char		*error_type = SYN_ERROR;
GString		*error_mesg;

%}

%union
    {
	char	*string;
	GString	*g_string;
    }

%token		  ERROR
%token <string>   ID VALUE TID
%token <g_string> TEXT

%start DocXML

%%

DocXML :    '<' ID
	    {
		if (strcmp($2,"DOC")) {
		    error_type = SEM_ERROR;
		    error_mesg = g_string_new("Document must start with <DOC>");
		    yyerror(NULL);
		}
	    }
	    '>' ElemList '<' '/' ID '>'
	    {
		if (strcmp($8,"DOC")) {
		    error_type = SEM_ERROR;
		    error_mesg = g_string_new("Document must finish with </DOC>");
		    yyerror(NULL);
		}
		printf("*** This is a valid XML Document. ***\n");
	    };

ElemList :  ElemList Elem
	  | ;

Elem :	    TID
	  | '<' ID AttrList '>' ElemList '<' '/' ID AttrList '>'
	    {
		if (strcmp($2,$8)) {
		    error_type = SEM_ERROR;
		    error_mesg = g_string_new("</");
		    error_mesg = g_string_append(error_mesg, $8);
		    error_mesg = g_string_append(error_mesg, "> does not match with previous <");
		    error_mesg = g_string_append(error_mesg, $2);
		    error_mesg = g_string_append(error_mesg, ">");
		    yyerror(NULL);
		}
	    }
	  | '<' ID AttrList '/' '>'
	  | TEXT ;

AttrList :  AttrList Attr
	  | ;

Attr :	    ID '=' VALUE ;

%%

int yyerror(char *msg) {
	fprintf (stderr, "%d: %s.\n", yylineno, error_type);
	if (error_mesg)
		fprintf (stderr, "\t%s\n", *error_mesg);
	if (msg)
		fprintf (stderr, "\tYACC msg: %s\n", msg);
	exit(1);
}
        

makefile


CC = gcc
CFLAGS = -O3 -I/usr/lib/glib/include -ggdb -ansi
OCLIBS = -L/usr/lib
XCLIBS = $(OCLIBS) -lefence -lglib
LEX = flex
YACC = yacc
OBJ = lex.yy.o y.tab.o main.o 

all: parser clean

parser: $(OBJ)
	$(CC) $(CFLAGS) $(XCLIBS) -o parser $(OBJ)

lex.yy.o: lex.yy.c y.tab.h
	$(CC) $(CFLAGS) $(OCLIBS) -c lex.yy.c

lex.yy.c: tokenizer.lex
	$(LEX) tokenizer.lex

y.tab.o: y.tab.c
	$(CC) $(CFLAGS) $(OCLIBS) -c y.tab.c

y.tab.c y.tab.h: grammar.y
	$(YACC) -d grammar.y

main.o: main.c y.tab.h
	$(CC) $(CFLAGS) $(OCLIBS) -c main.c

clean:
	@rm -fr y.tab.?
	@rm -fr lex.yy.?
	@rm -fr main.o
	@rm -fr core
	@echo MSG: Object and temporary files removed.

veryclean: clean
	@rm -fr parser
	@echo MSG: Executable files removed.
        

main.c


#include <stdio.h>
#include <glib.h>
#include "y.tab.h"

main()
{
	yyparse();
}
        

Agradecimentos:

Gostariamos de agradecer aos Professores Jose Carlos Ramalho e Pedro Rangel Henriques a compreensao mostrada por ambos em relacao ao nosso caso.

Bibliografia: