Vous êtes sur la page 1sur 165

Curso de VisualLISP

NDICE DE CONTENIDOS

INTRODUCCIN

LISP: PARADIGMA DEL ESTILO DE PROGRAMACIN


FUNCIONAL

PRIMERA PARTE:
EL ENTORNO DE DESARROLLO VISUAL LISP
1. VISUAL LISP
2. EL ENTORNO DE DESARROLLO VISUAL LISP
o
o
o
o
o

El Trabajo con Visual LISP y AutoCAD


Barra de Mens
Las Barras de Herramientas
La Consola Visual LISP
El Editor Visual LISP
Barras de Herramientas
Men Contextual
Teclas Rpidas

SEGUNDA PARTE:
TCNICAS FUNDAMENTALES DE LA PROGRAMACIN LISP
1. TIPOS DE DATOS
o
o
o

TOMOS
TOMOS SIMBLICOS (S-ATOMS)
CONSTANTES
NMEROS
CADENAS DE TEXTO
LISTAS Y CONSES
LISTAS DE UN NIVEL
LISTAS ANIDADAS
LISTAS DE ASOCIACIN (A-LIST)
LA LISTA VACA (NIL)
FUNCIN TYPE: EXAMEN DEL TIPO DE DATO

TIPOS DE DATOS LISP


TIPOS DE DATOS AUTOCAD
TIPOS DE DATOS ACTIVE-X
2. FUNCIONES
o FUNCIONES PRIMITIVAS
OPERADORES ARITMTICOS
FUNCIONES DE ACCESO A LISTAS
CONSTRUCCIN DE LISTAS
PROCESAMIENTO DE LISTAS
TRATAMIENTO DE CADENAS
TRATAMIENTO DE CADENAS CON VLISP
o FORMAS ESPECIALES
o FUNCIONES DEFINIDAS POR EL USUARIO
DEFUN: NUEVAS FUNCIONES PARA LA
EXTENSIN DE LISP
REALES A ENTEROS: TRUCAMIENTO O
REDONDEO
FUNCIONES TRIGONOMTRICAS
LAMBDA
FUNCTION
LOAD
3. ESTRUCTURAS DE CONTROL
o PREDICADOS GENERALES
o PREDICADOS ARITMTICOS
o OPERADORES LGICOS
o OPERADORES LGICOS BINARIOS
Nmeros Binarios
Funcin LSH
Funcin ~ (NOT lgico binario)
Funcin LOGAND
CONVERSIN ENTRE BINARIOS Y
DECIMALES (I)
CONVERSIN ENTRE BINARIOS Y
DECIMALES (II)
Funcin LOGIOR
Funcin BOOLE
o PREDICADOS DEFINIDOS POR EL USUARIO
o ESTRUCTURAS CONDICIONALES

4. FUNCIONES RECURSIVAS E ITERATIVAS


o

FUNCIONES RECURSIVAS
EXTRACCIN DE LOS VRTICES DE UNA
POLILNEA
FUNCIONES ITERATIVAS
REPETICIN UN NMERO DETERMINADO
DE VECES
ITERACIONES SOBRE ELEMENTOS DE UNA
SECUENCIA
CICLOS DEPENDIENTES DE UNA
CONDICIONAL
FUNCIONES DE MAPEADO SOBRE SECUENCIAS
EXTRACCIN DE LOS VRTICES DE UNA
POLILNEA
Una solucin ms eficaz.
CUNDO RECURSIN Y CUNDO ITERACIN?

TERCERA PARTE:
ACCESO A LA BASE DE DATOS GEOMTRICA

ACCESO A LA LISTA DE DATOS DE OBJETO


o EXTRACCIN DE LISTAS DE DATOS DE OBJETO
o TRANSFORMACIN DE LOS DATOS DE OBJETO:
CONVERSIN DE POLILNEAS EN SPLINES
PROGRAMA PL2SP.LSP
EJEMPLOS DE LA UTILIZACIN DE ENTMAKE
o DEFINICIN DE BLOQUES
o DEFINICIN DE CAPAS
SISTEMAS DE COORDENADAS
o EJEMPLO DE TRANSFORMACIN ENTRE SISTEMAS
DE COORDENADAS:
CONVERSIN DE POLILNEAS 3D EN 2D

Visual LISP

LISP fu inicialmente fue desarrollado como un lenguaje


interpretado, aunque las modernas versiones cuentan siempre
con un compilador que transforma el cdigo fuente en lenguaje
de mquina optimizado. Esta compilacin puede ejecutarse de
manera inmediata al cargar en el entorno de desarrollo el
cdigo fuente del programa, lo que facilita el desarrollo al
disponer de una evaluacin de manera inmediata. Para acceder
a este entorno, en el caso del Visual LISP, se teclea desde la
lnea de comando de AutoCAD las instrucciones VLISP VLIDE
(esta ltima para compatibilidad con el Visual LISP de la
versin 14). Las instrucciones LISP se introducen para su
evaluacin en una ventana especial conocida como la Consola
Visual LISP. Si no est a la vista, se puede abrir esta ventana
pulsando el botn de la barra de herramientas.

El cursor que aparece junto al smbolo _$ indica que le sistema


est listo para recibir las expresiones LISP del usuario. La
imagen anterior muestra el resultado de evaluar una expresin
usando funciones aritmticas. La evaluacin se produce al
pulsar <INTRO>. Una vez impreso el resultado aparece de
nuevo el smbolo _$ indicando que el sistema est listo para
recibir una nueva expresin. Este ciclo que se desarrolla en el
intrprete se conoce como bucle de lectura-evaluacinimpresin (read-eval-print loop). Esto significa que el

intrprete lee lo que se ha tecleado, lo evala y entonces


imprime el resultado antes de quedar listo para la nueva
expresin. Al uso de la consola dedicaremos una seccin
especfica de este curso.
El entorno de desarrollo (IDE) Visual LISP cuenta adems con
un Editor especializado y una serie de medios para la
depuracin de los programas muy superiores a los que estaban
disponibles en el viejo AutoLISP.
No obstante, estas lecciones podrn ser seguidas utilizando
cualquier versin de AutoLISP. Se ha tratado de sealar
cuando se est hablando de funciones o modos de operacin
propios del Visual LISP que noi estn disponibles en el entorno
AutoLISP.
Hay otras implementaciones de LISP para uso general
disponibles muchas veces como software gratuito a travs de
internet. Para ms informacin se recomienda acceder a los
siguientes sitios WEB:
AutoCAD-AutoLISP info+tools Pgina AutoCAD/AutoLISP de
Reini Urban.
The Association of Lisp Users Pgina WEB de la Asociacin
de Usuarios de LISP.
Un caso particular es el del Corman Common Lisp, para el
que Reini Urban ha implementado la posibilidad de su
ejecucin desde el entorno AutoCAD y que pudiera sealar un
camino de desarrollo interesante para el futuro. Tambin
existen utilidades para la transferencia de programas
AutoLISP-XLISP desarrolladas por Tony Tanzillo.
EL ENTORNO DE DESARROLLO VISUAL LISP

Visual LISP (VLISP) representa una renovacin de LISP para


AutoCAD, actualizndolo para incluir prestaciones que ya son

normales en los modernos dialectos de LISP que se ajustan a


la normativa COMMON LISP. An sin llegar a ser totalmente
compatible con esta normativa, es significativo el incremento
de su potencia como lenguaje de programacin.
Es particularmente til la posibilidad que se incorpora para la
interaccin con la jerarqua de objetos de la aplicacin
mediante la interfaz ActiveX Automation de Microsoft, y la
posibilidad de responder a eventos mediante la
implementacin de funciones diseadas como reactores.
Como herramienta de desarrollo se aporta un Entorno de
Desarrollo Integrado (IDE) que incluye un compilador y varias
utilidades para la depuracin.
El IDE Visual LISP incluye:

Comprobador de Sintaxis que reconoce secuencias


AutoLISP errneas y el uso incorrecto de los argumentos
en llamadas a las funciones primitivas del lenguaje.
Compilador de Ficheros que incrementa la velocidad de
ejecucin y constituye una plataforma de distribucin que
brinda seguridad al cdigo fuente.
Depurador de Fuentes, diseado especficamente para
AutoLISP, que permite la ejecucin paso a paso del
cdigo fuente en una ventana mientras se observan
simultneamente los resultados obtenidos en la pantalla
grfica de AutoCAD.
Editor de Programacin que emplea la codificacin por
color para LISP y DCL, as como otras caractersticas de
apoyo sintctico.
Formateo LISP automtico que redistribuye las lneas de
cdigo y las identa para facilitar la lectura de los
programas.
Amplias caractersticas de Inspeccin y Vigilancia (Watch)
que permiten el acceso en tiempo real a los valores de las
expresiones y las variables, y que pueden ser empleadas
tanto para datos LISP como para objetos grficos de
AutoCAD.

Ayuda sensible al contexto sobre las funciones AutoLISP y


una ventana Apropos para bsqueda de nombres de
smbolos.
Sistema de Administracin de Proyectos que facilitan el
mantenimiento de aplicaciones con mltiples ficheros
fuente.
Empaquetado de los ficheros AutoLISP compilados en un
nico mdulo de programa.
Capacidad para guardar y recuperar la configuracin del
Escritorio para reutilizar la distribucin de ventanas de
cualquier sesin anterior de VLISP.
Consola Visual LISP Inteligente que permite un nuevo
nivel de interaccin del usuario, con funciones que
amplan las de la ventana de texto habitual de AutoCAD.

El Trabajo con Visual LISP y AutoCAD

VLISP posee su propia ventana de aplicacin distinta de la de


AutoCAD, pero no puede ejecutarse de manera independiente.
Para acceder al IDE Visiual LISP, antes deber haberse iniciado
una sesin de AutoCAD.
Iniciar Visual LISP

Como se dijo antes, Debe haberse iniciado una sesin de


AutoCAD. Esta sesin puede contener slo un dibujo vaco, o
pueden estar abiertos dibujos cuyo contenido se desee
procesar.
Para activar el IDE VLISP tenemos tres opciones:

Seleccionar del men


Herramientas>AutoLISP>Editor Visual LISP
Teclear en la lnea de comandos: VLISP
Nota: Hemos encontrado al menos en una
versin localizada espaola que el comando
VLIDE no es reconocido por el sistema. La
Ayuda de esa misma versin aeala como
alternativa el comando VISUALLISPIDE, que

tampoco es reconocido. En estos casos siempre


se puede recurrir al comando VLIDE, descrito en
el punto siguiente.

La versin anterior de Visual LISP utilizaba con


los mismos fines el comando VLIDE, que sigue
siendo reconocido por la versin 2000. De
hecho, internamente la llamada de AutoCAD al
IDE Visual LISP se realiza mediante este
comando, que veremos aparecer en la lnea de
comandos cada vez que se cambie a ese
entorno.

La Ventana de la Aplicacin

Al iniciarse Visual LISP pasa a primer plano la siguiente


ventana de aplicacin:

Puede seleccionar cada parte de la ventana para una breve


descripcin
Barra de Mens

Asumimos que el lector est familiarizado con el uso de mens


desplegables en AutoCAD u otras aplicaciones. Slo cabra
destacar que stos mens son sensibles al contexto en que se
utilizan. Es decir, que algunas opciones que pueden estar
activas si se abre la ventana del Editor pueden no estarlas si el
foco se encuentra en la Consola o en la ventana de TRACE.
Las funciones de la aplicacin se distribuyen entre los mens
desplegables de la siguiente manera
FILE
Creacin de nuevos ficheros de programas abiertos para
su edicin
Apertura de ficheros existentes
Guardar los cambios efectuados
Compilar aplicaciones Visual LISP
Imprimir los ficheros de programas
EDIT
Copiar y Pegar texto
Deshacer el ltimo cambio en el Editor o la ltima funcin
ejecutada desde la Consola
Seleccionar texto en el Editor o la Consola
Comprobar el cierre de parntesis
Recuperar funciones ejecutadas desde la Consola
SEARCH
Buscar y Reemplazar texto
Colocar marcadores de referencia (bookmarks) y navegar
en el texto utilizando estos marcadores.
VIEW
Buscar y mostrar el valor de variables y smbolos en su
cdigo AutoLISP.
PROJECT
Trabaja con los proyectos y la compilacin de programas
DEBUG

Establecer y quitar puntos de ruptura en los programas


Ejecutar programas paso a paso comprobando el estado
de las variables y el valor devuelto por las expresiones.
TOOLS
Establecer las opciones para el formateado del texto y
varias otras opciones del entorno, tales como la ubicacin
de ventanas y barras de herramientas.
WINDOW
Organiza, abre y cierra ventanas en el IDE.
HELP
Pues eso, la Ayuda en lnea.
Las Barras de Herramientas

Visual LISP dispone de cinco Barras de Herramientas que


pueden activarse/desactivarse desde el men View>Toolbars...
que abre el siguiente dilogo:

Estas cinco Barras de Herramientas contienen las opciones u


comandos esenciales del IDE, facilitando el acceso a los
mismos.

Contiene las herramientas usuales de Crear Nuevo, Abrir,


Guardar, Imprimir, Cortar, Copiar, Pegar, Deshacer,
Rehacer y por ltimo un acceso a la fucin Apropos que

sirve para completar el texto buscando una correlacin de


una subcadena con nombres de funciones, etc.
Incluye las funciones de Buscar, Buscar y Reemplazar.
Adems una casilla de lista desplegable donde se guardan
los trminos anteriormente buscados durante la sesin de
trabajo, lo que permite repetir una busqueda con ms
facilidad, cosa que se hace con la herramienta situada a
la derecha de la casilla. Por ltimo incluye una serie de
herramientas para navegar dentro del texto mediante
marcadores, que se introducen con la herramienta de la
izquierda, se avanza o retrocede con las dos siguientes y
se eliminan con la ltima.
La barra Tools (Herramientas) opera slo con la ventana
del Editor activa. Sus funciones son, de izquierda a
derecha: cargar el cdigo del Editor para su ejecucin
desde la Consola, cargar slo el cdigo seleccionado,
comprobar la sintaxis de todo el contenido de la ventana
del Editor, o con la siguiente, comprobar slo lo
seleccionado. Para formatear el texto se utilizan los
prximos dos botones, el primero para todo el editor y el
segundo slo para el textoseleccionado. Los dos
siguientes botones sirven para marcar como coimentario
el texto seleccionado o para desmarcarlo. Y por supuesto,
el ltimo se trata de la Ayuda en lnea.
Los tres primeros botones de esta barra determinan la
accin al encontrar un punto de ruptura durante la
evaluacin. El primero entra en las expresiones anidadas
posteriores al punto de ruptura, evalundolas desde la
ms interior. El segundo evala esta expresin y se
detiene antes de la siguiente para de nuevo decidir si se
quiere entrar a evaluar las expresiones anidadas. El
tercer botn contina hasta el final de la funcin en curso

y entonces cuando se detiene de nuevo la evaluacin.


El segundo tro de botones tene que ver con las acciones
a tomar cuando se produce una ruptura del flujo de
ejecucin a causa de un error, o de que se alcance un
punto de ruptura prefijado dentro del programa. Aunque
es un tema que se explicar ms adelante, cabe decir
ahora que estos estados de suspensin en la ejecucin
del programa se utilizan para examinar los valores
asumidos por las variables, cambiarlos si es preciso, etc.
El primer botn (Continue) permite terminar con esta
pausa y continuar la ejecucin normal del programa. El
segundo botn (Quit) permite abandonar el nivel de
evaluacin actual (pueden superponerse varios ciclos de
evaluacin si se producen varios errores durante la
depuracin) y pasar al nivel de ms arriba. Y el tercer
botn (Reset) pasa el control de la ejecucin
directamente al nivel superior (Top Level).
El tercer grupo de botones incluye otras tiles
herramientas de depuracin. El botn Toggle Breakpoint
permite aadir un nuevo punto de ruptura en el
programa, situado en la posicin actual del cursor. El
segundo botn (Add Watch) da acceso al dilogo que
permite seleccionar un nombre de variable para observar
sus resultados durante la ejecucin. Estos resultados se
exhiben en una ventana especial, la ventana Watch.
El botn Last Break resalta en la ventana del editor la
expresin que dio origen a la ltima ruptura. En caso de
error, de esta manera se detecta de inmediato dnde se
produjo ste.
El ltimo botn no es realmente un botn de comando.
Sirve simplemente para indicar si la interrupcin actual se
encuentra antes o despus de la expresin.
El primer botn sirve para poner en primer plano la
ventana de aplicacin de AutoCAD. El segundo botn abre

un men donde podemos seleccionar la ventana del IDE


Visual LISP que deseamos poner en primer plano. Esto se
hace necesario pues podemos tener abiertas de manera
simultnea un gran nmero de programas y puede no der
fcil localizar aqulo que queremos.
El tercer botn traslada el foco a la Consola de Visual
LISP. El siguiente permite activar la caracterstica de
Inspeccin (Inspect). Inspect permite examinar y
modificar objetos AutoLISP as como AutoCAD. La
herramienta Inspect crea una ventana separada para
cada objeto sometido a inspeccin.
La siguiente herramienta (Trace Stack) necesita
explicaciones que se salen del marco de esta
introduccin. Baste decir que nos permite acceder a la
memoria de pila donde se guardan las llamadas a
funcin. Puede invocarse en un momento de suspensin
en la ejecucin de un programa y permite mediante un
men contextual acceder a datos relacionados con la
operacin del programa.
El botn que le sigue (Symbol Service) est diseado
para simplificar el acceso a las distintas utilidades de
depuracin relacionadas con smbolos. Podemos resaltar
cualquier nombre de smbolo en el Editor y al pulsar
sobre este botn se abrir la ventana Symbol Service
donde se muestra el valor vinculado. Este valor se puede
cambiar directamente en esta ventana. Adems tiene una
barra de herramientas que permiten otros procesos con el
smbolo seleccionado.
El siguiente botn permite abrir la ventana Apropos que
describimos en detalle ms adelante
Y por ltimo un botn que permite acceder a la ventana
Watch.
La Consola Visual LISP

Aunque parecida a la ventana de texto de AutoCAD en el


hecho de que se puden introducir funciones para evaluarlas y
obtener el resultado en pantalla, la Consola es una
herramienta de mucha mayor potencia y existen varias
diferencias en su manera de operar que es importante tener en
cuenta.
Por ejemplo, para conocer el valor asociado a un smbolo no es
necesario, como en AutoCAD, precederlo de un signo de
admiracin <!>. Basta teclear el nombre de la variable y
pulsar <INTRO>. En la Consola se emiten una serie de
mensajes de diagnstico durante la ejecucin de las funciones
y si se encuentra un error interrumpe la ejecucin y habilita un
nuevo nivel de evaluacin donde podemos ensayar cambios en
valores de variables y realizar pruebas para detectar los
problemas existentes. De producirse un nuevo error, se habilita
un nuevo nivel y as sucesivamente, hasta que decidamos
regresar al nivel superior. Las baras de desplazamiento de la
consola nos permiten revisar los resultados anteriores.
Las prestaciones ms importantes de la Consola se resumen a
continuacin:

Evaluar expresiones AutoLISP y mostrar el resultado


devuelto por dichas expresiones.
Introducir expresiones AutoLISP en lneas mltiples
pulsando para el cambio de lne la combinacin <CTRL>

+ <INTRO>. Pulsar slo <INTRO> provocara la


evaluacin de la expresin tecleada hasta entonces.
Evaluar mltiples expresiones a la misma vez.
Copiar y transferir texto entre las ventanas de la Consola
y el Editor. La mayor parte de los comandos de texto
estn disponibles tambin en la Consola.
Recuperar expresiones tecleadas anteriormente en la
Consola, pulsando la tecla <TAB>. Pulsando esta tecla
varias veces se van recuperando las expresiones
anteriores. Para realizar el ciclo en sentido inverso puede
utilizarse la combinacin <SHIFT> + <TAB>.
La tecla <TAB> tambin permite realizar una bsqueda
de carcter asociativo a travs del conjunto de
expresiones anteriores. Si se quiere buscar anteriores
expresiones de creacin de variables bastara teclear
(SETQ y entonces pulsar <TAB>, con lo que se ira
directamente a la ltima expresin tecleada que
comenzaba as. Para realizar el ciclo en sentido inverso
aqu tambin puede utilizarse la combinacin <SHIFT> +
<TAB>.
Pulsando <ESC> se elimina cualquier texto a
continuacin del smbolo (prompt) del evaluador.
Pulsando <SHIFT> + <ESC> abre una nueva Consola,
dejando el texto escrito en la ventana de Consola anterior
sin evaluar.
Al pulsar el botn derecho del ratn en cualquier punto
de la Consola o tecleando <SHIFT> + <F10> abre un
men contextual de funciones y opviones VLISP. Esto
facilita, por ejemplo, copiar y pegar texto en la lnea de
comandos de la consola, buscar texto e iniciar las
utilidades de depuracin VLISP.

La Consola Visual LISP en Entorno Multidocumento (MDI)

AutoCAD 2000 es capaz de abrir varios dibujos a la vez. Esto


se conoce como Interfaz Multidocumento (Multiple Document
Interface - MDI) en contraposicin con la interfaz de
documento nico de versiones anteriores*. Hay una nica
ventana de Consola para todos los dibujos AutoCAD abiertos.

Cuando se utilizan las barras de desplazamiento para revisar


las expresiones y mensajes de la consola, los veremos todos,
aunque se hayan emitido para distintos dibujos. Esta es otra
diferencia en relacin con la ventana de texto de AutoCAD, que
slo es capaz de mostrar los comandosque corresponden al
dibujo activo. Dicho de otra manera, cada dibujo tiene su
propia ventana de texto, pero comparten una sla Consola
VLISP. El cambio de contexto es automtico al cambiar de
dibujo en AutoCAD. El dibujo activo en AutoCAD es siempre el
dibujo activo en VLISP. El nombre del dibujo activo aparece en
la barra de ttulo de la aplicacin.
El men Contextual en la Consola

El pulsar el botn derecho del


ratn sobre cualquier lugar de la
ventana de la Consola abre un
men contextual donde, segn
est o no seleccionado algn
texto, se habilitarn algunas de
las siguientes opciones:

Cut
Borra el texto seleccionado de la Consola y lo transfiere al
Portapapeles de Windows**.
Copy
Copia el texto seleccionado al Portapapeles de
Windows**.
Paste
Pega el contenido del Portapapeles de Windows en la
posicin indicada por el cursor**.
Clear Console window
Vaca la Ventana de la Consola.
Find
Busca el texto especificado en la Consola.
Inspect

Abre el dilogo de la utilidad Inspect.


Add Watch
Abre la ventana de la utilidad Watch.
Apropos
Abre la ventana del Apropos.
Symbol Service
Abre el dilogo de la utilidad Symbol Service.
Undo
Deshace la ltima operacin.
Redo
Anula el efecto del ltimo Deshacer (Undo).
AutoCAD Mode
Transfiere toda las entradas a la lnea de comandos de
AutoCAD para su evaluacin.
Toggle Console Log
Copia la salida de la Consola a un archivo de registro (log
file).
Cmo utilizar la Consola para seguir este Curso:

La consola es la herramienta fundamental que utilizaremos


para seguir este curso. Encontraremos fragmentos de cdigo
como ste (que fue ya citado en la Introduccin):
(defun extents (plist)
(list (apply 'mapcar (cons 'min plist))
(apply 'mapcar (cons 'max plist))))
Podemos seleccionar dicho fragmento en nuestro browser
utilizando el ratn y copiarlo (<CTRL> + <V>), para despus
pegarlo en la consola.

Hecho esto, pulsamos <INTRO> para que se evale el


contenido de la consola, con lo que ya estar definida la
funcin EXTENTS. Esta funcin requiere como argumento una
lista de puntos (entendindose por puntos una lista de tres
nmeros reales representando las coordenadas X, Y, Z.
Supongamos que queremos utilizar la lista:
'((162.75 35.76 145.99)
(127.77 25.37 91.72)(139.355 1.40 0.088)
(242.12 59.34 121.08)(260.897 64.92 30.33)
(299.29 76.33 -55.96)(187.13 -9.28 235.85)
(313.10 -37.47 96.17))
Para ello la introducirmos en la consola (tambin podemos
copiar y pegar) una nueva expresin con el nombre de la
funcin y la lista como nico argumento:

Y entonces, pulsando <INTRO> obtendremos el resultado


devuelto:

Obsrvese cmo los colores identifican los componentes de las


expresiones, rojo para los parntesis, azul para las funciones,
verdeazul para los nmeros reales. Una vez evaluada los
colores del texto cambian a negro, con lo que se identifica
fcilmente qu formas son las que est en condiciones de ser
evaluadas.

* AutoCAD 2000 puede configurarse para trabajar en modo de


documento nico. Para ello se activa la variable de sistema
SDI. El valor por defecto de SDI es 0, cambindolo a 1 se pasa
a trabajar en modo de documento nico. Trabajando en este
modo, la ventana de texto de AutoCAD contendr los
comandos emitidos para los sucesivos dibujos abiertos.
** Es posible realizar operaciones de cortar, copiar y pegar
entre la consola de VLISP y la ventana de texto de AutoCAD.
El Editor Visual LISP

Es ms que un simple editor de texto. Ser, en realidad,


nuestro lugar de trabajo habitual para la programacin LISP
dentro de AutoCAD. Cada fichero de programa abierto tendr
su propia ventana del Editor
Un programa en el editor tendr ms o menos este aspecto:

Codificacin sintctica por color

Lo que primero llama la atencin la ventana del editor es el


color que adoptan los diferentes componentes del programa. El
editor identifica las distintas partes de un programa LISP y le
asigna distintos colores. Esto permite detectar a primera vista
elementos tales como nombres de funcin, nmeros enteros o
reales y cadenas, distinguindolos de los nombres de funciones
y variables asignados por el usuario. Los errores
mecanogrficos saltan as a la vista de manera inmediata.
Estos colores pueden personalizarse a gusto del usuario.
Controles de la Ventana del Editor

La ventana del Editor no posee Barras de Mens ni de


Herramientas. Al estar el foco situado en una ventana del
Editor se activarn las opciones de Men y las Herramientas de
la ventana de la Aplicacin que pueden usarse para
operaciones del Editor. Muchas de las opciones pueden
tambin ser ejecutadas desde el men contextual que se abre
al pusar el botn derecho del ratn. Existe la posibilidad de
utilizar tambin las combinaciones de teclas rpidas usuales en
los editores de texto y adems algunas combinaciones que se
utilizan para funciones exclusivas de este editor. En trminos
generales, adems de la codificacin por color el editor ofrece
otras ayudas que facilitan grandemente el desarrollo de
programas. Algunas de estas utildades son:

Comprobacin del cierre de parntesis


Formateo del Texto
Comentarios automticos en los cierres de Expresiones

Comentado y Descomentado automtico de las lneas


seleccionadas
Bsqueda y Sustitucin de Texto
Comprobacin de la Sintaxis
Carga de expresiones LISP para ser probadas.

En los prximos apartados pasaremos a exponer estas


funcionalidades:

Barras de Herramientas
Men Contextual
Teclas Rpidas
Copias de Seguridad

El Editor VLISP viene configurado para


hacer siempre copias de seguridad de los
ficheros. Estas copias de seguridad se
sitan en el mismo directorio de la
fuente del programa usando el mismo

nombre y la extensin _ls. De esta


manera la copia de seguridad del fichero
caras.lsp se llamar caras._ls.
Para recuperar la ltima versin
guardada de un fichero se emplea la
opcin Revert del men Files.
Barras de Herramientas

Casi todas las funcionalidades del programa pueden accederse


desde iconos de las Barras de Herramientas. Los iconos que
aparecen agrisados cuando se activa la ventana del Editor no
son utilizables en este contexto. Las Herramientas utilizables
para operaciones en el Editor son:
Herramientas de
Edicin
Bsqueda y
Marcadores
Revisin y
Formateo
Acceso a otras
Ventanas de la
Aplicacin
Utilidades de
Depuracin
Herramientas de Edicin
Esta barra incluye las herramientas de edicin acostumbradas en todo

programa Windows, adems de una propia para completar nombres de


smbolos:

Crear nuevo archivo.


Abrir un archivo existente.
Guardar el contenido de la ventana del editor.
Imprimir
Cortar Texto copindolo al Portapapeles. *
Copiar Texto al Portapapeles.*
Pegar Texto desde el Portapapeles.*
Deshacer la ltima operacin.
Rehacer lo deshecho en la operacin anterior.
Completar el nombre de un smbolo.

Completar Nombres de Smbolos

La Barra de Herramientas de Edicin incluye


una herramienta para completar nombres de
Smbolos. Este Icono realiza una bsqueda
inteligente de nombres de smbolos definidos en
el sistema. Al teclear algunas letras del nombre,
el pulsar este icono inicia la bsqueda. Segn la
cantidad de smbolos que pudieran
corresponder a los caracteres tecleados, puede
abrir un men contextual en la posicin del
cursor, abrir la ventana de resultados de
Apropos o abrir la ventana de inicio de
bsqueda de Apropos si fuera demasiado
extensas las opciones posibles (por ejemplo,
teclear una sla letra inicial). A esta funcin
puede accederse desde el Men
Search>Complete Word by Apropos... y
tambin con la combinacin de teclas rpidas
<CTRL> + <SHIFT> + <BARRA
ESPACIADORA>

