快速调试的老秘诀:动画源代码

星期五晚上常常变成记忆的夜晚​​,不仅是过去一周,而且还有许多早期活动。 这个星期五,我记得一个有趣的MS DOS程序(以及Mac OS,UNIX和VAX / VMS)-Pascal解释器和IDEDr。 帕斯卡。 有关功能和评论的详细信息,可在存档中存储的制造商Visible Software (USA)的网站上找到,我将仅局限于我最记得的想法,并且我认为这些想法直到今天还没有失去意义。 首先,我回顾一下图片:

图片

稍后我们将返回到这张图片,但是现在我们将从头开始,即 从主菜单:

图片

如您所见,该菜单在DOS程序中非常常见。 下载著名拼图的文件

“ 8个皇后区”:
program EightQueens(output); { Place 8 hostile queens on a chessboard, such that none can be captured. } { From Wirth: Algorithms + Data Structures = Programs, page 146. } var i: integer; RowFree: array [1..8] of boolean; UpDiag: array [2..16] of boolean; { diagonal to upper right } DownDiag: array [-7..7] of boolean; { diagonal to lower right } QueenIn: array [1..8] of integer; procedure print; { Write out one solution } var k: integer; begin { print } for k := 1 to 8 do write(QueenIn[k]: 4); writeln; end { print }; procedure try(col: integer); { Try to place a queen in this column } var row: integer; begin { try } for row := 1 to 8 do if RowFree[row] and UpDiag[col+row] and DownDiag[col-row] then begin QueenIn[col] := row; RowFree[row] := false; UpDiag[col+row] := false; DownDiag[col-row] := false; if col < 8 then try(col+1) else print; RowFree[row] := true; UpDiag[col+row] := true; DownDiag[col-row] := true; end; end { try }; begin { EightQueens } for i := 1 to 8 do RowFree[i] := true; for i := 2 to 16 do UpDiag[i] := true; for i := -7 to 7 do DownDiag[i] := true; try(1) end { EightQueens }. 


然后按F9(运行)。 屏幕上显示程序执行:

图片

下面是程序(输出)输出的结果,左上方是在此步骤执行的过程(或函数)的代码片段,其中可执行操作符用箭头标记,右边是当前相关变量的值,上面的调用过程也是如此。 同时,从操作员到操作员的过渡会自动发生,并且会发生用户定义的延迟-当“电影”在加载到IDE中的程序(在本例中为“ 8 Queens”)停止或通过“冻结”命令停止时,可以通过按相应的功能键发出来停止。 如果程序尚未结束,则可以像其他调试器中一样,通过按向下箭头逐步移动,或按F8返回到“电影”(继续)。 屏幕顶部的第二行显示了一系列过程调用。 尤其值得一提的是,上述Doctor自己选择了“当前相关变量”,用户只需要下载程序并单击Run。 从评论的角度来看,这种极其简单的管理对于在编程基础方面的入门级学生课程非常方便,而Dr. 实际上,Pascal是有目的的。 但是,用户手册指出,对于高级专业程序员而言,快速查看小型程序如何运行一个动作可能是有用的。 这就提出了一个有趣的问题:多小?

我带了用Pascal编写的Wirth PascalS口译员。 与皇后区相比,它是一个包含约2000行源代码的程序,复杂得多。 对于医生来说,它的原始形式实在太多了,因此我将其分为两部分。

