U N l V E R S l D A D A U T ó N O M A M E T R O P O L I T A N A UNIDAD tZTAPALAFA PROYECTO TERMINAL DE LA LICENCIATURA EN COMPUTACI6N

63 

Texto completo

(1)

U N l V E R S l D A D A U T ó N O M A M E T R O P O L I T A N A

U N I D A D t Z T A P A L A F A

PROYECTO TERMINAL DE LA LICENCIATURA EN COMPUTACI6N

SISTEMA DE A W f S T C I 6 M DE CONOCIMIENTOS PARA SISTEMAS EXPERTOS

M A N U A L T € C M I C O

ASESORES: ELIZABETH P€REZ CORTES JOHNGODDARD RENE MACKINNEY

ALUMNOS: BEJARANO LUNA JOS€ MIGUEL

(2)

P&S

INTRODUCC16N ... i

1

.

SISTEMAS EXPERTOS

...

3

II

.

SHELL

...

6

Ill

.

SISTEMA DE ADQUlSlCldN DE CONOCIMIENTO

...

8

CONCLUSIONES

...

56

APENDICE A LEX

...

58

APiNDlCE B YACC

...

60

(3)

Un Sistema Experto es un programa que procede como un experto para algunos problemas de algún drea de dominio.

Un Sistema Experto tiene tres componentes principales:

(1 1 Una base de conocimiento, (2) Una mtlquina de inferencia,

(3) Una interface de usuario.

Un Sistema de Adquisicidn de Conocimientos (SAC) es una interfaz entre el usuario y la base

de

conocimiento.

En este manual se explica en que consiste el Sistema de Adquisicidn de Conocimientos hecho por nosotros, y que herramientas utilizamos en su eíaboracidn.

Hay varias formas de representar el conocimiento acerca de algun drea del saber. Nos

parecid mas adecuado elegir una gramatica en Lenguaje Natural para representar el

conocimiento, porque asf es fdcil para el usuario introducirlo en la base de conocimiento. Los Sistemas Expertos son usados en aplicaciones de diagn6stico medico, localizaci6n de fallas en equipo mecdnico, mMico, etc., para interpretar la medicidn de datos, para ayudar a tomar decisiones de planeacidn financiera, subscribir polizas de seguros, y tambien llevan a

cabo otros servicios que requieren de un experto humano.

El Sistema de Adquisici6n de Conocimientos es útil para un experto que lo utilice para atmacenar informaci6n de a l g h &ea del conocimiento, pues le permite introducir la informacidn a la base de conocimiento de una manera natural, gracias a una gramdtica establecida.

Una vez que el experto introduce la informacidn de acuerdo a la gramdtica establecida; Bsta se transforma a una manera reconocible por la mtlquina de inferencia de Prolog y se guarda en la base de conocimiento.

Este manual esta dirigido a aquellas personas que tengan nociones de Sistemas Expertos, lenguaje de programacion C y Prolog.

Para aquellas personas que quieran tener un panorama mtls amplio de lo que realiza un Sistema Experto pueden referirse a la bilbiografía presentada al final de este manual.

A continuacidn mencionamos los objetivos que se pretenden en este proyecto.

Objetivo General:

Construir una herramienta con la cual se le permita al usuario introducir informacidn a la base de conocimiento, por medio de Lenguaje Natural.

(4)

- Construir una herramienta para adquisicibn de conocimiento que sea compatible con la msquina de inferencia de Prolog.

(5)

I . S I S T E M A S E X P E R T O S

Un Sistema Experto es un programa que emula a un experto en algOn dominio de aplicaci6n limitado. Los Sistemas Expertos tienen que ser capaces de resolver problemas que requieren conocimiento experto en un dominio particular, y deben poseer ese conocimiento en alguna forma. Un Sistema Experto tambien tiene que ser capaz, de alguna manera, de explicar su comportamiento y sus decisiones al usuario, como los expertos humanos lo hacen.

Dar explicaciones es especialmente necesario en dominios inciertos para aumentar la confianza del usuario en la advertencia del sistema, o para facilitar al usuario detectar posibles defectos en el razonamiento del sistema. Por lo tanto, los sistemas expertos deben tener una favorable capacidad de interacci6n con el usuario; lo que hard el razonamiento del sistema transparente al usuario.

Un Sistema Experto, como ya se dijo, tiene tres componentes principales: (1 1 Una base de conocimiento,

(21 Una msquina de inferencia, (3) Una interfaz de usuario.

Una base de conocimiento es una representacidn declarativa del experto, a menudo en reglas SI ENTONCES. Comprende el conocimiento que es específico para el dominio de aplicacibn, incluyendo cosas tales como simples hechos, reglas que describen relaciones o

fen6menos, y posiblemente tambien metodos y heurísticas para resolver problemas en este dominio.

Una mdquina de inferencia es el c6digo en el núcleo del sistema que deriva recomendaciones a partir de la base de conocimiento y datos de un problema específico. Esta sabe como usar activamente el conocimiento en la base.

Una interfaz de usuario es el cddigo que controla el didlogo entre el usuario y el sistema. Provee igual comunicaci6n entre el usuario y el sistema, y permite al usuario comprender el proceso de resoluci6n del problema llevado fuera por la mdquina de inferencia.

A la mdquina de inferencia junto con la interface de usuario generalmente se le llama shell del sistema experto, o simplemente un shell.

A continuacidn se presenta un esquema con la estructura de los Sistemas Expertos:

Base de

usuario

inferencías

conocimientos

lnterfaz

de

"---)-

Máquina

de

Shell

(6)

Las funciones típicas que realiza un Sistema Experto son:

- Solucidn de problemas en un drea de conocimiento específico

-

Explicaci6n del proceso de soluci6n del problema

Una funci6n adicional que con frecuencia realiza un sistema experto es tratar con incertidumbre e incompletitud. La informaci6n acerca del problema a ser resuelto puede ser incompleta o inconfiable; las relaciones en el dominio del problema pueden ser aproximadas. Por ejemplo, podemos no estar del todo seguros de que algún síntoma este presente en un paciente, o de que algunas mediciones de datos sean absolutamente correctas; alguna droga puede causar algún problema, pero generalmente no. Todo esto requiere razonamiento probabilístico.

Muchas veces en problemas de selecci6n estructurada la respuesta final no es conocida con completa seguridad. Las reglas del experto podrían ser vagas, y el usuario podría estar inseguro de las respuestas a las preguntas. Esto puede ser visto fdcilmente en los sistemas de diagndstico medico donde el experto no es capaz de ser preciso acerca de la relacidn entre los síntomas y las enfermedades. De hecho, el medico podría ofrecer múltiples diagn6sticos posibles.

Para que los Sistemas Expertos trabajen en el mundo real ademas deben ser capaces de tratar con incertidumbre. Uno de los esquemas mds simples es asociar un valor numerico con cada pieza de informaci6n en el sistema. El valor numerico representa la certeza con la cual la informacidn es conocida.

Hay numerosas maneras en las cuales pueden ser definidos esos números, y cbmo ellos son combinados durante el proceso de inferencia.

(7)

A continuaci6n se presenta un ejemplo :

Supongamos que los factores de certidumbre (precedidos por cf) son números enteros. si las luces estdn bajas

entonces la batería est3 mal cf 50 si hay dolor de cuerpo y

entonces hay resfriado cf 90

fiebre alta

Sería natural emplear probabilidades reales en lugar de asignar números a la informacibn, pero entonces surgen problemas por las siguientes razones:

-

Los expertos humanos parece que tienen dificultades al pensar en tkrminos de probabilidades reales; sus estimaciones de probabilidad no corresponden del todo a

las

probabilidades definidas matemdticamente.

(8)

El shell es una pieza de software que contiene la interfaz de usuario, un formato para representar el conocimiento en la base de conocimiento, y una mdquina de inferencia.

El esquema de la estructura de los Sistemas Expertos muestra al conocimiento separado de

los algoritmos que lo utilizan. Esta divisi6n se debe a que la base de conocimiento depende de la aplicaci6n y, el shell es un dominio independiente. As1 una manera racional de desarrollar sistemas expertos para varias aplicaciones consiste en desarrollar un shell que pueda ser usado universalmente, y despues conectar una nueva base de conocimiento para cada aplicaci6n.

Por supuesto, todas las bases de conocimiento tendrdn que conformarse al mismo formalismo que es 'entendido' por el shell.

La construcci6n de un shell implica decisiones con respecto al formalismo de representaci6n del conocimiento, el mecanismo de inferencia, la facilidad de interacci6n con el usuario y el trato de incertidumbre.

En principio, cualquier formalismo 16gico en el cual podamos expresar el conocimiento acerca de algún Area de dominio, puede ser considerado para emplearse en un Sistema Experto. Sin embargo, el lenguaje de las reglas SI ENTONCES, tambidn llamadas reglas de producci6n, es con mucho el formalismo m& popular para representar el conocimiento.

Los shells proveen las siguientes caracterlticas:

1) Razonamiento del manejo de metas o encadenamiento hacia atrds.

Es una t6cnica de inferencia que usa reglas SI ENTONCES para dividir repetitivamente una meta en submetas mds pequeñas que son mAs fAciles de encontrar.

2)

Trato con incertidumbre.

Es la habilidad del sistema para razonar con reglas y datos que no son precisamente conocidos.

3) Razonamiento del manejo de datos o encadenamiento hacia adelante.