Herramientas de Bsqueda de Texto

Bsqueda de texto en mltiples ficheros


La bsqueda de una expresin puede realizarse tanto en el fichero
que se edita como en los ficheros del proyecto u otros grupos de
ficheros seleccionados. Desde el Men se accede mediante
Search>Find o mediante las teclas rpidas <CTRL> + <F>.
La caracterstica ms
interesante de la
herramienta de
bsqueda del Editor
VLISP es su capacidad
de buscar en un grupo
de ficheros
seleccionados y mejor
an, en los ficheros que
configuran un proyecto.
El resultado de la
bsqueda se muestra
en una ventana de
salida, llamada <Find
Output>, donde
aparecen completas las
expresiones donde se
emplea el trmino
buscado. Se puede
configurar la

bsqueda para que


inserte marcadores
(bookmarks) cada vez
que encuentre el
trmino buscado, de
manera automtica.
Buscar y Reemplazar
Para ello
se deber
Permite buscar y reemplazar texto en la ventana
activa
del Editor. Se
marcar la casilla Mark
accede a esta opcin desde el men Search>Replace... (Teclas <CTRL>
Instances (Marcar
+ <H>).
Instancias)
Memorizacin de bsquedas anteriores
Los trminos utilizados en bsquedas anteriores se guardan en una lista
desplegable para su reutilizacin.
Insercin de Marcadores
Los marcadores permiten desplazarse dentro del texto de marcador en
marcador. Disponible en el men Search>Bookmarks>Toggle Bookmark.
Hay problemas con los marcadores al usar la opcin de formateo
automtico del texto. (ver nota ms abajo).

Herramientas de Revisin y Formateo


Carga de Expresiones LISP Seleccionadas
A medida que se escriben, las expresiones seleccionadas pueden
cargarse para ser evaluadas. Al ejecutarse la carga el foco pasa a la
ventana de la Consola VLISP. Disponible en el Men como Tools>Load
Selection (<CTRL> + <SHIFT> + <E>)
Carga de la Ventana del Editor
Puede cargarse tambin para su
ejecucin el contenido total
actual de la ventana del Editor y
no slo las expresiones
seleccionadas. En ambos casos
se informar de los errores que
impidan la carga del programa,
aunque no de los errores
sintcticos que pudieran existir.
Desde el men Tools>Load Text
in Editor (<CTRL> + <ALT> +
<E>)
Comprobacin del Cdigo Seleccionado
Comprueba automticamente la correccin del cdigo tecleado. Puede
comprobar todo el contenido de la ventana o slo de las expresiones
seleccionadas. Los resultados de la comprobacin pasan a la ventana
Build Output. En el ejemplo siguiente se ha suprimido intencionalmente
uno de los argumentos necesarios para ls funcin CONS, lo que es
detectado al ejecutar la comprobacin. Esta opcin est disponible

desde el men Tools>Check Selection o con la combinacin de teclas


<CTRL> + <SHIFT> + <C>.

Comprobacin de la Sintaxis del Programa


El Editor posee una herramienta para comprobar la sintaxis del cdigo
tecleado. El resultado pasa a una ventana llamada Build Output,
donde se sealan no slo los errores evidentes sino determinadas
situaciones que deben ser manejadas con cierto cuidado. Aplicada la
comprobacin de Sintaxis al cdigo anterior obtendramos la siguiente
advertencia:

Esto no impide la ejecucin del programa y corresponde a una tcnica


de programacin perfectamente vlida en LISP, donde una funcin
puede siempre ser empleada como dato. Esta opcin se encuentra
tambin en el men Tools>Check Text in Editor
(<CTRL> + <SHIFT> + <C>).
Formateo del Texto
El editor tiene opciones para formateo del texto, haciendo identaciones
de manera automtica. El estilo de formateo puede ser personalizado en
cierta medida. Puede formatearse todo el contenido de la ventana o slo
las lneas seleccionadas.
Nota: Aunque no lo hemos encontrado descrito en la documentacin del
programa, cuando se formatea un texto que contiene marcadores, stos
se trasladan al inicio del bloque seleccionado para su formateo. De
manera que si tenemos varios marcadores establecidos y formateamos

todo el contenido de la ventana del editor, perderemos los marcadores


quedando slo uno en la primera lnea de la ventana del editor, lo que
obviamente quita toda utilidad que pudiera tener esta funcin de
insercin de marcadores.Comentarios automticos de cierre de
Expresin
Entre las opciones de formateo del texto, adems de la identacin se
incluye la posibilidad de incluir comentarios al cierre de los parntesis
que indican a que funcin corresponden cuando dicha funcin abarca
varias lneas.
Comentado y Descomentado automtico de las lneas seleccionadas
Los comentarios se destacan mediante el esquema de colores elegido
con fondo gris, pero adems de ello, la inclusin de los caracteres <;;;>
al inicio de la lnea se realiza mediante una opcin del men Edit>Extra
Commands>Comment Block y se quitan mediante Edit>Extra
Commands>Uncomment Block.
Si se estuvieran editando archivos DCL, los caracteres introducidos como
seal de comentario sern dos barras inclinadas <//>.
Ayuda
Esta barra de Herramientas incluye tambin el Icono para el Acceso a la
Ayuda en-lnea.

Acceso a Otras Ventanas de la Aplicacin


Estas Herramientas permiten Acceder a las ventanas de:

Autocad
Otras Ventanasde Visual LISP, incluyendo las de otros ficheros abiertos
para su edicin.
La Consola Visual LISP
La ventana de Inspeccin de objetos LISP y AutoCAD.
El Trace Stack, que guarda la memoria de pila de errores.
El Symbol Service para la gestin de Smbolos.
La Utilidad de Apropos.
La Utilidad de Watch.

Utilidades de Depuracin
Slo tres de las herramientas se encuentran disponibles cuando est activa la
ventana del Editor:

Insertar Punto de Ruptura.


Aadir el smbolo seleccionado a la ventana de Watch.

Resaltar en el editor el cdigo que provoc la ltima interrupcin en la


ejecucin del programa.

* Es posible realizar operaciones de cortar, copiar y pegar


entre el Editor VLISP y la ventana de texto de AutoCAD.
Men Contextual del Editor

El pulsar el botn derecho del ratn sobre cualquier


lugar de la ventana del Editor abre un men
contextual donde, segn est o no seleccionado algn
texto, se habilitarn algunas de las siguientes
opciones:
Cut
Borra el texto seleccionado de la Consola y lo
transfiere al Portapapeles de Windows*.
Copy
Copia el texto seleccionado al Portapapeles de
Windows*.
Paste
Pega el contenido del Portapapeles de Windows
en la posicin indicada por el cursor*.
Find
Busca el texto especificado en una o ms
ventanas del Editor.
Go to Last Edited
Desplaza el cursor hacia la ltima posicin
editada.
Toggle Breakpoint
Coloca un punto de ruptura en la posicin del
cursor, o lo elimina en caso de que ya existiera
uno en dicha posicin.
Inspect

Abre el dilogo de la utilidad Inspect.


Add Watch
Abre la ventana de la utilidad Watch.
Apropos
Abre la ventana del Apropos.
Symbol Service
Abre el dilogo de la utilidad Symbol Service.
Undo
Deshace la ltima operacin.
Teclas Rpidas

Las siguientes combinaciones de teclas rpidas son


caractersticas especficas de este editor:
Comandos de ARCHIVO:

<CTRL> + <S>
Guarda el contenido de la ventana activa del Editor.
<CTRL> + <ALT> + <S>
Guarda el contenido de la ventana activa del Editor con
otro nombre de archivo.
<CTRL> + <SHIFT> + <S>
Guarda el contenido de todas las ventanas de Editor
abiertas.
<CTRL> + <F4>
Cierra la ventana de Editor activa.
<CTRL> + <P>

Imprime el contenido de la ventana de Editor activa.