第一部分准备数据文件:
 {%F- no reformatting } {%O+} program Pas1 (input,output,paskey,pasksy,spsfile,enterf,symsetf{,textf}); const nkw = 27; (*no. of key words*) alng = 10; (*no. of significant chars in identifiers*) type symbol = (intcon,realcon,charcon,string, notsy,plus,minus,times,idiv,rdiv,imod,andsy,orsy, eql,neq,gtr,geq,lss,leq, lparent,rparent,lbrack,rbrack,comma,semicolon,period, colon,becomes,constsy,typesy,varsy,functionsy, proceduresy,arraysy,recordsy,programsy,ident, beginsy,ifsy,casesy,repeatsy,whilesy,forsy, endsy,elsesy,untilsy,ofsy,dosy,tosy,downtosy,thensy); alfa = packed array [1..alng] of char; object = (konstant,variable,type1,prozedure,funktion); types = (notyp,ints,reals,bools,chars,arrays,records); keytype = array [1..nkw] of alfa; ksytype = array [1..nkw] of symbol; spstype = array [char] of symbol; symset = set of symbol; entertype = record fx0: alfa; fx1: object; fx2: types; fx3: integer; end; var key: keytype; ksy: ksytype; sps: spstype; (*special symbols*) syset : symset; pasksy : file of ksytype; paskey : file of keytype; spsfile : file of spstype; enterf : file of entertype; symsetf : file of symset; { textf : text;} procedure enter(x0: alfa; x1: object; x2: types; x3: integer); var EnterRec : EnterType; begin with EnterRec do begin fx0 := x0; fx1 := x1; fx2 := x2; fx3 := x3 end; write ( enterf, EnterRec ); end (*enter*) ; begin {main program} key[ 1] := 'and '; key[ 2] := 'array '; key[ 3] := 'begin '; key[ 4] := 'case '; key[ 5] := 'const '; key[ 6] := 'div '; key[ 7] := 'do '; key[ 8] := 'downto '; key[ 9] := 'else '; key[10] := 'end '; key[11] := 'for '; key[12] := 'function '; key[13] := 'if '; key[14] := 'mod '; key[15] := 'not '; key[16] := 'of '; key[17] := 'or '; key[18] := 'procedure '; key[19] := 'program '; key[20] := 'record '; key[21] := 'repeat '; key[22] := 'then '; key[23] := 'to '; key[24] := 'type '; key[25] := 'until '; key[26] := 'var '; key[27] := 'while '; ksy[ 1] := andsy; ksy[ 2] := arraysy; ksy[ 3] := beginsy; ksy[ 4] := casesy; ksy[ 5] := constsy; ksy[ 6] := idiv; ksy[ 7] := dosy; ksy[ 8] := downtosy; ksy[ 9] := elsesy; ksy[10] := endsy; ksy[11] := forsy; ksy[12] := functionsy; ksy[13] := ifsy; ksy[14] := imod; ksy[15] := notsy; ksy[16] := ofsy; ksy[17] := orsy; ksy[18] := proceduresy; ksy[19] := programsy; ksy[20] := recordsy; ksy[21] := repeatsy; ksy[22] := thensy; ksy[23] := tosy; ksy[24] := typesy; ksy[25] := untilsy; ksy[26] := varsy; ksy[27] := whilesy; rewrite (paskey); write (paskey, key); ksy[ 1] := andsy; ksy[ 2] := arraysy; ksy[ 3] := beginsy; ksy[ 4] := casesy; ksy[ 5] := constsy; ksy[ 6] := idiv; ksy[ 7] := dosy; ksy[ 8] := downtosy; ksy[ 9] := elsesy; ksy[10] := endsy; ksy[11] := forsy; ksy[12] := functionsy; ksy[13] := ifsy; ksy[14] := imod; ksy[15] := notsy; ksy[16] := ofsy; ksy[17] := orsy; ksy[18] := proceduresy; ksy[19] := programsy; ksy[20] := recordsy; ksy[21] := repeatsy; ksy[22] := thensy; ksy[23] := tosy; ksy[24] := typesy; ksy[25] := untilsy; ksy[26] := varsy; ksy[27] := whilesy; rewrite (pasksy); write (pasksy, ksy); sps['+'] := plus; sps['-'] := minus; sps['*'] := times; sps['/'] := rdiv; sps['('] := lparent; sps[')'] := rparent; sps['='] := eql; sps[','] := comma; sps['['] := lbrack; sps[']'] := rbrack; sps['#'] := neq; sps['&'] := andsy; sps[';'] := semicolon; rewrite (spsfile); write (spsfile, sps); rewrite (enterf); enter(' ', variable, notyp, 0); (*sentinel*) enter('false ', konstant, bools, 0); enter('true ', konstant, bools, 1); enter('real ', type1, reals, 1); enter('char ', type1, chars, 1); enter('boolean ', type1, bools, 1); enter('integer ', type1, ints , 1); enter('abs ', funktion, reals,0); enter('sqr ', funktion, reals,2); enter('odd ', funktion, bools,4); enter('chr ', funktion, chars,5); enter('ord ', funktion, ints, 6); enter('succ ', funktion, chars,7); enter('pred ', funktion, chars,8); enter('round ', funktion, ints, 9); enter('trunc ', funktion, ints, 10); enter('sin ', funktion, reals, 11); enter('cos ', funktion, reals, 12); enter('exp ', funktion, reals, 13); enter('ln ', funktion, reals, 14); enter('sqrt ', funktion, reals, 15); enter('arctan ', funktion, reals, 16); enter('eof ', funktion, bools, 17); enter('eoln ', funktion, bools, 18); enter('read ', prozedure, notyp, 1); enter('readln ', prozedure, notyp, 2); enter('write ', prozedure, notyp, 3); enter('writeln ', prozedure, notyp, 4); enter(' ', prozedure, notyp, 0); rewrite (symsetf); syset := [plus,minus,intcon,realcon,charcon,ident]; write ( symsetf, syset ); syset := [ident,arraysy,recordsy]; write ( symsetf, syset ); syset := [constsy,typesy,varsy,proceduresy,functionsy,beginsy]; write ( symsetf, syset ); syset := [intcon,realcon,charcon,ident,lparent,notsy]; write ( symsetf, syset ); syset := [beginsy,ifsy,whilesy,repeatsy,forsy,casesy]; write ( symsetf, syset ); end. 


