De vieux secrets au débogage rapide: animation du code source

Le vendredi soir se révèle souvent être une soirée de souvenirs, et pas seulement sur la semaine dernière, mais aussi sur des événements beaucoup plus anciens. Ce vendredi, je me suis souvenu d'un programme intéressant pour MS DOS (ainsi que pour Mac OS, UNIX et VAX / VMS) - l'interprète Pascal et IDE Dr. Pascal. Des informations détaillées sur les fonctionnalités et les critiques peuvent être trouvées sur le site Web du fabricant Visible Software (USA) stocké dans les archives, et je me limiterai aux seules idées dont je me souviens le plus, et ces idées, à mon avis, n'ont pas perdu leur pertinence, même aujourd'hui. Tout d'abord, je me souviens de l'image:

image

Plus tard, nous reviendrons sur cette image, mais pour l'instant, nous recommencerons depuis le début, c'est-à-dire depuis le menu principal:

image

Comme vous pouvez le voir, le menu est assez courant pour un programme DOS. Téléchargez le fichier du puzzle bien connu

"8 reines":
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 }. 


et appuyez sur F9 (Exécuter). L'exécution du programme s'affiche à l'écran:

image

Vous trouverez ci-dessous les résultats générés par le programme (sortie), au-dessus de la gauche se trouve le fragment de code de la procédure (ou fonction) exécutée à cette étape, où l'opérateur exécutable est marqué d'une flèche, les valeurs des variables actuellement pertinentes à droite, et les mêmes pour la procédure d'appel ci-dessus. Dans le même temps, la transition d'un opérateur à l'autre se produit automatiquement avec un délai défini par l'utilisateur - un tel «film» s'arrête lorsque le programme chargé dans l'IDE (dans notre cas, «8 Queens») est arrêté ou par la commande Freeze, qui peut être émise en appuyant sur la touche de fonction correspondante. Si le programme n'est pas terminé, vous pouvez avancer pas à pas, comme dans les autres débogueurs, en appuyant sur la flèche vers le bas, ou revenir au «film» en appuyant sur F8 (Continuer). La deuxième ligne en haut de l'écran affiche une chaîne d'appels de procédure. Il est particulièrement intéressant de noter que le médecin mentionné ci-dessus sélectionne lui-même les «variables actuellement pertinentes», l'utilisateur n'a qu'à télécharger le programme et à cliquer sur Exécuter. À en juger par les critiques, une telle gestion extrêmement simple s'est avérée très pratique pour les cours d'introduction des étudiants sur les bases de la programmation, pour lesquels le Dr Pascal, en fait, est destiné. Cependant, le manuel d'utilisation note que pour un programmeur professionnel avancé, une occasion rapide de voir comment un petit programme fonctionne avec un mouvement peut être utile. Cela soulève une question intéressante: quelle est sa taille?

J'ai pris l'interprète Wirth PascalS écrit en Pascal. Comparé aux reines, ce programme, avec un volume d'environ 2000 lignes de code source, est beaucoup plus compliqué. Pour le médecin, dans sa forme originale, c'était trop pour lui, alors je l'ai coupé en deux.

La première partie prépare les fichiers de données:
 {%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. 


Ici, il est nécessaire de préciser que le Dr. Pascal est placé entre accolades de commentaires et commence par le caractère «%». La directive {% O +} inclut un nom de fichier simplifié, dans lequel, par exemple, un fichier externe défini comme

 pasksy : file of ksytype; 

on l'appellera pasksy. Comme tout fichier externe, il doit être spécifié dans l'en-tête du programme:

 program Pas1 (input,output,paskey, 

Dans le reste de PascalS, nous spécifions également des fichiers de données:

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

La directive% D + permet d'arrêter par programmation une animation en appelant une procédure Freeze prédéfinie.

Le corps du programme PascalS ressemblera à ceci:

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

Où sont les routines init et finish:
 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}; 


La directive% s désactive l'animation et l'affichage des valeurs des variables dans la procédure dans laquelle elle est spécifiée.

Après avoir apporté ces modifications, j'ai téléchargé et exécuté la première partie (Pas1), puis la seconde. PascalS a lu les reines et a commencé à les diffuser (voir l'image au début). Le suivi de l'animation continue de code aussi volumineux que PascalS était difficile, j'ai donc appelé le gel aux points clés et les appels numérotés dans les commentaires. Ayant compris la situation, il a poursuivi l'animation avec l'équipe Continue. Je pense que dans les IDE modernes des langues modernes, de tels animateurs seraient utiles.

J'ai fait les «jeux» décrits ici depuis longtemps sur le CPU 286 sous MS DOS 3.2 , maintenant je viens de lancer les anciens fichiers pour faire des photos. En conclusion, j’ai rappelé un fait intéressant sur la répartition du Dr Pascal. La livraison de base consistait en un guide de l'utilisateur - un livre d'environ 200 pages sur du bon papier épais et une disquette. Il a coûté 99,95 $ US et a été positionné comme un logiciel à faible coût. Les licences pour des dizaines d'emplois dans les universités coûtent beaucoup moins en une seule copie. Mais outre les États et, par exemple, l'Australie, le Dr Pascal était également populaire en Inde. Pour autant que je sache, une entreprise locale s'est vu vendre une licence de distribution en Inde, et cette entreprise elle-même a imprimé des livres (également en anglais 1: 1 avec l'original) et écrit des disquettes. Les livres étaient sur du papier journal avec un texte aveugle, mais le prix était en roupies d'environ 4 $ US. La même entreprise a répliqué d'autres produits populaires à l'époque, tels que LOTUS 1-2-3 , dBase-4 , ChiWriter , etc. pour environ le même prix.

Source: https://habr.com/ru/post/fr432414/


All Articles