Rahasia Lama untuk Debugging Cepat: Animasi Kode Sumber

Jumat malam seringkali menjadi malam kenangan, dan tidak hanya tentang minggu lalu, tetapi juga tentang banyak peristiwa sebelumnya. Jumat ini saya ingat satu program yang menarik untuk MS DOS (juga untuk Mac OS, UNIX, dan VAX / VMS) - penerjemah Pascal dan IDE Dr. Pascal. Informasi terperinci tentang fitur dan ulasan dapat ditemukan di situs web produsen Visible Software (USA) yang disimpan dalam arsip, dan saya akan membatasi diri hanya pada ide yang paling saya ingat, dan ide-ide ini, menurut pendapat saya, belum kehilangan relevansinya bahkan hingga hari ini. Pertama-tama, saya ingat gambar itu:

gambar

Nanti kita akan kembali ke gambar ini, tetapi untuk sekarang kita akan mulai dari awal, mis. dari menu utama:

gambar

Seperti yang Anda lihat, menu ini cukup umum untuk program DOS. Unduh file teka-teki terkenal

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


dan tekan F9 (Jalankan). Eksekusi program ditampilkan di layar:

gambar

Di bawah ini adalah hasil yang dihasilkan oleh program (output), di atas sebelah kiri adalah fragmen kode dari prosedur (atau fungsi) yang dieksekusi pada langkah ini, di mana operator yang dapat dieksekusi ditandai dengan panah, nilai dari variabel yang saat ini relevan di sebelah kanan, dan sama untuk prosedur panggilan di atas. Pada saat yang sama, transisi dari operator ke operator terjadi secara otomatis dengan penundaan yang ditentukan pengguna - "film" berhenti ketika program dimuat ke dalam IDE (dalam kasus kami, "8 Queens") dihentikan atau dengan perintah Freeze, yang dapat dikeluarkan dengan menekan tombol fungsi yang sesuai. Jika program belum berakhir, maka Anda dapat bergerak selangkah demi selangkah, seperti pada debugger lainnya, dengan menekan panah ke bawah, atau kembali ke "film" dengan menekan F8 (Lanjutkan). Baris kedua di bagian atas layar menampilkan serangkaian panggilan prosedur. Perlu dicatat bahwa Dokter yang disebutkan di atas memilih "variabel yang relevan saat ini" sendiri, pengguna hanya perlu mengunduh program dan klik Jalankan. Dilihat oleh ulasan, manajemen yang sangat sederhana ternyata sangat nyaman untuk perkenalan siswa tentang dasar-dasar pemrograman, yang mana Dr. Pascal, sebenarnya, dimaksudkan. Namun, panduan pengguna mencatat bahwa untuk programmer profesional tingkat lanjut, kesempatan cepat untuk melihat bagaimana program kecil bekerja dengan satu gerakan dapat bermanfaat. Ini menimbulkan pertanyaan yang menarik: seberapa kecil?

Saya mengambil interpreter Wirth PascalS yang ditulis dalam Pascal. Dibandingkan dengan ratu, program ini, dengan volume sekitar 2.000 baris kode sumber, jauh lebih rumit. Bagi dokter, dalam bentuk aslinya, itu terlalu banyak untuk itu, jadi saya memotongnya menjadi dua bagian.

Bagian pertama menyiapkan file data:
 {%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. 


Di sini perlu diperjelas bahwa Dr. Pascal dilampirkan dalam kurung komentar dan mulai dengan karakter “%”. Arahan {% O +} termasuk nama file yang disederhanakan, di mana, misalnya, file eksternal didefinisikan sebagai

 pasksy : file of ksytype; 

itu akan disebut pasksy. Seperti file eksternal apa pun, itu harus ditentukan dalam header program:

 program Pas1 (input,output,paskey, 

Di sisa PascalS, kami juga menentukan file data:

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

Arahan% D + memungkinkan untuk menghentikan animasi secara terprogram dengan memanggil prosedur Freeze yang telah ditentukan.

Badan program PascalS akan terlihat seperti ini:

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

Di mana init dan menyelesaikan rutinitas:
 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}; 


Arahan% s menonaktifkan animasi dan tampilan nilai variabel di dalam prosedur yang ditentukan.

Setelah melakukan perubahan ini, saya mengunduh dan mengeksekusi bagian pertama (Pas1), dan kemudian yang kedua. PascalS membaca ratu dan mulai menyiarkannya (lihat gambar di awal). Melacak animasi terus menerus kode sebesar PascalS itu sulit, jadi saya menelepon membeku pada titik-titik kunci dan panggilan bernomor dalam komentar. Setelah memahami situasinya, ia melanjutkan animasi dengan tim Lanjutkan. Saya pikir dalam IDE modern bahasa modern animator seperti itu akan berguna.

Saya membuat "permainan" yang dijelaskan di sini untuk waktu yang lama pada CPU 286 di bawah MS DOS 3.2 , sekarang saya baru saja meluncurkan file lama untuk membuat gambar. Sebagai kesimpulan, saya mengingat sebuah fakta menarik tentang distribusi Dr. Pascal. Pengiriman dasar terdiri dari Panduan Pengguna - sebuah buku yang berisi sekitar 200 halaman tentang kertas tebal dan floppy disk yang bagus. Harganya $ 99,95US dan diposisikan sebagai perangkat lunak berbiaya rendah. Lisensi untuk banyak pekerjaan di universitas jauh lebih murah dalam hal 1 salinan. Tetapi selain Amerika dan, misalnya, Australia, Dr. Pascal juga populer di India. Sejauh yang saya tahu, sebuah perusahaan lokal dijual lisensi distribusi di India, dan perusahaan ini sendiri mencetak buku (juga dalam bahasa Inggris 1: 1 dengan aslinya) dan menulis floppy disk. Buku-buku itu di atas kertas koran dengan teks buta, tetapi harganya dalam hal rupee sekitar $ 4US. Perusahaan yang sama mereplikasi produk populer lainnya pada waktu itu, seperti LOTUS 1-2-3 , dBase-4 , ChiWriter , dll. sekitar harga yang sama.

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


All Articles