在这里有必要澄清一下 Pascal括在注释括号中,并以“%”字符开头。 伪指令{%O +}包含一个简化的文件名,例如,其中的外部文件定义为

 pasksy : file of ksytype; 

它会被称为pasksy。 像任何外部文件一样,必须在程序标头中指定该文件:

 program Pas1 (input,output,paskey, 

在PascalS的其余部分中,我们还指定数据文件:

 {%D+} {%F- no reformatting } {%O+} program Pascals(input,output,paskey,pasksy,spsfile,enterf,symsetf);{1.6.75} 

%D +指令可以通过调用预定义的Freeze过程以编程方式停止动画。

PascalS程序的主体将如下所示:

 begin {main program} assign (input,'QUEENS.PAS'); reset (input); init; block(blockbegsys+statbegsys, false, 1); finish; 99: end. 

初始化和完成例程在哪里:
 procedure init; {%s-} var i : integer; EnterRec : EnterType; begin writeln; reset (paskey); read (paskey, key); reset (pasksy); read (pasksy, ksy); reset (spsfile); read (spsfile, sps); reset (symsetf); read (symsetf,constbegsys,typebegsys,blockbegsys,facbegsys,statbegsys); stantyps := [notyp,ints,reals,bools,chars]; lc := 0; ll := 0; cc := 0; ch := ' '; errpos := 0; errs := []; insymbol; t := -1; a := 0; b := 1; sx := 0; c2 := 0; display[0] := 1; iflag := false; oflag := false; if sy <> programsy then freeze{3} else begin insymbol; if sy <> ident then freeze{2} else begin progname := id; insymbol; if sy <> lparent then freeze{9} else repeat insymbol; if sy <> ident then freeze{2} else begin if id = 'input ' then iflag := true else if id = 'output ' then oflag := true else freeze{0}; insymbol; end until sy <> comma; if sy = rparent then insymbol else freeze{4}; if not oflag then freeze{20}; end end ; reset (enterf); while not eof (enterf) do begin read (enterf,EnterRec ); with EnterRec do enter (fx0,fx1,fx2,fx3); end; with btab[1] do begin last := t; lastpar := 1; psize := 0; vsize := 0 end ; end {init}; procedure finish; {%s-} begin if sy <> period then freeze{22}; {emit(31)}; {halt} if btab[2].vsize > stacksize then freeze{49}; end {finish}; 


%s伪指令在指定的过程中禁用动画和变量值的显示。

进行这些更改之后,我下载并执行了第一部分(Pas1),然后执行了第二部分。 PascalS读完皇后乐队并开始广播(见开头图片)。 跟踪像PascalS一样大的代码的连续动画非常困难,因此我在关键点调用了冻结,并在注释中编号了调用。 了解了情况后,他在Continue团队中继续制作动画。 我认为在现代语言的现代IDE中,此类动画师会很有用。

我在MS DOS 3.2下的286 CPU上长时间制作了此处描述的“游戏”,现在我只是启动了旧文件来制作图片。 最后,我回想起有关Dr. 帕斯卡。 基本交付内容包括用户指南-一本约200页的优质重磅纸和一张软盘。 它的价格为99.95美元,被定位为低成本软件。 一份大学的几十个工作的许可证成本要低得多。 但是除了美国以外,例如澳大利亚。 Pascal在印度也很受欢迎。 据我所知,这家当地公司在印度被出售了一份发行许可证,而该公司本身也印刷了书籍(也与原文印成1:1的文字)并写了软盘。 这些书在新闻纸上带有盲文,但价格约为卢比(4美元)。 同一家公司当时复制了其他受欢迎的产品,例如LOTUS 1-2-3dBase-4ChiWriter等。 大约相同的价格。

Source: https://habr.com/ru/post/zh-CN432414/


All Articles