1、第第2章章 数据类型、表达式和函数数据类型、表达式和函数 AutoLISP的数据类型丰富,除了一般程序设计语言具有的整的数据类型丰富,除了一般程序设计语言具有的整型、实型、字符串等类型之外,还有表、函数、文件描述符、型、实型、字符串等类型之外,还有表、函数、文件描述符、AutoCAD选择集、选择集、AutoCAD图元名、图元名、VLA对象、函数分页表和对象、函数分页表和外部函数等数据类型。外部函数等数据类型。2.1 数据类型数据类型1.整型(整型(INT)整型即整数,整数由数字和正负号组成,正号可省略。整数为整型即整数,整数由数字和正负号组成,正号可省略。整数为32位带符号的数字,其范围从位带
2、符号的数字,其范围从2147483648到到2147483647。2.实型(实型(REAL)实型数是带小数点的数。在实型数是带小数点的数。在-1和和1之间的实数必须以之间的实数必须以0开头,例开头,例如:如:.5是错误的,应该写成是错误的,应该写成0.5。实数用双精度的浮点数表示,并。实数用双精度的浮点数表示,并且至少有且至少有14位有效位数的精度。注意,位有效位数的精度。注意,Visual LISP不显示所有的不显示所有的有效位。有效位。3.字符串(字符串(STR)字符串又被称为字符常数,它是由双引号括起来的字符序列字符串又被称为字符常数,它是由双引号括起来的字符序列。字符串中字母的大、小写
3、和空格符都是有意义的。字符串中字母的大、小写和空格符都是有意义的。字符串中字符的个数(不包括双引号)称为字符串的长度。字字符串中字符的个数(不包括双引号)称为字符串的长度。字符串的最大长度为符串的最大长度为100,如果超过,如果超过100,第,第100个字符后面的字符个字符后面的字符将是无效的。字符串可以是空的,即将是无效的。字符串可以是空的,即,称为空串,其长度为,称为空串,其长度为0。任何字符都可以用任何字符都可以用nnn的格式表示,其中反斜杠的格式表示,其中反斜杠“”是是ASCII码的前导标识字符,码的前导标识字符,nnn是该字符八进制的是该字符八进制的ASCII码。例如,字码。例如,字
4、符串符串ABCD也可表示为也可表示为101102123104。一些常用的控制字符,。一些常用的控制字符,象反斜杠、双引号,除了可以用象反斜杠、双引号,除了可以用 nnn的格式表示之外,还可以的格式表示之外,还可以用用“”转义字符的格式表示为转义字符的格式表示为“”、“”等特殊字符,见下表等特殊字符,见下表。表表2-12-1常用控制字符的表示方法常用控制字符的表示方法控制字符控制字符 用用“”为前导字符为前导字符 用用“”为前导的为前导的ASCIIASCII码表码表示示反斜杠反斜杠“”134134双引号双引号“”042042EscEsc键键 e e 033033换行换行 n n 012012回车
5、键回车键 r r 015015TabTab键键 t t 011011注意,其中的字符注意,其中的字符e e,n n,r r,t t必须小写。必须小写。4.表表 表以左圆括号开始,以配对的右圆括号结束,表可以是空表以左圆括号开始,以配对的右圆括号结束,表可以是空的,可以有若干个元素;元素可以是简单的,也可以是复杂的的,可以有若干个元素;元素可以是简单的,也可以是复杂的,还可以是其它的表。例如:(,还可以是其它的表。例如:(+1 2 3)、()、(sin(*0.5 pi)、()、(A B)、()、(A B)C(C D)、()、(0 LINE)、()、(10 1.5 2.6 0.0)、()都是合法的
6、表。)、()都是合法的表。表中元素的个数称为表的长度。例如,表(表中元素的个数称为表的长度。例如,表(+1 2 3)的长)的长度为度为4、表(、表(sin(*0.5 pi)的长度为)的长度为2、表(、表(A B)C(C D)的长度为)的长度为3、表()的长度为、表()的长度为0。用表可以方便地构造出复杂的数据结构,例如,(用表可以方便地构造出复杂的数据结构,例如,(1.5 3.6)可以表示为一个)可以表示为一个X等于等于1.5、Y等于等于3.6的二维点的二维点,(2.5 2.0 1.0)可以表示为一个)可以表示为一个X等于等于2.5、Y等于等于2.0、Z等于等于1.0的三维点。的三维点。5.函
7、数(函数(SUBS)函数相当于子程序或过程。函数分为内部函数和外部函数函数相当于子程序或过程。函数分为内部函数和外部函数。AutoLISP提供的或用提供的或用AutoLISP定义的函数为内部函数。用定义的函数为内部函数。用ADS、ADSRX或或ARX定义的函数为外部函数。例如定义的函数为外部函数。例如sin、cos、sqrt为内部函数。为内部函数。运算符在运算符在AutoLISP里属于函数,例如里属于函数,例如“”、“”、“*”、“/”分别称之为加、减、乘、除函数,分别称之为加、减、乘、除函数,“”、“”分别称之为小于、小于等于和大于函数。分别称之为小于、小于等于和大于函数。其它计算机语言里的
8、子程序、过程、程序流程控制的关字其它计算机语言里的子程序、过程、程序流程控制的关字,在,在AutoLISP里也属于函数,例如里也属于函数,例如“if”、“while”分别称之分别称之为条件和条件循环函数。为条件和条件循环函数。6.文件描述符(文件描述符(FILE)文件描述符是文件描述符是AutoLISP赋于被打开文件的标识号,它类似于赋于被打开文件的标识号,它类似于文件指针。下面的例子是以文件指针。下面的例子是以“读读”的方式打开文件的方式打开文件myfile.dat,并将该文件的描述符赋予符号并将该文件的描述符赋予符号f1。(setq f1(open myfile.dat r)返回返回7.图
9、元名(图元名(ENAME)图元名是图元名是AutoCAD为图形对象指定的为图形对象指定的16进制的数字标识。进制的数字标识。AutoLISP通过该标识,找到该图形对象在图形数据库中的位通过该标识,找到该图形对象在图形数据库中的位置,以便对其进行访问或编辑。置,以便对其进行访问或编辑。8.选择集(选择集(PICKSET)选择集是一个或多个图形对象命名的集合。可以通过选择集是一个或多个图形对象命名的集合。可以通过AutoLISP程序建立选择集、向指定的选择集添加或移去图形对程序建立选择集、向指定的选择集添加或移去图形对象,通过选择集可以对其内指定的成员进行访问或编辑。象,通过选择集可以对其内指定的
10、成员进行访问或编辑。9.VLA 对象对象 VLA 对象是对象是ActiveX 应用程序的主要组成部分。应用程序的主要组成部分。不仅直线不仅直线、圆弧、多义线和圆等都被称为、圆弧、多义线和圆等都被称为VLA对象,图层、组、块、视对象,图层、组、块、视图、视口、图形的模型空间、图纸空间、线型和尺寸标注样式图、视口、图形的模型空间、图纸空间、线型和尺寸标注样式等也被称为等也被称为VLA对象,甚至连对象,甚至连AutoCAD本身也被认为是本身也被认为是VLA对对象。象。2.2 变量变量2.2.1 符号符号 符号(符号(SYMBOL)可以理解为标识,用来作为变量、函数)可以理解为标识,用来作为变量、函数
11、的名字。它的命名规则是不能只含数字,可以由下列字符以的名字。它的命名规则是不能只含数字,可以由下列字符以外的任何可打印的字符所组成:外的任何可打印的字符所组成:“(”、“)”、“”、“”、“”、“;”例如,例如,a1、b2、c_3是合法的符号,是合法的符号,(a、)b、.c、4、5是非法的符号。注意:是非法的符号。注意:1、2、3、!4、/5、1a、3c、-d、+e、b-2、c*3也是合法的符号,这是与多数计算机语言的不也是合法的符号,这是与多数计算机语言的不同之处。同之处。在在AutoLISP中,符号的大小写等价,符号的长中,符号的大小写等价,符号的长度没有限制,且所有的字符都是有意义的。度
12、没有限制,且所有的字符都是有意义的。如果一个符号的长度不超过如果一个符号的长度不超过6,就用节点本身来存,就用节点本身来存储;如果符号的长度超过储;如果符号的长度超过6,这样的符号就不能用节,这样的符号就不能用节点来存储,而是在节点中存放一个指向实际存储符号点来存储,而是在节点中存放一个指向实际存储符号名的指针。这将会多占用存储空间,且减慢了执行速名的指针。这将会多占用存储空间,且减慢了执行速度。因此,符号的长度最好不要超过度。因此,符号的长度最好不要超过6。2.2.2 变量的数据类型变量的数据类型 AutoLISP变量属于符号,是指存储静态数据的符号。变量属于符号,是指存储静态数据的符号。数
13、据类型是变量的重要的特征,因为它关系到存放变量值的数据类型是变量的重要的特征,因为它关系到存放变量值的存储空间的大小。多数的计算机语言都在为变量赋值前对变量做存储空间的大小。多数的计算机语言都在为变量赋值前对变量做显式或隐式的说明。显式或隐式的说明。AutoLISP无须对变量做事先的类型说明,无须对变量做事先的类型说明,变量被赋予值的类型即为变量的类型。变量被赋予值的类型即为变量的类型。用用setq函数对变量赋值,例如,(函数对变量赋值,例如,(setq a 5),赋值后的结果是赋值后的结果是:变量:变量a是整型的,因为是整型的,因为5是整型的;同样的原因是整型的;同样的原因,(setq b
14、2.5)之后之后,b是实型的,(是实型的,(setq c ABC)之后)之后,c就是字符串类型的。就是字符串类型的。在程序运行过程中,同一变量在不同的时刻可以被赋予在程序运行过程中,同一变量在不同的时刻可以被赋予不同类型的值,因此在程序运行过程中,变量的数据类型是不同类型的值,因此在程序运行过程中,变量的数据类型是可以被改变的。可以被改变的。例如,在一个程序里有以下两行:例如,在一个程序里有以下两行:(setq a 5)当前的变量)当前的变量a是整型的。是整型的。(setq a ABC)当前的变量当前的变量a是字符串类型的。是字符串类型的。用用type函数了解变量的类型,例如,(函数了解变量的
15、类型,例如,(type a)返回返回INT,显示变量,显示变量a是整型的;(是整型的;(type b)返回)返回REAL,显示变量,显示变量b是是实型的,(实型的,(type c)返回返回STR,显示变量,显示变量c是字符串类型的。是字符串类型的。2.2.3 为变量赋值为变量赋值 用用setq函数为变量赋值,其格式如下:函数为变量赋值,其格式如下:(setq 变量变量1 值值1变量变量2 值值2.)例如:例如:Command:(setq x 1.5 y 20 p Center)返回返回“Center”除了为变量除了为变量x、y、p赋值外,还返回最后一个表达式的结果赋值外,还返回最后一个表达式的
16、结果“Center”。如果上述表达式还有外层表达式,那么,将把该表。如果上述表达式还有外层表达式,那么,将把该表达式的返回值达式的返回值“Center”赋给外层表达式的变量。例如,赋给外层表达式的变量。例如,Command:(setq v(setq x 1.5 y 20 p Center)返回返回“Center”该表达式同样为变量该表达式同样为变量x、y、p赋值赋值,并将内层表达式返回的结并将内层表达式返回的结果果“Center”赋给变量赋给变量v,最后返回外层表达式的结果,最后返回外层表达式的结果“Center”。没有被赋值的变量属于无定义的变量。没有被赋值的变量属于无定义的变量。2.2.4
17、 预定义的符号预定义的符号 AutoLISP对变量对变量nil、T、Pause和和Pi进行了预定义,用户可以进行了预定义,用户可以在编写在编写AutoLISP程序时直接使用。程序时直接使用。(1)nil 如果变量没有被赋值,它的值为如果变量没有被赋值,它的值为nil。nil与空和与空和0不同的是,不同的是,它既不是空串,也不是它既不是空串,也不是0值,它表示尚无定义。引用未被赋值的值,它表示尚无定义。引用未被赋值的变量是错误的。例如,变量变量是错误的。例如,变量x尚未被赋值,(尚未被赋值,(+1 x)就会出现)就会出现error:bad argument type(坏的参数类型错)。(坏的参数
18、类型错)。将将nil赋给某一有定义的变量,其结果是:取消该变量的定义赋给某一有定义的变量,其结果是:取消该变量的定义,并释放其所占存储空间。,并释放其所占存储空间。nil作为逻辑变量的值,表示不成立,相当于其他程序设计语作为逻辑变量的值,表示不成立,相当于其他程序设计语言的言的false。(2)T T为常量,它作为逻辑变量的值,表示成立,相当于其他程为常量,它作为逻辑变量的值,表示成立,相当于其他程序设计语言的序设计语言的true。(3)PAUSE PAUSE与与command函数配合使用,用于暂停,等候用户输函数配合使用,用于暂停,等候用户输入。入。(4)PI PI被定义为常量被定义为常量
19、。每个变量都占用一些内存空间。为了节省存储空间,可重复每个变量都占用一些内存空间。为了节省存储空间,可重复使用变量名,或者将不再使用的变量设为使用变量名,或者将不再使用的变量设为nil,以便释放该变量,以便释放该变量所占的内存空间。所占的内存空间。必须注意,一般的编程语言不允许将内部函数名必须注意,一般的编程语言不允许将内部函数名或流程控制的关键字作为变量名,而或流程控制的关键字作为变量名,而AutoLISP没有没有这样的限制。因此,程序中定义的符号名称不要与系这样的限制。因此,程序中定义的符号名称不要与系统定义的函数名和预定义的变量名相同,否则,后面统定义的函数名和预定义的变量名相同,否则,
20、后面的定义将取代已有的定义,从而引起混乱。例如,的定义将取代已有的定义,从而引起混乱。例如,sin是正弦函数,可是在执行表达式(是正弦函数,可是在执行表达式(setq sin 1)之)之后,后,sin不再是正弦函数,而是一个值为不再是正弦函数,而是一个值为1的整型变量的整型变量。2.2.5 显示变量的值显示变量的值 要想在要想在AutoCAD命令提示区显示变量的值,必须在变量名命令提示区显示变量的值,必须在变量名前添加惊叹号前添加惊叹号!。例如了解前面已赋值的变量。例如了解前面已赋值的变量x、v的值,操作的值,操作如下:如下:Command:!x1.5Command:!vCenterComma
21、nd:!znil(假定变量(假定变量z尚未被定义)尚未被定义)2.2.6 在交互方式下将变量的值传递给在交互方式下将变量的值传递给AutoCAD 在变量前加一个感叹号在变量前加一个感叹号“!”,即可将表达式的值传递给,即可将表达式的值传递给AutoCAD。例如:。例如:Command:(setq p(20 10)r 5)Command:circle Specify center point for circle or 3P/2P/Ttr(tan tan radius):!p Specify radius of circle or Diameter::!r 即可画出圆心的坐标为(即可画出圆心的坐
22、标为(20,10)半径为)半径为5的圆。的圆。2.3 表达式表达式 AutoLISP处理的对象是符号表达式(简称表达式)。表达式相处理的对象是符号表达式(简称表达式)。表达式相当于其他编程语言中程序的语句。当于其他编程语言中程序的语句。2.3.1 表达式的构成表达式的构成 表达式是由原子或表构成的。原子可细分为数原子、串原子和表达式是由原子或表构成的。原子可细分为数原子、串原子和符号原子。数或串原子的值是数或串本身,符号原子的值是赋给符号原子。数或串原子的值是数或串本身,符号原子的值是赋给该符号的值。例如:该符号的值。例如:5、12.5、“ABC是单个原子构成的表达式是单个原子构成的表达式。多
23、数情况下,表达式以表的形式存在,其格式如下:多数情况下,表达式以表的形式存在,其格式如下:(函数名函数名 变元变元)变元的数量可能为变元的数量可能为0,也可能任意多个,这取决于具体函数。每,也可能任意多个,这取决于具体函数。每个参数还可以是一个表达式。个参数还可以是一个表达式。表达式表达式形式形式的表,左圆括号之后的第一个元素必须是函数名。的表,左圆括号之后的第一个元素必须是函数名。2.3.2 表达式的前缀表示法表达式的前缀表示法 大多数计算机语言的表达式采用中缀表示法,即运算符在操大多数计算机语言的表达式采用中缀表示法,即运算符在操作数中间。如,作数中间。如,x=2.5,y=1+2。Auto
24、LISP采用前缀表示法,将函数名放在所有操作数之前。采用前缀表示法,将函数名放在所有操作数之前。如,如,(setq x 2.5),(setq y(+1 2)。若将若将x=(a+b)*c 改写为改写为AutoLISP表达式,则为:表达式,则为:(setq x(*(+a b)c)前缀表示法使得运算和函数调用的形式得到了统一。前面提前缀表示法使得运算和函数调用的形式得到了统一。前面提到,在到,在AutoLISP语言里,运算符也属于函数。语言里,运算符也属于函数。2.3.3 表达式的求值过程表达式的求值过程 在在LISP语言中,函数之间不存在是否优先的关系,运算的语言中,函数之间不存在是否优先的关系,
25、运算的先后顺序只能通过表的层次来实现,最里层的表最先被求值,先后顺序只能通过表的层次来实现,最里层的表最先被求值,把求值的结果返回给外层表,直至求值完毕。把求值的结果返回给外层表,直至求值完毕。例如,表达式例如,表达式(setq x(*(+a b)c),先求出最内层,先求出最内层a与与b之和之和,然后求出,然后求出a、b之和与之和与 c的积,将求得的积赋给的积,将求得的积赋给x,最后返回,最后返回x的值。的值。可以在可以在Command:提示下,输入一个表达式,:提示下,输入一个表达式,AutoCAD将将计算该表达式并返回计算结果。计算该表达式并返回计算结果。AutoCAD至多显示至多显示6位
26、小数。位小数。例如,在例如,在Command:提示下,键入(:提示下,键入(sin 0.5)之后回车,将)之后回车,将返回返回0.479426。如果输入的或者从文件中读入的表达式不正确,将显示出错信如果输入的或者从文件中读入的表达式不正确,将显示出错信息,最常见的出错信息是:息,最常见的出错信息是:(_ 表示缺少与左圆括号匹配的右圆括号,表示缺少与左圆括号匹配的右圆括号,“(”的个数即为缺少的个数即为缺少右圆括号的数量。如果出现该信息,输入与所提示的左圆括号相右圆括号的数量。如果出现该信息,输入与所提示的左圆括号相等的右圆括号既可。由于所缺的右圆括号不一定都是最后的,所等的右圆括号既可。由于所
27、缺的右圆括号不一定都是最后的,所以可能产生错误的结果。以可能产生错误的结果。如果遗漏了与左端双引号匹配的右端的双引号,显示的出错信如果遗漏了与左端双引号匹配的右端的双引号,显示的出错信息为:息为:(_ 在这种情况下输入匹配的双引号也不一定使表达式能正常求值在这种情况下输入匹配的双引号也不一定使表达式能正常求值。此时只能按。此时只能按Esc键终止当前的输入,重新输入表达式。键终止当前的输入,重新输入表达式。2.3.4 表达式的求值规则表达式的求值规则 (1)整型数、实型数、字符串,以它们本身的值作为求值结)整型数、实型数、字符串,以它们本身的值作为求值结果。果。(2)符号以它们当前的约束值作为求
28、值结果。)符号以它们当前的约束值作为求值结果。(3)表是根据其第一个元素来进行求值的。)表是根据其第一个元素来进行求值的。如果第一个元素或第一个元素的计算结果是一个函数名如果第一个元素或第一个元素的计算结果是一个函数名,那么以表中剩余的元素作为该函数的变元,计算出该函数的,那么以表中剩余的元素作为该函数的变元,计算出该函数的值。例如,表达式:值。例如,表达式:(+(*2 3)(/50 3)先计算最内层的表达式(先计算最内层的表达式(*2 3)和)和(/50 3),将结果),将结果6和和16返回给其外层表达式,原表达式变为:(返回给其外层表达式,原表达式变为:(+6 16)继续计算表达式(继续计
29、算表达式(+6 16),返回),返回22。如果第一个元素是一个表,该表不是调用而是定义函数如果第一个元素是一个表,该表不是调用而是定义函数,若语法正确,首先定义这个函数,然后继续表达式求值。,若语法正确,首先定义这个函数,然后继续表达式求值。如果第一个元素既不是函数名,也不是定义函数,将停如果第一个元素既不是函数名,也不是定义函数,将停止求值并显示出错信息。止求值并显示出错信息。例如(例如(25 a b c),将停止求值并显示),将停止求值并显示“error:bad function:25”,因为,因为25是非法的函数名,所以显示是非法的函数名,所以显示25是坏函数的出错信是坏函数的出错信息。
30、息。又比如又比如(fx a b c),将停止求值并显示,将停止求值并显示“error:no function definition:FX”,指出没有定义,指出没有定义fx这个函数。这个函数。用用quote函数可以禁止对表求值。函数可以禁止对表求值。对于不需求值而直接整体引用的表,例如将一个表示三维对于不需求值而直接整体引用的表,例如将一个表示三维点的表(点的表(3 2 1)赋给变量)赋给变量p,如果表达式为(,如果表达式为(setq p(3 2 1),将中断求值过程并显示将中断求值过程并显示“error:bad function:3”出错信息。出错信息。因为首先对内层表求值,而内层表的第因为首
31、先对内层表求值,而内层表的第1个元素个元素“3”不是函数不是函数名,所以停止求值。此时应该用名,所以停止求值。此时应该用quote函数,将表达式改为(函数,将表达式改为(setq p(quote(3 2 1),这样就不再对表(),这样就不再对表(3 2 1)求值,)求值,而是将将表(而是将将表(3 2 1)整体赋给变量)整体赋给变量p,使之表示一个,使之表示一个3维的点。维的点。quote是是AutoLISP程序中使用最多的函数,因此该函数可用程序中使用最多的函数,因此该函数可用一个单引号一个单引号“”表示。例如表示。例如(quote(10 20)可以表示为可以表示为(10 20)。如果将()
32、。如果将(10 20)这个)这个2维点赋给变量维点赋给变量p2,可写成:,可写成:(setq p2 (10 20)2.4 数据的存储结构数据的存储结构 计算机的内存是由许多编了码的内存单元组成。一个特定内计算机的内存是由许多编了码的内存单元组成。一个特定内存单元的编号称为内存地址。内存单元的内容是数字,也可以存单元的编号称为内存地址。内存单元的内容是数字,也可以是内存单元的编号,即另一内存单元的地址。如果一个内存单是内存单元的编号,即另一内存单元的地址。如果一个内存单元的内容是另一个内存单元的地址,那么,这个内存单元被称元的内容是另一个内存单元的地址,那么,这个内存单元被称为是指向另一个内存单
33、元的指针。如果一个内存单元分为左、为是指向另一个内存单元的指针。如果一个内存单元分为左、右两部分,分别存放两个内存单元的地址,那么,这个内存单右两部分,分别存放两个内存单元的地址,那么,这个内存单元就具有左、右两个指针。元就具有左、右两个指针。这种具有左、右两个指针的内存单元被称为节点。每个节点这种具有左、右两个指针的内存单元被称为节点。每个节点的长度是的长度是12个字节,等分为左、右两部分,作为左、右指针,个字节,等分为左、右两部分,作为左、右指针,每个节点都有它的地址。每个节点都有它的地址。AutoLISP通过这样的一些节点构成链通过这样的一些节点构成链表,以链式方式存储各种数据。表,以链
34、式方式存储各种数据。1.符号符号 创建一个符号,例如(创建一个符号,例如(setq radius 10),至少需要),至少需要3个节点。个节点。一个节点链接到符号原子表的链尾并指向存放符号名的节点,一个节点链接到符号原子表的链尾并指向存放符号名的节点,一个节点存放符号名和存放符号值的指针,最后一个节点存放一个节点存放符号名和存放符号值的指针,最后一个节点存放符号的值,见图符号的值,见图(a)。如果符号的长度超过如果符号的长度超过6字符,例如(字符,例如(setq fillet_radius 5),需),需要申请存放符号名的存储空间,用原来存放符号名的半个节点要申请存放符号名的存储空间,用原来存
35、放符号名的半个节点作为指向存放符号名的指针,见图作为指向存放符号名的指针,见图(b)。显然要多占用一些存储。显然要多占用一些存储空间。空间。2.字符串字符串 字符串在内存中是以连续的空间存储的。字符串在内存中是以连续的空间存储的。3.表表 表通过一组节点来存储。这些节点用右指针指向各自下一个元表通过一组节点来存储。这些节点用右指针指向各自下一个元素的地址,最后一个节点的右指针为空,用左指针指向各自的元素的地址,最后一个节点的右指针为空,用左指针指向各自的元素。素。下图依次是表下图依次是表(A B C D)、(、(A(B C)()(D E)和(和(setq x(+(*a)()(d)的存储结构。)
36、的存储结构。4.点对(点对(dotted pair)点对是一种特殊的表。若表只有两个元素,且每个元素都点对是一种特殊的表。若表只有两个元素,且每个元素都是原子,这样的表可以用点对表示。点对的形式为(原子是原子,这样的表可以用点对表示。点对的形式为(原子.原原子),如(子),如(0 .LINE)、)、(8 .A1)、(40 .15.0)。用一个结。用一个结点存放点对,结点的左指针指向第一个元素,右指针指向第二点存放点对,结点的左指针指向第一个元素,右指针指向第二个元素。图是只有两个元素(元素为原子)的表的存储结构,个元素。图是只有两个元素(元素为原子)的表的存储结构,图(图(b)是点对的存储结构
37、。从图中不难得出结论,两个元素)是点对的存储结构。从图中不难得出结论,两个元素都是原子的表,用点对会节省存储空间。点对的另一个特点是都是原子的表,用点对会节省存储空间。点对的另一个特点是简化了某些函数对表的运算。由于点对具有这些优点,因此是简化了某些函数对表的运算。由于点对具有这些优点,因此是AutoLISP常用的数据结构。常用的数据结构。2.5 函数函数 前面提到,一般计算机语言所说的函数,前面提到,一般计算机语言所说的函数,AutoLISP照常称之为照常称之为函数;一般计算机语言里的子程序、过程、运算符、程序流程控函数;一般计算机语言里的子程序、过程、运算符、程序流程控制的关键字,在制的关
38、键字,在AutoLISP里都被称之为函数。里都被称之为函数。AutoLISP将函数分为内部和外部函数。将函数分为内部和外部函数。AutoLISP提供的或用提供的或用AutoLISP定义的函数为内部函数。用定义的函数为内部函数。用ADS、ADSRX或或ARX定义定义的函数为外部函数。的函数为外部函数。2.5.1 定义定义AutoLISP函数函数 定义函数用定义函数用defun函数。格式如下:函数。格式如下:(defun 函数名函数名(变元变元./局部变量局部变量.)表达式表达式.)函数名:函数名和变量名的命名规则相同,是代表一个函数的函数名:函数名和变量名的命名规则相同,是代表一个函数的符号,不
39、应与现有的符号,不应与现有的AutoLISP函数同函数同名,否则现有名,否则现有函数的功能被函数的功能被新定义函数的功能所取代新定义函数的功能所取代。变元:变元即该函数的参数,变元的数量根据实际需要而定,变元:变元即该函数的参数,变元的数量根据实际需要而定,可以没有变元,但不能省略一对括号可以没有变元,但不能省略一对括号“()()”。局部变量:在定义函数时,除了用到函数的参数之外,还可能局部变量:在定义函数时,除了用到函数的参数之外,还可能用到其他一些变量。在该域列举这些变量的名字,这些变量就用到其他一些变量。在该域列举这些变量的名字,这些变量就成为局部变量。局部变量是指局限于该函数内部所用的
40、变量,成为局部变量。局部变量是指局限于该函数内部所用的变量,它只在该函数调用期间得到定义,函数调用结束,局部变量的它只在该函数调用期间得到定义,函数调用结束,局部变量的值均为值均为nil,同时释放其所占存储空间。如果不作声明,它们将,同时释放其所占存储空间。如果不作声明,它们将成为全程变量,即使函数调用结束,仍然保留各自的值,可被成为全程变量,即使函数调用结束,仍然保留各自的值,可被其他函数所存取,直至退出当前的图形文件。进行局部变量声其他函数所存取,直至退出当前的图形文件。进行局部变量声明不仅可以节省存储空间,而且可以避免函数之间相互干扰。明不仅可以节省存储空间,而且可以避免函数之间相互干扰
41、。局部变量与变元之间用除号隔开,即使没有变元,也可以有局局部变量与变元之间用除号隔开,即使没有变元,也可以有局部变量说明,但前面要有除号。部变量说明,但前面要有除号。表达式:表达式的数量不限,用于描述该函数的运算。表达式:表达式的数量不限,用于描述该函数的运算。函数的返回值:最后一个表达式的返回值即为该函数的返回函数的返回值:最后一个表达式的返回值即为该函数的返回值。值。【例例2-1】定义一个加定义一个加10函数,源代码如下:函数,源代码如下:(defun add10(x)(setq x(+10 x)或者:或者:(defun add10(x)(+10 x)该函数的函数名是该函数的函数名是add
42、10,只有一个变元,只有一个变元x,没有局部变量说,没有局部变量说明,它返回表达式明,它返回表达式(setq x(+10 x)或或(+10 x)的值(二者是相的值(二者是相等的)。等的)。【例例2-2】定义一个已知圆柱体的半径和高度,计算其定义一个已知圆柱体的半径和高度,计算其体积的函数。源代码如下:体积的函数。源代码如下:(defun volume(r h /v)(setq v(*r r pi h)该函数的函数名是该函数的函数名是volume,有两个变元,有两个变元r(半径)和(半径)和h(高度),有一个局部变量(高度),有一个局部变量v,它返回表达式,它返回表达式(setq v(*r r
43、pi h)的值。的值。2.5.2 调用调用AutoLISP函数函数 AutoLISP以表的形式调用函数,其格式如下:以表的形式调用函数,其格式如下:(函数名函数名 变元变元)表的第一个元素是函数名,其余是该函数所要求的变元,变元表的第一个元素是函数名,其余是该函数所要求的变元,变元的数量可能为的数量可能为0,也可能任意多个,这取决于具体函数。例如,也可能任意多个,这取决于具体函数。例如,(sqrt 4),调用的函数名为),调用的函数名为sqrt(求平方根),函数的变元是(求平方根),函数的变元是4、只有一个变元;、只有一个变元;(+1 2 3),调用的函数名为),调用的函数名为“+”(加),函
44、数的变元是(加),函数的变元是1、2、3,共有,共有3个变元。个变元。每个变元还可以是一个表达式。例如:每个变元还可以是一个表达式。例如:(sqrt(+1 2 3)。每调用一个函数,都会得到函数的返回值。例如,每调用一个函数,都会得到函数的返回值。例如,(sqrt 4),返回返回2 (+1 2 3),返回返回6 有些函数返回逻辑常数有些函数返回逻辑常数T或或nil,例如,例如,(1 2),返回返回T;(not 1),返回),返回nil。调用自定义的函数与调用系统提供的函数的格式相同。例如调用自定义的函数与调用系统提供的函数的格式相同。例如,(add10 3)(setq y(add10(+2 3
45、)(volume 12.5 20)1)2.5.3 递归调用递归调用AutoLISP函数函数 AutoLISP可以在一个函数的内部定义另一个函数,可以递归可以在一个函数的内部定义另一个函数,可以递归定义和调用函数。定义和调用函数。【例例2-3】定义阶乘函数定义阶乘函数 阶乘的定义是,阶乘的定义是,0的阶乘等于的阶乘等于1,n的阶乘等于的阶乘等于n(n-1)的阶)的阶乘。程序的源代码如下:乘。程序的源代码如下:(defun factorial(x)(if(=x 0)1 (*x(factorial(-x 1)2.5.4 调用调用AutoCAD命令命令 AutoLISP用用command函数调用函数调
46、用AutoCAD命令,其格式如下:命令,其格式如下:(command“AutoCAD命令命令”命令所需的数据命令所需的数据)【例例2-4】绘制以绘制以(2,4)为圆心,为圆心,5为半径的圆。为半径的圆。(command circle 2,4 5)或者或者(command circle (2 4)5)【例例2-5】已知已知p1、p2、p3为不在同一直线上的三个点,利用这为不在同一直线上的三个点,利用这三个点画圆。三个点画圆。(command circle 3p p1 p2 p3)【例例2-6】画从点画从点p1(0,0)到点到点p2(10,0)的一段直线。的一段直线。(command line 0
47、,0 10,0 )或者或者(command line (0 0)(10 0)或者或者(command line (list 0 0)(list 10 0)或者或者(command line“p1 p2 );假定;假定p1、p2是两个点是两个点注意:因为绘制直线时用空回车或空格响应注意:因为绘制直线时用空回车或空格响应“Specify next point or Undo:”提示才能结束提示才能结束line命令,所以在最后一个点的后面要命令,所以在最后一个点的后面要增加两个双引号,代表一个回车或空格。增加两个双引号,代表一个回车或空格。2.5.5 定义定义AutoCAD命令命令 定义定义Auto
48、CAD命令用命令用defun函数。格式如下:函数。格式如下:(defun C:AutoCAD命令名命令名 (/局部变量局部变量.)表达式表达式.)定义定义AutoCAD命令与定义函数基本相同,不同之处是命令与定义函数基本相同,不同之处是:命令名前加命令名前加“C:”。没有变元,但可以有局部变量说明。没有变元,但可以有局部变量说明。此外要注意所定义的此外要注意所定义的AutoCAD命令不应与现有的命令不应与现有的AutoCAD命令同名。命令同名。【例例2-7】定义输入矩形的对角点绘制矩形的命令。定义输入矩形的对角点绘制矩形的命令。源代码如下:源代码如下:(defun c:rect1(/p1 p2
49、 p3 p4);p1、p2、p3、p4是局部变元是局部变元 (setq p1(getpoint n输入矩形的一个角点输入矩形的一个角点)(setq p3(getcorner p1 n输入矩形的另一个角点:输入矩形的另一个角点:)(setq p2(list(car p3)(cadr p1)(setq p4(list(car p1)(cadr p3)(command pline p1 p2 p3 p4 c)加载含有以上代码的程序后,在加载含有以上代码的程序后,在AutoCAD的的Command:命:命令提示下,象调用普通命令一样键入令提示下,象调用普通命令一样键入rect1,即可调用自定义的,即可调用自定义的绘制矩形的命令(见下图绘制矩形的命令(见下图)。p1p2p3p4