Es

una t6cnica de inferencia que usa reglas SI ENTONCES para deducir la soluci6n de un problema de datos iniciales.

4) Representaci6n de datos.

Es la manera en la cual los datos del problema específico en el sistema son almacenados y

accesados.

5) Interface de usuario.

(9)

6) Explicaciones.

Es la habilidad del sistema para explicar el proceso de razonamiento que us6 para llegar a

una recomendací6n.

Prolog tiene una mdquina de inferencia construida con encadenamiento hacia atras que puede ser usada para implantar algunos sistemas expertos. Las reglas de Prolog son usadas para la representaci6n del conocimiento, y la maquina de inferencia de Prolog es usada para derivar conclusiones. Otras porciones del sistema, tales como la interfaz de usuario, debe ser codificada usando a Prolog como lenguaje de prQgramaCi6n.

La maquina de inferencia de Prolog hace encadenamiento hacia atras. Cada regla tiene una meta y un número de submetas. La maquina de inferencia de Prolog prueba o desaprueba cada meta. No hay incertidumbre asociada con to$ resultados.

(10)

111. SISTEMA DE ADQUiSlClON DE CONOCiMiENTOS

El intervalo semdntico es la diferencia entre la representacisn natural de algún conocimiento

y la representacidn programada del mismo. Escribir el conocimiento del experto en el formato declarativo de reglas que reconoce Prolog puede ser una tarea difícil y tediosa. El objetivo de SAC es reducir el intervalo semdntico.

El Sistema de Adquisicidn de Conocimientos (SAC) es una herramienta útil para un Sistema Experto, pues permite que un experto en algún drea del conocimiento introduzca informacidn de esa drea en la base de conocimiento, mediante Lenguaje Natural, de manera que el experto ya no tendrd que introducir esa informaci6n directamente con el formalismo reconocido por la mbquina de inferencia del Sistema Experto, sino que SAC transforma esa informacidn al formalismo.

El esquema de SAC es el siguiente:

Primero, se eligid una forma para interactuar con el sistema y comunicarle el conocimiento, se contaba con las siguientes opciones:

-

Guiar al experto por medio de menús para que introduzca el conocimiento. Es decir, un submenú del menú principal sería para que el experto introduzca oraciones completas (sujeto

y predicado) por medio de opciones que lo lleven a irlas construyendo. Otro submenú sería para que introduzca oraciones simples (sujeto) por medio de opciones como el anterior. Tanto las oraciones simples como las completas serían traducidas a hechos en Prolog. Otro submenú sería para que introduzca reglas de produccidn (de la forma Si ENTONCES) que serían traducidas a reglas en Prolog. Podría haber mds submenús para introducir informacidn estructurada de diferente manera.

-

Otra opcidn consiste en establecer una gramdtica para que el experto introduzca el conocimiento. Aunque aquí puede haber varias modalidades debido a que se pueden definir diferentes grambticas.

Elegimos esta última, porque nos pareci6 que al generar cddigo intermedio de acuerdo a una gram&tica, sería mds fdcil traducir ese cddigo a la forma deseada.

(11)