Comandos de Edicin:
<CTRL> + <Z>
Deshacer la ltima operacin en el Editor. Soporta ilimitadas
operaciones de Deshacer, hasta la ltima ocasin en que se
guard el contenido del Editor a disco. Una vez guardado es
imposible deshacer. En ese caso, si fuera necesario, habra que
recuperar la copia de seguridad mediante la opcin Files>Revert.
<CTRL> + <V>
Pegar el contenido del Portapapeles en el lugar sealado por el
cursor.
<SUPR>
Borrar el Texto sealado o el carcter a la derecha del cursor.
<CTRL> + <A>
Seleccionar todo el contenido de la ventana del Editor.
<CTRL> + <M>
Abre un men desplegable con las opciones de bsqueda del
cierre de parntesis.
<CTRL> + <)>
Desplaza el cursor hasta el parntesis de cierre correspondiente.
<CTRL> + <(>
Desplaza el cursor hasta el parntesis de apertura
correspondiente.
<CTRL> + <SHIFT> + <)>
Selecciona la expresin hasta el parntesis de cierre
corresondiente, resaltndola en vdeo inverso.
<CTRL> + <SHIFT> + <(>
Selecciona la expresin hasta el parntesis de apertura
corresondiente, resaltndola en vdeo inverso.
<CTRL> + <E>
Abre un men desplegable con una serie de comandos
adicionales:

Identar Bloque de Texto.


Suprimir la Identacin de un
bloque de Texto.
Identar hasta el nivel actual
Aadir un prefijo a cada lnea de
texto seleccionada.
Aadir texto al final de cada lnea
seleccionada.
Marcar el bloque seleccionado
como comentario.
Desmarcar como comentario el
bloque seleccionado.
Guardar bloque de texto
seleccionado a un archivo.
Convertir el texto seleccionado a
maysculas.
Convertir el texto seleccionado a
minsculas.
Cambiar a maysculas la primera
letra de cada palabra.

Insertar Fecha.
Insertar Hora.
Definir el formato de fecha y
hora.

Ordenar alfabticamente las


lneas seleccionadas.

Insertar el contenido de un
archivo de texto en el lugar
indicado por el cursor

Borrar desde la posicin del


cursor hasta el final de la lnea.

Borrar espacios en torno a la


posicin actual del cursor.

Comandos de Bsqueda:

<CTRL> + <F>
Buscar texto.
<CTRL> + <H>
Buscar y sustituir texto.
<CTRL> + <BARRA ESPACIADORA>

Completar una palabra por similitud a otras existentes en


la ventana actual del Editor. Cuando ya se ha tecleado un
nombre anteriormente, El editor VLISP facilita el
incorporarlo de nuevo al documento con slo teclear los
caracteres iniciales. Si en el ejemplo de arriba
quisiramos teclear de nuevo el nombre de la funcin
PosVert bastara teclear Po y despus pulsar <CTRL> +
<BARRA ESPACIADORA>. Si en lugar de encontrar
PosVert encontrara el nombre de variable pos, bastara
con volver a pulsar <CTRL> + <BARRA ESPACIADORA>
cuantas veces fuera necesaro para llegar al texto
deseado.
<CTRL> + <SHIFT> + <BARRA ESPACIADORA>
Completar una palabra mediante APROPOS (buscando en
todo el conjunto de smbolos AutoLISP.
<ALT> + <.>
Poner o quitar marcador.
<CTRL> + <.>
Desplazarse al prximo marcador.
<CTRL> + <,>
Desplazarse al marcador anterior.
<CTRL> + <SHIFT> + <.>
Seleccionar hasta el prximo marcador.
<CTRL> + <SHIFT> + <,>
Seleccionar hasta el marcador anterior.
Comandos de Vistas:

<CTRL> + <SHIFT> + <I>


Abre una ventana de Inspeccin para introducir una
expresin.
<CTRL> + <SHIFT> + <T>
Abre la ventana de Inspeccin de Trace.
<CTRL> + <SHIFT> + <R>
Abre la ventana de Inspeccin para la ltima pila de error.
<CTRL> + <SHIFT> + <S>
Abre una ventana de Inspeccin para un smbolo.

<CTRL> + <SHIFT> + <W>


Abre la ventana de Vigilancia (WATCH).
<CTRL> + <SHIFT> + <A>
Abre la ventana APROPOS para ayuda con expresiones
LISP.
<CTRL> + <SHIFT> + <B>
Muestra los puntos de interrupcin actuales (en todos los
programas abiertos, no slo la ventana activa).
<F6>
Abre la Consola Visual LISP y/o la pone en primer plano.
Comandos del Proyecto:

<CTRL> + <SHIFT> + <P>


Abre un proyecto existente.
Comandos de Depuracin:

<CTRL> + <W>
Aadir una expresin a la ventana de Vigilancia (WATCH).
<F9>
Aade o suprime un punto de interrupcin en la posicin
actual del cursor.
<CTRL> + <SHIFT> + <F9>
Suprime todos los puntos de interrupcin.
<CTRL> + <F9>
Busca y resalta el cdigo que dio origen a la ltima
interrupcin.
Herramientas de Desarrollo:

<CTRL> + <SHIFT> + <E>


Carga y evala el cdigo seleccionado.
<CTRL> + <ALT> + <E>
Carga y evala el cdigo contenido en la ventana activa
del Editor.
<CTRL> + <SHIFT> + <C>
Comprueba la sintaxis de las expresiones seleccionadas.
<CTRL> + <ALT> + <C>

Comprueba la sintaxis del cdigo contenido en la ventana


activa del Editor.
<CTRL> + <SHIFT> + <F>
Formatea las expresiones seleccionadas.
<CTRL> + <ALT> + <F>
Formatea el cdigo contenido en la ventana activa del
Editor.
Controles de Ventanas:

<ALT> + <F6>
Ajusta la ventana activa al espacio disponible en pantalla.
Comprobacin del cierre de parntesis
Las combinaciones de teclas <CTRL> + <(> y <CTRL> +
<)> permiten localizar el parntesis de apertura o el
parntesis de cierre respectivamente que corresponda a
partir de la posicin donde se sita el cursor. Si se pulsa
simultneamente <SHIFT> el texto quedar seleccionado
(en vdeo inverso).
Completar Texto
Cuando ya se ha tecleado un nombre anteriormente, El
editor VLISP facilita el incorporarlo de nuevo al
documento con slo teclear los caracteres iniciales. Si en
el ejemplo de arriba quisiramos teclear de nuevo el
nombre de la funcin PosVert bastara teclear Po y
despus pulsar <CTRL> + <BARRA ESPACIADORA>. Si
en lugar de encontrar PosVert encontrara el nombre de
variable pos, bastara con volver a pulsar <CTRL> +
<BARRA ESPACIADORA> cuantas veces fuera necesaro
para llegar al texto deseado.

TIPOS DE DATOS

Antes de iniciarnos en la programacin LISP, examinaremos los


datos con que este lenguaje opera. Las posibilidades de un
lenguaje de programacin estn directamente relacionadas con
la oferta de procedimientos y funciones y en sobre qu tipos
de datos pueden ellos operar.
Los tipos de datos originales son los TOMOS y las LISTAS.
Los TOMOS y las LISTAS son mutuamente excluyentes: un
objeto LISP es lo uno o lo otro. Con una excepcin: la lista
vaca o NIL, que estudiaremos ms adelante. Las listas se
construyen recursivamente a partir de tomos y/o listas.
Ejemplos:
TOMOS

LISTAS

a
juan
45

()
(juan)
(a juan 45 z5mn)
((juan 45) a
((z5mn)))

z5mn

AutoLISP y Visual LISP utilizan adems otros tipos de datos


que estudiaremos ms adelante y que resultan necesarios para
la gestin de los dibujos en el entorno AutoCAD.
Tanto los tomos como las listas son expresiones vlidas LISP
que el intrprete lee y evala. Las reglas para la evaluacin de
ambos tipos de objetos se describen a continuacin:
TOMOS
Los tomos son las expresiones LISP ms elementales.
Siempre tienen un nombre constituido por una secuencia
de caracteres y por ello se asemejan a las palabras de un
lenguaje. Los nombres de tomos se separan de otras
expresiones mediante espacios en blanco, parntesis o

cambios de lnea. Un tomo no es divisible. Como norma


general, todos los elementos que no sean una lista se
consideran tomos. Al recibir un tomo, el evaluador lisp
intenta determinar su valor. Este valor puede estar
representado por el nombre mismo del tomo, que
entonces consideraremos como una "constante" o puede
ser un objeto LISP distinto, en cuyo caso estaremos ante
un tomo "simblico". Los tomos simblicos se utilizan
dentro de los programas para almacenar valores, siendo
conocidos entonces como "variables".
LISTAS:
El nombre LISP viene de LISt Processing (Procesamiento
de Listas), indicando el mecanismo fundamental sobre el
que se desarrolla el lenguaje. Las listas LISP son grupos
de valores relacionados, separados por espacios e
incluidos entre parntesis redondos "(" y ")". En LISP, el
orden de los elementos incluidos en una lista es
significativo. En esto se distingue el concepto de lista del
concepto de conjunto, en el que el ordenamiento de los
trminos no tiene relevancia. Otra diferencia entre listas
y conjuntos reside en que en una lista pueden haber
trminos repetidos, mientras que en un conjunto cada
trmino ocurre una sla vez. Las listas proporcionan un
mtodo eficaz para almacenar valores relacionados.
AutoCAD expresa los puntos 3D como una lista de tres
nmeros reales donde el primer valor es el de la
coordenada X, el segundo la coordenada Y, el tercero la
coordenada Z. Esto indica que el orden de los trminos
de una lista es significativo y en esto se diferencia del
concepto de conjunto. Adems una lista admite trminos
repetidos. Dentro de las posibles listas podemos
distinguir tres casos:
Listas de un nivel
Listas anidadas
La lista vaca

TIPOS DE DATOS ESPECFICOS DE AUTOCAD:

CONJUNTOS DE SELECCIN
Los conjuntos de seleccin son grupos compuestos por
uno o varios objetos (entidades). Las rutinas de AutoLISP
permiten aadir o suprimir de forma interactiva objetos
de los conjuntos de seleccin.
NOMBRES DE ENTIDAD
Un nombre de entidad es un identificador numrico
asignado a los objetos de un dibujo. En realidad, se trata
de un puntero a un archivo mantenido por AutoCAD, en el
que AutoLISP puede encontrar el registro de la base de
datos de objetos. Este puntero suele cambiar de una
sesin de trabajo a otra.
DESCRIPTORES DE ARCHIVO
Los descriptores de archivo son identificadores
alfanumricos asignados a archivos abiertos por Visual
LISP. Cuando sea necesario que una funcin de Visual
LISP lea o escriba en un archivo, debe hacerse referencia
a su identificador.
SUBRUTINAS, SUBRUTINAS EXTERNAS Y
FUNCIONES DE USUARIO
Funciones Nativas LISP o funciones externas cargadas
desde archivos compilados FAS VLX y archivos fuente
LISP.
TABLAS DE PAGINACIN
OBJETOS Y TIPOS DE DATOS ACTIVEX
Objetos propios y determinados formatos para los datos
que se pasan a los mtodos ActiveX.

COMPROBACIN DEL TIPO DE DATO:

FUNCIN TYPE
Devuelve el tipo de un elemento designado
(type elemento)

LISTAS Y CONSES

Por la importancia dentro de LISP del tipo de datos LISTA,


citamos in extenso el apartado 2.4 de CLTL2,
Un CONS es una estructura de informacin que contiene dos
componentes llamados el CAR y el CDR. La utilizacin
fundamental de los CONSES es como representacin de
LISTAS.
Una LISTA se define recursivamente ya sea como la lista vaca o

como un CONS cuyo componente CDR es una lista. Una lista


es, por consiguiente, una cadena de CONSES enlazados por
sus componentes CDR y terminada por un NIL, la lista vaca.
Los componentes CAR de los conses son conocidos como los
elementos de la lista. Para cada elemento de la lista hay un
CONS. La lista vaca no tiene ningn elemento.
Para comprender mejor lo anterior, adelantaremos la mencin
de la funcin bsica de construccin de listas, que es la funcin
CONS (que se explica en el apartado FUNCIONES DE
CONSTRUCCIN DE LISTAS). Expresado en trminos de
esta funcin, la anterior definicin de una lista como una
cadena de CONSES sera:

Una LISTA se expresa mediante la escritura de los elementos


de la lista ordenados, separados por espacios en blanco
(caracteres de espacio, tabulador o retorno) y rodeados por
parntesis. Por ejemplo:
(a b c)
;Una lista de tres smbolos
(2.0 (a 1) "*")
;Una lista de tres cosas
diferentes: un nmero real
;otra lista y un carcter asterisco
Nota: El cdigo del ejemplo anterior ha sido
modificado para adaptarlo a las convenciones de
AutoLISP/Visual LISP

La lista vaca puede por lo tanto ser expresada como (), ya que
se trata de una lista sin elementos.
Una lista punteada (dotted list) es una cuyo ltimo cons no
tiene NIL como su CDR, sino otro objeto de informacin (que
tampoco ser un CONS, ya que entonces el CONS
anteriormente mencionado no hubiera sido el ltimo CONS de
la lista).

Tal tipo de lista se conoce como "punteada" debido a la


notacin especial que se emplea en ella: los elementos de la
lista se escriben, al igual que antes, entre parntesis, pero ...
antes del parntesis derecho se escriben un punto (rodeado
por espacios en blanco) y entonces el CDR del ltimo CONS.
Como caso especial, un CONS aislado se expresa escribiendo el
CAR y el CDR entre parntesis y separados por un punto
rodeado de espacios (par punteado). Por ejemplo:
(a . 4)

;Un cons cuyo car es el smbolo a


;y cuyo cdr es un entero
(a b c . d) ;Una lista punteada con tres elementos
cuyo cons final
;tiene el smbolo d en su cdr
Con frecuencia se utiliza el trmino lista para hacer referencia
tanto a verdaderas listas como a listas punteadas. Cuando
resulta importante la distincin, se utilizar el trmino
"verdadera lista" para referirnos a una lista terminada por NIL.
La mayora de las funciones que se dice operan sobre listas
esperan recibir verdaderas listas como argumento.
Por ejemplo, si en el ejemplo de concatenacin de CONSES anterior el
elemento de la derecha del ltimo CONS no hubiera sido NIL (lo que
hubiera incluido un par punteado en la lista), el pasar esta lista como
argumento a una funcin de tratamiento de listas hubiera producido
en determinados casos un error:

A veces se utiliza el trmino rbol para referirse a algunos


CONS y todos los dems CONSES accesibles a l de manera
transitiva a travs de enlaces de CAR y CDR hasta alcanzar
objetos NO-CONS; stos NO-CONSES son conocidos como las
hojas del rbol.

Representacin de LISTAS como rboles.


Tomado de: Corts y Sierra, LISP. Editorial Marcombo,
Barcelona. 1987.
Las listas, las listas punteadas y los rboles no son tipos de
datos mutuamente excluyentes; no son ms que puntos de
vista tiles en torno a las estructuras de CONSES. Hay an
otros trminos tales como LISTA DE ASOCIACIN. Ninguno de
stos son verdaderos tipos de datos LISP.
Los CONSES constituyen un tipo de dato, y NIL es el nico
objeto de tipo NULL. El tipo de dato LISTA significa en LISP la
unin de los tipos de datos CONS y NULL, y por ello engloba
tanto las listas verdaderas como las listas punteadas.
FORMATOS DE LISTAS:

Adems de lo apuntado ms arriba, es conveniente distinguir


entre los siguientes tres formatos de listas:

LISTAS DE UN NIVEL
Contienen slo tomos.
LISTAS ANIDADAS
Contienen a su vez otras listas que se dicen anidadas.
Estas listas anidadas suelen ser conocidas como sublistas. El nmero de niveles de anidacin no est
restringido ni en su profundidad ni en su complejidad. El
nivel ms externo lo llamamos nivel superior o primer
nivel. A los elementos que conforman este nivel los
llamamos elementos de primer nivel.
LISTAS DE ASOCIACIN (A-LIST)
Son listas anidadas que se utilizan con frecuencia como
estructura de datos en LISP. Una A-LIST es una lista de
pares (CONSES) en que cada par constituye una
asociacin. El CAR de uno de estos pares se conoce como
la CLAVE y el CDR constituye el DATO. Una ventaja de la
representacin como A-LIST es la posibilidad de
incrementarla aadindole nuevas entradas al principio
de la lista. Ms an, como la funcin de bsqueda ASSOC
recorre la A-LIST de manera ordenada, las nuevas
entradas pueden "enmascarar" las ms antiguas de
manera que la informacin puede ser modificada de
forma no destructiva.
LA LISTA VACA (NIL)
Como se dijo antes, es la que no contiene ningn
elemento. Se indica como () y recibe un nombre
particular, el de NIL.
La lista vaca tiene un status peculiar en LISP. Es a la vez
un tomo y una lista. Como smbolo representa el valor
lgico de FALSO:

_$ ()
nil
_$ (atom nil)
T
_$ (listp nil)
T
CIERTO Y FALSO
Su negacin (not nil) sera el smbolo T que representa la
condicin lgica de CIERTO.

El smbolo T es tambin una constante en el sentido de


que slo se representa a s mismo.
En Visual LISP, nil y T as como otros elementos que
incluyen los operadores aritmticos (+, -. etc.) son
smbolos protegidos. Cualquier intento de asignarle otro
valor producir un mensaje de advertencia:

Este mensaje aparece como la opcin por defecto y pide


si se desea entrar en un bucle de interrupcin (break
loop). Si se escoge No, el valor del smbolo es
modificado. Si se selecciona S, se interrumpe el
procesamiento y se entra en un ciclo de interrupcin de
Visual LISP, lo que se conoce por el aspecto del smbolo
del evaluador, por ejemplo: _1_$.

El control se ha trasladado a la consola de Visual LISP.


Para asignar valor al smbolo y continuar el
procesamiento se deber pular el botn Continuar en la
barra de herramientas de Visual LISP. Para abortar el
procesamiento se pulsar Reset .
VALORES DEVUELTOS POR LA FUNCIN TYPE

(type dato)
La funcin TYPE permite examinar el tipo a que corresponde
un dato determinado. Los datos que evalan como NIL (por
ejemplo tomos simblicos no vinculados a un valor)
devuelven nil.

El valor devuelto para cada tipo de dato ser alguno de los


tomos que se describen a continuacin:
Tipos LISP:

INT
Nmeros Enteros
REAL
Nmeros de Coma Decimal Flotante
LIST
Listas
STR
Cadenas
SYM
Smbolos
Tipos AutoCAD:

ENAME
Nombres de entidades
FILE
Descriptores de archivo
PAGETB
Tablas de Paginacin de Funciones

PICKSET
Conjuntos de seleccin
SUBR
Funciones AutoLISP internas o funciones cargadas desde
archivos (FAS o VLX) compilados.
USUBR
Funciones de usuario cargadas desde ficheros fuente LSP.
EXRXSUBR
Aplicaciones ObjectARX Externas.
Tipos ActiveX:

SAFEARRAY
Matriz del tipo Safearray. Las matrices que se pasan a los
mtodos ActiveX deben ser del tipo safearray. Estas
matrices son seguras (safe) porque no es posible el
asignar de manera accidental valores fuera de los lmites
de la matriz provocando una excepcin de datos.
VARIANT
Datos del tipo Variant. Los Variant son en esencia
estructuras que se auto-definen y que pueden contener
diferentes tipos de datos. Por ejemplo, cadenas, enteros
y matrices pueden ser representados por Variants. Junto
a los datos se guarda la informacin que identifica el tipo
de dato. Esta caracterstica de auto-definicin hace de los
Variant tiles medios para pasar parmetros a los
servidores ActiveX.
VLA-object
Objetos ActiveX
FUNCIONES

Una vez conocidos los tipos de datos pasaremos a estudiar


cmo utilizarlos. LISP es un lenguaje de programacin

funcional, es decir que suministra funciones para la


manipulacin de los datos.
Los programas LISP se estructuran como formas y funciones.
Segn Corts y Sierra*,
una FORMA es "una expresin simblica en posicin de ser
evaluada. El cmputo de valores, en LISP, se realiza
simplemente mediante la evaluacin de una FORMA. Todas las
FORMAS tienen valor, sean estas constantes numricas,
tomos literales o expresiones simblicas. Uno de los errores
ms tpicos al programar en LISP es el de tratar de evaluar
una FORMA que no tiene valor. El valor de una FORMA es el
resultado de evaluarla...
Hay que remarcar que los trminos expresin simblica y
FORMA pueden aplicarse a la misma entidad; su aplicacin
depender del contexto. Una LISTA puede considerarse como
un dato, como una expresin simblica o considerarse como
parte de un procedimiento; la misma LISTA puede ser
considerada como una FORMA" .
Las formas se evalan (en relacin con determinado contexto)
para producir valores y efectos colaterales. Las funciones se
invocan aplicndolas a argumentos. (Guy L. Steele Jr., Common
Lisp the Language, captulo 5). En el entorno Visual LISP se
identifican como FORMAS las funciones de usuario definidas
dentro de un fichero fuente LSP. Al cargar un programa se
recibe la confirmacin de la carga exitosa del mismo mediante
el siguiente mensaje:

Las funciones son conocidas en matemticas. Mediante ellas se


describe algn tipo de relacin entre un grupo de valores. La
adicin y la multiplicacin son funciones simples. Una funcin
ms compleja sera: f(x)=3x2+2x-15

Esta ltima funcin tambin describe una regla de clculo o


algoritmo. Las funciones realizan los clculos (en trminos
LISP, evaluacin) utilizando para ello sus argumentos y
devuelven un resultado. A iguales argumentos correspondern
iguales resultados.
Segn Corts y Sierra**:
En LISP, los programas se construyen a partir de la
composicin de funciones. Esto permite que tales programas
expresen sus propsitos ms claramente que los programas
convencioneles, y que resulten ms fciles de entender y de
mantener, adems de ser ms fciles de construir.
AutoCAD identifica sus funciones LISP primitivas como el tipo
de dato SUBR, mientras que las formas definidas a partir de
ellas pertenecen al tipo de dato USUBR o "sub-rutina de
usuario" La funcin typedevuelve los tipos correspondientes.
La llamada a una funcin toma la forma de una lista cuyo
primer elemento es un tomo simblico que representa a la
funcin llamada. El resto de los elementos de esa lista pueden
ser tomos y otras listas. Estas sublistas se consideran
tambin llamadas a funciones y se evalan para que su valor
resultante pueda ser pasado como argumento a la funcin que
las contiene.
FUNCIONES PRIMITIVAS

Describimos una serie de funciones como primitivas en el


sentido de que estn definidas en la norma del lenguaje, para
distinguirlas de las funciones creadas por el usuario a partir de
aqullas. En LISP se llama a una funcin mediante la siguiente
sintaxis:
(NOMBREFUNCION <Argumento_1> ... <Argumento_n>)
La suma de dos nmeros sera (+ 5 1)
Para evaluarla LISP procede de la siguiente manera:
a. Lee la expresin completa (+ 5 1)
b. La interpreta como una llamada a una funcin y la identifica
como SUMAR <+>
c. Interpreta 5 como primer argumento y 1 como segundo. El

parntesis de cierre le indica que no hay ms argumentos.


d. La funcin <+> se evala para 5 y 1, devolviendo 6 como
resultado, que a falta de otro destino es impreso en pantalla.
Programar LISP significa llamar a funciones. Bsicamente esto
se hace usando el tipo de dato LISTA. Cualquier lista que no
tenga otra interpretacin como forma especial se considerar
una llamada a una funcin, donde el primer trmino se tomar
como el nombre de la funcin y el resto como sus argumentos.
Las listas de llamadas a funcin pueden estar anidadas, es
decir, que una llamada a funcin se puede estar utilizando
como argumento en otra lista que corresponda a una llamada
a otra funcin. El resultado de la evaluacin de cada nivel de
anidacin es devuelto al nivel de superior, hasta llegar al nivel
ms alto, cuyo valor devuelto se imprimira en la pantalla de
texto o la lnea de comandos.
ARGUMENTOS FUNCIONALES

De lo expuesto ms arriba se concluye que en LISP una


funcin es adems un objeto de datos que puede ser
suministrado a otra funcin como argumento. Esta posibilidad
contribuye a la facilidad con que LISP se puede adaptar a las
necesidades de cualquier programa mediante la incorporacin
de nuevas funciones que en su comportamiento resultan
idnticas a las primitivas.
Un programa que admite funciones como datos debe tambin
suministrar alguna manera de invocarlas. Esto se logra en
Visual LISP mediante la funcin APPLY.
APPLY
(apply funcin lista-args)

APPLY, como su nombre en ingls indica, aplica una funcin


(que recibe como primer argumento) a una lista de
argumentos. La funcin puede ser un objeto de cdigo
compilado, una expresin-lambda, o un smbolo. En este
ltimo caso se utiliza el valor funcional global de dicho
smbolo, aunque ste no puede ser una forma especial.

_$ (apply '+ '(2 4 6))


12
_$ (apply '(lambda (x y z)(+ x y z)) '(2 4 6))
12
_$ (apply 'quote '(2 4 6))
; error: bad QUOTE syntax: ((QUOTE 2) (QUOTE 4)
(QUOTE 6))
_1$
; reset after error
Obsrvese el error provocado por utilizar la forma especial
QUOTE.
Otras muchas funciones LISP requieren argumentos
funcionales. Entre las de uso ms frecuente estn las funciones
de mapeado. MAPCAR, por ejemplo toma dos o ms
argumentos: una funcin y una o ms listas (tantas como
parmetros requiera la funcin) y aplica la funcin
sucesivamente a los elementos de cada lista, devolviendo una
lista con los resultados.
_$ (mapcar '+ '(1 2 3) '(10 100 1000))
(11 102 1003)
Otras muchas funciones admiten funciones como argumentos.
Entre las ms utilizadas tenemos VL-SORT y VL-REMOVE-IF. La
primera es una funcin de ordenacin de uso general. Requiere
una lista y un predicado, y devuelve una lista ordenada
pasando sus elementos dos a dos al predicado.
_$ (vl-sort '(3 2 1 3) '<)
(1 2 3)
VL-REMOVE-IF acepta una funcin y una lista, y devuelve
todos los elementos de la lista para los cuales la funcin
devuelva NIL (falso).
_$ (vl-remove-if 'numberp '("a" 3 4 "c" 5 "d" "e"))
("a" "c" "d" "e")

El programar nuevas funciones utilitarias que aceptan


argumentos funcionales es una parte importante del estilo de
programacin funcional que caracteriza a LISP.
FUNCIONES ARITMTICAS BSICAS

Las funciones aritmticas que tienen como argumento un


nmero devuelven distintos valores dependiendo de que el
argumento proporcionado sea un nmero entero o real. Si
todos los argumentos son enteros, el valor devuelto ser
entero. Por el contrario, si alguno o todos los argumentos son
reales, el valor devuelto ser un nmero real. Por ejemplo:
(/ 12 5) devuelve 2, mientras que (/ 12.0 5) devuelve 2.4
Los argumentos de una funcin aritmtica no son
necesariamente nmeros. Cualquier otra funcin que devuelva
un nmero como resultado es admisible como argumento de
una funcin aritmtica. Ejemplo (* (+ 1 5)(- 20 10))
FUNCIONES BSICAS DE TRATAMIENTO DE CADENAS

Para el tratamiento de cadenas tenemos funciones que


permiten unificar cadenas diferentes, extraer subcadenas de
una cadena mayor, determinar cuntos caracteres hay en una
cadena y transformar los caracteres a maysculas o
minsculas. El predicado WCMATCH permite determinar la
semejanza de cadenas utiliando comodines.
FUNCIONES BSICAS DE ACCESO A LISTAS

Una lista es una manera de representar un conjunto de tomos


y de otras listas. Una lista tiene la forma de un parntesis de
apertura "(" seguido de una serie de tomos o listas, seguido
por otro parntesis de cierre ")". De manera que cualquier
cosa encerrada entre parntesis ser considerada una lista.
Una lista pasada al evaluador LISP ser tratada como una
expresin simblica (S-expresin), es decir, una llamada a
funcin y se considerar el primer trmino de la lista como el
nombre de la funcin. Para que una lista sea tratada como
dato y no como una expresin simblica debe estar contenida

en la forma especial QUOTE. Las funciones bsicas cuya


comprensin es imprescindible para el acceso a la informacin
contenida en listas se pueden reducir a cuatro: QUOTE, CAR,
CDR, y NTH.
FUNCIONES DE CONSTRUCCIN DE LISTAS

Con las funciones del epgrafe anterior podemos descomponer


listas, accediendo a suscomponentes a distintos niveles de
anidacin. Existen otras funciones que podemos utilizar para
componer nuevas listas a base de elementos individuales, ya
sean tomos u otras listas. CONS, LIST y APPEND son funciones
que construyen listas por distintos procedimientos y con
resultados diversos, por lo que es necesario distinguirlas bien.
FUNCIONES ARITMTICAS BSICAS

Cada una de las funciones incluidas en este apartado requiere


que sus argumentos sean todos nmeros. El pasarle un
argumnto no numrico provocar un error. Operan tanto
sobre nmeros enteros como sobre nmeros reales, realizando
los ajustes pertinentes cuando dichos argumentos fueran de
diferente tipo.
+ (suma)
(+ [nmero nmero] ...)
Si proporciona slo un argumento nmero, esta funcin
devuelve el resultado de sumarlo a cero. Ningn
argumento, devuelve 0.
_$ (+ 1 2 3)
6
_$ (+ 1.0 2 3)
6.0
- (resta)
(- [nmero nmero] ...)
Si utiliza ms de dos argumentos nmero, esta funcin
devuelve el resultado de restar del primer nmero la

suma de todos los nmeros, desde el segundo hasta el


ltimo. Si slo utiliza un argumento nmero, la funcin
devuelve el valor resultante de restar nmero a cero.
Ningn argumento, devuelve 0.
_$ (- 10 1 2 3)
4
_$ (- 10 1 2.0 3)
4.0
* (multiplicacin)
(* [nmero nmero] ...)
Si proporciona slo un argumento nmero, esta funcin
devuelve el resultado de multiplicarlo por uno. Ningn
argumento, devuelve 0.
_$ (* 1 2 3)
6
_$ (* 1 2 3.0)
6.0
/ (divisin)
(/ [nmero nmero] ...)
Si utiliza ms de dos argumentos nmero, esta funcin
divide el primer nmero por el producto de todos los
nmeros del segundo al ltimo y devuelve el cociente
final. Si proporciona slo un argumento nmero, esta
funcin devuelve el resultado de dividirlo por uno. Ningn
argumento, devuelve 0.
_$ (/ 30 2 4)
3
_$ (/ 30 2.0 4)
3.75
1+ (incremento)
(1+ nmero)
Devuelve el argumento aumentado (incrementado) en 1
_$ (1+ 6)
7
1- (decremento)
(1- nmero)
Devuelve el argumento reducido (decrementado) en 1
_$ (1- 6)

5
FUNCIONES DE ACCESO A LISTAS

Existen tres funciones bsicas para acceder a los trminos de


una lista: CAR, QUOTE y CDR.
Funciones CAR y QUOTE:

CAR
CAR admite un nico argumento que debe ser una lista o
una expresin cuyo valor sea una lista y devuelve el
primer elemento de dicha lista. Como LISP siempre
interpreta una lista como una llamada a una funcin,
necesitamos una manera de pasar una lista a CAR sin que
LISP trate de procesarla como llamada a funcin.
QUOTE
Con este objetivo se suministra la funcin QUOTE . Una
lista dentro de una funcin QUOTE no se tratar de evaluar
como llamada a una funcin. La llamada a la funcin
QUOTE se puede abreviar utilizando el signo apstrofe <
>.
Funciones CDR y NTH:

CDR

CDR recibe tambin una lista y devuelve el resto de la


lista despus de eliminar el primer elemento (CAR
lista). Por lo tanto puede contemplarse como la funcin
complementaria de CAR. Una manera de interpretar una
lista en LISP es como la conjuncin de un CAR y un CDR.
Se podr acceder a cualquier trmino de una lista
mediante los anidamientos apropiados de CAR y CDR.
(CAR lista) ;primer trmino
(CAR (CDR lista)) ;segundo trmino
(CAR (CDR (CDR lista))) ;tercer trmino

y as sucesivamente... Para simplificar las expresiones se


permite crear nombres compuestos para anidamientos de
CAR y CDR de la siguiente manera:
comenzando por una primera letra C
una letra A por cada CAR o una D por cada CDR
terminando con una letra R
as (CAR (CDR (CDR lista))) sera lo mismo que
(CADDR lista).

De esta manera podemos construir hasta 28 funciones


distintas para acceso a listas. Segn Johnson* estas 28
concatenaciones se pueden dividir en cuatro grupos,
tomando como base la profundidad a que pueden acceder
en listas anidadas en varios niveles.
Funciones de acceso al nivel superior:

Funciones de acceso al segundo nivel de anidamiento:

Funciones de acceso al tercer nivel de anidamiento:

Funciones de acceso al cuarto nivel de anidamiento:

Por supuesto, que estas funciones pueden a su vez


combinarse para acceder a niveles an ms profundos de
anidacin.
NTH

NTH permite simplificar estas expresiones para listas muy


largas:
(nth n lista)
Donde el argumento n es el nmero del elemento que
debe devolverse (cero es el primer elemento). Si n es
mayor que el nmero de elemento mayor de la lista, NTH
devuelve nil .

EJEMPLOS:

De lo antes expuesto resultara:


_$ (car '(a b c))
normal
A
_$ (cdr '(a b c))
(B C)
_$ (cddr '(a b c))
(D)
_$ (cdddr '(a b c))
es una lista vaca
nil
_$ (car '(a b . c))
lista termina en un par punteado
A
_$ (cdr '(a b . c))
(B . C)
_$ (cddr '(a b . c))
C
de la lista no es un CONS

;Caso de una lista

;el ltimo objeto


;Caso en que la

;el ltimo objeto

_$ (cdddr '(a b . c))


;lo que provoca
un error
; error: bad argument type: consp C
_1$

FUNCIONES DE CONSTRUCCIN DE LISTAS

La funcin CONS

CONS es el constructor de lista bsico. Construye listas


insertando elementos en listas existentes (incluso vacas). El
nuevo elemento ocupa el primer lugar de la lista (CAR lista).
(cons nuevo_elemento lista)
El nuevo_elemento puede ser un tomo o una lista.
La funcin CONS tambin acepta un tomo en lugar del
argumento lista, en cuyo caso construye una estructura
denominada par punteado. El CDR de un par punteado es el
segundo trmino ya extrado de la lista, es decir, sin los
parntesis.
Ejemplo: (cons 'a 'b) devuelve (A . B) y (cdr '(a . b))
devuelve B.
Debe tenerse en cuenta que CONS, al igual que casi todas las
funciones LISP es una funcin no destructiva, es decir que no
altera los argumentos que recibe. As que para conservar la
lista con el nuevo primer elemento, ser necesario utilizar
SETQ. La funcin ms general para incorporar nuevos
elementos a una lista sera entonces:
(setq nombre_lista (cons nuevo_elemento
nombre_lista))
donde nombre_lista sera el smbolo asociado al objeto lista.
la funcin opera aunque nombre_lista no hubiera sido

previamente asociado a una lista, pues no debemos olvidar


que un smbolo no asociado se evala como NIL, que es, a su
vez, equivalente a una lista vaca.
Ejemplo:
_$
(A
_$
(A
_$
(A

(cons 'a 'b)


. B)
(cons 'a (cons 'b (cons 'c '())))
B C)
(cons 'a '(b c d))
B C D)

Funciones de ejemplo usando CONS/CAR/CDR


La funcin LIST
(list expr ...)

LIST Recupera cualquier nmero de expresiones y las combina


en una lista. Admite tanto tomos como listas. Si uno de los
agumentos es una lista vaca NIL aparecer como uno de los
trminos de la lista.
Ejemplo:
_$ (list 3 4 'a (car '(b . c)) (+ 6 -2))
(3 4 A B 4)
_$ (list (list 'a 'b) (list 'c 'd 'e))
((A B) (C D E))
La funcin APPEND
(append lista lista ...)

APPEND Se utiliza para combinar listas. Elimina el primer nivel


de anidacin de cada una de las listas que recibe para
combinar todas en una misma lista. Si una de las listas que
recibe est vaca esta lista no aparecer en la lista resultante.
Ejemplo:
_$ (append '(a b c) '(d e f) '() '(g))
(A B C D E F G)

Una muestra de la utilizacin de APPEND para eliminar las


sublistas vacas:
_$ (apply 'append '(("M") ("a") nil ("r") ("i") nil))
("M" "a" "r" "i")
OTRAS FUNCIONES PARA TRATAMIENTO DE LISTAS

REVERSE devuelve una lista con sus elementos invertidos


(reverse lista)
Opera nicamente sobre el primer nivel de anidacin. Las listas
anidadas a otros niveles no son afectadas. Suele utilizarse para
volver a su orden original los objetos en listas construidas
mediante CONS.
_$ (reverse '("M" "a" "d" "r" "i" "d"))
("d" "i" "r" "d" "a" "M")
LENGTH devuelve un nmero entero que indica el nmero de
elementos de una lista
(length lista)
Slo cuenta elementos en el primer nivel de anidacin. No se
consideran los elementos incluidos en sub-listas.
_$ (length '((0 . "CIRCLE")(8 . "0")(10 242.426
157.686 0.0)(40 . 27.7503)))
4
ASSOC
(assoc elemento lista_asoc)
Busca una lista de asociaciones de un elemento y devuelve la
entrada asociada de la lista

_$ (assoc 10 '((0 . "CIRCLE")(8 . "0")(10 242.426


157.686 0.0)(40 . 27.7503)))
(10 242.426 157.686 0.0)
SUBST
(subst elemento_nuevo elemento_antiguo lista)
Busca un elemento antiguo en una lista y devuelve una copia
de sta con un elemento nuevo en lugar de cada aparicin del
elemento antiguo.
_$ (subst nil "d" '("M" "a" "d" "r" "i" "d"))
("M" "a" nil "r" "i" nil)
_$
FUNCIONES BSICAS DE TRATAMIENTO DE CADENAS

Las funciones bsicas de tratamiento de cadenas aqu


expuestas son las incluidas con AutoLISP nativo. A ellas se
unen una serie de funciones adicionales suministradas con
Visual LISP y los API especficos de las aplicaciones soportadas
sobre AutoCAD como AutoCAD MAP.
ASCII
Devuelve el cdigo ASCII (un nmero entero) del primer
carcter de una cadena
_$ (ascii "Madrid")
77
CHR
Devuelve el carcter que corresponde al cdigo ASCII (un
nmero entero) que se ler pasa como argumento
_$ (chr 77)
"M"
STRCAT
(strcat cadena1 [cadena2] ...)
Devuelve una cadena que es la concatenacin de varias
cadenas

_$ (strcat (chr 77) "adrid")


"Madrid"
STRLEN
(strlen [cadena] ...)
Devuelve un nmero entero que indica la cantidad de
caracteres de una cadena
_$ (strlen "Madrid")
6
SUBSTR
(substr cadena inicio [longitud])
Devuelve una subcadena de una cadena
_$ (substr "Madrid" 3 2)
"dr"
STRCASE
(strcase cadena [cul])
Devuelve todos los caracteres alfabticos de una cadena
en maysculas o minsculas
_$ (strcase "Madrid")
"MADRID"
_$ (strcase "Madrid" T)
"madrid"
WCMATCH
(wcmatch cadena patrn)
Realiza bsquedas con patrones de comodines en una
cadena
_$ (wcmatch "Madrid" "?a?r*")
T
_$ (wcmatch "Madrid" "?d?r*")
nil
READ
(read [cadena])
Devuelve el primer tomo o la primera lista contenida en
una cadena
_$ (read "Madrid es una ciudad")
MADRID
_$ (read (strcat "(" "Madrid es una ciudad" ")"))
(MADRID ES UNA CIUDAD)
FUNCIONES VISUAL LISP DE TRATAMIENTO DE CADENAS

(vl-prin1-to-string object)
Devuelve la representacin como cadena de cualquier
objeto LISP tal como si fuera la salida de la funcin PRIN1
_$ (setq file_id (open "test.tmp" "w"))
#<file "test.tmp">
_$ (vl-prin1-to-string file_id)
"#<file \"test.tmp\">"
(vl-princ-to-string object)
Devuelve la representacin como cadena de cualquier
objeto LISP tal como si fuera la salida de la funcin
PRINC
_$ (setq file_id (open "test.tmp" "w"))
#<file "test.tmp">
_$ (vl-princ-to-string file_id)
"#<file test.tmp>"
(vl-string->list string)
Convierte una cadena en una lista de cdigos de carcter
numricos ASCII
_$ (vl-string->list "Madrid")
(77 97 100 114 105 100)
(vl-string-elt string position)
Devuelve la representacin ASCII del carcter situado en
la posicin especificada en una cadena. El primer carcter
ocupa la posicin cero
_$ (vl-string-elt "Madrid" 0)
77
_$ (chr 77)
"M"
_$
(vl-string-left-trim character-set string)
Quita los caracteres especificados del inicio de una
cadena
_$ (vl-string-left-trim "PRE" "PREFIJO")
"FIJO"
(vl-string-mismatch cad1 cad2 [pos1 pos2 ignorarcaja])

Devuelve la longitud del prefijo comn ms largo para


dos cadenas (cad1 cad2), comenzando en las posiciones
que se especifican (pos1 pos2) teniendo en cuenta o no
la diferencia entre maysculas y minsculas (ignorarcaja)
_$ (vl-string-mismatch "vl-fun" "avl-var")
0
_$ (vl-string-mismatch "vl-fun" "avl-var" 0 1)
3
_$ (vl-string-mismatch "VL-FUN" "VL-VAR")
3
_$ (vl-string-mismatch "VL-FUN" "Vl-vAR")
1
_$ (vl-string-mismatch "VL-FUN" "Vl-vAR" 0 0 T)
3
(vl-string-position code-car cad [pos-inic [desde-final]])
Busca el carcter con el cdigo ASCII especificado en una
cadena
_$ (vl-string-position 100 "Madrid")
2
_$ (vl-string-position 100 "Madrid" nil T)
5 ;a partir de la derecha se encuentra la ltima 'd'
(vl-string-right-trim conj-caracteres cadena)
Quita los caracteres especificados del final de una cadena
_$ (vl-string-right-trim "FIJO" "PREFIJO")
"PRE"
(vl-string-search patron cadena [pos-inicial])
Busca el patrn especificado dentro de una cadena
_$ (vl-string-search "dr" "Madrid")
2
(vl-string-subst nueva-cad patron cadena [pos-inicial])
Sustituye una subcadena (patron) por otra (nueva-cad)
dentro de una cadena dada, a partir de la posicin (posinicial) especificada
_$ (vl-string-subst "leyenda" "cadena" "Una cadena
sustituida")
"Una leyenda sustituida"
_$ (vl-string-subst "esta" "cadena" "Una cadena u
otra cadena a sustituir" 0)

"Una esta u otra cadena a sustituir"


_$ (vl-string-subst "esta" "cadena" "Una cadena u
otra cadena a sustituir" 10)
"Una cadena u otra esta a sustituir"
(vl-string-translate conj-origen conj-dest cad)
Reemplaza caracteres en una cadena con un conjunto
especificado de caracteres
_$ (vl-string-translate "abcABC" "123123" "A = a, B =
b, C = C")
"1 = 1, 2 = 2, 3 = 3"
_$ (vl-string-translate "abc" "123" "A = a, B = b, C
= C")
"A = 1, B = 2, C = C"
(vl-string-trim conj-caract cadena)
Quita los caracteres especificados del inicio y del final de
una cadena
_$ (vl-string-trim "Ser" "Ser o no Ser")
" o no "
FORMAS ESPECIALES

Algunas funciones LISP se consideran como Formas


Especiales porque evalan los argumentos recibidos de
una manera diferente que la mayora de las funciones
llamadas desde Visual LISP. Una funcin tpica evala
todos los argumentos que se le pasan antes de actuar
sobre ellos. Las Formas Especiales o no evalan todos sus
argumentos, o slo evalan algunos argumentos bajo
determinadas condiciones. Por ejemplo, defun se
considera una Forma Especial, ya que tiene como
resultado el definir una nueva funcin de usuario a partir
de los argumentos que recibe, sin evaluar los mismos.
Las siguientes funciones AutoLISP y Visual LISP se
incluyen en la categora de Formas Especiales:
AND
OR
COMMAND
PROGN
COND
QUOTE

DEFUN
DEFUN-Q
FOREACH
FUNCTION
IF
LAMBDA

REPEAT
SETQ
TRACE
UNTRACE
VLAX-FOR
WHILE

FUNCIONES DEFINIDAS POR EL USUARIO

Un programa grande suele dividirse en una serie de pequeas


formas o funciones de usuario ms fciles de implementar y
depurar. Las mismas se componen a partir de llamadas a las
funciones primitivas. Estas llamadas tendrn la forma de listas
que podrn anidarse unas dentro de otras de acuerdo a lo que
requiera la complejidad de la manipulacin que quiera
realizarse de los datos aportados como argumentos. Para la
definicin de funciones de usuario normalmente utilizaremos la
forma especial DEFUN. Otra manera de representar funciones
de usuario son las expresiones LAMBDA. El estudio de su
relacin con DEFUN contribuir a una mejor comprensin del
proceso. La carga de las funciones de usuario guardadas en
ficheros se realiza mediante la funcin LOAD. Un fichero en que
se guarda un programa LISP contiene las distintas formas o
funciones de usuario, una a continuacin de la otra,
terminando por la funcin que debe invocarse para iniciar la
ejecucin del programa. Esto se debe a que la funcin LOAD
imprimir en pantalla el nombre de la ltima forma evaluada.
El nombre de esta funcin inicial se suele comenzar con los
caracteres "C:" lo que indica al sistema que dicha funcin de
usuario debe tratarse como si fuera un comando nativo de
AutoCAD, en el sentido de que pueda invocarse tecleando el
nombre (sin el prefijo "C:") sin encerrarlo entre parntesis.
Una funcin de este tipo no admite argumentos en su lista de
parmetros, aunque s la declaracin de variables locales.
FUNCIONES DEFINIDAS POR EL USUARIO

LA PRIMITIVA DEFUN

(defun sm lista-argumentos expresin ...)


DEFUN permite definir una nueva funcin de usuario con el
nombre sm (el nombre de la funcin se incluye
automticamente en un QUOTE). Detrs del nombre de la
funcin aparece una lista de parmetros (posiblemente vaca),
con los argumentos a recibir, y que puede estar seguida por
una barra oblicua y los nombres de uno o ms smbolos locales
(variables locales) que sern definidas para uso exclusivo de
esta funcin. Esta barra oblicua debe ir separada del primer
smbolo local y del ltimo argumento, si existe, por un espacio
como mnimo. Si no declara ningn argumento ni variable
local, se debe incluir una lista vaca tras el nombre de la
funcin. Los argumentos son tratados como una especie de
variables locales en el sentido de que no estarn disponibles
fuera de la funcin. Los nombres de argumentos deben ser
nicos dentro de la misma funcin.
A continuacin de la lista de parmetros se debern incluir
todas las expresiones que debern ser evaluadas al llamar a la
nueva funcin de usuario.
A diferencia de muchas funciones primitivas AutoLISP, las
funciones definidas por el usuario no pueden tener argumentos
opcionales. Una llamada a una funcin de usuario debe
suministrar valores para todos los argumentos declarados.
DEFUN no es una funcin normal, sino lo que se incluye entre
las llamadas formas especiales, en el sentido de que sus
argumentos no son evaluados. Lo sern ms tarde, al llamar a
la nueva funcin, sustituyendo sus argumentos por los valores
que se desea procesar.
La siguiente expresin define una funcin llamada DOBLE que
devuelve el doble de su argumento (nmero real o entero).
_$ (defun doble (x)(* x 2))
DOBLE
As hemos creado una nueva funcin Lisp que puede llamarse
desde el nivel superior o anidada en otras funciones:

_$ (doble 1)
2
Un programa Lisp usualmente incluye una coleccin de tales
defuns, asemejndose en ello a un fichero de definiciones de
procedimientos en lenguajes tales como C o Pascal.
Pero, segn puntualiza Graham, "algo muy diferente est
sucediendo aqu. Las funciones Lisp son objetos por s mismas.
Lo que realmente hace DEFUN es construir una funcin y
guardarla bajo el nombre que aparece como primer
argumento." Paul Graham, On Lisp, pg. 10
Podemos acceder a la funcin asociada al smbolo DOBLE
utilizando la funcin Visual LISP vl-symbol-value:
_$ (vl-symbol-value 'DOBLE)
#<USUBR @045677ac DOBLE>
En versiones anteriores de AutoLISP la funcin creada con
defun era una lista:
Command: (defun doble (x) (* x 2))
DOBLE
Command: !doble
((X) (* X 2))
Command: (car doble)
(X)
Command: (cdr doble)
((* X 2))
En Visual LISP la funcin de usuario creada con defun es una
funcin compilada que contiene instrucciones en lenguaje de
mquina, por lo tanto en Autocad 2000 obtendremos:
Command: (defun doble (x) (* x 2))
DOBLE
Command: !doble
#<SUBR @01d5ba28 DOBLE>
Command: (car doble)

; error: bad argument type: consp #<SUBR @01d5ba28


DOBLE>
Command: (cdr doble)
; error: bad argument type: consp #<SUBR @01d5ba28
DOBLE>
REALES A ENTEROS: TRUCAMIENTO O REDONDEO

Como explicbamos en un captulo anterior, la funcin FIX


convierte los nmeros reales a enteros a base de un simple
truncamiento de la parte no entera. Este procedimiento no es
satisfactorio en muchos casos donde se requiere un grado
mayor de precisin. As obtendremos el mismo resultado para
(fix 6.1) que para (fix 6.9), en ambos casos simplemente 6.
Una conversin ms precisa se obtiene utilizando para la
conversin la funcin RTOS que adems de convertir el nmero
real a binario, es capaz, cuando se especifica cero como
nmero de decimales, de realizar unna aproximacin al entero
ms cercano. As (rtos 6.1 2 0) devuelve 6 mientras que (rtos
6.9 2 0) devuelve 7.
Podemos definir una funcin ROUND de redondeo como sigue:
(defun round (num)
(read (rtos num 2 0))
) ;_ fin de defun
Hasta ah bien, pero para 6.5 esta funcin realizara la
aproximacin al entero mayor, que en este caso sera 7. Con lo
que no se cumplira la definicin propuesta para la norma de
Common LISP, donde se especifica que:
si el nmero se encuentra exactamente a mitad de camino
entre dos enteros (es decir, en la forma entero + 0.5),
entonces se redondea al entero par ms prximo (divisible por
2). (Steele, CLTL2)

Para cumplir esta especificacin deberemos desarrollar una


funcin ms compleja, que llamaremos CL-ROUND, siguiendo
la norma citada.
Esta funcin requerir un predicado tambn norma de
Common LISP, pero ausente an de AutoLISP-Visual LISP. El
predicado EVENP que comprueba si un nmero entero es par.
(defun evenp (num)
(zerop (rem num 2))
) ;_ fin de defun
La nueva funcin cl-round recibe el nmero del cual
comprueba:

si una vez redondeado el resultado NO es par (not


(evenp (setq tmp (rnd num))))
si la parte decimal (valor absoluto) es igual a 0.5 (=(abs
(rem num 1)) 0.5)

En caso de que ambas condiciones sean ciertas:

si el nmero es negativo, se le suma 1


si el nmero es positivo se le resta 1

(defun cl-round (num / tmp)


(if
(and
(not (evenp (setq tmp (rnd num))))
(= (abs (rem num 1)) 0.5)
)
(if (minusp tmp)(setq tmp (1+ tmp))(setq tmp (1tmp)))
) ;_ fin de if
tmp
) ;_ fin de defun
NUEVAS FUNCIONES TRIGONOMTRICAS

Las funciones trigonomtricas que ofrece AutoLISP como


primitivas se reducen a tres: SENO, COSENO y
ARCOTANGENTE. Muchas operaciones geomtricas requerirn,
sin embargo, recurrir a otros operadores trigonomtricos. Esto
puede servir de ejemplo a la posibilidad de desarrollar nuevas
funciones utilitaria dentro de LISP.
Funciones Trigonomtricas primitivas de AutoLISP:

SIN
(sin ang)
Devuelve el seno de un ngulo expresado en radianes.
COS
(cos ang)
Devuelve el coseno de un ngulo expresado en radianes.
ATAN
(atan num1 [num2])
Devuelve el arcotangente de num1, en radianes, si se le
suministra solamente num1. Si se suministraran ambos
argumentos num1 y num2, ATAN devuelve el arcotangente
de num1/num2, en radianes. Si num2 fuera cero, devolver
un ngulo de ms o menos 1.570796 radianes (+90
grados o 90 grados), segn el signo de num1. El rango
de ngulos devuelto es -pi/2 a +pi/2 radianes.
Funciones de conversin:

Puesto que AutoLISP trabaja con radianes mientras que


AutoCAD lo hace por defecto en ngulos sexagesimales, sera
necesario tener a mano siempre las funciones de conversin
grados-radianes.
Conversin entre grados y redianes:
;;;recibe ang en radianes y lo devuelve en grados
(defun grados (rad)
(* (/ rad pi) 180.0)
);_fin de defun
;;;recibe ang en grados y lo devuelve en radianes
(defun radianes (grd)

(* (/ grd 180.0) pi)


);_fin de defun
Las funciones trigonomtricas no incluidas con AutoLISP:

Las siguientes funciones trigonomtricas han sido publicadas


por Jon Fleming.
Autor: Jon Fleming < jonf@fleming-group.com>, Mayo
20 1997.
fuente: Grupo de Noticias
autodesk.autocad.customization
Obsrvese que:

Algunas de las funciones (ASEC -arcosecante- y ACSC


-arcocosecante-) utilizan otras funciones definidas en
este mismo archivo.
Ninguna de estas funciones comprueban la validez de los
argumentos que reciben. Esta comprobacin debe
hacerse en los programas que las invocan.
Las funciones se han desarrollado evitando la posibilidad
de un error de divisin por cero.
Se ha determinado experimentalmente que 9.7E307 es el
nmero mayor que puede ser generado en AutoLISP
(R14).
Visual LISP en Autocad 2000 (R15) y 2002 al
producirse un nmero en exceso del mayor valor real
admitido, en lugar de generar un error devuelve el
smbolo 1.#INF, que puede asignarse a una variable que
sea devuelta en caso de divisin por cero:
Podemos definir una funcin que nos devuelva este
smbolo. Para ello contamos con el predicado no
documentado VL-INFP que detecta cuando un nmero
rebasa el mximo valor admitido para los nmeros
reales:

(defun infinito ( )
(setq *INF* 2.0)
(while (not (VL-INFP *INF*))

(setq *MAX-REAL* *INF* *INF* (expt *INF* 2))))


_$ (infinito)
1.#INF
_$ *MAX-REAL*
1.34078e+154
_$ *inf*
1.#INF
as tendremos que cualquier nmero dividido entre *INF*
devolver cero y tendremos definida una variable global *MAXREAL* que nos permitir comprobar si un valor se aproxima al
mximo valor real admitido por el sistema:
(/ 254.98 *INF*) 0.0
TAN
acepta cualquier ngulo en radianes y devuelve la
tangente en un rango de -9.7E307+epsilon a 9.7E307,
ambos inclusive. Se analiza la posibilidad de que el
coseno del valor pasado sea igual a cero, para evitar un
error de divisin por cero.
(defun tan (z / cosz)
(if (zerop (setq cosz (cos z)))
*INF*
(/ (sin z) cosz)
) ;_fin de if
) ;_fin de defun
SEC
Acepta cualquier ngulo en radianes, devolviendo la
secante en los rangos de -9.7E307+epsilon a -1.0, ambos
inclusive y de 1.0 a 9.7E307, ambos inclusive
(defun sec (z / cosz)
(if (zerop (setq cosz (cos z)))
*INF*
(/ 1.0 cosz)
) ;_fin de if
) ;_fin de defun
CSC

Acepta cualquier ngulo en radianes, devolviendo la


cosecante en los rangos de -9.7E307+epsilon a -1.0,
ambos inclusive y de 1.0 a 9.7E307, ambos inclusive
(defun csc (z / sinz)
(if (zerop (setq sinz (sin z)))
*INF*
(/ 1.0 sinz)
)
)
ASIN (seno inverso)
acepta un argumento en el rango -1.0 a 1.0 ambos
inclusive, y devuelve un ngulo en radianes en el rango
de (-pi/2) a (pi/2) ambos inclusive.
(defun asin (z /)
(atan z (sqrt (- 1.0 (* z z))))
) ;_fin de defun
ACOS (coseno inverso)
acepta un argumento en el rango -1.0 a 1.0 ambos
inclusive, y devuelve un ngulo en radianes en el rango
de pi a 0 ambos inclusive
(defun acos (z /)
(atan (sqrt (- 1.0 (* z z))) z)
) ;_fin de defun
ASEC (secante inversa)
acepta un argumento en uno de dos rangos: menos
infinito a -1 ambos inclusive o 1 a infinito, ambos
inclusive, y devuelve un ngulo en radianes en el rango
de pi a 0, ambos inclusive (excepto EXACTAMENTE pi/2
que nunca ser devuelto en un ordenador con precisin
numrica finita)
(defun asec (z /)
(acos (/ 1.0 z))
) ;_fin de defun
ACSC (cosecante inversa)
acepta un argumento en uno de dos rangos: menos
infinito a -1, ambos inclusive o 1 a infinito, ambos
inclusive, y devuelve un ngulo en radians en el rango
-pi/2 a pi/2, ambos inclusive (excepto EXACTAMENTE 0.0

que nunca ser devuelto en un ordenador con precisin


numrica finita)
(defun acsc (z /)
(asin (/ 1.0 z))
) ;_fin de defun
ACOT (cotangente inversa)
acepta un argumento en el rango de menos infinito a ms
infinito, ambos inclusive y devuelve un ngulo en
radianes en el rango de pi a 0, ambos inclusive.
(defun acot (z /)
(- (/ pi 2.0) (atan z))
) ;_fin de defun
EXPRESIONES LAMBDA

La independencia de ambos procesos, la construccin de la


funcin y el asignarle un nombre se comprende claramente si
analizamos la funcin LAMBDA.
(lambda argumentos expr ...)
Mediante ella, podemos referirnos a una funcin literalmente
de la misma manera que lo haramos con un nmero o una
cadena de texto. Un nmero se representa a s mismo. Una
cadena se representa mediante una serie de caracteres
rodeados de comillas dobles. Para representar una funcin se
utilizan expresiones-lambda.
Una expresin-lambda es una lista de tres componentes:
1. El smbolo lambda
2. Una lista de parmetros
3. Una serie de expresiones que se evalan al ejecutar la
funcin.
Una funcin equivalente a doble es la referida por la siguente
expresin-lambda:
_$ (lambda (x)(* x 2))
#<USUBR @0344f0dc -lambda->

La forma especial setq puede servir a su vez para asignar esta


funcin a un smbolo:
_$ (setq doble (lambda (x)(* x 2)))
#<USUBR @0344f104 -lambda->
_$ (doble 4)
8
que podemos ejecutar perfectamente como funcin de usuario.
LAMBDA suele usarse conjuntamente con APPLY y/o MAPCAR
para ejecutar una funcin sobre una lista.
FUNCTION

El operador FUNCTION le indica al compilador Visual LISP que


enlace y optimice un argumento tal como si fuera una funcin
primitiva.
(function smbolo | expresin-lambda)
FUNCTION es idntico a la funcin QUOTE excepto en que fuerza
la compilacin del argumento de la misma manera que lo hara
DEFUN. Si inclumos las funciones internas en expresiones del
tipo (function (lambda <parmetros> <expresiones> ...) en
lugar de (quote (lambda <parmetros> <expresiones> ...))
'(lambda <parmetros> <expresiones> ...), nos aseguraremos
que el cdigo sea enlazado (linked) y optimizado en tiempo de
compilacin (como una USUBR annima) en lugar de ser
simplemente evaluado en tiempo de ejecucin. Las
expresiones-LAMBDA compiladas contendrn informacin para
su depuracin al ser cargadas en el IDE Visual LISP. Admite un
argumento smbolo que nombra una funcin y una expresinlambda de la forma: (LAMBDA argumentos {expresin-S}*)
Ejemplos:
El compilador Visual LISP no puede optimizar la expresin
lambda precedida de apstrofe (QUOTE) en la siguiente
expresin:

(mapcar
'(lambda (x) (* x x))
'(1 2 3))
Pero una vez incluida la expresin dentro de FUNCTION el
compilador podr optimizar la expresin lambda:
(mapcar
(function (lambda (x) (* x x)))
'(1 2 3))
Lo que redundar en un incremento de la velocidad de
ejecucin al generarse el correspondiente cdigo optimizado en
lenguaje de mquina.
LOAD

Una de las virtudes de LISP es la posibilidad de construir, a


partir de las primitivas aportadas por el lenguaje, las funciones
necesarias para el desarrollo de una aplicacin especfica.
Estas funciones operan de manera idntica a las funciones
primitivas. Si bien podemos evaluar las funciones LISP desde
la Consola de Visual LISP o desde la propia lnea de comandos
de AutoCAD, cuando se trata de funciones ms extensas lo
usual es escribirlas en un fichero de texto (con extensin LSP)
y cargarlas mediante la funcin LOAD. El IDE (Entorno de
Desarrollo Integrado) Visual LISP incluye un editor de
programacin que facilita la redaccin de programas lisp
mediante una serie de ayudas, tales como el texto coloreado
segn la sintaxis y la identacin y formateo automtico del
texto. Trabajando en este IDE se pueden cargar las funciones o
"formas" contenidas en el archivo fuente en desarrollo
mediante el correspondiente botn de la barra de
herramientas u opciones de men. La instruccin LISP para
cargar en memoria un programa LISP contenido en un fichero
es LOAD:

(load nombre_archivo [si_falla])

La funcin LOAD puede ser usada desde dentro de otra funcin


LISP e incluso de manera recursiva (en el fichero que se est
cargando).
nombre_archivo debe ser una cadena que representa el
nombre del fichero. Si no se incluye la extensin LOAD
comprobar la existencia de un fichero con ese nombre y
alguna de las siguientes extensiones en el orden que se
especifica a continuacin:

.vlx
.fas
.lsp

Se cargar el primer fichero encontrado. Si load no se ejecuta


de forma correcta, devuelve el valor del argumento si_falla.
Sin embargo, si si_falla no se especifica, un fallo de load
genera un error de Visual LISP. Si la operacin es correcta,
load devuelve el valor de la ltima expresin del archivo.
El nombre_archivo puede incluir un prefijo de directorio, como
en "/ funcin/prueba1". En los sistemas DOS tambin se
admite una letra de unidad. Una barra oblicua (/) o dos
contrabarras (\\ ) son delimitadores de directorio vlidos. Si
no incluye un prefijo de directorio en la cadena
nombre_archivo, load busca el archivo especificado en el
camino de la biblioteca AutoCAD. Si lo encuentra en cualquier
parte de este camino, load lo carga.
Si el argumento si_falla es una funcin vlida de Visual LISP,
se calcula. En la mayora de los casos, el argumento si_falla
debera ser una cadena o un tomo. Esto permite que una
aplicacin Visual LISP que llame a load tome una accin
alternativa cuando se produce un fallo.
ESTRUCTURAS DE CONTROL

Los predicados son funciones que devuelven respuestas lgicas


(cierto-falso), mientras que las estructuras de control
controlan la ejecucin del programa y permiten mltiples
ramificaciones.

PREDICADOS
Permiten comprobar caractersticas relacionadas con el
tipo de dato con que se est operando en cada momento.
Devuelve T (cierto) si la condicin se cumple y nil (falso)
en caso contrario.
PREDICADOS GENERALES: Suelen distinguirse
por terminar el nombre de la funcin en la letra P
que significa predicado. Se utiliza la siguiente regla
para decidir si la P est precedida por un guin: si el
nombre del predicado se forma aadiendo la P a un
nombre existente, tal como el nombre de un tipo de
dato, se aade un guin slo en el caso de que el
nombre original incluya alguno (BOUNDP, LISTP,
NUMBERP sin guin VL-FILE-DIRECTORY-P, VLAXERASED-P con guin). Los predicados que fueron
introducidos con Visual LISP se conocen por los
prefijos que se adicionan VL-, VLAX- o VLR- (VLCONSP, VLAX-PROPERTY-AVAILABLE-P, VLR-ADDEDP). En casos como VL-CONSP se hace una excepcin
a la regla anterior, puesto que en realidad se est
renombrando un predicado standard de Common
LISP.
PREDICADOS SOBRE TOMOS Y LISTAS
PREDICADOS ARITMTICOS: Corresponden a las
funciones de comparacin (mayor que, menor que,
igual a...).
OTROS PREDICADOS DEFINIDOS POR EL
USUARIO: muestra de la extensibilidad de LISP.
OPERADORES LGICOS
Corresponden a las operaciones Booleanas bsicas. LISP
suministra tres operadores sobre valores Booleanos: and,
or, y not. De ellos, and y or son tambin en cierto modo
estructuras de control ya que sus argumentos son
evaluados condicionalmente. Permiten agrupar las
condiciones de prueba, casi siempre a partir de la

utilizacin de predicados que se utilizan dentro de las


estructuras de programacin descritas ms adelante.La
funcin not tiene un slo argumento que analizar, y es
por ello una funcin simple.
ESTRUCTURAS CONDICIONALES
Visual LISP provee las dos estructuras de control
tradicionales de LISP. La estructura condicional de ms
tradicin en LISP es COND. Sin embargo IF resulta ms
simple y es directamente comparable a las estructuras
condicionales de otros lenguajes de programacin.
ATOM
Sabemos que dentro de las expresiones LISP se
distinguen los tomos y las listas. El predicado ATOM
verifica si un elemento determinado es un tomo
(atom elemento)
Devuelve nil si elemento es una lista y devuelve T en
caso contrario. Debe tenerse cuidado, si se trata de un
tomo simblico, en tener claro si lo que se quiere
evaluar es el sbolo o su contenido. Si no est precedido
de QUOTE <'>, lo que se evala es el valor asociado:
_$ (atom a)
T
_$ (atom 'a)
T
_$ (setq a '(a b c))
(A B C)
_$ (atom a)
nil
_$ (atom 'a)
T
LISTP
Comprueba si un elemento es una lista
(listp elemento)
Devuelve T si elemento es una lista y devuelve nil en
caso contrario. Obsrvese que como NIL es una lista
vaca, (listp nil) devolver T. Es decir, que todo

tomo simblico no asociado a un valor, devover T tanto


para ATOM como para LISTP:
_$ !b
nil
_$ (atom b)
T
_$ (listp b)
T
_$ (listp 'b)
nil
TOMOS SIMBLICOS:

VL-SYMBOLP
Identifica si un objeto especificado es o no un smbolo.
(vl-symbolp objeto)
Devuelve T si el objeto es un smbolo y nil si se trata de
una constante (nmero o cadena) o una lista.
Este predicado ha sido incorporado por Visual LISP
_$ (vl-symbolp 'a)
T
_$ (vl-symbolp 15)
nil
_$ (vl-symbolp "abc")
nil
_$ (vl-symbolp '(a b c))
nil
BOUNDP
Cuando se trata de un tomo simblico, puede ser
necesario determinar si tiene asociado un valor. BOUNDP
verifica la existencia de dicha asociacin.
(boundp sm)
Devuelve T si sm tiene un valor asociado. Si no hay
ningn valor asociado a sm (o se ha asociado a nil),
boundp devuelve nil. Si sm es un smbolo no definido, se
crea y se asocia a nil de forma automtica.

NUMRICOS:

NUMBERP
Los tomos no simblicos o constantes pueden ser
nmeros o cadenas. NUMBERP comprueba si el objeto es
un nmero (real o entero)
(numberp elemento)
Devuelve T si elemento es un valor numrico y devuelve
nil en caso contrario. El predicado complementario
STRINGP, que comprobara si se trata de una cadena no
est definido en Visual LISP, aunque se puede encontrar
entre los mensajes de error a la hora de depurar un
programa. En el ejemplo que sigue el mensaje "STRINGP
2" significara que se ha recibido un valor numrico (2)
en lugar del argumento esperado del tipo cadena.
_$ (strcat 2 "b")
; error: bad argument type:
stringp 2
MINUSP
Tratndose de valores numricos en ocasiones se deber
comprobar si son negativos. MINUSP realiza dicha
comprobacin.
(minusp nmero)
Devuelve T si nmero es negativo y nil en caso contrario.

Si el argumento no es numrico se recibir un mensaje


de error.
ZEROP
Igual que en el caso anterior, cuando se trata de valores
numricos ZEROP permite comprobar si un elemento se
evala como cero
(zerop nmero)
Devuelve T si nmero es cero y nil en caso contrario.
LISTAS VACAS O CONSES:

En LISP el valor asociado al smbolo NIL (condicin de


falso) es la lista vaca <'()>. Cualquier smbolo que
evale como NIL, devolver T (cierto) al pasarlo al
predicado LISTP. Para comprobar que se trata
efectivamente de una lista, pero que dicha lista contiene
algo (aunque fuera NIL) en las versiones anteriores de
AutoLISP era necesario utilizar adems de LISTP otros
predicados tales como BOUNDP o NULL.
NULL
Comprueba si un elemento est definido como nil
(null elemento)
Devuelve T si elemento est asociado a nil y devuelve
nil en caso contrario.
Puede emplearse para probar si se ha alcanzado el fin de
una lista en sustitucin del predicado ENDP de Common
Lisp que falta en Visual LISP
_$ (null (caddr '(a b)))
T
VL-CONSP
La situacin descrita en el prrafo anterior se resuelve
empleando en su lugar el predicado CONSP (vl-consp
para Visual LISP), que comprueba si el elemento
analizado evala como una lista no nula
(vl-consp elem-lista)
Devuelve T, si elem-lista es una lista y no est vaca,

de lo contrario devuelve nil. El trmino CONSP se deriva


de la funcin bsica de construccin de listas, que es la
funcin CONS. Una lista no vaca es el resultado de aplicar,
al menos una vez la funcin CONS.
Este predicado ha sido incorporado por Visual LISP
_$ (vl-consp a)
nil
_$ (setq a (cons 1 a))
(1)
_$ (vl-consp a)
T
El valor contenido en la lista puede incluso ser una lista
vaca:
_$ (setq b (cons nil b))
(nil)
_$ (vl-consp b)
T
_$ (vl-consp '(())) ;equivalente
a la lnea anterior
T
PERTENENCIA A UNA LISTA:

MEMBER
Es un tipo particular de predicado, que comprueba si un
tomo pertenece a una lista dada.
(member expr lista)
Si expr no aparece en la lista, member devuelve NIL. En
caso de encontrarlo, devuelve el resto de la lista, desde el
primer caso de la expresin encontrada. Lo devuelto por
MEMBER acta como T (cierto) ya que cualquier valor no
nulo actuar como la negacin de NIL (not NIL), es
decir, cierto. Debe tenerse cuidado en el caso de los
tomos simblicos de pasar el nombre del smbolo
precedido de QUOTE <'>.

_$ (member a '(c d 2 4 a '(a b)


"a" 3.0 j))
nil
_$ (member 'a '(c d 2 4 a '(a b)
"a" 3.0 j))
(A (QUOTE (A B)) "a" 3.0 J)
IGUALDAD O IDENTIDAD

Dos expresiones pueden considerarse iguales sin


necesidad de que sean idnticas. Los predicados EQUAL y
EQ permiten comprobar estas situaciones.
EQUAL
Determina si dos expresiones son iguales
(equal expr1 expr2 [aproximacin])
La funcin equal determina si expr1 y expr2 se evalan
igual. Cuando se comparan dos nmeros reales (o dos
listas de nmeros reales, como en el caso de los puntos),
los dos nmeros idnticos pueden presentar ligeras
diferencias derivadas de los mtodos utilizados para su
clculo. Para resolver esta situacin, puede utilizarse un
argumento numrico optativo, aproximacin, para
especificar la diferencia mxima que se puede admitir
entre expr1 y expr2, para que sigan considerndose
iguales.
EQ
Determina si dos expresiones son idnticas
(eq expr1 expr2)
La funcin eq determina si expr1 y expr2 estn asociadas
al mismo objeto (si apuntan a la misma direccin de
memoria). Devuelve T si las dos expresiones son iguales
y nil en caso contrario.
_$ (setq a (list 'm 'n 'o))
(M N O)
_$ (setq b (list 'm 'n 'o))
(M N O)

_$ (equal a b) ;las listas


representadas por a y b son iguales
T
_$ (eq a b)
;pero NO son la
misma lista
nil
_$ (eq (cons 'a 'b) (cons 'a
'b))
nil
;cada llamada a
cons crea una nueva lista
_$ (eq '(a . b) '(a . b))
nil
En el caso de los valores constantes, equal y eq
devuelven resultados similares, salvo lo explicado
respecto a los nmeros reales.
_$ (setq a 8)
8
_$ (setq b (+ 5 3))
8
_$ (eq a b)
T
PREDICADOS ARITMTICOS

Todos los argumentos pueden ser nmeros o cadenas.


COMPARACIONES BSICAS:

Permiten comparar nmeros o cadenas.


> (mayor que...)
Devuelve T si cada argumento es numricamente mayor
que el situado detrs de l y nil en caso contrario
(> cadnm [cadnm] ...)
< (menor que...)

Devuelve T si el primer argumento es numricamente


menor o igual que el situado detrs de l y nil en caso
contrario
(< cadnm [cadnm] ...)
=(igual que...)
Devuelve T si todos los argumentos son numricamente
iguales; de lo contrario, devuelve nil
(=cadnm [cadnm] ...)
/=(desigual a...)
Equivale a (not (=cadnm [cadnm] ...))
PREDICADOS COMPUESTOS:

(<=cadnm [cadnm] ...)


Devuelve T si cada argumento es numricamente menor
o igual que el situado detrs de l y nil en caso contrario
(> cadnm [cadnm] ...)
Devuelve T si cada argumento es numricamente mayor
que el situado detrs de l y nil en caso contrario
(>=cadnm [cadnm] ...)
Devuelve T si cada argumento es numricamente mayor
o igual que el situado detrs de l y nil en caso contrario
OPERADORES LGICOS

NOT
Negacin lgica. Cualquier expresin cuyo valor no sea
NIL evala como falsa. En cambio, (not NIL) evala como
T. Esto sucede puesto que cualquier cosa que no tenga el
valor NIL (o la lista vaca) evala en LISP como T (cierto).
OR
Devuelve el OR lgico de una lista de expresiones
(or expr...)
La funcin o calcula las expresiones de izquierda a
derecha en busca de una expresin distinta de nil. Si la
encuentra, OR deja de realizar clculos y devuelve T. Si el
valor de todas las expresiones es nil, or devuelve nil.

AND
Devuelve el operador lgico AND de una lista de
expresiones
(and expr ...)
Si alguna de las expresiones da como resultado nil, se
interrumpe la operacin y la funcin devuelve nil; en caso
contrario, devuelve T.
FUNCIONES LGICAS BINARIAS

Si un tema ha sido poco explicado en los manuales de


programacin LISP para AutoCAD, al menos, en los que se
puede consultar en espaol, que no son muchos, es la
utilizacinde los operadores lgicos binarios. Su importancia y
posibilidades de aplicacin son inversamente proporcionales a
esa escasa atencin que se le dedica. Su uso permite la
gestin de una multitud de parmetros de la aplicacin que
estn codificados como nmeros en formato binario.
Uno de estos parmetros es el de las referencias a objeto. El
valor de la variable de sistema OSMODE es el equivalente
decimal de un nmero binario. Al nmero binario 0000 0001
corresponde la referencia punto FINal y al nmero binario 0000
0100 corresponde la referencia CENtro. Si el valor de OSMODE
fuera equivalente al nmero binario 0000 0101 eso significara
que estn activas a la vez las referencias punto FINal y
CENtro.
Cada posicin de un nmero binario representa un BIT. Un BIT
es la unidad de informacin mnima que es capaz de manejar
un computador, y slo puede uno de dos valores, ACTIVADO o
DESACTIVADO, que en su representacin numrica
simbolizamos mediante 1 0. Por eso decimos que en la
referencia punto FINal se ACTIVA el primer BIT y para la
referencia CENtro se ACTIVA el tercer BIT. El valor binario
1111 1111 1111 activara todas las referencias a objeto
posibles.

Dicho as resulta secillo, pero las dificultades comienzan


cuando tenemos en cuenta que AutoCAD espera recibir no esta
representacin a base de ceros y unos, sino su equivalente en
formato DECIMAL. Y el equivalente dcimal de cada BIT vendra
dado por 2(n-1) dinde n sera la la posicin del bit cuyo valor
decimal se desea. Expresado en trminos de una funcin LISP
(expt 2 (1- n)).
Las operaciones lgicas sobre nmeros binarios disponibles en
Visual LISP son cuatro:

~ (NOT binario)
LOGAND (AND lgico binario)
LOGIOR (OR lgico binario)
BOOLE (operador lgico binario de carcter
general)

A estas operaciones debemos aadir la funcin LSH,


desplazamiento binario, que ser la primera funcin que
estudiaremos.
SISTEMA BINARIO

Internamente, la mquina computadora representa los valores


numricos mediante grupos de bits. agrupados en bytes. Por
ejemplo, el nmero 3 se representa mediante un byte que
tiene "activos" los bits primero y segundo (contando desde la
derecha); 00000011. Esta sera la forma de representacin del
nmero 3 en un sistema numrico de base 2, tambin
conocido como BINARIO. El sistema que utilizamos
normalmente es un sistema DECIMAL o de base 10. En un
sistema DECIMAL, contamos desde el 0 hasta el 9 antes de
aadir un nuevo dgito. El nmero 22 en un sistema decimal
significa que tenemos dos conjuntos de 10s y 2 conjuntos de
1s.
En un sistema BINARIO slo pueden haber dos valores para
cada dgito: ya sea un 0=DESACTIVADO un 1=ACTIVADO.

Para representar el nmero 22 en notacin BINARIA lo


haramos como 00010110, notacin que se explica segn la
siguiente tabla:
Posicin del BIT: 7
Valor Binario: 0
Valor Decimal: 128
Valores a Sumar: 0
Valor Resultante: 16 +

6 5 4
0 0 1
64 32 16
0 0 16
4 + 2=22

3
0
8
0

2
1
4
4

1
1
2
2

0
0
1
0

Todos los valores que corresponden a posiciones a las que se


asigna el valor binario de 0 (cero) no se cuentan, ya que 0
representa DESACTIVADO.
De la misma manera, los nmeros que corresponden a las
posiciones con valor binario 1 se sumarn, (16 + 4 + 2=22)
ya que 1 representa ACTIVADO.
Valores Decimales y sus equivalentes Binarios:
POSICIN
VALOR
BIT DECIMAL
1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8
9
9
10
10
11
16
12
32
13
64
14
100
15
256
16
512
17
1000

VALOR
BINARIO
1
10
11
100
101
110
111
1000
1001
1010
10000
100000
1000000
1100100
100000000
1000000000
1111110100

18

1024 10000000000

Bits, Bytes y Palabras...

Se suelen escribir los nmeros binarios como una secuencia de


grupos de cuatro bits, tambin conocidos como NIBBLES.
Segn el nmero de estas agrupaciones los nmeros binarios
se clasifican como:
Unidad: Nm. bits
Ejemplo:
Bit
1
1
Nibble
4
0101
Byte (Octeto)
8
0000 0101
Palabra
16
0000 0000 0000 0101
Doble Palabra
32 0000 0000 0000 0000 0000 0000 0000 0101

Los computadores personales con el sistema operativo MS DOS


utilizaban palabras de 16 BITS. Los sistemas operativos
actuales sobre los que corre AutoCAD 2000 utilizan Palabras de
32 BITS
Funcin LSH

Para el clculo del valor decimal de un determinado BIT sera


ms adecuado, como veremos ms adelante, utilizar la funcin
LSH. Sgn la explicacin de Reini Urban*:
(lsh <integer> <num>)
LSH quiere decir Left-SHift, en ingls desplazamiento a la
izquierda. Si se interpreta el nmero entero como una matriz
de bits ("bit-array") podemos interpretar LSH como el
desplazamiento de la matriz n-veces a la izquierda (insertando
ceros a la derecha)
Ejemplo:
int: 9 = 8+1 =>
2^0)

(1 0 1) como "bit-array" (2^3 +

(lsh 9 1)

=> (1 0 1 0)

que es (2^4 + 2^1) = 18.

Fcil, puesto que (LSH i 1) es siempre igual a i*2


LSH con un nmero negativo es un desplazamiento a la
derecha (suprimir el bit ms a la derecha). (LSH i -1) es lo
mismo que i/2 ( i dividido entre 2, "divisin de enteros")
De acuerdo con esto el valor decimal del primer BIT vendra
dado por (lsh 1 0) equivalente a 0000 0001 y devolvera el
valor decimal 1. Con un desplazamiento de dos a la izquierda
obtendramos 0000 0100 que ya hemos visto que equivale a
OSMODE CENtro y (lsh 1 2) devuelve el valor decimal de 4.
Con LSH podemos disear la funcin utilitaria siguiente, que
nos devuelve el valor decimal de cualquier BIT:
(defun bit (posicion)
(lsh 1 (1- posicion))
)
De manera que (bit 1) devolvera 1, (bit 5) devolvera 16,
etc.
Con lo que tenemos una manera sencilla de dar el valor
decimal que corresponde a la posicin de cualquier bit. Activar
el bit 8 (referencia PERpendicular) significara sumar (bit 8) al
valor actual de OSMODE:
(setvar "osmode" (+ (getvar "osmode")(bit 8)))
Claro que sera lo mismo
(setvar "osmode" (+ (getvar "osmode") 128))
e incluso:
(setvar "osmode" (+ (getvar "osmode") (expt 2 8)))
Pero (bit 8) resulta ms fcil de memorizar y seguramente
ms claro en cuanto a la intencin del programador. Debo
advertir que la cosa no es tan sencilla, pues debemos primero

haber comprobado que el bit 8 no estaba ya activado. Ms


adelante veremos cmo hacerlo valindonos de los operadores
LOGAND y LOGIOR.
Pero si continuamos incrementando los valores que pasamos a
la funcin BIT, descubriremos que hay un lmite:

Como se puede ver, cuando se activa el bit 32 (en un sistema


operativo de 32 bits) es decir, cuando la ltima posicin a la
izquierda de la palabra toma el valor de 1, su signo pasa a
negativo y un nuevo desplazamiento a la izquierda devolvera
de nuevo el valor del primer bit.
Esta propiedad nos permite definir una funcin para
determinar la longitud de palabra del sistema operativo actual:
(defun LongPalabra ( / pos)
(setq pos 0)
(while (not (minusp (lsh 1 pos)))
(setq pos (1+ pos))
)
(alert (strcat "Longitud de Palabra:\n\t" (itoa (1+
pos)) " Bits"))
)
En AutoCAD 2000 obtendramos como resultado:

Es inportante tener esto en cuenta para comprender el


funcionamiento del prximo operador a estudiar, el NOT lgico
binario (~ num).
Funcin ~ (NOT lgico binario)*

Esta funcin resulta especialmente incomprensible si


consultamos los manuales AutoLISP habituales, incluyendo la
"ayuda" que viene con el programa. Nos dirn que "esta
funcin devuelve la negacin lgica de una cifra binaria, es
decir, el complemento a uno". Y se nos ilustra con ejemplos
como:
(~ 3) devuelve -4
Si bien la explicacin es del todo correcta, a los que no
poseemos conocimientos matemticos tan completos no nos
aprovecha gran cosa esa explicacin. Para encontrar una
respuesta ms comprensible hemos tenido que recurrir al viejo
manual de Nelson Johnson** cuya traduccin al espaol fuera
publicada en 1990 por McGraw-Hill. Explica Johnson que:
(~ <nmero>)
Puede que deseemos verificar un nmero para encontrar su
funcin NOT bit a bit. En este caso, se invierten todos los bits.
el valor devuelto por la funcin "~" ser un nmero que tenga
todos los bits a 0 del argumento puestos a 1 y, viceversa,
todos los bits del argumento que estaban a 1 estarn a cero.
El nmero 9 en binario sera 1001, o mejor, considerando un
tamao de palabra de 32 bits:
0000 0000 0000 0000 0000 0000 0000 1001
(~ 9) devolvera -10

Lo que sera igual en nmeros binarios con tamao de palabra


de 32 bits a:
1111 1111 1111 1111 1111 1111 0110
El valor negativo se explica, segn lo dicho al explicar la
funcin LSH, al ocupar la posicin extrema izquierda un valor
1. La posibilidad de construir este "filtro negativo" de un valor
binario es extremadamente valioso para gestionar los valores
guardados en trminos de posiciones de bits.
Pero para la gestin de estos valores binarios nos deberemos
auxiliar de otras funciones como LOGAND, LOGIOR, y
BOOLE
No es muy frecuente el uso de esta funcin en los programas
LISP dentro de AutoCAD. Revisando los programas
suministrados con la aplicacin podemos encontrar ejemplos
de su uso en AI_UTILS.LSP y DDMODIFY.LSP de las
versiones 13 y 14 y FORMAT.LSP de la versin 12.
LOGAND

Para LOGAND transcribimos la explicacin de Jon Fleming * en


el mismo hilo de discusin donde fu expuesta la explicacin
anterior de Reini Urban:
(logand 13 22) es el AND lgico de [8 + 4 + 1] con [16 +
4 + 2] o, escribiendo los nmeros en binario, de 00001101
con 00010110.
Escribiendo los nmeros uno sobre el otro, podemos entonces
escribir la respuesta en binario de inmediato, escribiendo un 1
bajo dos nmeros uno y un 0 en cualquier otro lugar:
13 =
22 =
13 y 22 =

00001101
00010110
00000100

es decir, 4 en notacin decimal. Por lo tanto, (logand 13 22)


devuelve 4. El AND lgico se suele utilizar como filtro. Uno de
los nmeros que definimos contendr un 1 en su
representacin binaria dondequiera que deseamos que un
posible 1 en un nmero desconocido pase por el filtro. Esto se
debe a que un entero es un lugar muy eficiente para guardar
varios valores lgicos verdadero/falso relacionados como unos
y ceros en posiciones definidas en la representacin binaria de
un entero.
Un ejemplo perfecto lo constituye la variable de sistema
OSMODE. Queremos saber si la referencia a objeto
INTERSECCIN se encuentra activa? Nuestra referencia de
comandos nos dice que la presencia de 32 en el valor de
OSMODE indica la referencia INTERSECCIN. Como slo nos
interesa la referencia INTERSECCIN, escribimos la
representacin binaria de OSMODE con "x" en las posiciones
que no interesa comprobar: El valor de OSMODE podra ser:
xxxxxx1xxxxx
o: xxxxxx0xxxxx
As que si pasamos a (logand ...) cualquiera de esos valores
con 0000 0010 0000 que es 32 en base 10, obtenemos, ya sea
32 (si est activa la referencia INTERSECCIN) o 0 (cero) si no
lo est. En otras palabras:
(if (logand 32 (getvar "OSMODE"))
(prompt "\nLa referencia INTERSECCIN est
ACTIVA")
(prompt "\nLa referencia INTERSECCIN NO est
ACTIVA")
)
Utilizando las funciones LSH, ~ y LOGAND pudiramos
desarrollar funciones para la conversin de decimales en
binarios y viceversa, tiles al menos para comprender mejor la
operacin de estas funciones binarias. Este ser el tema de la
prxima seccin.

Los ejemplos de LOGAND en los programas LISP que vienen


con AutoCAD s son numerosos. Podemos enumerar para la
versin 14: BMAKE.LSP, DDATTDEF.LSP, DDGRIPS.LSP,
ATTREDEF.LSP, DDCHPROP.LSP, DDCOLOR.LSP,
DDINSERT.LSP, DDMODIFY.LSP, DDPTYPE.LSP,
DDSELECT.LSP, DDUNITS.LSP, DDVIEW.LSP, 3D.LSP,
EDGE.LSP, MVSETUP.LSP, BLK_LST.LSP, COUNT.LSP,
LMAN.LSP, TREXBLK.LSP, CLIPIT.LSP, EXCHPROP.LSP,
EXTRIM.LSP, XPLODE.LSP, CURSDLG.LSP,
SQLEDDLG.LSP.
Mucchos de estos programas ya aparecan en la versin 13.
Para indicar alguno de aquella versin que ha desaparecido
desde entonces podemos mencionar DDOSNAP.LSP.
Enumerando slo algunos de la versin 12 tendramos:
CHELEV.LSP, MAKE2D.LSP, MAKE3D.LSP, PTEXT.LSP,
CL.LSP y PROJECT.LSP, y de la versin 10 TABLES.LSP, lo
que nos puede dar una idea de lo til que resulta esta funcin.
CONVERSIN ENTRE BINARIOS Y DECIMALES (I)

CONVERSIN DECIMAL->BINARIO

Aplicando lo visto hasta ahora podemos crear una funcin que


convierta cualquier nmero decimal, positivo o negativo, en su
representacin binaria.
El manual de Personalizacin de AutoCAD * propone una
solucin, pero que es aplicable slo a enteros positivos:
;;;Del manual de Personalizacin:
;;;convierte un entero POSITIVO a una cadena
;;;en la base dada:
(defun base (bas int / ret yyy zot)
(defun zot (i1 i2 / xxx)
(if
(> (setq xxx (rem i2 i1)) 9)
(chr (+ 55 xxx))
(itoa xxx)
) ;_ fin de if
) ;_ fin de defun
(setq
ret (zot bas int)

yyy (/ int bas)


) ;_ fin de setq
(while (>= yyy bas)
(setq ret (strcat (zot bas yyy) ret))
(setq yyy (/ yyy bas))
) ;_ fin de while
(strcat (zot bas yyy) ret)
) ;_ fin de defun
Para nmeros enteros positivos opera correctamente pero no
as para los negativos, como puede verse en los siguientes
ejemplos:

Nuestra funcin BINARIO tiene en cuenta la longitud de


palabra del sistema operativo y devuelve la secuencia correcta
de ceros y unos incluso cuando se trate de valores negativos.
La funcin espera recibir un entero, pero prev el caso de un
nmero real, truncndolo al entero menor ms cercano.
Se definen las funciones utilitarias BIT y POSBIT, esta ltima
utilizada para guardar el valor de la posicin del bit que se
analiza. La conversin en s misma la realiza la funcin
ConvierteBinario que recibe como argumentos el nmero a
convertir y una funcin predicado a plicar segn el nmero sea
positivo o negativo.
Esta funcin de conversin es llamada desde la funcin
principal BINARIO que analiza si el nmero recibido es positivo
o negativo. En caso de ser negativo pasa a la funcin de
conversin su NOT lgico (~ numdec) y el predicado '= en
lugar del nmero recibido y el predicado '/= que pasara en
caso de ser el nmero positivo.

;;;Binario.lsp
;;;El ciclo continuar hasta que LSH devuelva un
valor negativo
;;;significando que se ha llegado al final de la
palabra (posicin
;;;extrema izquierda). El valor binario es devuelto
en formato de lista.
;;;
;;; Funcin auxiliar Bit: devuelve el valor decimal
del bit en la posicin indicada.
;;;
(defun Bit (pos) (lsh 1 (1- pos)))
;;;
;;;
;;Funcin utilizada como acumulador del valor de la
posicin
;;;
(defun PosBit ()
(if (null posicion)
(setq posicion 1)
(setq posicion (1+ posicion))
) ;_ fin de if
) ;_ fin de defun
;;;
;;;
;;;Funcin para procesamiento del nmero decimal
;;;Recibe como argumento el predicado a aplicar
;;;segn sea el argumento numrico positivo o
negativo
;;;
(defun ConvierteBinario (numdec predicado / posicion
numbin)
(while (not (minusp (bit (1- (PosBit)))))
(setq numbin
(cons
(if
(apply
predicado
(list (logand (bit posicion) (fix
numdec)) 0)
) ;_ fin de apply
1

0
) ;_ fin de if
numbin
) ;_ fin de cons
) ;_ fin de setq
) ;_ fin de while
) ;_ fin de defun
;;;
;;;Funcin principal
;;;Tiene en cuenta si se trata de un nmero positivo
o negativo:
;;;
(defun Binario (numdec /)
(if (minusp numdec)
(ConvierteBinario (~ numdec) '=)
(ConvierteBinario numdec '/=)
) ;_ fin de if
) ;_ fin de defun
A diferencia de la funcin BASE, se obtiene una respuesta
correcta tanto de enteros positivos como negativos:

Si deseramos el resultado en formato cadena en lugar de


lista, bastara mapear 'ITOA a la lista devuelta para convertir
los enteros en cadena y aplicarle despus 'STRCAT para unir
los caracteres en una cadena nica:

Dedicaremos la prxima seccin a la conversin en el otro


sentido, de binario a decimal
CONVERSIN ENTRE BINARIOS Y DECIMALES (II)

CONVERSIN BINARIO->DECIMAL

Esta funcin, complementaria de la anterior, nos permite hacer


la conversin en sentido inverso, partiendo de un valor binario
y convirtindolo en decimal.
Aunque lo ms probable es que el tipo de entrada del dato sea
numrico, hemos diseado una funcin como filtro de entrada
que analizar mediante un COND las posibles entradas
admitiendo listas y cadenas y rechazando cualquier otro tipo
de dato.
en caso de que el dato no sea de uno de estos tres tipos
admitidos, se imprimir un mensaje de error. Si el dato es
admitido pero no es de carcter binario (incluye trminos
distintos de cero uno, la funcin devolver NIL.
;;;DECIMAL.LSP
;;;Recibe un nmero binario y lo convierte en decimal
;;;debe comprobar el tipo de dato recibido,
;;;que puede ser cadena, nmero o lista
;;;
;;;Funcin utilitaria BIT
;;;devuelve el valor decimal del bit en la posicin
recibida:
;;;
(defun Bit (pos) (lsh 1 (1- pos)))
;;;
;;;

;;;Funcin utilizada como acumulador del valor de la


posicin:
;;;
(defun PosBit ()
(if (null posicion)
(setq posicion 1)
(setq posicion (1+ posicion))
) ;_ fin de if
) ;_ fin de defun
;;;
;;;PREDICADOS DEFINIDOS PARA ESTA FUNCIN:
;;;Como filtro de entrada se emplean tres predicados
;;;definidos expresamente para ella:
;;;STRINGP, STD-DOTTED-PAIR-P y BINARIOP
;;;
;;;Predicado STRINGP
;;;Comprueba si el dato es una cadena
;;;(ver PREDICADOS DEFINIDOS POR EL USUARIO)
;;;
(defun stringp (dato) (equal (type dato) 'STR))
;;;
;;;Predicado STD-DOTTED-PAIR-P
;;;Comprueba de que se trate de un par punteado:
;;;Adaptado de la Standard Lisp Library
;;;de Reini Urban:
;;;
(defun STD-DOTTED-PAIR-P (lst)
(and (vl-consp lst) (not (listp (cdr lst))))
) ;_ fin de defun
;;;
;;;Predicado Binariop
;;;Comprueba que la lista incluya valores slo 0 1
;;;
(defun Binariop (numbin /)
(apply 'and
(mapcar '(lambda (term) (or (equal term 0)
(equal term 1)))
numbin
) ;_ fin de mapcar
) ;_ fin de apply
) ;_ fin de defun
;;;

;;;Funcin utilitaria NUMLISTA


;;;Recibe cualquier nmero decimal y devuelve los
dgitos aislados
;;;en formato de lista
;;;Si el nmero es real, lo trunca despreciando los
decimales
;;;
(defun Numero->Lista (numero / lista)
(while (> numero 0)
(setq lista (cons (rem (fix numero) 10) lista))
(setq numero (/ (fix numero) 10))
) ;_ fin de while
lista
) ;_ fin de defun
;;;
;;;Funcin utilitaria Cadena->Lista
;;;Recibe una cadena de caracteres y devuelve los
caracteres
;;;aislados en formato de lista
;;;
(defun Cadena->Lista (cadena)
(mapcar
'chr
;3.- convierte los
cdigos ASCII a caracteres
(vl-string->list
;2.- convierte la
cadena a lista de cdigos ASCII
cadena
) ;_ fin de vl-string->list
) ;_ fin de mapcar
) ;_ fin de defun
;;;
;;;Funcin ConvierteDecimal
;;;Realiza la conversin, al ser la evaluacin
siempre de izquierda a derecha,
;;;debe invertir la lista para iniciar la
comprobacin por el bit ltimo de la derecha.
;;;Esta comprobacin se hace mediante el mapeado de
una funcin LAMBDA a la lista,
;;;que comprueba si el nmero es cero y en caso que
no lo sea, inserta el valor
;;;decimal del bit en la lista

;;;Una vez concluido este mapeado, se le aplica la


funcim '+ para sumar todos
;;;los valores, con lo que obtenemos el resultado de
la conversin Binario->Decimal.
;;;Devuelve un nmero decimal
;;;
(defun ConvierteDecimal
(numbin / posicion)
(if (Binariop numbin)
(apply
'+
;
suma los valores de
la lista devuelta por MAPCAR
(mapcar
(function
(lambda (x)
(PosBit)
;5.- valora la
variable posicion
(if
(not (zerop x))
(bit posicion)
0
;
en caso
contrario devuelve cero
) ;_ fin de if
) ;_ fin de lambda
7.- y los
valores devueltos quedan en una lista
) ;_ fin de function
(reverse numbin)
) ;_ fin de mapcar
) ;_ fin de apply
nil
) ;_ fin de if
) ;_ fin de defun
;;;
;;;Funcin filtro de entrada, considerando los
posibles tipos de entrada:
;;;Lista, cadena o nmero
;;;los nicos trminos aceptados sern en cualquier
caso ceros o unos
;;;de detectarse otro valor, la funcin devuelve NIL
;;;Otro error derivara de que la lista fuera un par
punteado
;;;Para comprobarlo utilizaramos la funcin STDDOTTED-PAIR-P adaptada de
;;;la Standard LISP library de Reini Urban

;;;
(defun Decimal (numbin /)
(cond
((STD-DOTTED-PAIR-P numbin)
(terpri)
(princ numbin)
(princ " no es un valor admitido.")
(princ)
)
((listp numbin)
;;si es lista, convierte los trminos
(setq
numbin ;;que sean cadenas en nmeros (o tomos
simblicos si fueran letras)
(mapcar
(function (lambda (term)
(if
(stringp term)
(read term)
term
) ;_ fin de if
) ;_ fin de lambda
) ;_ fin de function
numbin
) ;_ fin de mapcar
) ;_ fin de setq
(ConvierteDecimal numbin)
)
((numberp numbin)
;;si es nmero lo convierte en cadena para
despus hacerlo lista
(setq numbin (Numero->Lista numbin))
(ConvierteDecimal numbin)
)
((stringp numbin)
(setq numbin (mapcar 'read (Cadena->Lista
numbin)))
(ConvierteDecimal numbin)
)
(t
(terpri)
(princ numbin)
(princ " no es un valor admitido.")

(princ)
)
) ;_ fin de cond
) ;_ fin de defun
A continuacin algunos ejemplos tomados de la consola de
VISUAL Lisp:

A continuacin analizaremos la funcin LOGIOR.


LOGIOR

Ms arriba plantebamos que para activar un BIT


determinando mediante la suma del valor decimal que
devuelve nuestra funcin (bit posicin) era necesario verificar
que ese BIT no estuviera ya activo. Esto lo podemos lograr con
la funcin LOGIOR. Tambin para LOGIOR recurriremos a Jon
Fleming * en su aporte a la mencionada discusin en
autodesk.autocad.customization:

(LOGIOR ...) trabaja exactamente de la misma manera,


excepto de que escribimos un 1 en la posicin donde uno de
los valores o ambos valores de los argumentos que se le pasan
tienen un 1, y ponemos un 0 donde ambos argumentos deben
tener un 0. Esto es til para combinar nmeros. Quiere
asegurarse de que la referencia a objeto INTERSECCIN est
activa sin afectar a otros modos de referencia que se hubieren
establecido previamente?
(setvar "OSMODE" (logior 32 (getvar "OSMODE")))
Por supuesto, tanto (logand ...) como (logior ...)
pueden aceptar ms de dos argumentos. En este caso:
1. Se aplica la funcin a los dos primeros argumentos,
obteniendo un resultado provisional.
2. Se aplica la funcin al resultado provisional y al
tercer argumento, obteniendo un nuevo resultado
provisional.
3. Se repite el proceso de aplicar la funcin al
resultado provisional actual y al siguiente
argumento hasta agotar los argumentos pasados a
la funcin.
ALGUNOS EJEMPLOS:

De Tony Tanzillo <tony.tanzillo@worldnet.att.net>


tomamos los siguientes ejemplos del uso de estas funciones:
Determinar si un bloque es una Referencia Externa
(RefX):
Esta funcin toma la lista de asociacin devuelta por
(tblsearch/siguiente), y devuelve T si el bloque es una
referencia externa:
(defun isXref (data)
(eq 4 (logand 4 (cdr (assoc 70 data))))
)

Comprobar el valor de la variable CMDACTIVE:


No debemos utilizar la funcin = para comprobar el valor de
CMDACTIVE, ya que su valor puede variar (y de hecho asumir
valores no documentados y totalmente inesperados). En lugar
de
(= 1 (getvar "cmdactive")),
se debe utilizar:
(eq 1 (logand 1 (getvar "cmdactive")))
Desactivar REFENT:
Para dejar sin efecto mediante LISP las referencias a objeto de
carcter permanente (establecidas mediante REFENT) sin
cambiar los valores preestablecidos (lo que equivaldra a pulsar
la tecla F3), se puede activar el noveno bit (valor decimal de
16384):
(setvar "OSMODE" (logior (getvar "osmode") 16384))
o utilizando la funcin BIT antes definida:
(setvar "OSMODE" (logior (getvar "osmode")(bit 9)))
Otros ejemplos los podemos obtener de los mismos programas
LISP que acompaan a AutoCAD. Para el uso de LOGIOR puede
consultarse DDOSNAP.LSP de la versin 13, AI_UTILS.LSP,
DDCHPROP.LSP, DDMODIFY.LSP y DDSELECT.LSP, de las
versiones 13 y 14 y EXCHPROP.LSP y MPEDIT.LSP, estos
ltimos de la versin 14.
BOOLE

BOOLE opera como una funcin lgica binaria de carcter


general, con lo que incluira las estudiadas LOGAND y LOGIOR
y otras hasta completar las 16 posibles. su sintaxis es:

(Boole operador entero1 [entero2 ...])


El argumento operador es un entero que representa un
nmero binario de 4 bits. cada bit establecido representa una
opcin segn la tabla siguiente:
Bit

Entero1 Entero2 Resultado:

_$
(boole 1
1 1)
1

_$
(boole 2
1 0)
1

_$
(boole 4
0 1)
1

_$
(boole 8
0 0)
-1

Cda bit de entero1 es comparado con el correspondiente bit de


entero2, especificando una fila de la table de resultados anterior.
El bit resultante ser 0 1 segn est activado el bit del
nmero entero que damos como operador que corresponde a
esta posicin. Si el bit en cuestin est activado el bit
resultante es 1; de no ser as el resultado ser 0.
Para ciertos valores del operador, BOOLE equivale a las
operaciones Booleanas standard de AND, OR, XOR, y NOR.
Operador
Binario

Operacin
Booleana

AND

6 (4 + 2)

XOR

7 (4 + 2 +

OR

Resultado igual a 1 si de los


bits analizados:

Ambos son 1
Slo uno de ellos es
igual a 1
Cualquiera de ellos es

1)
8

NOR

1
Ambos son 0
(complemento de 1)

Para tratar de comprender mejor lo anterior analizaremos un


ejemplo tomado de la ayuda de Visual LISP:
(boole 6 6 5) devuelve 3
Aprovechando las funciones antes definidas hallaremos el
equivalente binario de 6, que sera (despreciando los ceros a la
izquierda) igual a 110.
Lo mismo para 5 devolvera 101.
ahira podemos hacer la comparacin para cada pareja de bits:
Primera pareja: (boole 6 0 1) devuelve 1
Segunda pareja (boole 6 1 0) devuelve 1
Tercera pareja: (boole 6 1 1) devuelve 0
Con lo que tendramos el nmero binario 011, que como
podemos comprobar aplicando la funcin DECIMAL equivale a
3. Todo esto visto desde la consola de Visual LISP sera:

Normalmente sera ms cmodo emplear LOGAND y LOGIOR


cuando fuera posible reservando BOOLE para otras operaciones
lgicas binarias. Si revisamos los programas LISP incluidos con
la aplicacin AutoCAD encontraremos al gunos ejemplos del
uso de esta funcin. Para ello podemos consultar los archivos
DDMODIFY.LSP, MPEDIT.LSP, BURST.LSP y ASESMP.LSP
de la versin 14, y PROJECT.LSP y FACE.LSP de la Versin
12.
PREDICADOS GENERALES DEFINIDOS POR EL USUARIO

La posibilidad de desarrollar funcuiones de carcter utilitario


nos permiten completar los predicados de Visual Lisp con otros
de uso probable dentro de las utilidades que se desarrollen
dentro de Autocad.
Predicados para comprobacin de tipo de objeto:
Tipos de Datos LISP:

INTEGERP
Comprueba si el argumento es un nmero entero.
(defun integerp (dato)(eq (type dato) 'INT))
REALP
Comprueba si el argumento es un nmero real.
(defun realp (dato)(eq (type dato) 'REAL))
STRINGP
Comprueba si el argumento es una cadena.
(defun stringp (dato)(eq (type dato) 'STR))
Tipos de Datos AutoCAD:

ENAMEP
Comprueba si el argumento es un nombre de entidad.

(defun enamep (dato)(eq (type dato) 'ENAME))


FILEP
Comprueba si el argumento es un identificador de archivo.
(defun filep (dato)(eq (type dato) 'FILE))
PAGETBP
Comprueba si el argumento es una Tablas de Paginacin de
Funciones.
(defun pagetbp (dato)(eq (type dato) 'PAGETB))
PICKSETP
Comprueba si el argumento es un Conjunto de Seleccin.
(defun picksetp (dato)(eq (type dato) 'PICKSET))
SUBRP
Comprueba si el argumento es una Funcin AutoLISP interna o
compilada.
(defun subrp (dato)(eq (type dato) 'SUBR))
USUBRP
Comprueba si el argumento es una funcin de usuario cargada
desde un fichero fuente LSP.
(defun usubrp (dato)(eq (type dato) 'USUBR))
EXRXSUBRP
Comprueba si el argumento es una Aplicacin ObjectARX
Externa.
(defun exrxsubrp (dato)(eq (type dato) 'EXRXSUBR))
Tipos de Datos ActiveX

SAFEARRAYP
Comprueba si el argumento es una Matriz del tipo Safearray.
(defun safearrayp (dato)(eq (type dato) 'SAFEARRAY))

VARIANTP
Comprueba si el argumento es del tipo Variant.
(defun variantp (dato)(eq (type dato) 'VARIANT))
VLA-OBJECT-P
Comprueba si el argumento es un Objeto ActiveX.
(defun vla-object-p (dato)(eq (type dato) 'VLAobject))
ESTRUCTURAS CONDICIONALES

CONDICIONAL IF

ESTRUCTURA IF-THEN-ELSE
Evala expresiones condicionalmente:
(if expr_prueba expr_then [expr_else])
Si expr_prueba no es nil, evala expr_then;
en caso contrario evala expr_else.
La funcin if devuelve el valor de la expresin
seleccionada. Si expr_else no existe y expr_prueba es
nil, entonces la funcin if devuelve nil.
Funcin PROGN
Calcula las expresiones secuencialmente y devuelve el
valor de la ltima expresin
(progn [expr]...)
Se suele utilizar progn para calcular varias expresiones
cuando slo se espera, como en cada una de las ramas
del IF, una sola expresin.
CONDICIONALES DE USO GENERAL

En muchos casos nos encontraremos que hay ms de dos


condiciones sobre las que decidir. En estos casos podemos
acudir a la funcin COND, que evala una serie de condiciones
de prueba secuencialmente.
COND

Se utiliza como la funcin condicional primaria de Visual


LISP
(cond (prueba1 resultado1 ...) ...)
La funcin cond acepta cualquier nmero de listas como
argumentos.
Evala el primer elemento de cada lista (en el orden indicado)
hasta que uno de ellos devuelva un valor distinto de nil. A
continuacin, evala las expresiones que siguen a este
elemento y devuelve el valor de la ltima expresin de la
sublista. Si esta sublista slo contiene un valor (es decir, si
falta resultado), se obtiene el valor de la expresin prueba.
COND se puede utilizar como una funcin de tipo case.
Es habitual utilizar T como ltima (por defecto) expresin de
prueba.
FUNCIONES RECURSIVAS E ITERATIVAS

Muchos de las tareas que tratamos de resolver con


ordenadores implican la ejecucin de procedimientos en forma
repetitiva. LISP suministra dos paradigmas para el control de
las tareas repetitivas: la recursin y la iteracin.
La definicin de nuevas funciones consiste bsicamente en la
combinacin de llamadas a otras funcin que resulten
adecuadas a los fines que nos proponemos. Un caso particular
surge cuando la funcin se llama a s misma. Estas funciones
suelen llamarse funciones recursivas. Obsrvese que la
funcin recursiva se repite invocndose a s misma. Esto lo
hace desde la llamada inicial al programa. As que para cada
repeticin hay una nueva llamada a la funcin original.
Cualquier otro procedimiento repetitivo que no implique una
recursin es un procedimiento iterativo. Visual LISP
suministra una serie de funciones especficas para la
implementacin de procedimientos iterativos. Las formas ms
simples de establecer una iteracin seran las funcin REPEAT y
FOREACH para listas y VLAX-FOR para colecciones de objetos

ActiveX (VLA-object). REPEAT realiza los procedimientos


especificados el nmero de veces que se especifique en su
primer argumento que debe ser un nmero entero positivo.
FOREACH suministra una iteracin de manera directa sobre los
elementos de una lista. FOREACH debe recibir como segundo
argumento una forma que evale como lista. Entonces ejecuta
el cuerpo de instrucciones suministrado como sucesivos
argumentos una vez para cada uno de los elementos de la
lista. Cuando la conclusin del ciclo de repeticiones dependa de
que se alcance determinado estado y no sea posible
predeterminar el nmero de iteraciones que ello exigir
podemos utilizar la funcin WHILE que admite como primer
argumento una funcin predicado cuyo no cumplimiento
(evaluacin como NIL) determinar la salida del bucle
iterativo.
Existen tambin las llamadas funciones de mapeado. El
Mapeado es un tipo de iteracin en la cual una funcin se aplica
sucesivamente a elementos de una o ms secuencias de
objetos. El resultado de la iteracin es una secuencia que
contiene los resultados de las aplicaciones de la funcin. Visual
LISP provee dos funciones de mapeado: MAPCAR, para listas y
VLAX-MAP-COLLECTION para colecciones de objetos ActiveX.
FUNCIONES RECURSIVAS

El ejemplo clsico de una funcin recursiva es el clculo del


factorial de un nmero. Por ejemplo, 4! (factorial) es igual a 4
X 3 X 2 X 1. Algebraicamente, podemos considerar un factorial
como (n!) as n X (n-1) X (n-2) X (n-3)...(n - (n+1)). sta sera
la definicin recursiva del factorial:
(defun factorial (n)
(cond
((zerop n) 1)
(T
(* n (factorial (1- n))))
) ;_ fin de cond
) ;_ fin de defun

Se analizan dos condiciones:


1. que el argumento recibido sea cero (predicado ZEROP). En
ese caso se devuelve 1.
2. en cualquier otro caso, se multiplica el argumento por el
resultado que devuelve aplicar de nuevo la funcin de
usuario factorial al argumento menos 1. Lgicamente
la evaluacin de esta operacin deber esperar al
resultado de la nueva llamada a la funcin factorial,
que si an no es cero, provocar una nueva llamada a la
misma funcin factorial y quedar a la espera de que
esta sea evaluada y as sucesivamente. Al llegar a cero el
argumento pasado a factorial, ya no se producir una
nueva llamada a la funcin y se comenzar a devolver
respuestas a todas la evaluaciones que han quedado
pendientes. Este comportamiento puede verse
claramente en la ventana TRACE de visua LISP, despus
de haber evaluado la funcin (trace factorial) .

La recursin, aunque aporta soluciones de gran elegancia,


debe ser utilizada con cautela. Lo ideal sera usarla con
funciones que no utilicen, o utilicen muy pocos argumentos, ya
que la recursin coloca cada vez una nueva copia de la funcin
en la memoria de pila junto con sus argumentos. Es muy
posible que una funcin efecte tantas recursiones que se
agote la memoria disponible provocando un error de
desbordamiento de la pila.

Para ms detalles, consultar el artculo WHAT IS


RECURSION? de Glenn Grotzinger.
ANLISIS DE UNA FUNCIN RECURSIVA

La siguiente funcin demuestra la posibilidad de desarrollar


funciones de usuario a partir de un corto nmero de primitivas.
La funcin BUSCA_EN_LISTA recibe como argumentos una
expresin cualquiera y una lista. En caso que la expresin est
contenida en la lista, la funcin devolver la expresin y todos
los trminos de la lista que ocurren despus de la expresin. Si
expresin no pertenece a la lista, la funcin devuelve nil. Los
resultados obtenidos son los mismos que los de la funcin
primitiva MEMBER. De hecho muchas de las funciones hoy
incorporadas a cualquiera de los dialectos modernos de LISP
surgieron como funciones utilitarias que eran incorporadas de
manera habitual por los usuarios.
;;;Funcin recursiva busca_en_lista.
;;;Equivale a la funcin member de LISP
;;;Esta funcin ha sido adaptada del tutorial
;;;LISP del ELM Research Group
(defun busca_en_lista (expresion lista)
(cond
((null lista) nil)
;si
lista est vaca o se acaba
((equal expresion (car lista)) lista)
;si se
encuentra expresion
(t (busca_en_lista expresion (cdr lista))) ;en
otro caso se efcta la recursin
)
)
_$ (busca_en_lista '(a b) (list 2 r "sdf" '(a b)
"KLM" 77 21 jfk))
((A B) "KLM" 77 21 nil)
_$ (member '(a b) (list 2 r "sdf" '(a b) "KLM" 77 21
jfk))
((A B) "KLM" 77 21 nil)
_$
Si antes de ejecutar esta funcin invocamos la funcin TRACE:

(trace busca_en_lista)
podemos seguir en la ventana TRACE de Visual LISP los pasos
seguidos en la evaluacin de esta funcin:
Entering (BUSCA_EN_LISTA (A B) (2 nil "sdf" (A B)
"KLM" 77 21 nil))
Entering (BUSCA_EN_LISTA (A B) (nil "sdf" (A B)
"KLM" 77 21 nil))
Entering (BUSCA_EN_LISTA (A B) ("sdf" (A B) "KLM"
77 21 nil))
Entering (BUSCA_EN_LISTA (A B) ((A B) "KLM" 77
21 nil))
Result: ((A B) "KLM" 77 21 nil)
Result: ((A B) "KLM" 77 21 nil)
Result: ((A B) "KLM" 77 21 nil)
Result: ((A B) "KLM" 77 21 nil)
Los objetivos perseguidos implican el recorrido de la lista,
elemento a elemento, comparando cada uno con la expresin
dada. La manera ms sencilla para extraer un elemento de la
lista (el primero) es utilizar la funcin CAR. Un segundo
elemento pudiera extraerse con CADR y as sucesivamente.
Pero este mtodo sera demasiado rgido si queremos que la
funcin sea aplicable a una lista de cualquier longitud.
Una solucin estara en que si el primer elemento no es el
buscado, volviramos a ejecutar la funcin pero que esta vez
el segundo argumento (lista) fuera el resto de la lista, quitando
el primer trmino ya analizado: (cdr lista).
As continuaramos probando el primer trmino (CAR de la
lista) del resto (CDR) de la lista hasta que o termine la lista o
que el primer trmino sea el elemento buscado.
Las condiciones que se prueban corresponden a los tres casos
posibles al suministrar a la funcin BUSCA_EN_LISTA dos
argumentos, el primero de los cuales puede ser un tomo o
una lista y el segundo debe evaluar como una lista, incluso
vaca.

Primer caso: ((null lista) nil)


Cuando se encuentra esta condicin, la evaluacin
termina. La funcin evaluar en este caso como nil,
sealando que el trmino no ha sido encontrado. Este
sera tambin el caso si el segundo argumento fuera una
lista vaca.
Segundo caso: ((equal expresion (car lista)) lista)
Al igual que en el primer caso, la evaluacin termina.
Pero en este caso el primer trmino de la lista (car lista)
es el trmino buscado, y se devuelve el valor de lista.
Tercer caso: (t (busca_en_lista expresion (cdr lista)))
Este es el caso en que se produce la recursin. Siempre
que lista no est vaca (null lista) y que el primer
elemento de lista no sea igual al trmino buscado, se
llama de nuevo a la funcin BUSCA_EN_LISTA pero esta
vez se le pasa como argumento lista (cdr lista), el resto
de la lista, desechando el primer trmino. As a cada
ciclo, lista se acorta en un trmino. Al final, si expresion
no formara parte de lista, la recursin terminara al llegar
a ser una lista nula.
Si observamos lo devuelto en la ventana TRACE por una y otra
de estas dos funciones recursivas, observamos una diferencia.
Lo devuelto por el ltimo nivel de recursin en la funcin
FACTORIAL es diferente a lo devuelto por el nivel superior. De
hecho cada nivel devuelve un resultado diferente. Para llegar
al resultado definitivo, debemos esperar a lo que devuelve
cada uno de los ciclos de la recursin. Sin embargo, en la
segunda funcin BUSCA_EN_LISTA, el resultado del ltimo
nivel es ya el resultado definitivo. Es evidente que resulta una
prdida de tiempo el esperar a que cada nivel devuelva ese
mismo resultado hasta llegar al nivel superior. Los
compiladores LISP ms avanzados reconocern una funcin de
este tipo y cortarn el proceso en el instante que se obtiene el
resultado del ltimo nivel, mejorando sustancialmente la
velocidad de operacin de las funciones. Este tipo de funciones

recursivas se conocen por el trmino ingls de TAILRECURSIVE (~ recursivas por la cola).


En muchos casos, hacer una funcin recursiva por la cola (tailrecursive) es posible empleando tcnicas adecuadas de
programacin. Siempre que esto se logre podemos esperar un
incremento significativo en la eficacia de los programas.
Nota: Segn afirma Reini Urban, VLISP no es capaz de
reconocer la recursividad por la cola o tail-recursion, de
manera que an resulta en una utilizacin exhaustiva de la
memoria de pila (stack). Sobre los lmites valores mximos
admitidos de anidacin (tamao de pila) dicho autor propone
ejemplos en http://xarch.tugraz.ac.at/autocad/stdlib/STDINIT2.LSP
SU UTILIZACIN PRCTICA DENTRO DE AUTOCAD

Como ejemplo de la utilidad de los mtodos de programacin


expuestos, desarrollaremos un programa encaminado a
resolver un problema concreto dentro de la aplicacin. En
ocasiones tenemos la necesidad de extraer la informacin de
las coordenadas de los vrtices de una polilnea. En este caso
analizaremos una polilnea del tipo LWPOLYLINE, que se
introdujo con la versin 14 de AutoCAD. Las entidades de
AutoCAD guardan su informacin en forma de listas de
asociacin, una lista con sublistas donde el nmero inicial de
cada sublista identifica el tipo de dato de que se trata. Un
proceso recursivo sera especialmente adecuado para recorrer
dicha lista extrayendo de ella la informacin requerida.
Pasaremos entonces a estudiar el desarrollo de una FUNCIN
RECURSIVA PARA LA LECTURA DE LOS VRTICES DE
UNA POLILNEA
Extraccin de los vrtices de una LWPOLYLINE

Los datos que sirven para definir cada una de los objetos
grficos de AutoCAD estn organizados en forma de una lista

de asociacin, es decir, una lista de listas, donde la


informacin guardada en cada sublista se identifica mediante
un cdigo numrico (entero) que aparece como el primer
trmino (CAR) cada sublista. El significado de cada cdigo
coincide en trminos generales con los cdigos que identifican
los datos contenidos en los archivos del formato de fichero DXF
utilizado para la transferencia de dibujos AutoCAD a otras
aplicaciones. Para el desarrollo de la siguiente funcin basta
saber que los valores que corresponden a las coordenadas X e
Y de cada vrtice aparecen en sucesivas sublistas identificadas
mediante el cdigo de asociacin 10. La coordenada Z aparece
en una nica sublista (ya que debe ser la misma para todos los
vrtices) identificada mediante el cdigo 38. La funcin
recursiva descrita a continuacin ser llamada desde otra
funcin que permita seleccionar un objeto del dibujo,
compruebe a continuacin que se trata de la entidad deseada
(del tipo "LWPOLYLINE"), extraiga del objeto grfico
seleccionado la correspondiente lista de asociacin y la pase,
junto con el valor de la elevacin, como argumentos a la
funcin recursiva de extraccin VertPoly.
Funcin ExtraeVertices:

Existen varias formas para seleccionar objetos del dibujo.


Utilizaremos en este caso la funcin ENTSEL que pide al
usuario designar un objeto en el dibujo y devuelve una lista
con el nombre de entidad y la lista de coordenadas XYZ del
punto que ocupaba el cursor en el momento de hacer la
designacin. Este segundo dato no nos es necesario, por lo
que anidamos la funcin ENTSEL dentro de una funcin CAR. El
nombre de entidad que obtenemos de esta manera es en
realidad un puntero al archivo temporal que crea AutoCAD al
abrir un dibujo. Utilizando dicho puntero podemos localizar la
definicin interna del objeto grfico designado en pantalla y
extraerla mediante la funcin ENTGET:
(entget (car (entsel)))
Una sublista determinada se puede encontrar mediante la
funcin ASSOC, pero en este caso, las sublistas que guardan
las coordenadas de los vrtices todas poseen el cdigo 10. Por

este motivo, ser necesario recorrer toda la lista, trmino a


trmino para encontrar todos los valores de coordenadas
correspondientes a los vrtices. Estos valores son slo de las
coordenadas X e Y. La Z se encuentra en una lista asociada al
cdigo 38. Habr que extraer este valor inicialmente y luego
agregarlo a cada uno de los vrtices. Esto se har utilizando la
funcin APPEND en lugar de CONS, de manera que se aada el
valor de Z en la tercera posicin y no al principio de la lista. La
funcin devolver una lista de listas, estas ltimas cada una de
tres valores, correspondiendo a la X,Y,Z de cada vrtice.
;;;Extraccin de los vrtices de una LWPOLYLINE
;;;Funcin recursiva:
;;;Recorre la lista y extrae el valor de los cdigos
10
;;;Estas listas de asociacin slo incluyen los
valores
;;;de las coordenadas X e Y, el valor de Z para toda
la
;;;polilnea est asociado al cdigo 38 este valor
as
;;;como la lista de entidad se extraen en una funcin
;;;inicial que adems sirve para declarar como
variables
;;;locales las que almacenan la lista definitoria de
la
;;;entidad y la lista de vrtices.
;;;Esta funcin devuelve la lista de vrtices, que se
;;;puede asignar a una variable mediante setq:
;;;
(setq vertlis (ExtraeVertices))
;;;(c) Reinaldo Togores, Santander, Julio 1999.
(defun VertPoly (lista elevacion / )
(cond
((null lista) nil)
;funcin
de salida
((equal (caar lista) 10)
;si se
trata de un vrtice
(cons
;la
funcin append permite incluir la
(append (cdr (car lista))(list
elevacion)) ;coordenada Z en la posicin correcta

(VertPoly (cdr lista) elevacion)


;y
contina la recursin
)
)
(t (VertPoly (cdr lista) elevacion))
;si no es
un vrtice
) ;_ fin de cond
) ;_ fin de defun
(defun ExtraeVertices ( / lista_entidad)
(if
(equal
(cdr (assoc 0 (setq lista_entidad (entget (car
(entsel))))))
"LWPOLYLINE"
)
(VertPoly lista_entidad (cdr (assoc 38
lista_entidad)))
(alert "La entidad seleccionada no es una
LWPOLYLINE")
) ;_ fin de if
) ;_ fin de defun
Sin duda este cdigo cumplir su cometido, pero puede ser
mejorado. Este programa est redactado de manera tal que
ninguna de sus partes pudiera reutilizarse en otros futuros
programas. Un enfoque ms eficaz consistira en analizar qu
procesos de carcter ms general intervienen en la solucin y
programarlos como funciones utilitarias que se incorporen
como nuevas herramientas al lenguaje. Ms adelante, y
despus de estudiar algunos otros procedimientos y tcnicas,
intentaremos precisamente esto, cmo abordar de una manera
ms eficaz la solucin a este programa.
FUNCIONES ITERATIVAS

ITERACIONES SIMPLES

En algunos casos puede ser conveniente otro enfoque de las


operaciones repetitivas, mediante estructuras en bucle que no

implican procedimientos de auto-referencia. Los operadores


REPEAT y FOREACH ejecutan las expresiones dadas un nmero
defterminado de veces. En el primer caso se trata del nmero
de veces que resulta de la evaluacin del primero de sus
argumentos y en el segundo de la cantidad de elementos que
pertenecen a una lista. Esta ltima funcin tiene en Visual LISP
su equivalente aplicable a objetos de coleccin ActiveX bajo el
nombre de VLAX-FOR
Tanto para REPEAT como para FOREACH se puede establecer
de antemano el nmero de ciclos a realizar. Pero esa no es
siempre la situacin. En muchas ocasiones no hay manera de
saberlo. En estos casos se deber establecer, al igual que en
los procedimientos recursivos una condicin de prueba que
determine la conclusin del ciclo. Para ello disponemos de la
funcin WHILE.
REPETICIN UN NMERO DETERMINADO DE VECES

REPEAT
Evala cada expresin el nmero de veces que se
especifique en el argumento entero, y devuelve el valor
de la ltima expresin
(repeat entero expresin ...)
El argumento entero debe ser un nmero entero
positivo.
Ejemplos de iteraciones con REPEAT:

FACTORIAL ITERATIVO
Como primer ejemplo analizaremos la funcin FACT2
propuesta por Dennis Shinn <jeeper@halcyon.com> en
el newsgroup comp.cad.autocaden septiembre de 1996.
La explicacin es nuestra traduccin libre del original.
(defun fact2 (n / x y)
(setq x 1 y 1)
(repeat (1- n)
(setq x (1+ x) y (* x y) )

)
)
En la primera lnea se asigna el valor inicial correcto a las
dos variable que llamamos x e y.
La repeticin se establece para un nmero especfico de
veces segn el nmero que se pase como argumento a la
funcin. Puesto que la operacin del clculo del factorial
implica la cantidad de nmeros a multiplicar menos 1,
establecemos en (1- n) el nmero de repeticiones.
Ahora vienen los clculos matemticos: (setq x (1+ x)
y (* x y))
Durante cada iteracin de esta expresin, la x se
incrementa por un valor de 1 cada vez, e y se incrementa
como el producto de ella misma y el prximo valor mayor
de x, etc., etc.
Obsrvese que no se ha implementado un control de
errores, que es algo deseable en un lenguaje de
programacin. Tanto 0 como 1 quedan indefinidos, ya que
ninguno de los dos permitir que ocurra la iteracin. El
REPEAT simplemente no repite. Vale, sin embargo para
demostrar las posibilidades de un verdadero lenguaje de
programacin (como LISP) para realizar verdaderas
operaciones de recursin e iteracin.
Como muestra de una implementacin para atrapar
posibles errores podramos crear otra rutina fact3 que
llame a la rutina fact2 slo en los casos apropiados:
(defun fact3 (n)
(cond
((and (numberp n)(> n 1))
(fact2 n)
)
((= n 1) 1)
(t nil)
)
)

En este caso se prueba primero si el argumento n es un


nmero mayor que 1, en cuyo caso se ejecuta la funcin
fact2. En caso de ser igual a 1 se devuelve 1, y en
cualquier otro caso se devolver NIL.
Predicado PALINDROMOP
El predicado PALINDROMOP debe devolver T (cierto) si una
cadena de texto es un palndromo, es decir, si se lee lo
mismo de izquierda a derecha que al revs. Se ha
utilizado la funcin STRLEN para determinar el nmero de
repeticiones, la funcin SUBSTR para ir extrayendo
caracteres para compararlos, uno a uno, comenzando de
izquierda a derecha y de derecha a izquierda, y la funcin
STRCASE de manera que se ignore la caja (maysculas o
minsculas). Se emplean dos variables locales, cont y
resultado. Esta segunda se establece inicialmente como
T y bastar que no sea igual una de las parejas de letras
analizadas para que adopte el valor de NIL (falso). Es
obvio que bastar con un nmero de repeticiones igual a
la mitad de la longitud de la cadena de texto, pues ms
all de eso se estara comparando las mismas parejas de
caracteres. Al ser ambos argumentos de la divisin
nmeros enteros, el resultado tambin lo sera,
truncando los decimales, por lo que en una cadena con
nmero impar de caracteres no se comparara el carcter
centras consigo mismo.
(defun palindromop (cadena / cont resultado)
(setq
cont 0
resultado t
) ;_ fin de setq
(repeat (/ (strlen cadena) 2)
(if
(not
(equal
(strcase (substr cadena (1+ cont) 1))
(strcase (substr cadena (- (strlen cadena)
cont) 1))

) ;_ fin de equal
) ;_ fin de not
(setq resultado nil)
) ;_ fin de if
(setq cont (1+ cont))
) ;_ fin de repeat
resultado
) ;_ fin de defun
ITERACIONES SOBRE ELEMENTOS DE UNA SECUENCIA

FOREACH
Evala cada expresin para todos los miembros de una
lista
(foreach nombre lista expresin ...)
Recorre la lista, asignando sucesivamente cada elemento
de la lista a la variable nombre y evaluando de esta
manera cada expresin para cada uno de los elementos
de la lista representados por nombre. Puede especificar
tantas expresiones como desee. La funcin FOREACH
devuelve el resultado de la ltima expresin evaluada.
VLAX-FOR
Efecta una iteracin a travs de una coleccin de objetos
evaluando cada expresin
(vlax-for smbolo coleccin [expresin1
[expresin2 ...]])
El argumento smbolo ser asignado a cada Objeto-VLA
de la coleccin. El argumento coleccin representa un
objeto ActiveX del tipo coleccin. [expresin1
[expresin2 ...]] son las expresiones a evaluar. La funcin
devuelve el valor de la ltima expresin evaluada para el
ltimo objeto de la coleccin.
Ejemplos de iteraciones con FOREACH:

Esta pequea subrutina, parte de un programa mayor, imprime


en pantalla en formato de columna la lista que se le pase como
argumento. En el ejemplo se usa para imprimir de manera
ordenada la lista de definicin deuna entidad polilnea
(AutoCAD 2000).
;;;Listado de entidades
;;;Salida por pantalla
(defun disp_l (lis_e /)
(foreach sublista lis_e
(print sublista)
) ;_ fin de foreach
(princ)
;evita la repeticin de la
ltima lnea
) ;_ fin de defun
Command: (entget(car(entsel)))
Select object: ((-1 . <Entity name: 1487558>) (0 .
"LWPOLYLINE") (330 . <Entity
name: 14874f8>) (5 . "2B") (100 . "AcDbEntity") (67 .
0) (410 . "Model") (8 .
"0") (100 . "AcDbPolyline") (90 . 4) (70 . 0) (43 .
0.0) (38 . 0.0) (39 . 0.0)
(10 99.3432 134.975) (40 . 0.0) (41 . 0.0) (42 . 0.0)
(10 130.202 185.828) (40
. 0.0) (41 . 0.0) (42 . 0.0) (10 202.747 163.648) (40
. 0.0) (41 . 0.0) (42 .
0.0) (10 269.336 215.041) (40 . 0.0) (41 . 0.0) (42 .
0.0) (210 0.0 0.0 1.0))
;La lista impresa en pantalla resulta difcil de
leer, al no estar ordenada en columna
Command: (disp_l (entget(car(entsel))))
(-1 . <Entity name: 1487558>)
(0 . "LWPOLYLINE")
(330 . <Entity name: 14874f8>)
(5 . "2B")
(100 . "AcDbEntity")
(67 . 0)
(410 . "Model")
(8 . "0")
(100 . "AcDbPolyline")
(90 . 4)
(70 . 0)

(43 . 0.0)
(38 . 0.0)
(39 . 0.0)
(10 99.3432 134.975)
(40 . 0.0)
(41 . 0.0)
(42 . 0.0)
(10 130.202 185.828)
(40 . 0.0)
(41 . 0.0)
(42 . 0.0)
(10 202.747 163.648)
(40 . 0.0)
(41 . 0.0)
(42 . 0.0)
(10 269.336 215.041)
(40 . 0.0)
(41 . 0.0)
(42 . 0.0)
(210 0.0 0.0 1.0)
Ejemplos de iteraciones con VLAX-FOR:
LISTADO DE CAPAS

Considerado desde el punto de vista de la jerarqua de objetos


ActiveX a la que podemos acceder con Visual LISP,
AutoCAD y sus dibujos consisten en muchos objetos diferentes
tales como tipos de lneas, capas, bloques, etc. Estos objetos
se agrupan en colecciones. Las colecciones de Bloques (Block),
Grupos (Group), Conjuntos de Seleccin (SelectionSet),
EspacioModelo (ModelSpace) y EspacioPapel (PaperSpace)
pueden contener una variedad de objetos grficos diferentes,
tales como lneas, arcos, texto, etc. Todas las dems
colecciones contienen objetos de un slo tipo.
Las colecciones AutoCAD son de base cero, es decir que se
enumeran a partir de cero en sentido ascendente. Algunas
colecciones poseen objetos de manera automtica. Por
ejemplo, la coleccin Layers (capas) simpre contiene un objeto
capa de nombre "0", mientras que otras se encuentran vacas

inicialmente.
Sutphin, J. AutoCAD 2000 VBA Programmers Reference, pg 47.
La rutina que exponemos a continuacin extrae los nombres de
las capas de un dibujo aplicando la funcin VLAX-FOR a la
coleccin "Layers". Para obtener la coleccin "Layers"
tenemos que recorrer la jerarqua de objetos, a partir del nico
objeto accesible pblicamente que es el objeto "Application"
(Aplicacin). La secuencia a seguir es la siguiente:
1. Obtener el objeto "Aplicacin": (vlax-get-acad-object)
2. Obtener el objeto "Documento Activo" es decir, el dibujo
en que se trabaja: (vla-get-ActiveDocument (vlaxget-acad-object))
En caso de que se vaya a hacer referencia a este objeto
en mltiples ocasiones, sera conveniente extraerlo una
sla vez y guardarlo en una variable global:
(setq *EsteDibujo* (vla-get-ActiveDocument
(vlax-get-acad-object)))
Esta lnea la situamos fuera del defun. Se ejecutara al
cargar el programa.
3. Obtener la coleccin "Layers" (Capas): (vlax-get
*EsteDibujo* "Layers" )
Una vez obtenida la coleccin de capas se aplica mediante
VLAX-FOR a cada objeto-VLA de dicha coleccin la funcin
(setq ListaCapas (cons (vlax-get objeto-VLA "Name")
*ListaCapas*))
Aqu primero extraemos el nombre de la capa. El nombre de
cada objeto "Layer" se encuentra en la propiedad "Name" y se
puede extraer mediante (vlax-get objeto-VLA "Name"). Una
vez obtenido el nombre de la capa, la incluimos mediante
CONS en una variable local ListaCapas. Esta lista contendr al
terminar el ciclo de VLAX-FOR los nombres de todas las capas
del dibujo activo. Ya para terminar, ordenamos la lista de capas
mediante la funcin ACAD_STRLSORT. Esta lista servira, por
ejemplo para llenar una casilla de lista en un cuadro de dilogo
creado mediante el lenguaje DCL.
;;;Funcin ListaCapas

;;;Devuelve una lista con los nombres de capas


ordenados alfabticamente
;;;Obsrvese la posibilidad aqu demostrada de tener
una funcin y una variable
;;;con idntico nombre en un mismo entorno. Para ello
ser necesario que dicha
;;;variable, en este caso ListaCapas sea una variable
local de la funcin.
(setq *EsteDibujo* (vla-get-ActiveDocument (vlax-getacad-object)))
;se ejecuta previamente
(defun ListaCapas (/ ListaCapas)
(vlax-for objeto-VLA (vlax-get *EsteDibujo*
"Layers")
(setq ListaCapas (cons (vlax-get objeto-VLA
"Name") ListaCapas))
;el mismo nombre se utiliza para la variable
local que guarda
;temporalmente el listado de capas.
) ;_ fin de vlax-for
(acad_strlsort ListaCapas)
) ;_ fin de defun
Ejemplo de su utilizacin:
Command: (LOAD "C:/Mis
documentos/Lisp/Fuentes/ListaCapas.lsp") LISTACAPAS
Command: !*EsteDibujo*
<#VLA-OBJECT IAcadDocument 00eb6aa4>
Command: (listaCapas)
("0" "DEFPOINTS" "DOTACIONES" "IT" "RBA" "RE-2" "RI"
"RI-1" "RIA" "SG-EL"
"SG-M" "SGP")
Ms adelante se estudiar en ms detalle el acceso a los
objetos ActiveX desde Visual LISP.
Unos ejemplos para concluir...

Como ejemplo del empleo dentro de AutoCAD de estas ltimas


funciones estudiadas, aqu van algunas pequeas utilidades
creadas por Vladimir Nesterovsky. La primera de ellas,

SEL2LST crea una lista de nombres de entidad a partir de un


conjunto de seleccin. La segunda, LST2SEL, realiza el proceso
inverso, creando un conjunto de seleccin a partir de una lista
de nombres de entidad:
;;;SEL2LST
;;;Recibe un conjunto de seleccin y devuelve una
lista
(defun sel2lst( sel / n l)
(repeat (setq n (sslength sel))
(setq n (1- n) l (cons (ssname ss n) l))
)
)
;;;LST2SEL
;;;La funcin opuesta, recibe una lista y devuelve un
conjunto de seleccin
(defun lst2sel(l / ss)
(setq ss (ssadd))
(foreach e l (ssadd e ss))
)
La siguiente funcin extrae el resto de una lista l a partir del
trmino n indicado en el primer argumento:
(defun cdnr ( n l )
(repeat n
(setq l (cdr l))
)
)
La funcin STRTOL recibe una cadena de caracteres s y
devuelve los caracteres aislados (cadenas de un slo carcter)
agrupados en una lista:
(defun strtol ( s / lst c )
(repeat (setq c (strlen s))
(setq
lst (cons (substr s c 1) lst)
c
(1- c)
)

)
lst
)
Como se ve, esta puede ser otra va para abordar el desarrollo
del predicado PALINDROMOP: obtener mediante STRTOL la
cadena de caracteres en forma de lista y entonces compararla
con la lista invertida por reverse:
(defun palindromop (cadena)
(setq cadena (strtol cadena))
(equal cadena (reverse cadena))
)
CICLOS DEPENDIENTES DE UNA CONDICIONAL

Cuando no hay manera de establecer al incio del proceso


iterativo el nmero de repeticiones que sern necesarias se
deber establecer, al igual que en los procedimientos
recursivos una condicin de prueba que determine la
conclusin del ciclo. Para ello disponemos de la funcin WHILE.
WHILE
Evala una expresin de prueba y, si sta no da como
resultado nil, evala otras expresiones para volver de
nuevo a la expresin de prueba
(while expr_prueba expr...)
La funcin while contina hasta que expr_prueba es nil
. Entonces devuelve el valor ms reciente de la ltima
expresin.
Ejemplos de Iteraciones con WHILE:
CONTEO DE ENTIDADES:

Un caso lo tendramos en una funcin que tuviera como


propsito el contar las entidades que forman parte de un
dibujo. Para acceder de manera secuencial a las entidades que

forman parte de un dibujo tenemos la funcin ENTNEXT. Si


establecemos un contador que se incremente por cada entidad
del dibujo tendramos, al llegar a la ltima entidad, el nmero
total de entidades. La funcin concluir en el momento que la
variable ent evale como NIL , es decir, cuando ENTNEXT ya
no devuelva ms ninguna entidad por haber alcanzado el final
de la base da datos del dibujo.
;;;Funcin iterativa para conteo simple
;;;de las entidades en un dibujo
;;;Se establece la variable cont como contador
;;;y la variable ent para guardar el nombre de
;;;cada entidad leda
(defun CuentaEntidades ( / cont ent)
(setq
cont 1
ent (entnext)
;la funcin entnext
sin argumentos
;devuelve la primera
entidad del dibujo
) ;_ fin de setq
(while ent
(setq
cont (1+ cont)
ent (entnext ent) ;devuelve la entidad
que le sigue a ent
) ;_ fin de setq
) ;_ fin de while
cont
;devuelve el valor final
del contador
) ;_ fin de defun
Ms adelante utilizaremos este procedimiento para desarrollar
funciones ms sofisticadas dirigidas a inventariar los objetos
contenidos en un dibujo.
PREDICADO PALINDROMOP OPTIMIZADO:

La versin anterior del predicado PALINDROMOP no resulta muy


eficiente, pues comprueba de manera exhaustiva todos los
caracteres de la cadena, cuando bastara con detectar una
primera desigualdad para decidir que no se trata de un

palndromo. Una solucin ms eficaz debera interrumpir la


evaluacin en ese momento. Eso lo podemos lograr mediante
un ciclo condicional usando WHILE con dos condiciones
encerradas en un AND (que devolver NIL en cuanto una de
ellas deje de ser cierta): que no se hubiera alcanzado el
nmero de repeticiones determinado por (/ (strlen cadena)
2), y que el valor de resultado sea T. En cuanto se encuentre
una pareja de caracteres desigual resultado pasar a ser NIL,
con lo cual se detendr el ciclo.
(defun palindromop (cadena / cont resultado)
(setq
cont 0
resultado t
) ;_ fin de setq
(while (and (<= cont (/ (strlen cadena) 2))
resultado)
(if
(not
(equal
(substr cadena (1+ cont) 1)
(substr cadena (- (strlen cadena) cont) 1)
) ;_ fin de equal
) ;_ fin de not
(setq resultado nil)
) ;_ fin de if
(setq cont (1+ cont))
) ;_ fin de while
resultado
) ;_ fin de defun
No basta que un programa alcance los resultados deseados.
Debe hacerlo de manera rpida y eficaz. Este es un principio
que no debe olvidarse
FUNCIONES DE MAPEADO

LISP provee funciones que procesan secuencialmente los


trminos de una lista suministrada como argumento.

MAPCAR
(mapcar funcin lista1 ... listan)
MAPCAR opera sobre los elementos sucesivos de las listas.
Primero se aplica la funcin al CAR de cada lista, entonces
al CADR de cada una y as sucesivamente. Lo ideal sera
que todas las listas fueran de igual longitud. Si no lo
fueran, la iteracin concluye al agotarse la lista ms corta
y los elementos en exceso de las dems listas se ignoran.
MAPCAR devuelve una lista con los resultados de las
sucesivas llamadas a la funcin. Por ejemplo:
_1$ (mapcar 'cons '(a b c) '(1 2 3))
((A . 1) (B . 2) (C . 3))
Una expresin-LAMBDA puede ser utilizada con MAPCAR.
Esto resulta til cuando algunos de los argumentos de
funcin son constantes o se proporcionan mediante
variables u otros mtodos.
Sobre la funcin MAPCAR seguramente no encontraremos una
explicacin ms entusiasta que la de Vladimir Nemerovski a
quien citamos a continuacin:
Ahora trataremos de MAPCAR. Esta es una funcin que
requiere:
1. un smbolo dentro de QUOTE

o una EXPRESIN-LAMBDA (tabin dentro de un


QUOTE )
o una lista de funcin de usuario (igualmente dentro
del QUOTE)
2. alguna lista
3. y otras listas opcionales ms...
Digamos que la invocamos con (mapcar 'mifuncin
milista) El resultado ser una LISTA de los RESULTADOS de
invocar MIFUNCIN con cada elemento de MILISTA. Por
ejemplo, (defun mysqr(x)(* x x)) (mapcar 'mysqr (list
1 2 3 4)) devolvera (1 4 9 16) De nuevo MYSQR aparece

aqu precedida de un apstrofe (QUOTE), ya que MAPCAR espera


que as sea.
MYSQR espera un argumento numrico y eso es lo que
obtiene. Si yo la invocara como (MAPCAR 'MYSQR (list 1 2
"3")) LISP intentara construir una lista de resultados como
[1] (list (mysqr 1) (mysqr 2) (mysqr "3")) y yo
obtendra un error de BAD ARGUMENT TYPE al intentar procesar
el "3". Observe de nuevo que en esta expresin [1], MYSQR
es de nuevo un QUOTED-SYM de una funcin de usuario
previamente definida cuyo resultado evala como una lista,
teniendo tambin una lista como primer argumento, de
manera que en este punto LISP reconoce tal lista como una
funcin de usuario, tratando de evaluarla, sustituyendo los
argumentos ficticios de su lista de parmetros por los
argumentos reales.
De manera que si usted quiere que alguna funcin sea usada
en MAPCAR y no desea que sta permanezca por ah sin ser
utilizada de nuevo, usted puede emplear LAMBDA. Esta funcin
crea un tipo de FUNCIN ANNIMA y la devuelve como
encerrada en QUOTE, tal como lo hara DEFUN (slo que esta
creara una funcin vinculada a un NOMBRE que de esta
manera permanecera formando parte del entorno).
MAPCAR es grandiosa en que no necesita saber cual es la
longitud de una lista de datos. No le importa. Simplemente la
recorre hasta llegar al final, con lo que lo sabr en tiempo de
ejecucin. De manera que usted al escribir la funcin (que en
LISP equivaldra al tiempo de compilacin de lenguajes
compilados como C, etc.), no necesita saber la longitud exacta
de su lista de datos, lo que ES FENOMENAL! Le permite tratar
fcilmente con informacin de longitud variable, y no
olvidemos que toda la informacin real sin duda lo es.
As que puedo (mapcar 'mysqr '(1 2 3)) o puedo (mapcar
'mysqr '(1 2 3 4 5)), segn haga falta.

Y hay algo ms. Digamos que tengo esta funcin que SUMA
todos sus argumentos. Es un '+, que puedo invocar como:
(+ 1 2) (+ 1 2 3) etc.
Ahora cuando escribo (mapcar '+ '(1 2 3) '(4 5 6)) es lo
mismo que (list (+ 1 4)(+ 2 5)(+ 3 6)) Tambin puedo
escribir (mapcar '+ '(1 2 3)'(4 5 6)'(7 8 9)), que
equivale a (list (+ 1 4 7)(+ 2 5 8)(+ 3 6 9)) etc.
De manera que tenemos algo ms de flexibilidad aqu. Por
supuesto que yo ser el responsable de suministrar a la
funcin invocada con el nmero adecuado de argumentos que
le sern alimentados por MAPCAR, ya que de otra manera
obtendr un error de DEMASIADOS/MUY POCOS ARGUMENTOS
cuando LISP eventualmente la evale.
Fuente:
Subject: A short course in LISP, LAMBDA,
QUOTE, MAPCAR...
Date: Sat, 02 Nov 1996 08:50:38 -0800
From: Lu <learly@ix.netcom.com>
VLAX-MAP-COLLECTION
Aplica una funcin a todos los objetos de una coleccin.
(vlax-map-collection coleccin funcin)
El argumento coleccin representa un Objeto-VLA de tipo
coleccin. El argumento funcin ser un smbolo o una
expresin-LAMBDA que ser aplicada a coleccin.
Ejemplo de utilizacin de VLAX-MAP-COLLECTION:

Hemos visto anteriormente el desarrolo de una fincin que


devuelve una lista con los nombres de las capas contenidas en
el dibujo utilizando la funcin VLAX-FOR. Una funcin similar
puede desarrollarse con VLAX-MAP-COLLECTION, con un cdigo
resultante aun ms claro y conciso. La funcin que se pasa a
VLAX-MAP-COLLECTION se definir en este caso como una
expresin-LAMBDA. Obsrvese que esta expresin debe
pasarse dentro de un QUOTE.

;;Funcin ListaCapas utilizando VLAX-MAP-COLLECTION


;;;Devuelve una lista con los nombres de capas
ordenados alfabticamente
(setq *EsteDibujo* (vla-get-ActiveDocument (vlax-getacad-object)))
;se ejecuta previamente
(defun ListaCapas (/ ListaCapas objeto-VLA)
(vlax-map-collection
(vlax-get *EsteDibujo* "Layers")
'(lambda (objeto)
(setq ListaCapas (cons (vlax-get objeto
"Name") ListaCapas))
) ;_ fin de lambda
) ;_ fin de vlax-map-collection
(acad_strlsort ListaCapas)
) ;_ fin de defun
Su utilizacin devuelve idnticos resultado que la anterior
definida con VLAX-FOR.
Unos ejemplos para concluir...

Conversin de cadena a lista:

Conversin de cadena a lista, con MAPCAR, en una sla lnea.


Utilizando esta funcin podemos convertir al instante cadenas
en listas con sus caracteres aislados:
_$ (defun CadenaLista (cadena)(mapcar 'chr (vlstring->list cadena)))
CADENALISTA
_$ (cadenalista "Madrid")
("M" "a" "d" "r" "i" "d")
REMOVE en una sla lnea:

Gracias a Reini Urban hemos podido conocer este brillante


ejemplo desarrollado por Sergei Volkov, implementando la
funcin REMOVE (QUITAR) en una sla lnea:
;;;REMOVE, por Segei Volkov
;;;Recibe una expresin expr y una lista lst.

;;;Devuelve la lista eliminando de ella todas las


ocurrencias de la expresin.
;;;Paso 1: Mediante MAPCAR aplica la funcin LIST a
cada trmino de la lista
;;;
Si recibe '(a b c) obtendr '((a) (b) (c))
;;;Paso 2: Utiliza la funcin SUBST para sustituir
por NIL cada aparicin de
;;;
la expresin expr
;;;Paso 3: Aplica mediante APPLY la funcin APPEND a
los miembros de la lista.
;;;
de esta manera desaparecen los NIL (listas
vacas) que sustituyeron
;;;
a la expresin eliminada
(defun remove (expr lst)
(apply 'append (subst nil (list expr) (mapcar
'list lst)))
)
Ejemplo:
_$ (remove 'a '( b c d f a g h j))
(B C D F G H J)
_$
Extraccin de los vrtices de una Polilnea:

En un captulo anterior, al estudiar los procesos recursivos,


habamos desarrollado una funcin destinada a extraer los
valores de los vrtices de una polilnea. Con los procesos que
hemos estudiado hasta ahora pudiramos intentar el
enunciado de una funcin ms concisa y clara para obtener
este resultado. A ello dedicaremos el prximo apartado.
EXTRACCIN DE LOS VRTICES DE UNA POLILNEA:
Una manera ms eficaz de abordar el problema.

El programa expuesto en el captulo sobre los procedimientos


recusivos, ha sido elaborado utilizando slo las funciones
primitivas conocidas entonces de AutoLISP. Una manera ms
eficaz de encarar su anlisis sera la de tener en cuenta si

algunos de los procesos que se llevan a cabo dentro del mismo


pudieran programarse independientemente, como funciones
utilitarias. Una funcin utilitaria es un nuevo operador que
aadimos al lenguaje de programacin para resolver
situaciones que pueden presentarse con cierta frecuencia
dentro de nuestros programas. En el caso que estamos
analizando, podemos concebir la necesidad de una nueva
funcin que recorra una lista y de acuerdo con el resultado de
una funcin que se le pase como predicado elimine unos
trminos y conserve otros. Como resultado tendramos una
lista que slo incluyera los trminos deseados, en este caso las
listas de asociacin identificadas con los cdigos 10. Estas
funciones que pudiramos llamar QUITAR-SI y su
complementaria QUITAR-SI-NO han estado siempre entre las
primeras que los programadores LISP han aadido a su
repertorio de utilidades. Una definicin de las mismas pudiera
ser:
;;;QUITAR-SI
;;;Implementacin de la funcin REMOVE-IF
;;;en contexto AutoLISP
(defun quitar-si (predicado lista)
(cond
((null lista) nil)
((apply predicado (list (car lista)))
(quitar-si predicado (cdr lista))
)
(t (cons (car lista)(quitar-si predicado (cdr
lista))))
)
)
;;;QUITAR-SI-NO
;;;Implementacin de la funcin REMOVE-IF-NOT
;;;en contexto AutoLISP
(defun quitar-si-no (predicado lista)
(cond
((null lista) nil)
((apply predicado (list (car lista)))
(cons (car lista)(quitar-si-no predicado (cdr
lista)))
)

(t (quitar-si-no predicado (cdr lista)))


)
)
Tanto es as que se han incorporado como operadores a la
norma de Common LISP bajo los nombres de REMOVE-IF
(QUITAR-SI) y de REMOVE-IF-NOT (QUITAR-SI-NO). Visual
LISP les incorpora el prefijo VL- para distinguirlos de las
funciones del antiguo AutoLISP, y as las encontraremos en el
catlogo de funciones Visual LISP como VL-REMOVE-IF y VLREMOVE-IF-NOT.
Utilizando VL-REMOVE-IF-NOT y con la ayuda de la funcin de
mapeado sobre listas MAPCAR, estudiada en el apartado
anterior, nuestra funcin VertPoly pudiera escribirse de la
siguiente manera:
;;;Funcin VertPoly utilizando VL-REMOVE-IF-NOT
;;;Paso 1:
;;;Eliminar todos las sublistas que no correspondan
al cdigo 10
;;;Paso 2:
;;;Extraer el CDR de cada una de las sublistas.
;;;Se utiliza el mapeado de la funcin CDR a la lista
mediante MAPCAR
;;;Paso 3:
;;;Se aade el valor de la elevacin mapeando a la
lista una expresin LAMBDA.
(defun VertPoly (lista elevacion)
(mapcar
;Paso 3
(function (lambda (x) (append x (list
elevacion))))
(mapcar
;Paso 2
'cdr
(vl-remove-if-not
;Paso 1
(function (lambda (x) (equal (car x)
10)))
lista
) ;_ fin de vl-remove-if-not
) ;_ fin de mapcar
) ;_ fin de mapcar

) ;_ fin de defun
Obsrvese el uso de la funcin FUNCTION que fuerza la
compilacin de las dos expresiones-LAMBDA. Se utiliza en
lugar de QUOTE (o apstrofe) procurando una mayor eficacia y
rapidez.
Esta segunda formulacin resulta ms clara y ms econmica
en cuanto a esfuerzo de programacin. Por otra parte, supera
las limitaciones de Visual LISP en cuanto a la recursin que
pudiera provocar en caso de polilneas con un gran nmero de
vrtices un error por desbordamiento de pila.
Nota: esta funcin devuelve los resultados correctos para
Visual LISP en AutoCAD 2000. Sin embargo hemos encontrado
que falla si se ejecuta desde el IDE Visual LISP para la versin
14. El error se encuentra en los valores de la lista de
asociacin para el objeto LWPOLYLINE que se obtienen desde
este entorno:
(entget(car(entsel))) aplicado a una LWpolyline en la lnea
de comandos de AutoCAD R14 devuelve:
Command: (entget(car(entsel)))
Select object:
((-1 . <Entity name: 43b0500>) (0 . "LWPOLYLINE")
(5 . "20")
(100 . "AcDbEntity") (67 . 0) (8 . "0") (100 .
"AcDbPolyline")
(90 . 7) (70 . 0) (43 . 0.0) (38 . 0.0) (39 . 0.0)
(10 103.882 154.494) (40 . 0.0) (41 . 0.0) (42 . 0.0)
(10 180.771 201.906) (40 . 0.0) (41 . 0.0) (42 . 0.0)
(10 186.224 143.05) (40 . 0.0) (41 . 0.0) (42 . 0.0)
(10 267.476 167.028) (40 . 0.0) (41 . 0.0) (42 . 0.0)
(10 256.569 105.994) (40 . 0.0) (41 . 0.0) (42 . 0.0)
(10 298.558 123.432) (40 . 0.0) (41 . 0.0) (42 . 0.0)
(10 293.651 89.1) (40 . 0.0) (41 . 0.0) (42 . 0.0)
(210 0.0 0.0 1.0))
Obsrvese que las listas asociadas al cdigo 10 contienen dos
nmeros reales adems del cdigo de asociacin: (10 256.569

105.994) es decir, las coordenadas X e Y solamente. Sin


embargo, al ejecutarlo desde la consola de Visual LISP aparece
un tercer nmero real: (10 256.569 105.994 0.0),
representando el valor de Z:
_$ (entget(car(entsel)))
((-1 . <Entity name: 43b0500>) (0 . "LWPOLYLINE")
(5 . "20")
(100 . "AcDbEntity") (67 . 0) (8 . "0") (100 .
"AcDbPolyline")
(90 . 7) (70 . 0) (43 . 0.0) (38 . 0.0) (39 . 0.0)
(10 103.882 154.494 0.0) (40 . 0.0) (41 . 0.0) (42 .
0.0)
(10 180.771 201.906 0.0) (40 . 0.0) (41 . 0.0) (42 .
0.0)
(10 186.224 143.05 0.0) (40 . 0.0) (41 . 0.0) (42 .
0.0)
(10 267.476 167.028 0.0) (40 . 0.0) (41 . 0.0) (42 .
0.0)
(10 256.569 105.994 0.0) (40 . 0.0) (41 . 0.0) (42 .
0.0)
(10 298.558 123.432 0.0) (40 . 0.0) (41 . 0.0) (42 .
0.0)
(10 293.651 89.1 0.0) (40 . 0.0) (41 . 0.0) (42 .
0.0)
(210 0.0 0.0 1.0))
_$
Este comportamiento constituye un error que ya ha sido
superado en la versin 2000.
Cundo usar la Recursin y cundo la Iteracin?

Tomado del tutorial por Collin Allen y Maneesh


Dhagat, April 1997.
Traduccin del ingls: Reinaldo Togores, 1999.
Hay muchos problemas para los cuales la recursin resulta natural y para los cuales
la iteracin resulta extremadamente difcil. Esto sucede usualmente cuando se tienen
en cuenta objetos con una estructura compleja de listas anidadas. Por ejemplo,
consideremos esta expresin matemtica en formato LISP:

(setq math-formula
'(+ 3 (* (- 5 pi) 4 (/ 3 7))(* 15 2))
)
Math-formula contiene listas dentro de listas dentro de listas.

Supongamos que quisiramos saber cuntos nmeros estn


sepultados en las profundidades de esta frmula. He aqu una
funcin recursiva que lo averiguar:
(defun num-nums (mf)
(cond
((null mf) 0)
no contiene ninguno
((numberp (car mf))
trmino es un nmero
(1+ (num-nums (cdr mf))))
en el resto
((atom (car mf))
otro tomo
(num-nums (cdr mf)))
contar el resto
(t (+ (num-nums (car mf))
una lista a contar
(num-nums (cdr mf))))))
numero en el resto

;; la lista vaca
;; si el primer
;; sumar al nmero
;; si es cualquier
;; ignorarlo,
;; o se trata de
;; y sumar al

Pruebe esta funcin y examine su operacin usando TRACE. Observe que la


profundidad de recursin flucta a medida que las sublistas son procesadas.

>(num-nums math-formula)
1> (NUM-NUMS (+ 3 (* (- 5 PI) 4 (/ 3 7)) (* 15 2)))
2> (NUM-NUMS (3 (* (- 5 PI) 4 (/ 3 7)) (* 15 2)))
3> (NUM-NUMS ((* (- 5 PI) 4 (/ 3 7)) (* 15 2)))
4> (NUM-NUMS (* (- 5 PI) 4 (/ 3 7)))
5> (NUM-NUMS ((- 5 PI) 4 (/ 3 7)))
6> (NUM-NUMS (- 5 PI))
7> (NUM-NUMS (5 PI))
8> (NUM-NUMS (PI))
9> (NUM-NUMS NIL)
<9 (NUM-NUMS 0)
<8 (NUM-NUMS 0)
<7 (NUM-NUMS 1)

<6 (NUM-NUMS 1)
6> (NUM-NUMS (4 (/ 3 7)))
7> (NUM-NUMS ((/ 3 7)))
8> (NUM-NUMS (/ 3 7))
9> (NUM-NUMS (3 7))
10> (NUM-NUMS (7))
11> (NUM-NUMS NIL)
<11 (NUM-NUMS 0)
<10 (NUM-NUMS 1)
<9 (NUM-NUMS 2)
<8 (NUM-NUMS 2)
8> (NUM-NUMS NIL)
<8 (NUM-NUMS 0)
<7 (NUM-NUMS 2)
<6 (NUM-NUMS 3)
<5 (NUM-NUMS 4)
<4 (NUM-NUMS 4)
4> (NUM-NUMS ((* 15 2)))
5> (NUM-NUMS (* 15 2))
6> (NUM-NUMS (15 2))
7> (NUM-NUMS (2))
8> (NUM-NUMS NIL)
<8 (NUM-NUMS 0)
<7 (NUM-NUMS 1)
<6 (NUM-NUMS 2)
<5 (NUM-NUMS 2)
5> (NUM-NUMS NIL)
<5 (NUM-NUMS 0)
<4 (NUM-NUMS 2)
<3 (NUM-NUMS 6)
<2 (NUM-NUMS 7)
<1 (NUM-NUMS 7)
7
Sera difcil definir num-nums de forma iterativa. No es imposible, pero exige el saber
utilizar una pila para simular la recursin.

Muchas tareas de inteligencia artificial implican el buscar a


travs de estructuras anidadas. Por ejemplo, las
representaciones en rbol de los movimientos en un juego se
representan mejor como listas anidadas. Examinar este rbol
implica un rastreo recursivo a travs del mismo. Para este tipo

de aplicacin las funciones recursivas resultan una herramienta


esencial.
Cundo debemos utilizar la iteracin y cundo la recursin?
Hay por lo menos estos tres factores a considerar:
(1)
La funciones iterativas son usualmente ms rpidas que
sus contrapartes recursivas. Si la velocidad es
importante, normalmente usaramos la iteracin.
(2)
Si la memoria de pila es un limitante, se preferir la
iteracin sobre la recursin.
(3)
Algunos procedimientos se programan de manera
recursiva de forma muy natural, y resultan prcticamente
inabordables iterativamente. Aqu la eleccin es clara.
EXPORTAR LA LISTA DE ENTIDAD

Para los usuarios de DOS, las siguientes rutinas permiten


escribir en pantalla (con salto de lnea) o en fichero las listas
definitorias de las entidades seleccionadas.
Para utilizar el cdigo que sigue, seleccinelo en su browser,
utilizando el ratn, desde la lnea que dice -INICIO DEL
PROGRAMA- hasta la lnea -FIN DEL PROGRAMA-, copie el texto
seleccionado (Ctrl+C), abra un editor (Notepad o Visual LISP)
y pguelo all (Ctrl+V). Guarde el fichero as creado con el
nombre LISTENT.LSP en el subdirectorio SUPPORT . Para
cargarlo teclee (load "listent")
Reinaldo Togores. Profesor Asociado.
Departamento de Ingeniera Geogrfica y Tcnicas de
Expresin Grfica
Universidad de Cantabria. Diciembre de 1996.
Se autoriza la utilizacin del cdigo de estos programas,
mencionando siempre su origen.

Para comentarios y sugerencias:


reinaldo.togores@unican.es
;;;----------------------INICIO DEL
PROGRAMA-----------------------------------------------;;;(c) Reinaldo Togores, Santander, 1997.
;;Listado de entidades
;;Salida por pantalla
;;Rutina DISP_L: Escribe lista de entidad en pantalla
(defun disp_l ( lis_e / )
(repeat (length lis_e)
(princ (nth cont lis_e))(terpri)
(setq cont (1+ cont))
)
)
;;Rutina PRN_L: Escribe lista de entidad en fichero
de texto
(defun prn_l (lis_e / )
(repeat (length lis_e)
(print (nth cont lis_e) if_w)
(setq cont (1+ cont))
)
)
;;Rutina OPN_L: Abre fichero de texto para escribir
lista de entidad
(defun opn_l ()
(if (null nomls)(setq nomls ""))
(if (setq nomls (getfiled "Lista de Entidad:"
nomls "txt" 5))
(if (wcmatch nomls "*`.*")
(setq if_w (open nomls "w"))
(setq if_w (open (strcat nomls ".txt") "w")
)
)
)
)
;;Programa Principal LISTX: Escribe la lista de
entidad a un fichero de texto
(defun c:listx ( / n_e lis_e ctrl cont)
(if (setq s_set (ssget))

(progn
(opn_l)(setq s_c 0)
(repeat (sslength s_set)
(if (setq n_e (ssname s_set s_c))(setq
lis_e (entget n_e (list "*"))))
(setq cont 0)
(prn_l lis_e)
(if
(or
(= (cdr (assoc 0 lis_e))
"POLYLINE")
(= (cdr (assoc 0 lis_e)) "INSERT")
)
(progn
(setq ctrl t)
(while (and ctrl (setq n_e (entnext
n_e)))
(setq cont 0)
(if (= (cdr (assoc 0 (setq lis_e
(entget n_e (list "*"))))) "SEQEND")
(progn (setq ctrl nil)(prn_l
lis_e))
(prn_l lis_e)
)
)
)
)
(setq s_c (1+ s_c))
)
(close if_w)
)
)
)
;;Programa Principal LIS: Salida por pantalla
(defun c:lis ( / n_e lis_e ctrl cont)
(if (setq n_e (car (entsel)))(setq lis_e (entget
n_e (list "*"))))
(setq cont 0)
(disp_l lis_e)
(setq ctrl t)
(while (and ctrl (setq n_e (entnext n_e)))
(setq cont 0)

(if (= (cdr (assoc 0 (setq lis_e (entget n_e


(list "*"))))) "SEQEND")
(setq ctrl nil)
(disp_l lis_e)
)
)
)
(alert "Lista de Entidades\teclee LIS para salida por
pantalla\nTeclee LISTX para salida a fichero...")
;;;----------------------FIN DEL
PROGRAMA-----------------------------------------------S O L U C I O N E S

C O N
SPLINE

por Reinaldo Togores

Este plano topogrfico construido con polilneas de


tramos rectos, sin amoldar a curva, ocupaba
originalmente 1.268 Kbytes. Con la aplicacin al
mismo del programa AutoLISP PL2SP logr una
reduccin a 581 Kbytes, un 46 % del original.
La aplicacin de este programa a polilneas adaptadas
a curva-B, como se explica en el texto, logra
reducciones mucho ms espectaculares. Segn
pruebas realizadas, hasta 17 veces menor.

PolyLINES & BYTES

Al utilizar AutoCAD para la realizacin de mapas, usualmente


tenemos que trabajar con ficheros extremadamente grandes.
En muchos casos el tamao de estos ficheros resulta de las
curvas de nivel, y son provocados por la manera en que estas
son generadas. Las curvas de nivel se digitalizan como
polilneas en modo "LINEA". Para curvarlas se aplica despus el
comando EDITPOL (PEDIT) con la opcin SPLINE. Este
procedimiento genera una gran cantidad de vrtices
suplementarios, provocando con ello un incremento en el
tamao del fichero respecto del original que contena slo
polilneas sin amoldar. Otra consecuencia de esta adaptacin
es que la polilnea as adaptada no pasar por todos los
vrtices, suavizndose el perfil original. He realizado algunas
pruebas para determinar la incidencia de este factor sobre el
tamao del fichero, dibujando una polilnea y creando con ella
una matriz de 10 x 10 elementos.

PLINE.DWG
Utilizando los parmetros por defecto de AutoCAD, y
adaptando las polilneas con EDITPOL(PEDIT)/SPLINE, el
resultado ha sido el siguiente:
Polilnea sin adaptar:
PLINE DWG
238.770
bytes
Polilnea adaptada a B-Spline: B-SPLINE DWG 1.930.838
bytes

Como se ve, el tamao del fichero se incrementa algo ms de


ocho veces. Este factor de incremento puede sin embargo
reducirse si antes de realizar la adaptacin se reduce el valor
de la variable SPLINESEGS (que por defecto es 8). Con
SPLINESEGS en 2 el resultado es:
Con SPLINESEGS=2
bytes

B-SPLIN1 DWG

375.520

Con ello se reduce el nmero de segmentos que se emplean


para aproximar la curva terica. Esta adaptacin, sin embargo
presentar un aspecto de lnea quebrada, tanto ms cuanto
menor sea el valor de SPLINESEGS empleado, pues los
segmentos generados son rectos. Un mejor resultado desde el
punto de vista de su apariencia se lograra a partir de dar a la
variable SPLINESEGS un valor negativo, en este caso -2 de
manera que la adaptacin se hiciera empleando arcos en lugar
de segmentos rectos. En este caso se estara combinando la
adaptacin tipo "curva-B" (B-spline) que se realiza a partir de
segmentos rectos, con un posterior curvamiento del tipo
"adaptar curva" (fit curve) tradicional de AutoCAD, a base de
arcos de crculo.
Para lograr una aproximacin mejor a los vrtices originales,
resulta tambin conveniente ajustar la variable SPLINETYPE,
cuyo valor por defecto es 6 (B-spline cbica), hacindola igual
a 5 (B-spline cuadrtica). Esto sera una solucin para nuevos
planos, pero resultara bastante laborioso aplicarlo
manualmente a los ya existentes, pues implicara el
"readaptar" las polilneas con el nuevo valor de SPLINESEGS,
para lo cual sera necesario seleccionarlas una a una con la
orden EDITPOL (PEDIT). Algo de este tipo pudiera
implementarse a partir de un programa AutoLISP que
automatizara el proceso.
Ms recomendable para los ficheros existentes, sera utilizar
algn programa que optimizara las curvas adaptadas,
eliminando los vrtices superfluos. Existen en el mercado
varias aplicaciones que cumplen este propsito. La ms
interesante parece ser la aplicacin CURVEFIT de TCI

Software. Esta aplicacin transforma las polilneas en


"poliarcos" aproximando los mismos a los vrtices originales
dentro del factor de tolerancia fijado por el usuario eliminando
aqullos que no fueran imprescindibles a esta aproximacin.
Otras utilidades que realizan una depuracin de vrtices segn
determinados parmetros ajustables por el usuario son WEED
(incluido en el paquete de utilidades shareware de Jerry
Workman VECTOR) distribuido por Mountain Software y
PFILTER, una utilidad de distribucin libre creada por Steve
Johnson para WAWA, la Water Authority of Western Australia.

LA SOLUCIN SpLINE

La versin 13 de AutoCAD introduce una entidad "SPLINE",


que dibuja directamente curvas cbicas o cuadrticas del tipo
NURBS. Esta curva se genera como tal, sin necesidad de un
amoldamiento posterior, y pasa por todos los vrtices que se
designen. Es una entidad nica, no como la polilnea que
resulta de una concatenacin o secuencia de entidades VERTEX
individuales, con lo que se logra adems un formato mucho
ms compacto en cuanto a su almacenaje en disco. Una spline
trazada con los mismos vrtices que la polilnea original (y
como ella reproducida 100 veces en matriz) dio el siguiente
resultado:
Curva NURBS

SPLINE DWG

109.090 bytes

Otro indicador de la eficacia en la gestin grfica a partir de


esta entidad la obtenemos de aplicar sobre los distintos
dibujos el comando STATUS:
DIBUJO UTILIZANDO SPLINES:
Command: _status 131 objects in C:\USR\DWG\spline
Free physical memory: 6.8 Mbytes (out of 31.4M).
Free swap file space: 84.6 Mbytes (out of 100.9M).
Virtual address space: 57.4 Mbytes.
DIBUJO UTILIZANDO POLILNEAS SIN ADAPTAR:
Command: status 5731 objects in C:\USR\DWG\pline

Free physical memory: 5.6 Mbytes (out of 31.4M).


Free swap file space: 84.3 Mbytes (out of 100.9M).
Virtual address space: 57.8 Mbytes.
DIBUJO CON POLILNEAS ADAPTADAS:
Command: _status 47431 objects in C:\USR\DWG\b-spline
Free physical memory: 0.2 Mbytes (out of 31.4M).
Free swap file space: 78.4 Mbytes (out of 100.9M).
Virtual address space: 76.3 Mbytes.

Es notable la diferencia en la cantidad de entidades registradas


en el dibujo: de 131 en el realizado con splines a 47.431 en el
de las polilneas adaptadas. Tambin merece atencin el hecho
de que despus de cargado el dibujo, el hecho con splines deja
libres 5.6 Megabytes de 31.4 totales, mientras que con el de
las polilneas adaptadas se consume prcticamente la totalidad
de la RAM, con lo que se empezara a paginar a disco de
inmediato, ralentizando con ello el proceso de trabajo.
La solucin ideal para la optimizacin de estos planos estara
en un programa (AutoLISP o ADS) que, una vez depuradas las
polilneas (con CURVEFIT, WEED, PFILTER u otro programa
similar), creara splines a partir de una lectura de los vrtices
resultantes, con lo que se lograra una dimensin ptima del
dibujo.

De SpLINES a PolyLINES:

Como nueva entidad en AutoCAD, SPLINE deja an muchos


cabos sueltos. Como de costumbre, estos cabos sueltos son
campo propicio para la accin de los programadores AutoLISP,
que vienen a aportar soluciones que en muchos casos se
incorporan a las prximas versiones del programa.
Uno de estos cabos sueltos est en la conversin entre las
entidades POLILNEA y SPLINE. La conversin polilnea - spline
est resuelta, siempre que se haya realizado previamente su
adaptacin mediante la opcin "curva-B" (SPLINE). Esta
posibilidad, que forma parte de las opciones del comando

SPLINE, tiene el inconveniente de exigir un amoldamiento


previo a curva-B utilizando el incmodo comando EDITPOL
(PEDIT).
Algo que no ofrece AutoCAD es la conversin en sentido
inverso: la conversin SPLINE > POLILNEA. Decimos "no
ofrece" pues no es que no est resuelta. Lo que no est es
disponible de manera directa, como tal conversin. El proceso
que habr de seguir resulta bastante alambicado: habr que
salvar el dibujo (o la parte de l que querramos convertir)
como dibujo de la versin 12 (saveasR12). Al reabrir el dibujo
en la versin 13 encontraremos que nuestra SPLINE es ahora
una perfecta polilnea. Aunque esta conversin deja an
mucho que desear, pues es polilnea, pero siempre 3D. Faltara
la capacidad de discriminar si se trata de entidades coplanares
para entonces convertirla a una polilnea 2D. Si la opcin de
conversin no aparece como tal, quizs se deba a que
Autodesk desea reservarse algunas "novedades" para
vendernos la prxima versin. De nuevo pudiramos
ingeniarnos para, aprovechando la posibilidad de salvar los
splines como versin 12, crear una orden que automatizara
(recurriendo a un simple SCRIPT) el siguiente proceso:

seleccionar las entidades spline del dibujo


exportarlas mediante la orden BLOQUEDISC (WBLOCK)
salir del dibujo actual y entrar en el nuevo dibujo creado
salvar este nuevo dibujo como R12
volver al dibujo anterior
importar, insertndolo, el dibujo salvado como R12
borrar los dibujos creados en los dos pasos intermedios

Un intento de programa AutoLISP que realiza una


conversin aproximada de una Spline en Polilnea fue publicado
hace algn tiempo por Vladimir Nesterowsky en el foro de
discusin comp.cad.autocad. An cuando la polilnea que se
logra no resulta idntica al spline original, resulta interesante
como ejemplo del procesamiento de entidades recurriendo al
examen de sus datos de entidad. Que la conversin no resulta
sencilla a nivel de programacin de usuario, lo demuestra la

rutina de conversin de B. Stamm y G. Stoykov publicada por


AutoDESK en su coleccin de documentacin tcnica on-line,
fit_spln.lsp - Converting Splines to Polylines . Esta rutina,
mucho menos pretenciosa que la de Vladimir, se reduce a
marcar puntos sobre la spline mediante el comando DIVIDE,
para despus unir los puntos con una polilnea de tramos
lineales.
Cabra preguntar porqu sera necesario transformar una curva
spline en polilnea. Se me ocurren, al menos, los cuatro
siguientes motivos:

Muchos programas que reciben sus datos de ficheros


DWG an no reconocen las splines.
AutoCAD no suministra la manera de "juntar" splines. Si
se interrumpiera accidentalmente el dibujo de una spline,
habra que iniciarla desde el principio para lograr
continuidad.
Tampoco permite darle un grosor a la entidad, cosa que s
hace con las polilneas.
El comando EQDIST (OFFSET) no opera de manera
satisfactoria con las SPLINES, fragmentndolas de
manera imprevisible.
La opcin TTR del comando CIRCULO no funciona con
SPLINES (y tampoco con ELIPSES)

El primero de estos problemas seguramente se resolver en


las prximas versiones de dichas aplicaciones. El segundo sera
tema para un programa AutoLISP. Seguramente alguno de
vosotros ya lo ha intentado. Si es as tendra mucho gusto en
publicarlo. En cuanto al grosor de las entidades, es un tema
pendiente para AutoCAD. Hasta cundo, AutoDESK? Mientras
tanto puede seguirse gestionando como se ha hecho para
todas las dems entidades (excepto polilneas) hasta ahora,
asignndole un grosor al color en el momento de trazar. En
cuanto al ltimo aspecto, suponemos que se trata de un "bug"
reparable en el futuro.

HACERLO AL REVS: DE PolyLINE A SpLINE

Desde mi punto de vista, el programa ms urgente a elaborar


era uno que convirtiera una polilnea en spline, pero no
mediante la opcin EDITPOL (PEDIT) que incrementa el
tamao de la entidad introduciendo nuevos vrtices y que no
acierta a pasar por los puntos originalmente digitizados. Esta
nueva funcin simplemente podra leer los vrtices originales
de la polilnea, descartando aqullos que fueran producto del
curvado. Con ello reduciramos en gran medida la dimensin
de los ficheros de dibujo que como los planos topogrficos
incluyan una gran cantidad de polilneas curvadas.
La solucin que proponemos para ello se encuentra en el
fichero PL2SP.LSP . Los resultados de su aplicacin son
impresionantes. Como prueba hemos utilizado uno de los
ficheros de dibujo mencionados ms arriba: el de las polilneas
adaptadas a B-Spline, B-SPLINE DWG de 1.9 Megabytes, el
que llega a reducirse a slo 110 Kbytes. Debo advertir que la
reduccin no es aparente a primera vista. Es necesario, una
vez ejecutado el programa, comprimir el dibujo mediante la
orden LIMPIA (PURGE), o salvndolo habiendo establecido
previamente el valor de la variable ISAVEPERCENT en 0 (cero),
o exportndolo mediante BLOQUEDISC (WBLOCK) Los efectos
conseguidos pueden verse en el siguiente listado:
Dibujo original:
B-SPLINE
Ejecutado PL2SP:
PRUEBA
Limpiando el DWG:
PURGE
bytes
Salvando con BLOQUEDISC: WBLOCK

DWG 1.930.838 bytes


DWG 2.027.294 bytes
DWG
110.683
DWG

110.228 bytes

C O N V E R S I N
PolyLINE>SpLINE

Para utilizar el cdigo que sigue, seleccinelo en su browser,


utilizando el ratn, desde la lnea que dice "-INICIO DEL
PROGRAMA-" hasta la lnea "-FIN DEL PROGRAMA-", copie el

texto seleccionado (Ctrl+C), abra un editor (Notepad o Visual


LISP) y pguelo all (Ctrl+V). Guarde el fichero as creado con
el nombre PL2SP.LSP en un directorio que figure en la variable
de entorno ACAD (por ejemplo, el subdirectorio SUPPORT) .
Para cargarlo teclee (load "PL2SP")
Reinaldo Togores. Profesor Asociado.
Departamento de Ingeniera Geogrfica y Tcnicas de
Expresin Grfica
Universidad de Cantabria. Marzo de 1997.
Se autoriza la utilizacin del cdigo de estos programas,
mencionando siempre su origen.
Para comentarios y sugerencias:
reinaldo.togores@unican.es
Una versin de este programa, capaz de procesar LWPOLYINES
ha sido elaborado por Oscar Rodrguez de Sevilla, Espaa. Para
acceder al mismo, pulse AQU.
;;--INICIO DEL PROGRAMA/PROGRAM BEGINS
HERE-------------;:***************************************************
****
;;Sustitucin PLINE->SPLINE
;;Lee los vrtices originales de una polilnea y crea
a
;;partir de ellos una SPLINE. Borra la pollnea
original.
;;(C) Reinaldo Togores, Santander, 1997
;;-----------------------------------------------------;;Nota: Este programa slo funcionar correctamente
si el
;;Sistema de Coordenadas de Objeto de la polilnea a
convertir
;;coincide con el Sistema de Coordenadas Universal,
es decir

;;que la polilnea est contenida en un plano


paralelo
;;al plano XY Universal.
;;***************************************************
*****
;;Rutina de seleccin de objetos:
;;Del conjunto de seleccin original, crea un nuevo
;;conjunto de seleccin que incluya slo polilneas:
(defun pl_sel ( / orig_selset pl_selset count)
(prompt "\nSeleccione Polilneas/Select Polylines:
")
(setq
orig_selset (ssget)
pl_selset (ssadd)
count -1
)
(repeat (sslength orig_selset)
(setq count (1+ count))
(if (= (cdr (assoc 0 (entget (ssname
orig_selset count)))) "POLYLINE")
(ssadd (ssname orig_selset count) pl_selset)
)
)
pl_selset
)
;;Rutina de lectura de los vrtices de la polilnea
;;crea una lista de entidad SPLINEa partir de los
;;vrtices originales de la polilnea, (sealados por
;;el cdigo 70=0 16) cambiando el cdigo 10 de la
;;entidad POLYLINE por el cdigo 11 de la entidad
;;SPLINE.
;;Slo se incluyen en la nueva lista los cdigos
;;imprescindibles para la creacin de la SPLINE.
;;Cada lista creada se pasa a entmake
;;para crear la nueva SPLINE. Despus se borra la
;;polilnea original
(defun vertex ( sset / count ent_sup act_ent
spl_list)
(setq count 0)
(repeat (sslength sset)
(setq
ent_sup (ssname sset count)

act_ent (entnext ent_sup)


count (1+ count)
spl_list nil
)
(while (/= (cdr (assoc 0 (entget act_ent )))
"SEQEND")
(if
(or
(= (cdr (assoc 70 (entget act_ent)))
0)
(= (cdr (assoc 70 (entget act_ent)))
16)
)
(setq
spl_list
(cons (cons 11 (cdr (assoc 10 (entget
act_ent)))) spl_list)
)
)
(setq
act_ent (entnext act_ent)
)
)
(setq spl_list (reverse spl_list))
;;Consruccin de la nueva lista de
entidad
(foreach
cod
(list
(assoc 8 (entget ent_sup))
(cons 74 (length spl_list))
(cons 71 3)
(cons 100 "AcDbSpline")
(cons 100 "AcDbEntity")
(cons 0 "SPLINE")
)
(setq spl_list (cons cod spl_list))
)
;;Hacer la SPLINE
(entmake spl_list)
;;Borrar la POLILNEA
(entdel ent_sup)

)
)
;;Funcin Principal/Command line function
(defun c:pl2sp ( / oce)
(setq oce (getvar "cmdecho"))
(setvar "cmdecho" 0)
(vertex (pl_sel))
(redraw)
(setvar "cmdecho" oce)
(princ)
)
;;----------------FIN DEL
PROGRAMA----------------------Many of you have posted requests to the Wizard's Lab asking how to use Visual LISP to
interface with other automated productivity tools like Microsoft Excel. This article is the first in a
series that shows you how to create such an interface. First I'll explain the basics and then we'll
start looking at the larger task: using Visual LISP to tie other automated programs into your CAD
drawings. As you'll see it's all about productivity gains.
Note: You can download the code used in this tutorial from here (1.5 KB).
What Is Automation?
Microsoft Windows holds some very powerful automation programs that, with some programming,
you can use to control (drive) other programs you've installed. Generally this mechanism is
referred to as automation. The Windows operating system has a series of guidelines that you
can follow to create an application that accepts automation.
An automated program publishes or sends information to the operating system, which defines the
types of commands the program supports and how other programs are to go about
communicating with it. That process is basically standardized. But as you might have guessed,
beyond that each program has its own unique way for other programs to drive it automatically.
Automating certain tasks can achieve marvelous results. A simple illustration is to tie drawing
information from a bill of materials into a spreadsheet for further analysis or reporting purposes.
Another: to import text generated by a word-processing application into a drawing so that you
don't have to reenter data. Or this: integrating a database containing details about elements used
in the drawing to determine loads or costs. Your only limit here is the power of your imagination.
This arena is a wonderful place for wizards to play!
Beginning a Conversation
First, let's look at the theory behind automation and then look at how to apply that theory in Visual
LISP.
The automation process begins when one program establishes a communications link to another
program. Any application built to run on the Windows OS can be automated if the developer
provides the required parts. During installation, the name of each application is placed in the
Windows Systems Registry and that name is used to reference the application from another
program. Learning that System Registry name is your first step. In most cases you can guess at

the name with reasonable accuracy. The name to activate a program such as Microsoft Excel is
simply Excel.Appliction. The dot that appears between the name Excel and the word Application
is a standard divider used when referencing an object inside Windows. If the application name is
not obvious then you have some detective work to do. Most applications will include some
documentation about automation that will provide assistance.
Once you know the name of the application object, open the application. (Of course it should go
without saying that you can't automate an application that isn't already installed on your PC.) To
begin automating an application, you can either communicate with an instance of the program
that is already running or you can create a new instance of the program. That is, you can open an
existing channel to the program or create a new channel by copying the program to memory and
working with the copy.
The requirements of your interface dictate your choice here. If you want to create a new
document or worksheet, create a new channel to the application. If you want to look up
information in the program, open the program. The main difference is in how much time is
required to establish communication. Opening an existing application in memory is significantly
faster than creating a new instance.
The following list defines a few terms that you should know as you begin to create an interface
that automates an application. One word of caution though, all the documents about automation
are likely written from the perspective of Visual BASIC and not Visual LISP. As a Visual LISP
programmer, you must translate this information into more relevant terms. We'll get to that a bit
later on. Here's the list of terms:

Active Xa Microsoft automation program that uses object-level interfaces


Objecta container that has properties and methods (and maybe other objects)
Object Referencea variable set to point to an object
Propertya data item contained in an object
Methoda function inside an object

Beginning Conversion Using Visual LISP


This process is relatively easy. First evaluate the expression (VL-LOAD-COM), which loads the
Components Object Model of Visual LISP. You need do this only once to enable the VLAX (Visual
LISP Active X) functions. Functions labeled VLAX are not available in Visual LISP until the library
has been called into memory. Many applications don't require Active X interfacing, so these
functions are not loaded automatically when you open the AutoCAD software. The loading is left
up to the Visual LISP application.
(VL-LOAD-COM) returns instantly if the VLAX functions are already available in memory, and
there is no degradation to your programs if you do end up calling more than once. I just include
(VL-LOAD-COM) in the base load of the application by placing it in my source file outside of a
function definition. That way, it is evaluated as the function set is loaded into AutoCAD.
This does slow down the loading process by a few seconds, but not to an unacceptable degree.
And I let the user know that a process is loading by issuing a prompt to the command line. VLLOAD-COM does not present a prompt. Without the prompt that I supply, the user may think the
process has frozen the computer or will complain about how slow my program is.
Once VLAX functions are available you can use one of three different functions to obtain an
object reference to the application with which you wish to communicate. Your application
requirements dictate which function you choose. The fastest options are to link to an already
running instance of the program with which you want to interface.

VLAX-GET-OBJECTestablish a link to an already running program


VLAX-CREATE-OBJECTcreate a new instance of the program
VLAX-GET-OR-CREATE-OBJECTlook first to see if the program is running. If it is,
then link to that copy. If not, then load a new instance for automation.

You must supply the name of the application you will be automating for each of these methods. If
the application is not available, a nil result is returned indicating that your request for an
automation link has failed. Otherwise, an object reference is returned. Save that result using
SETQ in your Visual LISP program. The following expression attempts to link to either a running
copy of Excel or to create a new instance of it if one is not currently available.

(setq xL (vlax-get-or-create-object
"Excel.Application"))
When this expression has completed, the symbol xL will be nil if Excel could not be located on the
computer. Otherwise xL contains the object reference to a running copy of the program. You will
use the object reference from this point forward to communicate with that specific instance of
Excel.
If you want to be sure that you are working with an exclusive instance of Excel, use the (VLAXCREATE-OBJECT) method. That way, if Excel is already running, a new copy is started in the
computer so that your application does not interfere with any other spreadsheets that may be
open and in use. Or use (VLAX-GET-OBJECT) and simply use an already running copy of Excel.
This option is useful when you are working with an active spreadsheet and simply want to move
data between it and a drawing. In all the cases, you will get an object reference if the link is
successful or a nil result if the link could not be established.
We can use the result immediately as in the following code segment:

(if (setq xL (vlax-get-or-create-object


"Excel.Application"))
(progn
;;operations with spreadsheet application
) ;;end PROGN
(alert "Unable to establish link with Excel!")
;else error message
)
Using the Object Reference
Once you have the object reference to a running copy of Excel, what do you do? Use the Visual
LISP functions (VLAX-GET) and (VLAX-PUT) to move through the objects. With the object
reference you can retrieve object properties and/or move data to the spreadsheet. However, I find
that the next step to take in most circumstances is to import the object library into Visual LISP,
which simplifies the remaining work you may want to perform with the spreadsheet.
What is an object library? It is a set of subroutines and data elements that the hosting application
has declared as being available to external tasks employing automation techniques. The
Windows OS uses a standard mechanism known as Object Linking and Embedding (OLE for
short) that programming systems can tie in to. OLE is an advanced method of program-toprogram communications allowing automation to take place.

Object libraries are declared in a file with an OLB extension, which you can usually find in the
same folder as the application executable files. Use Windows Explorer to locate the file (use the
Find option in the Tools drop-down menu and search for all files that have an extension of OLB).
You can either code the entire path to the object library into your application, use a variable to
house that information in case you want to change it later on, or have your program locate the file
you need.
Use the Visual LISP function (VLAX-IMPORT-TYPE-LIBRARY) to import the library into your
program. On import, a new host of functions becomes available to use in the interface you're
creating. Do this import only once in an application.
The Visual LISP documentation recommends that the import function be run at the topmost level
in your program, just like the (VL-LOAD-COM) expression. That method prevents attempts at
loading the type library more than once. You don't want to import a library more than once
because it is time consuming and could possibly foul symbol assignments you have already
made. Another way to prevent importing a library twice is to employ a conditional as in the
following expression:

(if (null xl-open)


(vlax-import-type-library
:tlb-filename "C:/Program Files/Microsoft
Office/Office/Excel8.olb"
:methods-prefix "xL-"
:properties-prefix "xLp-"
:constants-prefix "xLc-"))
Let's take a closer look at the VLAX-IMPORT-TYPE-LIBRARY expression in this code segment.
The first step is to determine if the function XL-OPEN is already defined. The name XL-OPEN
does not exist in normal Visual LISP and should have a null binding when the expression is first
encountered. You are going to create VL-OPEN as a result of the library import. You call this
function by supplying a string in the VLAX-IMPORT-TYPE-LIBRARY to serve as a common prefix
for all the new functions to be imported.
There are eight parameters containing four values supplied to the VLAX-IMPORT-TYPELIBRARY expression. Each value is supplied as a pair. The first part is a symbol name that starts
with a colon character " : " as in :tlb-filename. These symbols are constants inside Visual LISP
and are used by the VLAX-IMPORT-TYPE-LIBRARY function to identify what the immediately
following string represents. Following the constant :TLB-FILENAME is the file name, with path, of
the type library. In the above example the file is located in the Microsoft Office program directory.
The remaining three pairs are for prefixes to be added to the names of the methods, properties,
and constants of the imported library. The prefixes should be unique so that they do not interfere
with other functions already defined inside Visual LISP.
In the example the prefixes used are "XL-", "XLP-" and "XLC-". Thus VL-OPEN will have a
binding once the import has taken place, and the IF test will not allow the import to take place a
second time. This is why I strongly recommend using a conditional expression in association with
the import of an object library. If the import has taken place previously, then VL-OPEN will not be
nil and the NULL test will return a false answer, which prevents subsequent calls to the import.
Learning What Is Loaded
How do you learn what is in the object library you've imported? It's simple. In the APROPOS

dialog box in the Visual LISP editor, supply the prefix you specified during the import. In most
cases the list returned is extensive, including items that take you to the information in the online
help for the application to which you are interfacing. For example, you can learn what the
parameters of a given function might be by looking at the help data.
You must interpret this information from a Visual BASIC programming point of view because most
automation programming is done using Visual BASIC not Visual LISP. However, using the
methods described so farespecially the import object library functionVisual LISP is just as
powerful a tool. But remember that it is only found in AutoCAD.
To access the APROPOS feature in Visual LISP:
1.
2.
3.
4.
5.

Start the VLIDE (Visual LISP Interactive Development Environment.


Select the APROPOS icon or select the APROPOS option from the View pull-down menu.
Enter the prefix that you specified when loading the library.
Select the Match by prefix option.
Click OK. The list appears.

Remember that the list only reveals object names. You must go into the other application and find
the associated information in the help system.
What's Next?
So far you've learned that you can use Visual LISP to interface with another program such as
Excel through the use of the OLE or automation system. You've also seen how to establish a link
to the automation tools from another application.
The next steps involve the actual sending and receiving of data using the interface. This requires
that you use either the VLAX-GET and VLAX-PUT functions or that you allow Visual LISP to
import a new library of functions as defined in an OLB (Object Library) file. Check out the scrolls
and potions in the Wizard's Lab to see how this might be accomplished or join me next month
when we'll explore how to transfer data to Excel.
Until then, keep on programmin'.
Continuing on, we want to create a command called ZAP that erases all the objects in
the drawing. To do this we'll need to execute the ERASE command, input the ALL
option (all three characters), and then an additional ENTER to get out of the
command.
So how do we tell Visual LISP to hit ENTER? A pair of double quotes will do. For those
of you who have customized menus, this is the equivalent of using a semicolon to
represent an ENTER.
(defun c:ZAP ()
(command "erase" "all" "")
)
So how are we going to create a square? We'll execute the POLYGON command,
make the object four-sided, select the EDGE option, and pause twice to let the user
pick the two corners that will make up our square. If you're lost, please go into the
POLYGON command in AutoCAD and go through all of these steps manually. Let's
look at the code.

(defun c:SQ ()
(command "polygon" "4" "E" pause pause)
)
Using pause in a Visual LISP routine will instruct the program to wait for user input.
Those two pauses will enable the user to pick the two corners of the square. This is
equivalent of the backslash \ in menu customization. So what do we have so far?
(defun c:ZP ()
(command "zoom" "p")
)
(defun c:ZAP ()
(command "erase" "all")
)
(defun c:SQ ()
(command "polygon" "4" "e" pause pause)
)

Figure 1. The APPLOAD dialog makes it easy to load your Visual LISP
routines.

Test-Drive Your New Commands


Now we're ready to load and run our routines. We'll use the APPLOAD command to
load our newly created Visual LISP routine. This can be found in the Tools pull-down
menu under Load Application as a dialog box, as shown in Figure 1.
You'll simply select the file you just created and load it. If you've made any errors,
this dialog will be happy to notify you. If all goes as planned, you should now be able
to key in ZP, ZAP, and SQ at the command line. Give them a try.
You've just become a budding programmer.
Now that was pretty easy, wasn't it? This is just a peek into the powerful world of
Visual LISP. For more, you should look to the guru, Bill Kramer, to lead you down the
path of true programming enlightenment.
Until next month...Happy AutoCADing! I wish you all a wonderful holiday season.

Vous aimerez peut-être aussi