资源描述
,*,Click to edit Master title style,Click to edit Master text styles,Second level,Third level,Fourth level,Fifth level,第,6,章,调试程序,6.1,概述,语法正确的程序并不能保证正常运行,在运行时可能会产生错误的结果或者发生崩溃现象,这就需要调试。,调试程序的步骤是:,控制程序在指定的位置暂停;,查看、分析有关变量的值;,修改程序的源代码;,继续或重新运行程序;,如果程序不能正常运行,继续调试程序,直至程序正常运行。,为了便于调试程序,,Visual LISP,提供了一些调试程序的工具,帮助用户迅速查找并改正程序中的错误。,VisualLISP,提供了监视窗口、检验窗口、符号服务对话框、中断和继续执行程序的模式、命令跟踪、跟踪堆栈、跟踪窗口等调试程序的工具。,通过图,6-1,示,View,下拉菜单和,View,工具栏可以调用监视窗口、检验窗口等调试工具。,检验窗口,跟踪堆栈,出错跟踪,符号服务,监视窗口,自动匹配窗口,断点窗口,编译输出窗口,VisualLISP,控制台,浏览图形数据库,选择工具栏,图,6-1 View,下拉菜单,打开监视窗口,匹配,符号服务,堆栈跟踪功能,打开检测窗口,激活控制台窗口,确定活动窗口,切换到,AutoCAD,图形窗口,通过图,6-2,所示,Debug,下拉菜单和,Debug,工具栏的选项可以设置程序暂停的模式和继续程序运行的方式。,只执行一步表达式求值。,执行到下一个断点,如无断点,则执行一个完整的表达式求值。,执行到下一个断点,如无断点,则执行一个最外层的表达式求值。,继续执行程序,结束当前程序。返回到控制台的上一层中断顶层读算写循环。,结束所有当前活动的断点循环并返回到控制台的顶层读算写循环。,添加监视,回到最近一次监视窗口的环境,设置,/,删除断点,清除所有的断点,回到源程序上的最近一次的断点,跟踪命令,立即暂停,出错断开,自动运行,终止求值,图,6-2 Debug,下拉菜单,调试指示器按钮,显示上一个断点,添加监视,设置或取消断点切换,重置为顶层,退出当前层,继续执行,跳出表达式,下一个表达式,下一层嵌套表达式,Debug,工具栏,6.2,监视窗口,监视窗口用于监视变量、函数在程序运行过程中的结果。选择菜单,D,ebug,W,atch Last Evaluation,。将弹出图,6-3,所示的监视窗口。,图,6-3,监视窗口,1.,监视窗口的工具栏,监视窗口的工具栏有四个图像按钮,从左至右依次是:,添加监视:将新的变量加入到监视窗口。,清除变量:清除监视窗口内的所有的变量。,排序:将监视窗口内的变量名按字母顺序排序。,复制到跟踪,/,日志:将监视窗口的内容复制到跟踪窗口。,如果打开了日志选项,监视窗口中的这些内容也将被复制到跟踪日志文件。,2.,监视窗口的快捷菜单,选择监视列表中的某一项并单击鼠标右键,可显示图,6-4,所示监视窗口的快捷菜单。,调用检验功能,查看所选值。,将所选变量的值复制到系统变量*,obj*,中。,将所选变量值加上一个单引号前缀,,打印到控制台窗口。,对所选变量调用符号服务对话框。,调用自动匹配选项对话框,用所选变量名作自动匹配参数。,从监视窗口中删除所选变量。,图,6-4,监视窗口的快捷菜单,3.,将变量加入到监视窗口,有三种途径可以将新的变量加入到监视窗口。,(,1,),点取工具栏上的添加监视按钮 ,在随后弹出的图,6-5,所示的添加监视窗口内填入变量名,然后单击,OK,按钮。,图,6-5,添加监视窗口,(,2,)亮显要添加的变量名,然后点取工具栏上的添加监视按钮 ,随后弹出的图,6-6,所示的已填写了该变量名的添加监视窗口,然后单击,OK,按钮。,(,3,)将光标移至将要添加的变量名,单击鼠标右键,在随后弹出的快捷菜单上选取,Add Watch,菜单项,将弹出已填写了该变量名的添加监视窗口,然后单击,OK,按钮。,4.,监视变量的值,监视列表的每一行的格式是,变量名,=,变量值,,例如:,A=1,。如果程序尚未运行,变量的值是空的;随着程序的运行,在监视窗口可以看到变量的值也在不断变化。,5.,利用断点和监视窗口调试程序,假定在编辑器窗口已键入了图,6-6,所示的源程序。该程序的功能是根据用户输入的两个对角点绘制矩形。,首先检查该程序是否存在语法错误。选择菜单,T,ools,Text in Editor,或单击按钮,在,Build Output,(输出)窗口显示,;Check done.,。说明该程序没有语法错误。,选择菜单,T,ools,Load Text in Editor,或单击按钮 ,,VisualLISP,自动将控制切换到,AutoCAD,界面。当出现,输入矩形的一个角点:,的提示时,输入,(0,0),点,该点是,p1,点的坐标;当出现,输入矩形的对角点:,的提示时,输入,(100,100),点,该点是,p2,点的坐标。程序运行结束,只得到了矩形的两条边,显然,这不是预期的运行结果。,下面演示如何利用监视窗口调试程序。调试程序的步骤如下:,(,1,)确定要监视的变量。选择菜单,D,ebug,A,dd Watch,或单击工具栏上的添加监视按钮 ,在随后弹出的添加监视窗口内填入变量名,p1,,然后单击,OK,按钮。用同样的操作监视变量,P2,、,P3,、,P4,。,图,6-6,监视,P1,、,P2,、,P3,、,P4,点的值,(,2,)从图,6-7,所示监视窗口可以看到:,P1=0.0 0.0 0.0,、,p2=100.0 0.0,、,p3=100.0 100.0 0.0,、,P4=nil 100.0,。说明,P4,点的,X,坐标是无定义的,而,X,坐标是,(car pl),的返回值,检查,(car pl),,,car,是正确的,亮显,pl,,单击添加监视按钮 ,监视窗口内出现,PL=nil,,,PL,本不是该程序的变量,是,p1,的误写。,(,3,)修改源程序代码,将,pl,改写为,p1,;重新加载、运行该程序;直到该程序可以正常运行,调试结束。,6.3,在不设置断点的情况下分步调试程序,分步调试就是将一个完整的程序分为若干步,逐步调试。每步可以是最内层的一个表达式,也可以是一个复杂的表达式,还可以是多个表达式。可以通过设置断点将程序分为若干段,也可以不用断点而是通过步长将程序分为若干步。,结合下例程序介绍几种调试程序的方法。,【,例,6-1】,定义绘制矩形的命令,矩形的一个角点、宽、高和旋转角为交互输入的参数。,程序的源代码如下:,(defun c:rectr(/w h alf p1 p2 p3 p4),(setq p1(getpoint,输入矩形的一个角点:,),w(getdist p1,输入矩形的宽:,),h(getdist p1,输入矩形的高,:),alf(getangle p1,输入矩形的旋转角,:),),W,alf,h,p1,p2,p3,p4,(setq p2(polar p1 alf w),(setq p3(polar p2(+alf(*0.5 pi)h),(setq p4(polar p3(+alf pi)w),(command pline p1 p2 p3 p4 c),(princ),),1.,从第一个表达式开始,逐步调试程序,(,1,)选择菜单,F,ile,O,pen File,或单击按钮 ,将,例,6-1,所示源代码录入文本编辑窗口。选择菜单,D,ebug,A,dd Watch,或单击按钮 ,监视变量,w,、,h,、,alf,、,p1,、,p2,、,p3,、,p4,。选择菜单,T,ools,Load Text in,E,ditor,或单击按钮 ,加载该程序。,(,2,)通过菜单,D,ebug,Stop O,n,ce,,使之处于打开的状态。,(,3,)单击按钮 ,切换到,AutoCAD,窗口,在,AutoCAD,的,Command,:提示下,键入,rect3,命令。,W,alf,h,p1,p2,p3,p4,控制自动切换到,VisualLISP,文本编辑窗口,监视窗口内的变量值均为,nil,。此时光标停在,(defun,之前,整个程序被加亮显示。选取下拉菜单,D,ebug,的,Step,I,nto,项、,F8,功能键或单击按钮 ,光标停在,(setq p1,之前,与之匹配的右括号之间被加亮显示。单击按钮 ,光标停在,(getpoint,输入矩形的一个角点:,),之前,并亮显该表达式。注意,指示按钮内的,I,在,(),之前。,单击按钮 ,程序切换到,AutoCAD,窗口,出现,输入矩形的一个角点:,的提示,输入,(100,80),,程序切换到,VisualLISP,的文本编辑窗口。光标停在,(getpoint,输入矩形的一个角点:,),之后,仍然亮显该表达式。注意,指示按钮内的,I,在,(),之后。,单击按钮 ,光标停在,(getdist p1,输入矩形的宽:,),之前,并亮显该表达式。注意,指示按钮内的,I,回到,(),之前。监视窗口内的变量,p1=100.0 80.0 0.0,。重复类似的操作,在,AutoCAD,窗口输入矩形的宽度为,200,、高度为,150,,旋转角为,30,。在操作过程中指示按钮随时显示着光标相对于表达式的位置,监视窗口显示着这些变量的当前值(注意,,alf,的单位为弧度)。也说明单击按钮 只执行了一步表达式求值。,当光标停在,(setq p3(polar p2(+alf(*0.5 pi)h),之前时,单击按钮 ,整个程序被加亮显示,光标停在整个程序的结尾,再单击以上任一按钮,程序运行结束。,切换到,AutoCAD,窗口,显示着刚才绘制的矩形。,假定程序的第,5,行误写为,(getangl p1,输入矩形的旋转角,:),,仍旧用上述的方法调试该程序,当执行到,输入矩形的旋转角,:,时,将出现提示,;error:no function definition:GETANGL,(没有,GETANGL,这个函数定义),。点取查找按钮 ,在随后弹出的,FIND,对话框的,Fi,n,dWhat,编辑框输入查找内容为,GETANGL,,单击,F,ind,按钮,找到,getangl,并改正为,getangle,。,重新调试程序,直至程序正常运行。,2.,自动分步调试程序,(,1,)自动分步调试程序的步骤,将例,6-1,源代码的文件装入文本编辑窗口。监视变量,w,、,h,、,alf,、,p1,、,p2,、,p3,、,p4,。加载该程序。选择菜单,D,ebug,Animat,e,。,在,AutoCAD,的,Command,:,提示下,键入,rect3,命令。,Visua lLISP,自动切换到文本编辑窗口。随着光标的位置、指示按钮 内,I,和,(),的变化,自动地执行每一个表达式的求值,监视窗口内的变量值也相应地改变。如果遇到了错误的函数调用,程序停止运行,并报告,;error:no function definition:,信息。找到并改正错误的函数。继续调试程序,直至程序正常运行。,(,2,)设置每步延迟的时间,选择菜单,T,ools,Environmant,O,ptions,G,eneral,O,ptions,弹出图,6-7,所示,General,O,ptions,对话框。单击该对话框的,Diagnostic,(诊断)卡,在,A,nimation delay,编辑框输入每步延迟的时间(以毫秒为单位),单击确定按钮即可。,图,6-7,诊断选项卡,6.4,断点循环,表达式是,AutoLISP,程序的基本单元,,LISP,的工作实际上是不断地对表达式进行读入、求值和输出操作,在,LISP,术语中,被称为读算写循环。,如果不用调试工具而是正常地运行,AutoLISP,程序时,程序将处于顶层的读算写循环。如果在,VisualLISP,控制台窗口内对表达式求值时,也是处于顶层的读算写循环。,如果程序在运行时被中断或挂起,,VisualLISP,将控制转交给控制台,就进入了断点循环(,Break loop,)。断点循环是一个单独的读算写循环,它嵌套在原有的读算写循环内。断点循环也可以被中断,这时将开始一个嵌套于该断点循环内的读算写循环。断点循环相对于顶层循环嵌套的层数称为该中断的层数。,进入断点循环时,,VisualLISP,将在控制台提示,_$,前加一个数字来指出所处循环的层数。例如,当首次进入程序的断点循环时,提示为,_1_$,。如果处于断点循环状态,就不能将控制切换到,AutoCAD,窗口。,从断点循环退出,将恢复上一层循环。如果在该断点循环中修改了某变量的值,程序继续运行时将使用变量修改后的值。,断点循环分为可继续断点循环和不可继续断点循环。,1.,可继续的断点循环,可继续的断点循环是指可以在程序中断处,继续向下执行剩余的表达式。用以下方法进入可继续断点循环:,(,1,)打开,Stop Once,模式,碰到带调试信息的表达式时。,(,2,)遇到带,Debug on Entry,(进入时调试)标志的函数时。,(,3,)遇到程序中设置的断点时。,(,4,)单击暂停按钮进入断点循环时。,(,5,)在前一个断点循环状态下,执行,Step Into,、,Step Over,或,Step Out,时。,如果程序在某函数中被中断,可以访问被该函数声明的局部变量,甚至可以在控制台提示下用,setq,函数修改它们的值。,2.,不可继续的断点循环,当程序出现错误导致崩溃时,如果设置了,Break On Error,选项,将激活一个不可继续的断点循环。此时可以访问出错环境中的所有变量,但不能继续执行程序或执行任何单步调试程序的命令。,如果工具栏上的单步调试的按钮 、或继续运行的按钮 处于可用状态,说明此时进入了可继续的断点循环。,处于不可继续的断点循环时,选取,D,ebug,菜单的,R,eset to Top Level,项或单击按钮 ,退出断点循环并跳转至控制台顶层循环;选取,D,ebug,菜单的,Q,uit Current,项或单击按钮 ,退出断点循环并返回到上一层循环。,6.5,利用断点调试程序,运行的程序遇到断点时,将产生一个中断。当程序中断时,可查看、分析变量的值,修改程序的源代码。利用断点可提高调试程序的效率。,1.,有关断点的操作,(,1,)在程序中设置,/,删除断点,只能在,VisualLISP,的文本编辑器窗口内设置断点。断点应位于表达式的左、右括号上。设置断点的步骤如下:,将光标移到需要程序暂停的位置。例如,需要在某表达式 之前暂停,则应将光标移至与表达式的左括号相邻的位置。,选择菜单,D,ebug,T,oggle Breakpoint,、单击按钮 或按,F9,键。如果该位置没有断点,就加入一个断点,否则,删除该断点。单击鼠标右键在快捷菜单中选择,Toggle Breakpoint,项也可以设置或删除断点。如果光标不与括号相邻,,Visual LISP,暂时将光标移到后面最近的右括号处,并通过对话框询问用户是否在该处设置断点。,选择菜单,D,ebugClear All,B,reakpoints,项,删除已设置的所有断点。,(,2,)改变断点的颜色,VisualLISP,用高亮矩形显示每一个断点,默认情况下,活动的断点是红色的。选择菜单,T,ools,W,indow Attributes,C,onfigure Current,,通过随后弹出的,Window Attributes,对话框内的,WINDOW-TEXT,下拉列表的,:BPT-ACTIVE,项可改变断点的颜色。,(,3,)临时禁用断点,断点可以被临时禁用和恢复使用。禁用断点的步骤如下:,将光标置于断点处并单击鼠标右键。,从显示的快捷菜单上选择,Breakpoints service,项,将弹出图,6-8,所示断点服务对话框。,图,6-8,断点服务对话框,在断点服务对话框中单击,D,isable,按钮可临时禁用该断点;若该断点已被禁用,图,6-9,所示断点服务对话框将出现,E,nable,按钮,单击该按钮,所选断点将改变为可用状态。,默认情况下,被禁用的断点显示为蓝色。用设置断点颜色的方法也可以改变被禁用断点的颜色。,(,4,)浏览和编辑程序中的断点,选择菜单,V,iewBrea,k,points Window,将看到图,6-9,所示的断点对话框。,图,6-9,断点对话框,该断点窗口列出了所有编辑器窗口的断点。其中有程序,6-1.lsp,的,3,个断点、,6-2.lsp,的,2,个断点。每项包含断点的源文件名以及断点在源文件中的位置,位置是以,0,开始的西文字符数量,前面的,+,号表示该断点是活动的,,-,号表示该断点是被禁用的。,单击该对话框的,Delete all,按钮可以删除所有的断点;亮显一项,单击,S,how,按钮可显示该断点所在的源文件及其在源文件中的位置;单击,Delete,按钮可删除该断点;单击,E,dit,按钮可打开图,6-9,所示的断点服务对话框,利用该对话框可以改变断点可用或禁用的状态。,(,5,)断点的生命周期,可以在加载程序之前或之后设置断点。如果在加载程序之后设置断点,该断点只有在重新加载程序之后才有效。,2.,在断点处继续运行程序,运行的程序遇到断点时,将产生一个中断,即断点循环。单击分布调试按钮 、和 可继续运行程序。如果在复杂的表达式之内还有一些断点,单击按钮 和 ,首先在断点处暂停。此外还有以下控制程序继续运行的工具栏按钮、快捷键或,D,ebug,菜单的菜单项。,Continue,或,Ctrl+F8,:继续执行程序直至遇到下一个断点(如果有)或程序结束。,Quit Current,或,Ctrl+Q,:结束当前程序,返回到控制台的上一层断点循环。,Reset to Top Level,或,Ctrl+R,:结束当前程序,结束所有的断点循环。,3.,利用断点调试程序实例,【,例,6-2】,定义绘制图,6-10,所示图形的命令,,p0,、,d,、,b,、,t1,、,alf,是交互输入的参数。,图,6-10,轴的键槽部位截面,程序源代码如下:,(defun c:tuxing(/p0 alf d b t1 r l b1 sit p1 p2 p3 p4 p5),(setq p0 (getpoint nEnter P0:),(setq d (getdist p0 nEnter d:),(setq b (getdist p0 nEnter b:),(setq tl (getdist p0 nEnter t1:);tl,应改为,t1,(setq alf(getangle p0 nEnter alf:),;断点,1,的位置,(setq r(*0.5 d)bl(*0.5 b),(setq l(sqrt(-(*r r)(*b1 b1),(setq sit(tan b1 l);tan,应改为,atan,(setq p1(polar p0(+alf sit)r),(setq p2(polar p0(+pi alf)r),(setq p3(polar p0(-alf sit)r),(setq p4(polar p3(+pi alf)(-(+r l)t1),(setq p5(polar p1(+alf pi)(-(+r l)t1),(command pline p1 a s p2 p3 l p4 p5 c),),选择菜单,F,ile,O,pen File,将例,6-2,所示源代码的文件装入文本编辑窗口。选择菜单,D,ebug,A,dd Watch,或单击按钮 ,监视变量,p0,、,d,、,b,、,t1,、,alf,、,r,、,l,、,b1,、,sit,、,p1,、,p2,、,p3,、,p4,、,p5,。,加载该程序,单击按钮 ,在,AutoCAD,的,Command:,提示下键入,TUXING,命令,程序停止运行,出现提示,;error:bad argument type:numberp:nil,(错误的参数类型,出现了无定义的参数),。,将光标移至程序的第,6,行末尾,选择菜单,D,ebug,T,oggle Breakpoint,、按功能键,F9,或单击按钮 ,在该处设置一个断点。,单击按钮 ,加载当前文本编辑窗口内的源程序。单击按钮 ,在,Command:,提示下键入,TUXING,命令,依次输入,p0,、,d,、,b,、,t1,、,alf,的值之后,回到文本编辑窗口。光标停留在断点,1,的位置,说明已执行了,5,个,get,表达式。,浏览监视窗口,,p0,、,d,、,b,、,alf,已有具体的数值,而,T1=nil,,说明表达式(,setq tl(getdist p0 nEnter t1:),)有错误,仔细检查,发现误将,t1,写为,tl,。改正之后,单击按钮 ,单击按钮 ,在,Command:,提示下键入,TUXING,命令,依次输入,p0,等的数据,当程序停留在断点,1,的位置时,浏览监视窗口,t1,已有定义了。,单击继续按钮 ,程序停止运行,出现提示,;error:no function definition:TAN,(错误,没有定义函数:,TAN,),,正确的函数应该是兰色的,找到黑色的函数名,tan,,改正为,atan,。将光标移至断点,1,处单击按钮,,删除断点,1,。单击按钮 ,在,Command:,提示下键入,TUXING,命令,依次,输入,p0,等的数据,程序正常结束,并得到,图,6-10,所示图形。,图,6-10,在此例中,在断点,1,暂停时,调试按钮从 到 都处于可用状态,因为此时处于可继续的断点循环。,如果运行该程序前,选择菜单,D,ebug,Brea,k,On Error,,执行到,tan,函数时,因出现了无定义的函数而程序崩溃,但在该处产生了一个不可继续的断点循环。此时只有调试按钮 和,是可用的。用户只能选择退到上一层断点循环还是退到顶层断点循环。,如果在,Command,:提示下,键入,TUXING,命令,在要求用户输入数据时,按下,Esc,键,程序停止运行,此时也产生了一个不可继续的断点循环。,6.6,跟踪程序运行,跟踪程序运行的工具有命令跟踪、出错跟踪和跟踪堆栈。,1.,命令跟踪,如果打开命令跟踪模式,,VisualLISP,将在窗口跟踪有关,AutoCAD,命令的执行情况,以便监控程序是否在执行,AutoCAD,命令时出现了问题。,例如,选择菜单,D,ebug,Trace Co,m,mand,,在,Command,:提示下,键入,TUXING,命令(假定程序能够正常运行),将在图,6-11,所示,Trace,窗口显示有关,AutoCAD,命令的执行情况的信息。,图,6-11,显示有关,AutoCAD,命令的执行情况的跟踪窗口,2.,出错跟踪,出错跟踪是用,Error Trace,窗口录跟踪程序运行的结果。在跟踪窗口按鼠标右键,将弹出跟踪窗口的快捷菜单,见图,6-13,。,下面以例,6-3,为例,介绍利用,Error Trace,窗口调试程序的方法。,【,例,6-3】,定义求解一元二次方程的函数,一元二次方程的表达式为:,如果,a=0,,它不是一个二次方程;如果,方程有实数解,否则无解。方程的求根公式为:,程序内容如下:,(defun roots(a b c/t1 t2 x1 x2),;,t1,、,t2,、,x1,、,x2,是局部变量,(if(/=a 0),(progn,(setq t1(-(*b b)(*4 a c),;,(if(=t1 0.0),(progn,(setq t2(sqrt t1),;,(setq x1(/(+-b t2)(*2 a),;此处有错,(setq x2(/(-b t2)(*2 a),;此处有错,(print(list x1 x2),),(print n,根是复数,.),),),(print n,不是一个二次方程,.),),(princ),;静默退出,),选择菜单,F,ile,O,pen File,将例,6-3,所示源代码的文件装入文本编辑窗口。单击工具栏按钮 。在,Visual LISP Console(,控制台,),窗口的,_$,提示下键入,(ROOTS 1,5 6),。显示了出错原因是,错误的参数类型,,见图,6-12,。,图,6-12,显示出运行错误的控制台窗口,选择菜单,V,iew,E,r,ror Trace,或,Ctrl+Shift+R,。将出现图,6-13,所示的出错跟踪窗口。,图,6-13,出错跟踪窗口及其快捷菜单,出错跟踪窗口的第,1,行为,:ERROR BREAK,,表示因出错产生了一个中断。第,2,行为,2+nil 1.0,,记录了中断的原因是,1.0,与一个无定义的参数求和。亮显第,2,行,按鼠标右键,弹出图,6-14,所示的快捷菜单。选取快捷菜单的,C,a,ll point source,,与该错相关的表达式,(+-b t2),被加亮显示。单击添加监视按钮,监视,-b,的值,在监视窗口看到,-b,的值为,nil,。原因是,-b,不是,b,的相反数,而是另一个尚未定义的变量。应改正为,(-t2 b),。,同样的过程可发现下一行的,(-b t2),有相同性质的错误,应改为,(-0 b t2),。,运行改正后的程序,结果为,(3.0 2.0),。,3.,跟踪堆栈,跟踪堆栈保存着调用函数的历史记录。利用堆栈后进先出的特点,记录一系列的嵌套表达式的出口。当程序运行中断,如遇到断点,通过跟踪堆栈可以了解程序的运行状态。如果程序运行出现错误,导致程序崩溃,通过跟踪堆栈可以分析程序崩溃的原因。,首先通过以下实例了解跟踪堆栈。将例,6-4,所示程序代码复制到,VisualLISP,文本编辑器窗口,在程序的第,6,行的右括号处设置断点。,【,例,6-4】,了解跟踪堆栈的结构,程序说明:,stack-tracing,是一个递归调用的,,indexval,是序号的初始值,,maxval,是序号的最大值。当,indexval,小于,maxval,时,打印,indexval,的值。,st5,是调用,stack-tracing,的主函数。,(defun stack-tracing(indexval maxval),(princ n,递归函数实参,=),(princ indexval),(if(indexval maxval),(stack-tracing(1+indexval)maxval),(princ n,递归结束。,);,在这里设置一个断点,),单击按钮 ,在控制台窗口键入,(stack-tracing 1 5),运行该程序。当程序运行到断点暂停时,单击按钮 ,将弹出图,6-14,所示跟踪堆栈窗口。通过该跟踪堆栈窗口了解该程序的运行状态。,图,6-14,跟踪堆栈窗口,(,1,)跟踪堆栈窗口的结构,按钮 用于刷新跟踪堆栈窗口,按钮 用于将跟踪堆栈窗口中的内容复制到跟踪窗口或日志文件。,每个堆栈元素占一行。每一行的前面都有一个用,或,括起的数字,数字表示该元素在跟踪堆栈的序号。,(,2,)堆栈元素的种类,堆栈元素可分为:函数调用框架、跟踪堆栈最顶端和最底端关键字的框架、顶端结构、,Lambda,结构和特殊结构五种类型。,函数调用框架。表示单个函数调用。其格式如下:,序号,函数名 参数,.,图,6-14,所示跟踪堆栈窗口的,2,6,行显示了调用,stack-tracing,函数时的函数调用框架。例如:,2,(,STACK-TRACING 5 5,),2,表示它是堆栈元素列表的第二个元素,,STACK-TRACING,是函数名,其后的两个数字是传给该函数的实际参数值。,跟踪堆栈最顶端和最底端的关键字框架。其格式如下:,:,关键字框架类型 与程序状态相关的其他信息,关键字框架代表,VisualLISP,环境中的一种特定的操作,关键字指明操作的类型。关键字框架只可能出现在堆栈的顶端或底端。,框架类型 发生的操作,:ACAD-REQUEST,由,AutoCAD,命令行调用的函数。,:DCL-ACTION,由,AutoCAD,要求执行对话框控件的动作。关键字,:DCL-ACTION,后的,两个字符串分别是控件名和控件值。如果出现的是一个数,则是对,话框回调函数的值。,:INSPECT-EVAL,执行了检验功能。,:INSPECT-VERBOSE,进入了图形检验器的入口函数。,:TOP-COMMAND VisualLISP,交互环境的动作。例如,加载文件或选取文本时直接运,行一个函数。,:USER-INPUT,框架内的字符串是在控制台输入的。,:WATCH-EVAL,执行了监视功能。,表,6-1,所示的关键字框架只能出现在堆栈的底端。,表,6-1,底端关键字框架,图,6-14,所示跟踪堆栈窗口的第,8,行显示了本例堆栈底端关键字框架的信息。内容如下:,:USER-INPUT(stack-tracing 1 5),表示是用户在控制台输入了,(stack-tracing 1 5),。,表,6-2,所示的关键字框架只能出现在堆栈顶端。,框架类型发生的操作,:ACMD-CALLBACK,调用了已注册的,AutoCAD,命令。,:AFTER-EXP,程序正处于调试中断模式,且刚用,Step Into,或,Step Over,选项步出某表达式。,:ARQ-SUBR-CALLBACK,表示从,AutoCAD,窗口调用标准的,VisualLISP,定义的函数。,:AXVLO-IO-CALLBACK,:DWF,或,:DWG,在,DWG,或,DWF,文件保存或恢复,VLA,对象。,:BEFORE-EXP,进入函数时用调试器中断了程序。当用户用,Step Into,或,Step Over,命令步入某表达式,时会出现该消息。,:BREAK-POINT,用户指定的断点。,:ENTRY-NAMESPACE,一个独立,VLX,命名空间上下文中的调用。,:ERROR-BREAK,一般的运行时错误。单击鼠标右键,选择菜单中的,Show Message,菜单项,可以查看更,详细的出错信息。,:FUNCTION-ENTRY,在进入函数时调试器中断了程序。该消息后的下一个堆栈元素包含了引发中断的函数,的调用框架。,:KBD-BREAK,按下了,Pause,键,程序被挂起。,:PROTECT-ASSIGN,为受保护的符号赋值。单击鼠标右键,选择菜单中的,Show Message,菜单项,查看变量,名、变量当前值和试图赋给该变量的新值。也可以选择,Inspect,项,查看包含该符号的,表,以及跟随在,:PROTECT-ASSIGN,之后的新值。,:REACTOR-CALLBACK,调用了反应器。,:READ-ERROR,在读操作时发生的错误。单击鼠标右键,选择菜单中的,Show Message,菜单项,可获得,更详细的出错信息。,:SYNTAX-ERROR,遇到了,AutoLISP,语法错误。,表,6-2,顶端关键字框架表,6-2,顶端关键字框架,图,6-14,所示跟踪堆栈窗口的第,1,行显示了本例堆栈顶端关键字框架的信息。内容如下:,:BREAK-POINT,表示程序运行的最后一个操作是遇到用户设置的断点。,顶端结构。它说明相应动作是由顶层控制台窗口中输入的表达式引起,或在,VisualLISP,文本编辑器窗口中加载文件或所选文本时触发的函数调用引起的。,Lambda,结构。当程序调用,lambda,函数时,,VisualLISP,会在堆栈中放入该结构。,特殊结构。调用,foreach,和,repeat,函数时,,VisualLISP,在堆栈中加入该结构,该结构中不显示函数的参数,其格式如下:,FOREACH,或,REPEAT,l,FOREACH,框架表示对,foreach,函数的调用。例如,对以下表达式求值:,(foreach n(a b c)(print n),;在表达式开始处设置断点,单步运行该表达式,当执行到,(print n),时,选择菜单,V,iew,T,race stack,项,将弹出图,6-15,所示跟踪堆栈窗口。,图,6-15,调用,foreach,函数时的跟踪堆栈窗口,该窗口的第一行为,:,AFTER-EXP,,其中,1,是该元素的序号,从表,6-2,所示顶端关键字框架表中可看到,AFTER-EXP,表示程序正处于调试中断模式,且刚用,Step Into,或,Step Over,选项步出某表达式。,该窗口的第二行为,2FOREACH,,其中,2,是该元素的序号,,FOREACH,是该函数的形式。,l,REPEAT,框架表示对,repeat,函数的调用。例如,对以下表达式求值:,(setq i 0),(repeat 10,(princ(1+i),),单步运行该表达式,执行到,(1+i),时,选择菜单,V,iew,T,race stack,项,将弹出图,6-16,所示跟踪堆栈窗口。,图,6-16,调用,repeat,函数时的跟踪堆栈窗口,if,、,cond,和,setq,等函数并不出现在跟踪堆栈里,因为在源文件的,VisualLISP,文本编辑器窗口可以看到它们被调用的位置。,根据图,6-14,所示跟踪堆栈窗口,可以看出,stack-tracing,从调用到中断的过程如下:,第,8,行:,:USER-INPUT(stack-tracing 1 5),用户在控制台输入了,(stack-tracing 1 5),,调用了该函数,。,图,6-14,跟踪堆栈窗口,第,7,行:,7(,USUBR034086e0-top-,),该函数的地址。,第,6,行:,6(stack-tracing 1 5),indexval,等于,1,,,maxval,等于,5,调用该函数。,第,5,行:,5(stack-tracing 2 5),indexval,等于,2,,,maxval,等于,5,调用该函数。,第,4,行:,4(stack-tracing 3 5),indexval,等于,3,,,maxval,等于,5,调用该函数。,第,3,行:,3(stack-tracing 4 5),indexval,等于,4,,,maxval,等于,5,调用该函数。,第,2,行:,2(stack-tracing 5 5),indexval,等于,5,,,maxval,等于,5,调用该函数。,第,1,行:,:BREAK-POINT,遇到用户设置的断点暂停,6.7,修改变量和函数的特性,1.,符号服务对话框的功能,符号可以是变量或函数名。通过符号服务对话框可以查看或修改变量的当前值,可以设置变量或函数的一些特性。,2.,符号服务对话框的组成,图,6-17,符号服务对话框,工具栏,符号名,符号值,符号标志,图,6-17,所示为符号服务对话框,它由工具栏、符号名、符号值和符号标志四部分组成。,(,1,)工具栏:工具栏提供了对符号操作的工具。它包括以下四个图像按钮:,将当前符号加入到监视窗口。,检验该符号的值。,如果该符号是用户定义的函数名,则打开包含该函数定义的文本编辑器窗口,并亮显该函数的定义。,如果该符号是一个内部函数名,则显示,VisualLISP,帮助文件中的相关信息。,(,2,),Name,编辑框:显示被操作的符号名。,(,3,),Value,编辑框:显示符号值或它最初的子串。,(,4,),Flags,组:该组有以下四个切换开关,其特性如下:,Trace,切换开关:对设置为,Trace,标志的函数,在,Trace,窗口显示对其跟踪的信息。该标志只对作为函数名的符号有效。,Protect Assign,切换开关:该标志的符号受到保护。程序运行时如果对受到保护的符号赋值,将产生询问信息。受到保护的符号在文本编辑窗口呈蓝色显示。在默认情况下,所有,AutoLISP,内置函数的函数名都受到保护。例如,符号,pi,、,setq,就是受到保护的符号。,Debug on Entry,切换开关:如果设置了该标志,不管是否加载了该函数的调试信息,在每次调用该函数时都会产生中断。该标
展开阅读全文