;;; -*- Mode:Lisp; Package:DYPAR; -*- ;;; Fichero que contiene el INTERFAZ DE USUARIO creado para DYPAR ;;; -------------------------------------------------------- ;;; ;;; Copyright (c) by Jesus Gonzalez Boticario ;;; para Rank Xerox Espana S.A. ;;; ;;; Septiembre de 1989 ;;; ;;; -------------------------------------------------------- ;;; Historia: ;;; 25-Sep-1989 Jesus Gonzalez Boticario para Rank Xerox Espa¤a ;;; Introduccion de una nueva variable llamada *interfaz* que ;;; indica cuando esta a un valor distinto de NIL que se esta dentro ;;; de la ejecucion del interfaz. ;;; 19-Sep-1989 Jesus Gonzalez Boticario para Rank Xerox Espa¤a ;;; Modificacion de la macor "escribe-mensaje" para que pueda sacar ;;; y recoger todos los mensajes que se quiera a traves de la ventana ;;; de mensajes. ;;; ;;; 18-Sep-1989 Jesus Gonzalez Boticario para Rank Xerox Espa¤a ;;; creacion de la funcion "enmarcar" para poner un cuadro alrededor ;;; de una ventana. Correccion del error que no permitia ver la linea ;;; superior de la ventan del menu. El alto de la pantalla a enmarcarse ;;; tiene que ser una unidad superior al alto dado como argumento a ;;; la funcion "enmarcar". Eliminacion de la funcion "pinta-recuadro" ;;; y cambio de la funcion "pinta-pant-menu". ;;; 13-Sep-1989 Jesus Gonzalez Boticario para Rank Xerox Espa¤a ;;; modificacion de la funcion interfaz para proteger la restauracion ;;; de los valores de las variables del sistema aunque ocurra un error ;;; durante la ejecucion. ;;; 01-Sep-1989 Jesus Gonzalez Boticario para Rank Xerox, Espa¤a ;;; Declaracion de todas las variables globales del fichero para ;;; poder realizar una primera version compilada del mismo. ;;; 29-Jul-1989 Jesus Gonzalez Boticario para Rank Xerox, Espa¤a ;;; Creacion de la funcion "def-pant-resp-grande" para por si ;;; acaso los ficheros de respuesta de la Base de Datos son ;;; demasiado grandes para caber en la pantalla de respuestas ;;; inicial. ;;; Ajuste y peque¤as modificaciones en los mensajes de las ;;; pantallas. ;;; 21-Jul-1989 Jesus Gonzalez Boticario para Rank Xerox, Espa¤a ;;; Creacion de una nueva pantalla que le indica al usuario cuales ;;; son los tipos de frases que la gramatica creada con Dypar para ;;; Banesto, es capaz de aceptar. Para sacar dicha pantalla se debe ;;; llamar a la funcion "pinta-pant-ayuda". ;;; Estructuracion y redefinicion de la funcion interfaz, de forma que ;;; sea mucho mas modular y se eliminen algunas repeticion de codigo ;;; existentes anteriormente. ;;; 7-Jul-1989 Jesus Gonzalez Boticario para Rank Xerox, Espa¤a ;;; Modificacion del interfaz, de tal forma que aparezca una pantalla ;;; de mensajes cada vez que desde la parte consecuente de una regla se ;;; invoque a la macro "escribe-mensaje" de tal forma que se puedan ;;; determinar las ambiguedades existentes en las frases del usuario. ;;; 25-Jun-1989 Jesus Gonzalez Boticario para Rank Xerox, Espa¤a ;;; Segun implementan nuevas peticiones realizadas por Banesto para ;;; el interfaz de usuario. Como son; cambio de tama¤o de ventanas ;;; y de colores, creacion de la variable *enable-output* en el fichero ;;; BABEL.LSP para asi poder eliminar el numero excesivo de mensajes ;;; devueltos por DYPAR pensando en una version "runtime". ;;; 12-Jun-1989 Jesus Gonzalez Boticario para Rank Xerox, Espa¤a ;;; En base a una primera version sin finalizar y con errores ;;; del interfaz de usuario para el Interprete de Lenguaje Natural ;;; Dypar, se plantea como primer trabajo hacer que dicho interfaz ;;; funcione. En primer lugar se resuelve el problema de "scrolling" ;;; y de posicionamiento y colores de las ventanas en la pantalla. ;;; para poder utilizar la funcion "mi-read-line" se debe cargar el fichero ;;; "conexion.lsp". ;;; aunque son demasiadas variables globales, esto permite que no haya que ;;; redefinir las ventanas cada vez que quieran volverse a mostrar en la ;;; pantalla, ya que cada ventana se salva en una variable. Es por lo ;;; tanto un codigo menos modular y estructurado (no tener en cuenta los ;;; mensajes durante la compilacion de este fichero) pero mucho mas rapido. (proclaim '(special *languaje* *dypar-stream* *pant-menu* *titulo-input* *borde-pregunta* *titulo-resp* *titulo-ayuda* *output-ayuda* *borde-ayuda* *titulo-resp-grande* *borde-inferior* *titulo-mensaje* *interfaz* *titulo-peque-1* *titulo-peque-2*)) ;;; Trabajar en el paquete DYPAR (in-package :dypar); :use '(:lisp :user :gclisp)) ;;; Por ahora se declaran un conjunto bastante extenso de variables globales, ;;; mas adelante se mejorara esta implementacion. ;;; para evitar que aparezcan las reglas que se van ejecutando (setq !ptrace nil) ;;; inicializa las variables para que los mensages salgan en Espanol (setq *language* 'spanish) ;;; la variable *dypar-stream* esta inicializada en el fichero BABEL.LSP ;;; al var *standard-output* ;;; (setq *interfaz* nil) ;;; esta pantalla define el tamano y color de la ventana en la cual ;;; va a aparecer el menu del usuario (defun def-pant-menu () (setf *pant-menu* (make-window-stream :top 0 :height 10 :width 80 :attribute 79))) ;;; pantalla de donde se van a recibir las preguntas del usuario ;;; esta pantalla va a tener un titulo que en realidad va a ser una pantalla ;;; en la que solo se va a escribir el mensaje "ESCRIBA AQUI SU PREGUNTA" ;;; ademas de esta la pantalla que realmente va a recibir los mensajes del ;;; usuario se asocia al stream *standard-input* de tal forma que el sistema ;;; que utilize entrada/salida no sea consciente de donde se van a ;;; redireccionar sus mensajes (defun def-pant-pregun () (setf *titulo-input* (make-window-stream :height 4 :width 80 :top 09 :attribute 56)) (setq *standard-input* (make-window-stream :height 3 :width 80 :top 12 :attribute 56)) (setf *borde-pregunta* (make-window-stream :height 1 :top 15 :attribute 56)) (send *standard-input* :scroll)) ;;; pantalla donde se van a escribir las respuestas a las preguntas ;;; del usuario (hay que tener en cuenta que DYPAR realiza las salidas ;;; en los streams *dypar-stream* y *standard-output*). ;;; Al igual que en la funcion def-pant-pregunta existe una pantalla de ;;; titulo. (defun def-pant-respuesta () (setf *titulo-resp* (make-window-stream :height 4 :width 80 :top 15 :attribute 79)) (setq *standard-output* (make-window-stream :height 7 :width 80 :top 18 :attribute 79)) (setq *dypar-stream* *standard-output*) ) ;;; pantalla que se puede utilizar para el caso de que las respuestas ;;; de la base de datos tengan demasiados datos. (defun def-pant-resp-grande () (setq *titulo-resp-grande* (make-window-stream :height 4 :width 80 :attribute 79)) (setq *standard-output* (make-window-stream :height 19 :width 80 :top 3 :attribute 56)) (setq *standard-input* *standard-output*) (setq *dypar-stream* *standard-output*) ) ;;; Para cuando el usuario necesite ayuda porque no sabe el tipo de preguntas ;;; que el sistema puede entender, se ha definido una pantalla de ayuda ;;; que contiene algunos ejemplos tipo. (defun def-pant-ayuda () (setf *titulo-ayuda* (make-window-stream :height 4 :top 0 :width 80 :attribute 79)) (setq *output-ayuda* (make-window-stream :height 20 :width 80 :top 3 :attribute 56)) (setf *borde-ayuda* (make-window-stream :height 4 :top 22 :attribute 79)) ) ;;; pantalla que va a ser el borde inferior de la pantalla, esta se ha definido ;;; ya que habia problemas con el "scroll" de la pantalla de respuestas, si ;;; esta alcanzaba el margen inferior de la consola. (defun def-pant-borde () (setf *borde-inferior* (make-window-stream :height 1 :top 24 :attribute 79)) (send *borde-inferior* :clear-screen) ) ;;; se ha definido una pantalla para sacar los mensajes que ayude al sistema ;;; a resolver ambiguedades. Se utiliza el stream *query-io* para dichas ;;; preguntas. (defun def-pant-mensaje () (setf *titulo-mensaje* (make-window-stream :height 4 :left 5 :width 70 :attribute 27)) (setq *query-io* (make-window-stream :height 12 :top 3 :left 5 :width 70 :attribute 27)) (setq *stream-io* *query-io*) ) ;(setq *stream-io* (setq *query-io* *standard-output*)) ;;; definicion de una pantalla peque¤a para sacar mensajes al recorrer ;;; las sucesivas pantallas que componen una salida de la base de datos. (defun def-pant-titulo-mensajes () (setq *titulo-peque-1* (make-window-stream :top 0 :left 0 :width 25 :height 4 :attribute 79)) (setq *titulo-peque-2* (make-window-stream :top 0 :left 25 :width 55 :height 4 :attribute 79))) ;;; funcion general que se encarga de crear adecuadamente todas las pantallas ;;; que van a configurar el Interfaz del Usuario. (defun interfaz () (unwind-protect (progn (inicializar) (pintar) (parser)) (restaurar)) (values) ) ;;; para restaurar el estado original del interfaz de usuario (defun restaurar () (setq *standard-output* (make-synonym-stream '*terminal-io*)) (setq *standard-input* (make-synonym-stream '*terminal-io*)) (setq *query-io* (make-synonym-stream '*terminal-io*)) (send *standard-output* :clear-screen) (setq *dypar-stream* *standard-output*) (setq *interfaz* nil) ) ;;; para inicializar el interfaz del usuario: (defun inicializar () (setq *interfaz* t) (send *standard-output* :clear-screen) (def-pant-menu) (def-pant-pregun) (def-pant-respuesta) ; (def-pant-borde) (def-pant-mensaje) (def-pant-ayuda) (def-pant-titulo-mensajes) ) ;;; pinta las tres ventanas de la pantalla principal del interfaz del usuario (defun pintar () (pinta-pant-menu) (pinta-pant-pregun) (pinta-pant-respuesta) ;(send *borde-inferior* :clear-screen) ) ;;; Inicializa y pinta la pantalla de respuestas del sistema a las preguntas ;;; del usuario (defun pinta-pant-respuesta () (send *dypar-stream* :clear-screen) (send *titulo-resp* :clear-screen) (enmarca *titulo-resp* :alto 3) (send *titulo-resp* :set-cursorpos 27 1) (send *titulo-resp* :write-string "RESPUESTAS Y MENSAJES") (send *standard-output* :set-cursorpos 0 0)) ;;; Macro creada para facilitar al escritor de gramaticas la posibilidad ;;; de preguntar al usuario por posibles ambiguedades en sus preguntas, ;;; un ejemplo seria: (escribe-mensaje (y-or-n-p "Es la primera opcion")) ;;; esta sentencia debera en la parte derecha de las reglas de alto nivel ;;; de la gramatica (defmacro escribe-mensaje ( &rest mensajes) `(if *interfaz* (let ((sal *standard-output*) (en *standard-input*) (resul)) (setq *standard-output* *query-io* *standard-input* *query-io*) (pinta-pant-mensaje) (setq resul (progn ,@mensajes)) (setq *standard-output* sal *standard-input* en) (pinta-pant-menu) (pinta-pant-pregun) resul) (progn ,@mensajes))) ;;; Para pinta la pantalla que va a contener la pregunta y la respuesta a ;;; dicha pregunta del usuario. (defun pinta-pant-mensaje () (send *titulo-mensaje* :clear-screen) (send *query-io* :clear-screen) (enmarca *titulo-mensaje* :alto 3) (send *titulo-mensaje* :set-cursorpos 28 1) (send *titulo-mensaje* :write-string "MENSAJE") (send *query-io* :set-cursorpos 0 0)) ;;; funcion para pintar la pantalla de ayuda que presentara las frases tipo ;;; que puede reconocer la gramatica (defun pinta-pant-ayuda () (if *interfaz* (progn (send *titulo-ayuda* :clear-screen) (enmarca *titulo-ayuda* :alto 3) (send *output-ayuda* :clear-screen) (send *titulo-ayuda* :set-cursorpos 18 1) (send *titulo-ayuda* :write-string "EJEMPLOS DE TIPOS DE FRASES RECONOCIDAS") (send *output-ayuda* :set-cursorpos 0 0) (pinta-frases *output-ayuda*) (send *borde-ayuda* :clear-screen) (enmarca *borde-ayuda* :alto 3) (send *borde-ayuda* :set-cursorpos 14 1) (send *borde-ayuda* :write-string "PULSE CUALQUIER TECLA PARA CONTINUAR") (read-char *borde-ayuda*) (pintar)) (progn (send *standard-output* :clear-screen) (pinta-frases *standard-output*) (format t "~2% !!! ESTOS SON ALGUNOS EJEMPLOS DE LOS TIPOS ~ DE FRASES RECONOCIDAS !!!"))) ) ;;; Escribe las frases tipo en la pantalla de ayuda. (defun pinta-frases (ventana) (send ventana :set-cursorpos 1 1) (send ventana :write-string "¨ Cu l es el total de pr‚stamos solicitados en Madrid desde Enero 89 hasta Marzo 89, por menores de veinticinco a¤os ?") (send ventana :set-cursorpos 1 4) (send ventana :write-string "¨ y cuantos de estos se han concedido ?") (send ventana :set-cursorpos 1 6) (send ventana :write-string "¨ Para unos ingresos mensuales de menos de 980000 pesetas, cu ntos pr‚stamos se han denegado en este trimestre ?") (send ventana :set-cursorpos 1 9) (send ventana :write-string " Listame los morosos de Madrid ") (send ventana :set-cursorpos 1 11) (send ventana :write-string " Porcentaje de concedidos sobre solicitados ") (send ventana :set-cursorpos 1 13) (send ventana :write-string "¨ Qu‚ porcentaje de morosos son clientes ?") (send ventana :set-cursorpos 1 15) (send ventana :write-string " Sucursales que producen impagos ") (send ventana :set-cursorpos 1 17) (send ventana :write-string "¨ Cu l es la cuant¡a media de pr‚stamos solicitados ?") ) ;;; funcion encargada de pintar el menu que aparece en todo momento durante ;;; la peticion de datos al usuario del sistema (defun pinta-pant-menu () (send *pant-menu* :clear-screen) (enmarca *pant-menu* :alto 9) (send *pant-menu* :set-cursorpos 30 1) (send *pant-menu* :write-string "DATOS EXISTENTES") (send *pant-menu* :set-cursorpos 30 2) (send *pant-menu* :write-string "ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ") (send *pant-menu* :set-cursorpos 5 3) (send *pant-menu* :write-string "Usted puede preguntar, en lo que se refiere al pr‚stamo scoring, sobre") (send *pant-menu* :set-cursorpos 5 4) (send *pant-menu* :write-string "datos personales, profesionales y econ¢micos del solicitante, datos de") (send *pant-menu* :set-cursorpos 5 5) (send *pant-menu* :write-string "intermediarios y datos estad¡sticos sobre operaciones.") (send *pant-menu* :set-cursorpos 12 7) (send *pant-menu* :write-string "­ Si necesita alg£n tipo de ayuda, solic¡tela !")) (defun pinta-pant-menu* () (send *pant-menu* :clear-screen) (enmarca *pant-menu* :alto 9) (send *pant-menu* :set-cursorpos 30 1) (send *pant-menu* :write-string "DATOS EXISTENTES") (send *pant-menu* :set-cursorpos 30 2) (send *pant-menu* :write-string "ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ") (send *pant-menu* :set-cursorpos 5 3) (send *pant-menu* :write-string "* solicitante : personales * gestion") (send *pant-menu* :set-cursorpos 5 4) (send *pant-menu* :write-string " profesionales") (send *pant-menu* :set-cursorpos 5 5) (send *pant-menu* :write-string " economicos * administrativos") (send *pant-menu* :set-cursorpos 5 7) (send *pant-menu* :write-string "* intermediarios")) ;;; funcion para dibujar el cuadro alrededor de una ventana, la ventana ;;; tiene que tener de alto una unidad mayor que el argumento "alto". (defun enmarca (ventana &key (alto 10) (ancho 79)) (dotimes (lin alto) (cond ((= lin 0) (progn (dotimes (col (1- ancho)) (send ventana :set-cursorpos (+ col 1) 0) (send ventana :write-string "Í")) (send ventana :set-cursorpos 0 lin) (send ventana :write-string "É") (send ventana :set-cursorpos ancho lin) (send ventana :write-string "»"))) ((< lin (1- alto)) (progn (send ventana :set-cursorpos 0 lin) (send ventana :write-string "º") (send ventana :set-cursorpos ancho lin) (send ventana :write-string "º"))) (t ;si es la ultima linea (dotimes (col (1- ancho)) (send ventana :set-cursorpos (+ col 1) lin) (send ventana :write-string "Í")) (send ventana :set-cursorpos 0 lin) (send ventana :write-string "È") (send ventana :set-cursorpos ancho lin) (send ventana :write-string "¼"))))) ;;; funcion que realiza la presentacion en pantalla de el espacio destinado ;;; a que el usuario realize sus preguntas. (defun pinta-pant-pregun () (send *titulo-input* :clear-screen) ; (send *borde-pregunta* :clear-screen) (enmarca *titulo-input* :alto 3) (send *titulo-input* :set-cursorpos 22 1) (send *titulo-input* :write-string "ESCRIBA AQUI SU PREGUNTA") (send *standard-input* :clear-screen) (send *standard-input* :set-cursorpos 0 0) ) ;;; funcion para crear una ventana de prueba en la que poder investigar ;;; opciones de colores y tamanos (defun dibuja-ventana (&key (ancho 80) (alto 4) (color 7) (fila 0) (margen 0) (borde nil)) (let ((ventana (make-window-stream :height alto :width ancho :top fila :left margen :attribute color))) (send ventana :clear-screen) (if borde (enmarca ventana :alto 3)) (send ventana :set-cursorpos 0 0) ventana)) ;;; Inicializa y pinta la pantalla para mensajes que sean muy grandes (defun pinta-pant-resp-grande () (send *dypar-stream* :clear-screen) (send *borde-ayuda* :clear-screen) (enmarca *borde-ayuda* :alto 3)) ;;; funcion para pintar la ventana inferior de la pantalla grande (defun pinta-pant-inferior-grande () (send *borde-ayuda* :set-cursorpos 5 1) (send *borde-ayuda* :write-string "Pulsar = pantalla anterior, = pantalla siguiente, = finalizar")) ;;; pantalla para correccion de errores ortograficos (defun pinta-pant-correc-orto () (def-pant-resp-grande) (pinta-pant-resp-grande) (send *titulo-resp-grande* :clear-screen) (enmarca *titulo-resp-grande* :alto 3) (send *titulo-resp-grande* :set-cursorpos 25 1) (send *titulo-resp-grande* :write-string "RESPUESTAS Y MENSAJES") (send *standard-output* :clear-screen) (send *standard-output* :set-cursorpos 0 0)) ;;; pinta la pantalla de titulo de la derecha de la pantalla grande (defun pinta-peque-2 (&optional (mensaje nil)) (if mensaje (progn (send *titulo-peque-2* :set-cursorpos 15 1) (send *titulo-peque-2* :write-string " ") (send *titulo-peque-2* :set-cursorpos 15 1) (send *titulo-peque-2* :write-string mensaje)))) ;;; pinta las dos ventanas del titulo de la pantalla grande (defun pinta-pant-titulo-mensajes () (send *titulo-peque-1* :clear-screen) (enmarca *titulo-peque-1* :alto 3 :ancho 24) (send *titulo-peque-1* :set-cursorpos 8 1) (send *titulo-peque-1* :write-string "RESPUESTA") (send *titulo-peque-2* :clear-screen) (enmarca *titulo-peque-2* :alto 3 :ancho 54) (pinta-peque-2)) ;;; funcion para contar el numero de lineas de un fichero (defun num-lineas (entrada) (do ((leido (read-line entrada nil 'fin) (read-line entrada nil 'fin)) (numero 0 (1+ numero))) ((eql leido 'fin) (file-position entrada 0) numero))) ;;; funcion para construir un string fijo: (defun num-panta (ini fin) (concatenate 'string (princ-to-string ini) " de " (princ-to-string fin) " pantallas")) ;;; funcion para homogeneizar el mensaje que se saca en la ventana ;;; superior derecha de la pantalla encargada de presentar los datos ;;; de la base. (defun sacar-titulo-derecho (ini fin) (if (eql fin 1) (pinta-peque-2 "1 de 1 pantalla") (pinta-peque-2 (num-panta ini fin)))) ;;; funcion para mostrar en sucesivas pantallas los datos de un ;;; fichero que ocupa mas de 5 lineas. (defun recoge-datos-grandes (stream alto-ventana &key (long-fich (num-lineas stream))) (let* ((num-pantallas (ceiling (/ (float long-fich) alto-ventana))) (posiciones (make-array (list num-pantallas) :initial-element nil))) (file-position stream 0) (do ((panta 0) (condicion)) ((eql condicion #\F)) (setf (aref posiciones panta) (file-position stream)) (sacar-titulo-derecho (1+ panta) num-pantallas) (pinta-pant-fichero stream alto-ventana) (cond ((eql panta 0) (setq condicion (do ((condi (char-upcase (read-char *borde-ayuda*)) (char-upcase (read-char *borde-ayuda*)))) ((or (eql condi #\F) (and (/= num-pantallas 1) (eql condi #\S) (incf panta))) condi)))) ((eql panta (1- num-pantallas)) (setq condicion (do ((condi (char-upcase (read-char *borde-ayuda*)) (char-upcase (read-char *borde-ayuda*)))) ((or (eql condi #\F) (and (eql condi #\A) (file-position stream (aref posiciones (decf panta))))) condi)))) (t (setq condicion (do ((condi (char-upcase (read-char *borde-ayuda*)) (char-upcase (read-char *borde-ayuda*)))) ((or (eql condi #\F) (and (eql condi #\A) (file-position stream (aref posiciones (decf panta)))) (and (eql condi #\S) (incf panta))) condi)))))))) ;;; funcion para sacar el contenido del fichero en la ventana, devuelve ;;; FIN si se ha encontrado el final de fichero. (defun pinta-pant-fichero (en long-ventana) (send *standard-output* :clear-screen) (send *standard-output* :set-cursorpos 0 0) (do ((final (peek-char nil en nil 'fin) (peek-char nil en nil 'fin)) (cont 1 (1+ cont))) ((or (eql final 'fin) (>= (1- cont) long-ventana))) (format t "~&~A" (mi-read-line (read-line en))))) ;;; para los mensajes devueltos en un fichero por la base de datos. (defun recoge-datos (fichero) (if (not (probe-file fichero)) (format t "~%! No hay contestaci¢n del Host, puede ~ haberse producido un error !") (with-open-file (en fichero :direction :input) (let ((num-l (num-lineas en))) (cond ((= num-l 0) (format t "~&No hay respuesta de la Base de Datos")) ((<= num-l 5) (do ((linea (read-line en nil 'fin) (read-line en nil 'fin))) ((eql linea 'fin)) (format t "~&~A" (mi-read-line linea)))) (t (if *interfaz* (unwind-protect (progn (def-pant-resp-grande) (pinta-pant-resp-grande) (pinta-pant-titulo-mensajes) (pinta-pant-inferior-grande) (recoge-datos-grandes en 19 :long-fich num-l)) (restaurar-resp-grande)) (do ((linea (read-line en nil 'fin) (read-line en nil 'fin))) ((eql linea 'fin)) (format t "~&~A" (mi-read-line linea)))))))))) ;;; para restaurar la modificacion de la respuesta en pantalla grande (defun restaurar-resp-grande () (restaurar) (inicializar) (pintar)) (defvar *grafic-loaded* t)