incondicionalmente verdaderas, por ejemplo! mujer(lit), padre(tom,lizi. Mediante esta gramatica el experto introduce el conocimiento, el cual debe guardarse en un archivo de tipo texto.

A continuacidn se presenta esta graméítica : <Conocimiento>

-->

<List-Hecho> fin I

<

List-tlecho> fin

<

Reglas> I

<Reglas> I

<Reglas>

<

List-Mecho> fin

<Reglas>

--

> <

Definicion

>

I

<

Reglas>

<

Definicion

>

<

Definition>

-->

SI-ENT fin I

SI-ENT otro

<

EspecConsec>

<

List-Ora-Asig> fin

<

SI-ENT>

-->

si

<

EspecConsec>

<

List-Exp-Ora> entonces

<

EspecConsec>

<

List-Ora-Asig

>

<

EspecConsec>

-->

pregunta I

Nulo

<

List-Hecho

>

--

> <

List-Ora-Asig

>

<

List

-

Exp-Ora>

--

> <

Exp-Ari-Ora> I

<

Exp-Ari-Ora

> <

Texto

>

I

<Texto> I

4

<

List-Exp-Ora> 1 I

<

List-Exp-Ora

>

,

c

EspecConsec

>

<

List-Exp-Ora

>

I

<

List-Exp-Ora

>

;

<

EspecConsec

> <

List-Exp-Ora

>

<

List-Ora-Asig

>

--

> <

Ora-Asig

>

I

<

Ora-Asig> <Texto> I

<Texto> I

(

<

List-Ora-Asig

>

1

I

<

List-Ora-Asig

>

,

<

EspecConsec

>

c List-Ora-Asig

>

I

<

List-Ora-Asig

>

;

<

EspecConsec

> <

List-Ora-Asig

>

I

<

Definicion

>

<Texto>

-->

t

<

Mensaje

>

I

<

Mensaje>

-->

<

Palabra> 1

<

Mensaje

> <

Palabra

>

c Palabra>

--

>

o 1

Y /

# I ; I

->

I

+ I

- 1 “ I

(12)

< I

> I

> =

I

< =

I

< >

/

= I

si I

entonces /

( 1 1 1 ! I

atomo / variable I

articulo I

verbo I

numero / se I

le I

que I

no

<

Exp-Ari-Ora

>

--> <

Comparacion

>

I

<

Ora-Asig

>

<

Ora-Asig

>

--> <

Oracion

>

I

<

Asignacion

>

<

Asignacion

>

--

>

<

variable>

<

-

<

Exp-Ari

>

c Exp Ari -

> --> <

Expresion

>

I

<

Exp-Ari>

+

<

Exp-Ari> I

<

Exp-Ari>

-

<

Exp-Ari> /

<

Exp-Ari>

* <

Exp-Ari> I

<

Exp-Ari> I

<

Exp-Ari> I

-

c Exp-Ari> I

(

<

Exp-Ari> 1

<

Expresion>

-->

<variable> I (Palabra que empieza con mayúscula)

<

numero> (Reales o enteros)

<

List-Sust>

">

<

L-S

>

I

(13)

<

L-Sust>

"> <

Sust

>

I

<

L-Sust

> <

Sust

>

<Sust>

-->

<An> <atomo>

I

<

atomo

>

(palabra con minúsculas solamente)

<Art>

-->

el, la, lo,

los,

las, un, una, unos, unas

<

List-Verbo>

-->

<Verbo> I (Definidos en un archivo, en tercera persona

del singular o plural, presente)

<

List-Verbo

>

y

<

List-VerboP

I

<

List-Verbo

>

o

<

List-Verbo

>

<Verbo>

-->

<verbo> J

no <verbo> I

le <verbo> f

no le e verbo>

I

se <verbo> I

no se <verbo> I

que <verbo> I

que no

<

verbo

>

Contemplamos muchos aspectos del Lenguaje Natural; sin embargo, existen cantidad de

detalles que seguramente no se tomaron en cuenta. La gramtltica no acepta combinaciones de oraciones y comparaciones o asignaciones en una misma frase. No es muy flexible, pues frases que no lleven verbos (el caso de oraciones que s6lO constan de sujeto) no son aceptadas por SAC; por ejemplo: el sol dorado. Aunque no tiene mucho sentido introducir informaci6n de este tipo.

Desputls de haber elegido la gramatica, es necesario definir la forma en la que se va a

transformar el conocimiento introducido por el experto para guardarlo en la base de conocimiento. Optamos por trabajar con la grametica en lenguaje C, debido a que se podkn utilizar los paquetes Lex y Yacc para manipularla. Toda la implantaci6n de SAC fue en lenguaje C. Et paquete Lex se utilizd para analizar lexicograficamente la informaci6n

contenida en el archivo de tipo texto que contiene el conocimiento del, experto. A

continuaci6n se presenta el archivo de especificaci6n para Lex :

%{

f

1

int yywrap (void)

return( 1 1;

int EsVerbo (char *Cadena) {

char VerboCon[ 1 61;

(14)

while ( (i

<

CantVerbos) && (SiEsVerbo = = FALSO) {

strcpy(VerboCon,"");

if (strcrnp(TablaVerbos[il,Cadena) = =

O)

strcat(VerboCon,TablaVerbos[il);

strcat(VerboCon,"n");

if (strcmp(VerboCon,Cadena) = =

O)

{

SiEsVerbo = CIERTO;

SiEsVerbo = CIERTO;

while ((p

<

CantVerbos) && (strcmp(TablaVerbos[pl,Cadena) ! = 0 ) )

+

+ P i

if (p

>

= CantVerbos) {

strcpy(TablaVerbos[NurnVerbosl,Cadena);

NurnVerbos

+

= 1; }

1

+

+i;

1

if (i

>

= CantVerbos)

else

return(0); return( 1 1;

1

int EsPalabra (char *Cadena, int "sernaforo)

{ int i =

O,

SiEsPal = FALSO;

while ( (i

<

CantVerbos) && (SiEsPal = = FALSO) ) { if (strcrnp(Tabla[il,Cadena) = =

O)

+

+i;

SiEsPal = CIERTO;

1

if (i

>

= CantVerbos)

else {

return(0);

*sernaforo = O;

return( 1 I;

1

1

void Ventana (int X1, int Y1, int X2, int y2)

{ int i;

gotoxy(X 1 ,Y 1 1; printf("

+

");

for (i = X1 + I ; i

<

X2; i + + )

printf("-"); printf("

+

"1;

for (i = Y1 +l; i

<

Y2; i + + )

{

gotoxy(X1,i); printf("

1

");

gotoxy(X2,i); printf(" "I;

1

(15)

printf("

+

");

for (i = X1 + l ; i

<

X2; ¡++I printf("-");

printf("

+

"1;

window(X1

+

1 ,Y1

+

1 ,X2-1 ,Y2-1); clrscr0;

window(l,1,80,25);

1

void Pregunta (char Arreglo[], int *semaforo)

{ char resp;

Ventana(l7,10,63,16); gotoxy(21,13);

printf("L'%s' es un verbolSIN)? ",Arreglo); resp = toupper(getch0);

while (resp! = 'S' && resp! = 'N')

if (resp = = 'S') {

resp = toupper(getch0);

strcpytTablaVerbos[NumVerbosl,Arreglo);

NumVerbos

+

=

1 ; +semaforo = 1 ;

1

else {

strcpy(Tabla[NumPall,Arreglo); NumPal

+

= 1 ;

*semaforo = O;

1

1

Revisa (char Arreglo[TamVerbol)

{

int p = O;

char letra; int semaforo;

while (Arreglotp

+-

111 =

'\O').

letra = Arreglotpl; switch (letra) {

+

+p;

case 'a': if (IEsPalabra(Arreglo,&sernaforo)) Pregunta(Arreglo,&semaforol;

case 'e': if (tEsPalabra(Arreglo,&semaforo))

Pregunta(Arreglo,&semaforo);

case 7': if (IEsPalabra(Arreglo,&sernaforo)) Pregunta(Arreglo,&semaforo);

case 'o': if (!EsPalabratArreglo,&semaforo))

Pregunta(Arreglo,&semaforo);

case 'u': if (!EsPalabralArreglo,&sernaforo)) Pregunta(Arreglo,&semaforo); break;

break;

break;

(16)

break;

case 'n': if (IEsPalabra(Arreglo,&semaforo)) Pregunta(Arreglo,&semaforo); break;

1

default: semaforo =

O;

if (semaforo)

return(1); else

return(0);

1

%} Tabulador [\tl

SaltoLinea [\nl Espacio " " Minuscula Ia-zl Digito 10-99

Entero { Digito}

+

Articulo "el"

I

"la"

I

"los"

I

"las" Variable [A-ZI[A-Za-z0-91*

Atomo {Minuscula}

+

Numero {Entero}

I

{Entero}".

Corch-lzq "["

Corch-Der "I"

PuntC ";"

Coma "," Par1 "(" ParD ")" Mayor

" > "

Menor "

<

"

Mayor1 "

>

= "

Menor1 "

<

= "

IgualA " = "

Diferente "

<

>

"

Asigna "

<

-"

%%

si { NumColumna

+

= 2;

return(si1;

1

entonces { NumColumna

+

= 8;

return(entonces); } return(y1; }

returnlo); }

Y { NumColumna

+

= 1 ; O { NumColumna

+

= 1 ;

corte { NumColumna

+

= 5;

1

"un"

I

"una"

I

"unos"

I

"unas"

I

"IO"

(17)

return(corte1; }

return(otro);} return(fin);}

otro { NumCotumna

+

= 4;

fin { NumColumna

+

= 3;

{Corch-lzq} { NumColumna

+

=

1;

{Corch-Der} { NumColumna

+

= 1;

return(corch-izq); }

{PuntC} {Coma}

{ Parl}

{Paro}

{MaYor} {Menor}

{ Mayorl}

{Menorl} {IgualA}

~.

returrdcorch-der); } { NumCotumna

+

= 1;

return(puntoycoma); } { NumColumna

+

= 1;

returnlcoma); } { NumColumna

+

= 1;

return(par-izq1; } { NumColumna

+

=

1 ;

returntpar-der); } { NumColurnna

+

= 1 ;

return(mayor-que); } { NumColumna

+

= 1;

return(menor-que); } { NumColumna

+

= 2;

return(mayor-igual); } { NumColumna

+

= 2;

returntmenor-igual); } { NumColumna

+

= 1;

return(igua1); }

{Diferente}

{Asigna}

{ NumColumna

+

= 2;

return(diferente1; } { NumColumna

+

= 2;

returnfasignal; }

no { NumColumna 3. = 2;

se { NumColumna

+

= 2;

le { NumColumna

+

= 2;

que { NumColumna

+

= 3;

pregunta { NumColumna

+

= 8; retumbo); }

return(se1; }

return(le1; }

return(que1; }

return(pregunta1; } { NumColumna

+

= 1;

return(rnas);

1

n-n { NumColumna

+

= 1;

return(menos1; }

{ NumColumna

+

= 1;

return(por1; }

n/" { NumColumna

+

= 1 ;

return(entre1; } n * n

(18)

NumColumna

+

= yyleng;

Ultimold = (char *)malloc(strlen(yytext)

+

1); strcpy(Ultimold,yytext);

return(variable1;

1

{Articulo} { NumColumna

+

= yyleng; return(articu1o); }

{Atomo} { NumColumna

+

= yyleng;

if (EsVerbo(yytext1 = = 1 1 {

UItimoVerbo = (char *)malIoc(strlen(yytext)

+

1);

strcpy(UItimoVerbo,yytext);

return(verbo1; else

if (strcmp(yytext,"diagnostico") = =

O)

{

UltimoVerbo = (char *)malloc(strlen(yytext)

+

1); strcpy(UltimoVerbo,yytext);

return(verbo1;

1

else

if {

1

(Bandera)

strcpy(Lista,yytext); if (Revisa(Lista)) {

UltimoVerbo = (char *)malloc(strlen(yytext)

+

1 );

strcpy(UltimoVerbo,yytext1;

returnberbo);

1

else

return(atomo1;

else

1

return(atom0);

{Numero} { NumColumna

+

= yyleng;

{SaltoLinea} {

+ +

NumLinea; return(numero1; }

NumColumna = 1; SaltoDeLinea = Prendido;

1

{Tabulador} NumColumna

+

= 8;

{Espacio} NumColumna

+

= 1 ;

%%

El paquete Yacc se utiliz6 para analizar sint&ticamente la informaci6n contenida en ese archivo. Si se desea tener conocimiento de lo que es Lex y Yacc puede referirse al apendice presentado al final de este manual. Con ambos paquetes se realiz6 un compilador, que recibe como entrada el archivo de tipo texto en Lenguaje Natural, y

lo

transforma en un archivo de tipo texto en lenguaje Prolog el cual constituye una base de conocimiento. Esta transformacidn se realiza de la siguiente manera :

(19)

para Lex se encuentra una funci6n llamada EsVerbo que revisa si cada token que se captura se encuentra en una tabla que contiene los verbos del archivo VERBOS.SAC, cuando ese token puede ser un verbo. Hay otra funci6n llamada Revisa que se encarga de preguntarle al usuario si un token es verbo o no, cuando ese token puede ser un verbo y no se encuentra en la tabla de verbos; si la respuesta es afirmativa, el archivo de verbos se actualiza, y si la respuesta es negativa, SAC guarda esa palabra en un archivo llamado PALABRAS.SAC que contiene aquellas palabras que SAC no sabia si eran verbos y que el usuario le indict3 que no lo son. La raz6n de crear este archivo se debe a que esas palabras pueden encontrarse varias veces en el archivo que se este compilando con SAC, y no es factible que SAC est6 preguntando al usuario por esa palabra cada vez que la encuentre, puesto Que si la primera vez le indict5 que no es verbo, las dernas ocasiones ya debe saber que no es para no volver a preguntarle. Por esta raz6n existe una funci6n llamada EsPalabra que se encarga

precisamente de aquellas palabras que no se encuentran en VERBOS.SAC y que pueden ser verbos, revisando si existen en el archivo PALABRASSAC; en caso de que la palabra se encuentre, SAC ya no le pregunta al usuario por esa palabra. Tambidn se especifica que tokens deben ser reconocidos; y en la secci6n de reglas se especifica ta acci6n

correspondiente a cada expresi6n regular.

En seguida se da una explicaci6n sobre el archivo de especificaci6n para Yacc : Con la finalidad de poder cambiar en un momento dado las estructuras en la parte de

definiciones, se opt6 por dejar formada la uni6n en base a un struct debido a la facilidad con la que se podrlan agregar campos en caso de necesitarse posteriormente; ya sea para correccidn o para ampliacibn.

Para efectos de compilaci6n, no dejamos algunas constantes globales al inicio del programa como se hubiera deseado, para mayor claridad. Lo mismo sucedi6 con las estructuras elegidas. La jerarqula de los operadores se tom6 asi por ser la usual.

Por cada fin se realiza, al igual que por cada oraci6n, una serie de funciones relacionadas con las tuplas. Estas funciones se resumen a pasar las tuplas a la lista global llamada

ListaProlog, la cual contiene la que sera la salida al archivo del mismo nombre que el que

contiene el conocimiento del experto pero con extensi6n ‘.SAC’. Las tuplas se ¡ran formando al terminar de revisar: a) Una oraci6n

b) Una asignacibn c) Una comparacibn

y por cada oraci6n se forman tantas tuplas como verbos tenga dicha oracibn.

Los errores son manejados directamente por Yacc. Se sugiere tambiCtn que si se desea una mayor ayuda al usuario se le dedique un tiempo razonable a los errores pues no se obtuvo una forma eficiente de su manejo por el tipo de gramzltica elegida. Causa varios problemas el identificar el momento en que el compilador ya no acepta la entrada.

Debido a que Yacc necesita leer un token adelantado para determinar por cual regla “irse”, se captur6 el último identificador (Variable) en la variable global Ultimold. Por la misma raz6n se hizo uso de las variables UltimoArt y UltimoVerbo.

Los

No Terminales en la gramdtica que

tienen asignado el tipo AlNum se definieron asi pues solamente recibimos el string para representarlo en “Lenguaje Prolog

-

Lenguaje Natural” para facilitar búsquedas. Es por ello que en cantidad de ocasiones solamente se regresa el valor de un No Terminal y a su vez este lo asigna a un No Terminal superior y asi sucesivamente hasta llegar a formar una o varias tuplas. Por cada salto de linea que se encuentre el lexico pueden suceder dos cosas : a) Si se estaba ubicado dentro de un Texto, se formara una tupla para el rengldn que acaba

de pasar, etiquetandolo con el número actual de etiqueta el cual lo contiene la variable EtiTexto; la que se ir4 incrementando conforme se pongan en el archivo de entrada mas Textos de aclaraciones.

b) En otro caso solamente se seguir3 revisando la sintaxis del archivo de conocimiento.

(20)

Los textos sirven para aclaraciones a una frase o a una actitud que debe tomar el usuario en determinado caso. Estos textos se ¡ran concatenando conforme vaya avanzando Yacc y

hasta que se encuentre un salto de línea.

Exp-Ari y Comparacion estan definidos como comúnmente se tienen en un compilador para evaluar expresiones.

Los verbos se aceptan en singular o en plural pero siempre en tiempo presente de la tercera persona. El archivo VERBOS.SAC contiene los verbos en presente y se le puede agregar a cada uno la letra n para hacerlo plural excepto el verbo es. Para algunos casos se pueden considerar expresiones con verbos conjugados en varios tiempos; si se desea que los verbos no contemplados en el archivo (debido a su conjugacibn) sean considerados como verbos y

no como sustantivos o complementos, se debe cambiar la gramatica o bien agrandar el archivo de verbos, empleando tambien la tabla de verbos la cual permite por el momento un maxim0 de 200 verbos. Los verbos se van encolando para salir en el mismo orden como llegaron para ademas tener un "conteo" inmediato de la cantidad de tuplas a formar. No es necesario regresar el valor sobre $ $ porque se tiene acceso a ellos por medio de la cola de

verbos la cual esta identificada por una variable llamada ColaVerbos.

La estructura para las colas, tambien es aprovechada para encolar las demas palabras en el Texto. Así cuando llega un salto de línea, simplemente concatenamos lo que se tenga en la cola. Esta cola de palabras est& guardada en una variable llamada ColaAtom.

Los verbos representan el nombre del predicado. Los predicados y los hechos, tienen tres pardmetros :

a) Lista de sustantivos b) Lista de complementos

c) Texto al que debe dirigirse en caso de estar activo este

Tanto la lista de sustantivos como la lista de complementos tienen la misma forma; es por ello que la gramatica las define a las dos como lista de sustantivos. Dentro de la lista se tienen dos posibilidades :

a) Se tiene un

solo

elemento el cual es o un sustantivo (Lista de sustantivos) o bien un complemento (Lista de complementos).

b) Se tienen tres elementos los cuales tienen un orden fijo. Este orden es : una nueva lista, una conjuncidn o disyuncidn y una lista mas. Estas listas internas estln a su vez hechas de la misma forma.

Esta solucidn se propuso con el objeto de poder realizar búsquedas en una forma binaria como en ABB. La finalidad de ello se puede ver mejor con un ejemplo: el experto introduce como conocimiento :

el sol y la luna tienen forma de esfera a lo lejos

Se forma el predicado:

tienen(~~el~soll,y,~la~lunall,~forma~de_esfera~a_lo~lejosl,").

El usuario puede desear saber si la luna tiene forma de esfera, sin importarle la forma del sol. Así que se puede tener de manera sencilla el predicado:

tiene([la~lunal,~forma_de_esfera_a~lo~lejosl,"~.

Sin tener limites para la cantidad de sustantivos, aprovechando la recursividad de Prolog para realizar búsquedas de este tipo. (La forma en la que se esta haciendo uso de ello es con uno o dos sustantivos úricamente; en la parte de salida al usuario. Sin embargo, no est6 limitado para realizar búsquedas mas generales.)

(21)

consecutivos. De esta forma se obtiene LTupla desanidada y lista para pasarse a la lista LProlog que contiene la informaci6n traducida a Prolog que se guarda en la base de conocimiento.

La salida al archivo del mismo nombre del que contiene el conocimiento del experto pero con extensi6n 'SAC', se realit6 conforme a la petici6n del otro equipo de trabajo del mismo proyecto. Esto se puede modificar al momento de trasladarse la informaci6n de las tuplas a

la lista gtobal.

A continuaci6n se presenta el archivo de especificaci6n para Yacc:

#define SI

o

/* Asignaciones para indicar en que parte del

#define ENTONCES 1 /* condicional se este, para la formacidn de tuplas.

#define OTRO 2

#define HECHO -1 /* Asignaci6n para indicar que se trata de un hecho. * / #define FALSO

O

/* Para la formacibn de tuplas, se necesita saber si #define CIERTO 1 /* una oraci6n, asignacibn o comparacibn; tiene

/* relacionado

/*un texto para seguir la secuencia en la búsqueda de /*predicados en la mequina de inferencias.

#define NADA O

/*

A cada tupla se le asigna en uno de sus #define COMA

objeto de determinar si se trata de un y o un

1 /* campos, un signo de puntuaci6n con el #define PUNTOYCOMA 2 /*

o en Prolog. #define Y 1

#define O 2

sttuct Subcadena { /* Aprovechando el uso que tiene Yacc de la unibn, char *Subcad; /* se us6 una estructura a pesar de no ser necesario

}; /* por ser un solo campo; sin embargo,

en

caso de que desee, solamente se agrega un campo y ya estuvo. typedef struct Subcadena AlfaNum;

%I

/* Especificaciones para Yacc */

%union {

AlfaNum AINum;

1

%type

<

AINum> Oracion, List-Sust, L-S, Ora-Asig, Exp-ArjOra, Asignacion, Exp-Ari, Expresion, Comparacion, EspecConsec

%left o /* Para separar sustantivos y verbos dentro de una oraci6n. */

%left y

%left coma /* Para separar oraciones. * /

%left puntoycoma

%right asigna /* Expresiones aritmdticas. */

(22)

%left por entre

%nonassoc menor-que mayor-que mayor-igual menor-igual diferente igual

%start Conocimiento I" Simbolo inicial de la gramdtica. " I

%token si entonces par-izq par-der corte atom0 variable articulo verbo numero se pero no otro fin le que corch-itq corch-der pregunta

1" Las especificaciones anteriores no deben causar ningún problema, y en caso contrario

referirse al apendice de Yacc presentado al final de este manual para aclaraciones de este tipo. * I

%% I" Gramdtica y acciones semdnticas " I

Conocimiento : List-Hecho fin { I* Con esto se aceptan solamente hechos TrabajaTuplasO;

HaceNulaTupla(&LTupla);

1

1

List-Hecho fin { I* Con esto se aceptan hechos seguidos TrabajaTuplasO; I' de definiciones

HaceNulaTupla(&LTupla);

1

Reglas

1

Reglas I* Con esto se aceptan solamente definiciones

1

Reglas I" Con esto se aceptan definiciones

List-Hecho fin { /* seguidas de hechos TrabajaTuplasO;

HaceNulaTupla(&LTupla);

1;

Reglas : Definicion {

DESANIDA(LTup1a);

TrabajaTuplasO; / * TrabajaTuplas transfiere las tuplas a una lista global, una vez que se form6 un bloque de tuplas. " I

HaceNulaTupla(&LTupla); I* Una vez que se ha

agregado el bloque de tuplas en la lista global, se libera la memoria de estas tuplas. * I

while (Pila != NULL) Push(HECHO,&Pila); Si-Entonces

= Pop(&Pila);

1

I

Reglas Definicion {

DESANIDA(LTupla1;

HaceNulaTupla(&LTupla); while (Pila ! = NULL) PushlHECHO,&Pila); TrabajaTuplasO;

Si-Entonces = Pop(&Pila);

(23)

/* Definicion es un no terminal, en el cual se puede tener expresiones de tipo general hasta cierto punto.

Las

siguientes formas son todas las posibilidades de su uso. * /

...

si Las posibilidades $on equivalentes para usarse

Oracion [Texto] despues de un otro, igual que despues de un entonces. Oracion [Texto]

entonces fin si

Condicion entonces

Oracion

fin

si

Oracion entonces

Asignacion fin

"""""""""""""""""*"""""""""""""""""""""

"""""""""_"""""""""""""""""""""""""""""

si

entonces

fin

Condicion Asignacion

"~""_C"_L"""""~~""""""""""""""""""""""""""

Definicion : SI-ENT fin {

1

otro

{

--Internado;

SI-ENT

Push(OTRO,&Pila); } /* Se apilan para desapilar al momento de formar las tuplas. * /

EspecConsec List-Ora-Asig fin {

--Internado;

1 :

SI-ENT : si {

Push(SI,&Pila);

+

-I- Internado;

1

EspecConsec List-Exp-Ora entonces {

(24)

EspecConsec List-Ora-Asig ;

EspecConsec : pregunta {

Indicador = 1: }

1

/* nulo * / {

Indicador = O; } ;

List-Hecho : List-Ora-Asig ;

List-Exp-Ora : Exp-Ari-Ora {

Si-Entonces = Pop(&Pilal;

VerTope(Pila,Si-Entonces,&Anidadol;

/* Las especificaciones de variables globales vienen despu6s. * I

UltimoSi = Si-Entonces;

FormaTuplas(S 1 .SubCad,FALSO,Anidado);

} /* FormaTuplas realiza por cada oracidn una serie de tuplas. Tantas como verbos haya en la oraci6n. * /

Exp-Ari-Ora Texto {

Si-Entonces = Pop(&Pila); UltimoSi = Si-Entonces;

FormaTuplas(S1 .SubCad,CIERTO,Anidado); VerTope(Pila,Si-Entonces,&Anidado);

1

Texto {

Si-Entonces = Pop(&Pila); UltimoSi = Si-Entonces;

FormaTuplas("",CIERTO,Anidado);

VerTope(Pila,Si-Entonces,&Anidado):

1

par-izq List-Exp-Ora par-der List-Exp-Ora coma {

Push(UltimoSi,&Pila);

UltimoTupla-> Conector = COMA:

1

EspecConsec List-Exp-Ora

List-Exp-Ora puntoycoma {

Push(UltimoSi,&Pila);

UltimoTupla-

>

Conector = PUNTOYCOMA;

1

EspecConsec List-Exp-Ora ;

List-Ora-Asig : Ora-Asig {

Si-Entonces = Pop(&Pila); UltimoSi = Si-Entonces;

(25)

FormaTuplas(S1 .SubCad,FALSO,Anidado);

1

I

Ora-Asig Texto {

Si-Entonces = Pop(&Pila),

VerTope(Pila,Si-Entonces, &Anidado); UttimoSi

=

Si-Entonces;

ForrnaTuplas(6 1 .SubCad,ClERTO,Anidado);

1

I

Texto {

Si-Entonces = Pop(&Pila); UltirnoSi = Si-Entonces;

FormaTuplas("n,CIERTO,Anidadol;

VerTope(Pila,Si-Entonces,&Anidadol;

1

I

par-irq List-Ora-Asig par-der

I

List-Ora-Asig coma {

Push(UltirnoSi,&Pila);

UitimoTupla-

>

Conector = COMA;

1

EspecConsec List-Ora-Asig

1

List-Ora-Asig puntoycoma {

Push(UltimoSi,&Pila);

UltimoTupla-

>

Conector = PUNTOYCOMA;

1

EspecConsec List-Ora-Asig

1

Definicion ;

Texto : corch-izq { /* El corchete se requiere para distinguir y "separarlo" de la gramatica. * I

itoa(EtiText0, EtiTextoCad, 1

O);

FrenteDeTexto = (char *I

rnalloc

(1 8);

strcpy(FrenteDeTexto,"texto("); strcat(FrenteDeTexto,EtiTextoCad); strcat(FrenteDeTexto,n):- \""I;

LineaTexto = Concatena("",""I; SaltoDeLinea = Apagado; Bandera =

O;

1

Mensaje corch-der {

Bandera = 1;

SaltoDeLinea = Prendido; /" Aclaraciones en AgregaRenglon(""); I* Separa las reglas de los

variables globales */

1;

textos en el archivo de

salida. * / Mensaje : Palabra

(26)

Palabra : o {

AgregaRenglod" o " ) ; }

AgregaRenglon(" y " ) ; }

I Y {

I

coma {

I

puntoycoma {

1

asigna {

AgregaRenglon(" ,"I; }

AgregaRenglon(" ;"I; }

AgregaRenglonV'

<

-"I; }

I

mas

i

AgregaRenglon("

+

"1; }

AgregaRenglont"

-"I;

}

I

menos {

I

por {

AgregaRenglont" ""1; }

AgregaRenglon(" /"I; }

1

entre {

I

menor-que {

I

mayor-que {

1

mayor-igual {

I

menor-igual {

I

diferente {

I

igual {

AgregaRenglon(" "1; }

AgregaRenglon("

>

"1; }

AgregaRenglon("

>

= "1; }

AgregaRenglont"

<

= "I; }

AgregaRenglon("

< >

"); }

AgregaRenglon(" = "1; }

I

si {

I

entonces {

AgregaRenglont" si"); }

AgregaRenglont" entonces"); }

AgregaRenglon(" ("); }

AgregaRenglon(" I"); }

I

Par-izq {

I

par-der {

1

corte {

I

atomo {

1

variable {

I

articulo {

I

verbo {

I

numero {

AgregaRenglon(" !"I; }

AgregaRenglon(Concatena(" ",yytext)); } AgregaRenglon(Concatena(" ",Ultimold)); } AgregaRenglon(Concatena(" ",yytext)); } AgregaRenglon(Concatena(" ",yytext)); }

AgregaRenglon(Concatena(" ",yytext)); }

I

se {

I

le {

(27)

I

que {

I

no {

AgregaRenglon(" que"); }

AgregaRenglon(" no");

1

;

Exp-Ari-Ora : Comparacion {

$$.Subcad = (char *)malloc(strlen($l .Subcad)

+

1);

$ $ .Subcad = strcpy($ $ .Subcad, $ 1 .Subcad); Encola( " ", &ColaVerbos);

3

1

Ora-Asig {

$$.Subcad = (char *)maltoc(strlen(S 1 .Subcad)

+

1 ) ;

SSSubCad = strcpy($S.SubCad,$l .Subcad);

1 ;

Ora-Asig : Oracion {

$$.Subcad = (char *)malloc(strlen(Sl .Subcad)

+

1 1; $$.Subcad = strcpy($$.SubCad,Sl .Subcad);

1

I

Asignacion

$$.Subcad = (char *)malloc(strlen($ 1 .Subcad)

+

1 ) ;

$$.Subcad = strcpy($$.SubCad,$l .Subcad);

Encolal" ",&ColaVerbos);

1;

Asignacion : variable {

Encola(Ultimold,&ColaAtom); TamVar = strlen(Ultimold1;

1

asigna Exp-Ari {

$ $ SubCad

=

(char

*

)malloc(strlen($4.SubCad)

+

TamVar

+

1

O);

$$.Subcad = strcpy($$.SubCad,"asigna(");

$$.Subcad = strcat($$.SubCad,DesEncola(&ColaAtom));

$$.Subcad = srrcat(S$.SubCad,","); $$.Subcad = strcat($S.SubCad,S4.SubCad);

1 ;

Comparacion : Exp-Ari menor-que Exp-Ari {

$$.Subcad = (char *)malloc(strlen($l .Subcad) t strlen(S3.SubCad)

+4);

$$.Subcad

=

strcpyl$S.SubCad,Sl .Subcad); $$.Subcad

=

strcat(S$.SubCad,"

<

"1;

$$.Subcad = strcat($S.SubCad,S3.SubCad);

1

1

Exp-Ari mayor-que Exp-Ari {

$$.Subcad = (char *)malloc(strlen($l .Subcad)

+

strlen(S3.SubCad) f

4);

$$.Subcad = strcpy($Q.SubCad,Sl .Subcad); $$.Subcad

=

strcat($$.SubCad,"

>

"1;

$$.Subcad = strcat($$.SubCad,$3.SubCad);

(28)

I

Exp-Ari mayor-igual Exp-Ari {

$$.Subcad = (char *)malloc(strlen($ 1 .Subcad)

+

strlen(S3.SubCad)

+

5); $$.Subcad = strcpy(S$.SubCad,Sl .Subcad);

$$.Subcad = strcat($S.SubCad,"

>

= "I; $$.Subcad = strcat(S$.SubCad,S3.SubCad);

1

I

Exp-Ari menor-igual Exp-Ari {

$$.Subcad = (char *)malloc(strlen($l .Subcad) +strlen(S3.SubCad)

+

5);

$$.Subcad = strcpy($$.SubCad,Sl .Subcad); $$.Subcad = strcat($$.SubCad,'

<

= "1; $$.Subcad = strcat($$.SubCad,$3.SubCad);

1

I

Exp-Ari diferente Exp-Ari {

$$.Subcad = (char *)malloc(strlen($l .Subcad) +strlen($3.SubCad)

+

5);

$$.Subcad = strcpy($$.SubCad,$l .Subcad); $$.Subcad = strcat($$.SubCad,"

< >

"1; $$.Subcad = strcat($$.SubCad,$3.SubCad);

1

I

Exp-Ari igual Exp-Ari {

$$.Subcad = (char *)malloc(strlen($ 1 .Subcad)

+

strlen(S3.SubCad) +4);

$$.Subcad = strcpy($$.SubCad,$l .Subcad); $$.Subcad = strcat(SS.SubCad," = "1;

$$.Subcad = strcat($$.SubCad,$3.SubCad);

1 ;

Exp-Ari : Expresion {

$$.Subcad = (char *)malloc(strlen(S 1 .Subcad)

+

1); $$.Subcad = strcpy(SS.SubCad,Sl .Subcad);

1

1

Exp-Ari mas Exp-Ari {

$$.Subcad = (char *)malloc(strlen($ 1 .Subcad)

+

strlen(S3.SubCad)

+

2);

$$.Subcad = strcpy(S$.SubCad,Sl .Subcad);

$$.Subcad = strcat(SS.SubCad,"

+

"1;

$$.Subcad = strcat(SS.SubCad,S3.SubCad);

1

I

Exp-Ari menos Exp-Ari {

$$.Subcad = (char *)malloc(strlen(S 1 .Subcad)

+

strlen(S3.SubCad)

+

21;

$$.Subcad = strcpy(SS.SubCad,Sl .Subcad); $$.Subcad = strcat(SS.SubCad,"-"1;

$$.Subcad = strcat(SS.SubCad,S3.SubCad);

1

1

Exp-Ari por Exp-Ari {

$$.Subcad = (char *)malloc(strlen(Sl .Subcad) +strlen($3.SubCad)

+2);

$$.Subcad = strcpy(SS.SubCad,Sl .Subcad);

$$.Subcad = strcat(SS.SubCad,"*");

$$.Subcad = strcat(SS.SubCad,S3.SubCad);

1

I

Exp-Ari entre Exp-Ari {

$$.Subcad = (char *)malloc(strlen(Sl .Subcad) +strlen($3.SubCad)

+

2);

$$.Subcad = strcpy(SS.SubCad,Sl .Subcad); $$.Subcad = strcat($$.SubCad,"/");

$$.Subcad = strcat($S.SubCad,$3.SubCad);

(29)

%prec por {

$ $

.

SubCad $$.Subcad $ $ .Subcad

1

Exp-Ari par-der {

$ $

.

SubCad $ $

.

SubCad $ $

.

SubCad $ $ .Subcad

1;

(char *)malloc(strlen($2.SubCad)

+

2); strcpy($$.SubCad,"-"1;

strcat($$.SubCad,$2.SubCad);

(char *)malloc(strlen($2.SubCad)

+

3);

strcpy($$.SubCad,"(");

strcat($$.SubCad,$2.SubCad);

strcpy($$.SubCad,")");

Expresion : variable {

$$.Subcad = (char *)malloc(strlen(Ultimold)

+

1); $$.Subcad = strcpy($$.SubCad,Ultimold);

1

1

numero {

$$.Subcad = (char *)malloc(strlen(yytext)+ 1 I; $$.Subcad = strcpy($$.SubCad,yytext);

1;

Oracion : List-Sust List-Verbo { Bandera = O; }

List-Sust {

Bandera = 1;

$$.Subcad = strcpy($$.SubCad,""); $$.Subcad = strcat($$.SubCad,"("); $$.Subcad = strcat(SS.SubCad,Sl .Subcad); $$.Subcad = strcat($$.SubCad,",");

$$.Subcad = strcat($$.SubCad,$4.SubCad);

$$.Subcad = (char *)malloc(strlen($ 1 .Subcad)

+

strlen($4.SubCad)+ 4);

1

I

corte {

$$.Subcad= (char *)malloc(2);

$$.SubCad=strcat($$.SubCad,"!");

$$.Subcad = strcpy($$.SubCad,"");

1 ;

List-Sust : L-S {

$$.Subcad = (char *)malloc(strlen($l .Subcad)

+

1); strcpy(S$.SubCad,"");

strcat($$.SubCad,$l .Subcad);

1

1

/* nulo "/ {

$$.Subcad = (char *)malloc(3); $$.Subcad = strcat($$.SubCad,"[l");

$$.Subcad = strcpy($$.SubCad,"");

(30)

L - S : L-Sust {

$$.Subcad = (char *)malloc(21; strcpy($S.SubCad,"t");

while (ColaAtom.lnicio ! = NULL) {

$$.Subcad = Concatena($$.SubCad,DesEncola(&ColaAtom)l;

if (ColaAtom.lnicio ! = NULL)

$$.Subcad = Concatena(SS.SubCad,"-"I;

1

$$.Subcad = Concatena($$.SubCad,"l");

1

I

L-S Y L-S {

$$.Subcad = (char *)malloc(strlen($l .Subcad) +strlen($3.SubCad) +6); $$.Subcad = strcpy(SS.SubCad,"");

$$.Subcad = strcat(SS.SubCad,"[");

$$.Subcad = strcat($S.SubCad,Sl .Subcad); $$.Subcad = strcat(SS.SubCad,",y,");

$$.Subcad = strcat($S.SubCad,$3.SubCad);

$$.Subcad = strcat(S$.SubCad,"l");

1

I

L-S 0 L-S {

$$.Subcad = (char *)malloc(strlen(S 1 .Subcad)

+

strlen(S3.SubCad)

+

6); $ .Subcad =

$$.Subcad =

$ $ .Subcad =

$$.Subcad =

$ .Subcad =

$$.Subcad =

1

strcpy($$.SubCad,""); strcat($$.SubCad,"[");

strcat($$.SubCad,$l .Subcad);

strcat(SS.SubCad,",o,"); strcat($$.SubCad,S3.SubCad);

strcat(S$.SubCad,"l");

I

par-izq L-S par-der {

$$.Subcad = $ .Subcad =

$ $. SubCad =

1;

L-Sust : Sust

1

L-Sust Sust ;

Sust : articulo

atomo {

I

atomo {

(char *)malloc(strlen($2.SubCad)

+

1 I; strcpy($$.SubCad,"");

strcat(SS.SubCad,S2.SubCad);

Encola(Concatena(UltimoArt,yytext),&ColaAtom); } Encola(yytext,&ColaAtom); } ;

List-Verbo : Verbo

1

Verbo y {

List-Verbo

(31)

I

Verbo o {

EncolaEntero(O,&ColaUnionDeVerbosl; List-Verbo ;

Verbo : verbo {

Encola(UltimoVerbo,&ColaVerbos); }

1

no verbo {

I

le verbo {

1

no le verbo {

I

se verbo {

\

que verbo {

1

que no verbo {

1

no se verbo {

Encola(Concatena("no_",UltimoVerbo),&ColaVerbos); } Encola(Concatena("le_",UltimoVerbo),&ColaVerbos);

1

Encola(Concatena("no_le~",U~imoVerbo),&ColaVerbos~; }

Encola(Concatena("se-",UltimoVerbo),&ColaVerbos); }

Encola(Concatena("que_",UltimoVerbo),&ColaVerbosi; }

Encola(Concatena("que_no_",UltimoVerbo),&ColaVerbosl;)

(32)

Si la información es correcta lexicográficamente y sintácticamente, entonces se realiza la generación de código intermedio, que convierte la información a tuplas en código de Prolog, las cuales se guardan en un archivo con el mismo nombre del que contiene el conocimiento del experto pero con extensión '.SAC' Cada oración se transforma a una tupla que tiene la siguiente forma (como ya se mencionó anteriormente):

verbo(lista_sustantivos,lista_complementos,etiqueta_texto)

Donde: etiqueta-texto es una etiqueta que identifica el texto correspondiente a una oración, o es la palabra 'pregu' cuando se trata de una oración

correspondiente a una pregunta.

El elegir la gramática en Lenguaje Natural nos pareció adecuado, pues al obtener tuplas de la información, la salida al archivo que contendrá la base de conocimiento se puede modificar de la manera deseada.

El archivo de salida tiene alguna de las siguiente formas:

2) si X,

y;

z

...

u;

v,

w

...

entonces

fin

si

x,

y;

z

...

u;

v,

w

...

(33)

entonces

u;

v,

w

...

fin

Donde a su vez, cada literal representa un si-entonces, comparación, asignación u oración.

La siguiente sección describe, las funciones de usuario de la implantación del compilador, así como

la

explicación del funcionamiento

y

el

porqué

de cada funcitin.

Conforme realizamos la generación de

ccidigo intermedio,

se fueron necesitando algunos archivos de librerias

los

cuales se llaman desde &a seccion antes de realizar acciones semiinticas e incluso antes de definir funciones, pues éstas necesitan dichas librefias.

010% '

"""Y"_I"""""""""II"~

lNCLUDES

"~"~"""""""""---"

#include

<stdio.h>

##include <stdlib.h>

#include <string.h>

#include

<ctype.h>

"cc"""~""-~"""""~""

-CONSTANTES GLOBALES

""""""""""""""""""~"~"""

#define CantVerbos 200

La tabla de verbos tiene como número

máximo

de verbos la cantidad de verbos que existan en VERBOS.SAC, sin embargo no puede contener

más

allá de la cantidad señalada por Cantverbas que seguramente superar-á a

los

200.

#define TamVerbo 15

El tamaño que pensamos que podría tener como máximo un verbo fué de 15 caracteres, pero si se desea cambiar, se debe modificar la constante TamVerbo.

#define Prendido 1 Wefine Apagado O

(34)

Las constantes definidas al inicio del programa, se definieron ahí para fines de claridad pues solamente se usan en la parte de las acciones semánticas en la gramática.

____"___"___"""______l_l___________""""""""""""""" ESTRUCTURA DE DATOS

"___""_____"___""""""""""""""""""""""~""""---

struct Tupla {

int SiEntonces, Inter, Conector, Pregunta, SiAnidado; char *UnVerbo,*UnEnunciado,*ClaveTexto;

struct Tupla *Liga;

1;

struct Tupla es una estructura en la cual se tienen variables necesarias para almacenar datos de cada una de las oraciones, asignaciones o comparaciones. Esta estructura sirve para ir guardando el código en semiprolog con datos necesarios para el "vaciado" a la lista.

SiEntonces es un campo que se ocupa para indicar si se trata de una expresión en la parte de la causa o en la parte del efecto.

Debido a que puede existir "si

...

entonces" anidados, se pueden realizar varias acciones dependiendo de las necesidades al momento de vaciar en la lista global. Es decir, si se requiere que haya un fin por cada si, ser& diferente la acción por realizar que cuando no se necesita. El que la tupla contenga la información de qué tan anidado está un si

...

entonces con respecto a otro,

permite realizar acciones para las dos necesidades anteriores. Las utilidades son más claras mientras más se tengan necesidades no al momento de formar el archivo de salida, sino al momento de accesar la información para ofrecerla al usuario o para seguir razonamientos. Inter es un campo que se ocupa por el momento para dos cosas:

a) Para que al final de cada si

...

entonces NO anidado, se escriba sobre el

b) Para estética en el archivo de salida pues el tabulador se agranda conforme

Cada frase puede estar "sola" o conectada por medio de comas y por medio de puntos y comas. Para saber si al momento de vaciar a la lista global las tuplas se requiere agregar uno de estos conectores, se usa un campo llamado Conector. Pregunta es un campo que sirve para saber si la oración

correspondiente es una pregunta o no. SiAnidado es un campo que sirve para saber si una oración corresponde a un si dentro de un otro. UnVerbo,

UnEnunciado y ClaveTexto, forman en conjunto lo que denominamos un predicado. UnVerbo es exclusivamente el verbo con sus posibles combinaciones. UnEnunciado tiene ya incluidos los corchetes de las listas que se formaron. Estas listas

se forman en las especificaciones de L-S. ClaveTexto, o bien es nula lllbll, o

bien es de la forma "texto(centero>". El apuntador a la siguiente tupla está referenciado por el campo Liga. La ventaja de tener las tuplas con código intermedio es que la salida se puede facilitar si se desea modificar. No es necesario modificar todo el programa para cambiar el aspecto del archivo de salida; nada más se modifica la función que traslada las tuplas a la lista global y con eso se resuelve el problema.

archivo un fin-si.

se anida más algún si

...

entonces.

struct Prolog { char *LineaProlog;

struct Prolog *Liga;

(35)

La estructura struct Prolog se creó para ir formando la salida antes de ser escrita en el archivo. En primer lugar, para ahorrar tiempo realizando de golpe una escritura, y en segundo lugar, para no crear un archivo que

probablemente no quede terminado pues no se sabe si compilará el archivo de entrada.

strud Textual {

char *Renglon;

struct

Textual *Liga;

1;

stwt ListaTextos {

char "Texto;

struct ListaTextos *Liga;

1

struct Listaverbos {

char *Cadenaverbo; struct Listaverbo *Sig;

1;

struct ColaDeCadenas {

strud Listaverbos *Inicio, *Fin;

1;

struct

PilaEnteros {

int SiEntOtro;

struct PilaEnteros *Liga;

1;

struct ColaDeEnteros {

struct PilaEnteros *Inicio, *Fin;

1;

/* "-1""""""""""""""""""""""

-VARIABLES GLOBALES

""""""""1""""""""""""""""

*I

int NumLinea

=

1 ; int NumVerbos; int NumPal; int EtiTexto

=

O; int Etiqueta

=

O;

int Si-Entonces

=

HECHO; int BanderaaTexto

=

FALSO; int Internado f -1 ;

int TamVar; int UltimoSi; int SaitoDeLinea; int NumColumna

=

1 ; int ConectorG

=

NADA; int EnteroAux;

(36)

int Anidado; int Repetido

=

O;

char TablaVerbos[CantVerbos][TamVerbo] ;

Tablaverbos es necesaria para guardar los verbos que se encuentran en el archivo VERBOS.SAC.

char Tabla[CantVerbos][TamVerbo];

Tabla es necesaria para guardar las palabras que se encuentran en el archivo PALABRAS.SAC.

char *CadenaProlog

=

"" ;

Cadena prolog se pensó usar para ir formando la cadena que se transforma de tupla a un elemento de la lista de prolog, solamente que ya no se ocupó por el momento ya que se manda como parámetro la concatenación de cadehas.

char UltimoArt[S];

Para conservar el valor del artículo después de ser leido otro token, se respalda en esta variable.

char *Ultimold;

AI igual que la variable anterior, se usa ésta para respaldar et valor de la última variable que se haya capturado.

char *UltimoVerbo;

Nuevamente se tiene una variable para respaldar el último verbo que se haya capturado.

char *LineaTexto;

Se usa LineaTexto para ir formando la cadena que se introduce en la lista global de texto. Se va concatenando cada vez que llega un token diferente de un punto y se inicializa con nulo cada vez que llega un nuevo texto y cada vez que hay un salto de línea dentro del texto. Esta línea va a ser introducida tal y como la haya introducido el experto.

char EtiTextoCad[7];

Para transformar a cadena el valor que tenga la variable EtiTexto, se creó la variable EtiTextoCad en la cual se guarda ésta cadena numérica. Se concatena

para el tercer parámetro del modelo de predicados elegido.

char *FrenteDeTexto;

Como todos los textos se iban a estar inicializando con Texto(<Número>):- ".., se inicializa una variable con éste texto y se le agrega posteriormente el número de texto al que corresponde. La salida del predicado de texto es de la forma: Texto(<Número>):- "<Texto>".

Figure

Actualización...

Referencias

Actualización...