Kemunduran Jumat: Beri nomor baru pada daftar BASIC spektrum ZX saya

15

Bahasa pemrograman pertama yang saya kenal adalah Sinclair BASIC . Seperti banyak dialek BASIC, semua baris kode sumber harus diberi nomor .

Akibatnya, penggunaan GO TOperintah itu idiomatis dan melompat eksekusi ke nomor baris yang diberikan (tidak ada label).

Juga ada GO SUBperintah terkait yang dapat digunakan sebagai panggilan fungsi yang belum sempurna. Sekali lagi, eksekusi melompat ke nomor baris yang diberikan, tetapi ketika aRETURN perintah tercapai, eksekusi melompat kembali ke instruksi berikutnya setelah GO SUB.

Demikian pula dengan RUN perintah akan memulai kembali eksekusi program pada baris yang diberikan.

Siapa pun yang telah menghabiskan waktu dalam juru bahasa BASIC bernomor garis akan belajar menggunakan skema penomoran dengan celah di dalamnya. Ini agar lebih mudah untuk menyisipkan baris kode baru. Namun demikian, Anda mungkin masih perlu memasukkan garis baru di antara garis yang diberi nomor secara berurutan.


Diberikan daftar BASIC bernomor garis sebagai input, output program yang sama tetapi dinomori ulang sehingga nomor baris mulai dari 10 dan bertambah dengan langkah 10. Daftar input mungkin memiliki GO TOatau GO SUBperintah, sehingga angka yang terkait dengan ini juga harus disesuaikan.

  • GO TOdan GO SUBperintah ada di baris mereka sendiri atau di ujung IF THENbaris. Aman untuk dikatakan ^(\d+) .*GO (TO|SUB) (\d+)$sudah cukup untuk mencocokkan garis tersebut. Perintah dalam tanda kutip ini harus diabaikan.

  • RUNperintah akan selalu berada di jalur mereka sendiri. Dalam hal ini nomor baris adalah opsional. Jika tidak ada, maka juru bahasa hanya memulai di bagian atas program.

  • Jika a GO TO, GO SUBatau RUNperintah mereferensikan baris yang tidak ada, maka ia akan melompat ke baris yang didefinisikan berikutnya. Entri Anda harus berurusan dengan ini dan memastikan referensi garis tersebut diperbaiki sehingga mengarah ke baris yang benar. Perilaku mungkin tidak terdefinisi jika nomor baris setelah akhir program diberikan dalam salah satu dari perintah ini.

  • Nomor baris akan selalu berupa bilangan bulat positif 1 hingga 9999 (sesuai manual). Ini berarti bahwa program input tidak akan pernah memiliki lebih dari 999 baris.

  • Baris input akan selalu diberi nomor dalam urutan menaik secara numerik.

  • Untuk keperluan tantangan ini, daftar masukan hanya akan berisi ASCII yang dapat dicetak. Anda tidak perlu khawatir tentang set karakter ZX. Karena itu, jika entri Anda sebenarnya ditulis dalam ZX BASIC atau kode perakitan / mesin z80 yang sesuai (dan ada emulator di luar sana ), maka Anda dapat memilih input Anda untuk dikodekan dalam set karakter ZX sebagai gantinya.

  • Anda tidak boleh menggunakan perpustakaan atau utilitas nomor baru yang khusus dirancang untuk tujuan ini.

Input Contoh:

1 REM "A rearranged guessing game"
2 INPUT A: CLS
3 INPUT "Guess the number ", B
10 IF A=B THEN PRINT "Correct": STOP
100 IF A<B THEN GO SUB 125
120 IF A>B THEN GO SUB 122
121 GO TO 3
125 PRINT "Try again"
126 RETURN
127 REM "An example of GO TO 7 and GO SUB 13 in quotes"

Contoh Output:

10 REM "A rearranged guessing game"
20 INPUT A: CLS
30 INPUT "Guess the number ", B
40 IF A=B THEN PRINT "Correct": STOP
50 IF A<B THEN GO SUB 80
60 IF A>B THEN GO SUB 80
70 GO TO 30
80 PRINT "Try again"
90 RETURN
100 REM "An example of GO TO 7 and GO SUB 13 in quotes"

Saya ingin menautkan ke manual ZX BASIC. Yang terbaik yang bisa saya temukan tampaknya adalah http://www.worldofspectrum.org/ZXBasicManual/index.html tetapi ini tampaknya merupakan tautan mati. Mesin wayback memiliki salinan .

Trauma Digital
sumber
7
Juga conrgats untuk menanyakan pertanyaan 5000!
FryAmTheEggman
1
Waktu nostalgia - PC pertama saya adalah Spectrum 48K dan salah satu program perakitan saya yang pertama adalah renumberer
edc65
2
@ edc65 Apakah Anda masih memiliki kode perakitan nomor baru? Jika demikian, Anda dapat mengirimkannya sebagai jawaban!
Digital Trauma
1
Kasing uji harus mencakup setidaknya satu goto / gosub dalam string literal.
Peter Taylor
1
Saya menemukan menyebutkan: yang ZX81 memungkinkan GOTOs dihitung dan GOSUBs seperti dalamGOTO 100 + A*10 , dan Lampiran C dari ZX Spectrum Pedoman daftar GO TOsebagai menerima ekspresi numerik (tidak ada pembatasan untuk konstanta). Berikut ini adalah diskusi tentang manfaat yang dihitung GOTOpada ZX80 dan ZX81. BTW, saya tidak tahu mengapa ruang ditambahkan dalam versi Spectrum.
Toby Speight

Jawaban:

5

JavaScript (ES6) 177

Edit Menambahkan pemindaian (mahal) untuk nomor baris yang valid berikutnya

l=>l.split`
`.map((x,i)=>([,n,t]=x.match(/(\d+)(.*)/),l[n]=10*-~i,t),l=[]).map((x,i)=>10*-~i+x.replace(/(UN |GO TO |UB )(\d+)$/,(a,b,c)=>(l.some((v,i)=>i<c?0:a=b+v),a))).join`
`

UJI

f=l=>
  l.split`\n`
  .map((x,i)=>([,n,t]=x.match(/(\d+)(.*)/),l[n]=10*-~i,t),l=[])
  .map((x,i)=>10*-~i+x.replace(/(UN |GO TO |UB )(\d+)$/,(a,b,c)=>(l.some((v,i)=>i<c?0:a=b+v),a)))
  .join`\n`
        
//TEST
console.log=x=>O.textContent+=x+'\n'
  
test=`1 REM "A rearranged guessing game"
2 INPUT A: CLS
3 INPUT "Guess the number ", B
10 IF A=B THEN PRINT "Correct": STOP
100 IF A<B THEN GO SUB 125
120 IF A>B THEN GO SUB 122
121 GO TO 3
125 PRINT "Try again"
126 RETURN`
console.log(test+'\n\n'+f(test))
<pre id=O></pre>

edc65
sumber
1
Kelihatan bagus. Stand +1 saya :)
Digital Trauma
2

Perl 6, 147 145 144 142 byte

{my%a;.trans(/^^(\d+)/=>{%a{$0}=$+=10}).trans(/:s<!after \"\N*>(UN |GO TO |UB )(\d+)<!before \N*\">/=>{$0~%a{%a.keys».Num.grep(*>=$1).min}})}

Ini mungkin bisa diturunkan sedikit lebih.

Diperluas

my &f = -> $s { 
    my %line-map; # This will map the old line numbers to the new ones

    $s.trans(/^^(\d+)/                    # This .trans creates the line number map
             => { %line-map{$0} = $+=10 } # as well as replaces the actual line numbers
            )\
      # This .trans replaces all the line numbers for each GO TO, GO SUB, RUN
      .trans(/:s<!after \"\N*>(UN |GO TO |UB )(\d+)<!before \N*\">/ 
             => {$0 ~ %line-map{%line-map.keys».Num.grep(*>=$1).min} } 
            )
}
Tombol cepat
sumber
tidak ada alasan untuk menggunakan metode ini .min. gunakan {min %line-map.keys».Num.grep:*>=$1sebagai gantinya
Ven
1

Visual Basic for Applications, 288 byte

Saya tidak bisa menolak memberikan solusi dalam dialek BASIC. Mungkin berfungsi dengan Visual Basic 6 / .NET atau varian modern lainnya dengan perubahan kecil.

Sub n(t,a)
f=Chr(10)
u=Chr(0)
Open t For Input As 1
a=f &Input(LOF(1),1)&f
Close
j=10
For i=1 To 9999
q=f &j &u
g=" GO TO "
w=i &f
m=j &f
a=Replace(Replace(Replace(Replace(a,g &w,g &m),f &i &" ",q),"B "&w,"B "&m),"UN "&w,"UN "&m)
If InStr(1,a,q)Then j=j+10
Next
a=Replace(a,u," ")
End Sub

Saya menggunakan banyak variabel satu huruf untuk keringkasan. Juga, saya menekan semua spasi putih yang tidak perlu (VBE memperluasnya secara otomatis saat impor). Hitungan byte untuk file .BAS final, dengan CHR (10) sebagai baris baru.

Subrutin, yang dapat dipanggil dari jendela langsung VBE, membuka program Sinclair BASIC (parameter pertama adalah path ke file ASCII - dengan CHR (10) sebagai baris baru - yang berisi program), memberi nomor baru baris dan menulis hasil ke variabel Variant (parameter kedua).

Idenya adalah untuk beralih pada semua nomor baris sumber yang mungkin, urutan naik, dan untuk masing-masing, ganti sekaligus semua nomor baris yang cocok juga GO TO, GO SUBdanRUN referensi dengan nomor baris target berikutnya yang tersedia. Dengan menggunakan pendekatan ini kita tidak perlu tabel terjemahan apa pun. Nomor baris target bertambah setiap kali ditemukan kecocokan dalam nomor baris sumber, sehingga referensi baris "salah" disesuaikan secara otomatis ke nomor valid berikutnya. Karakter baris baru digunakan sebagai penanda awal dan akhir garis, dan CHR (0) - tidak pernah digunakan dalam program karena tidak dapat dicetak - digunakan sebagai penanda sementara, untuk menghindari pemberian nomor baru pada baris yang sama beberapa kali.

Beberapa komentar:

  • Untuk keringkasan, kami menggunakan string yang lebih kecil untuk pertandingan dengan pernyataan melompat. Menggunakan end-of-line pada string pencarian kami, kami tidak mengalami risiko memasukkan kejadian-kejadian yang dikutip atau fungsi pengguna (yang selalu menggunakan tanda kurung di Sinclair). GO TOmembutuhkan string yang lebih besar karena FOR ... TOkonstruknya (mis. bandingkan 50 FOR X=AGO TO 100dan 50 GO TO 100)

  • Kode tidak mendukung pernyataan dalam bentuk GO TO200(tanpa spasi), meskipun manual ZX menyiratkan bahwa itu adalah kode yang valid pada beberapa contoh (Akan membutuhkan selusin byte lebih banyak untuk menghadapinya).

  • Kode menambahkan baris baru di awal dan lainnya di akhir program. Saya bisa membersihkan ini pada akhirnya (selusin byte lebih) tetapi angka bahwa ZX mungkin akan mengabaikan garis kosong.

Di bawah, versi yang lebih mudah dibaca:

Sub Renumber(ByVal ProgramPath As String, ByRef Program As Variant)

    Open ProgramPath For Input As #1
    Program = Chr(10) & Input(LOF(1), 1) & Chr(10)
    Close

    NewNumber = 10
    For OldNumber = 1 To 9999
        Program = Replace(Program, " GO TO" & OldNumber & Chr(10), " GO TO" & NewNumber & Chr(10)) 'self-explaining
        Program = Replace(Program, Chr(10) & OldNumber & " ", Chr(10) & NewNumber & Chr(0)) 'matches line number (and replaces whistespace with Chr(0) to avoid re-replacing
        Program = Replace(Program, "B " & OldNumber & Chr(10), "B " & NewNumber & Chr(10)) 'matches GO SUB
        Program = Replace(Program, "UN " & OldNumber & Chr(10), "UN " & NewNumber & Chr(10)) 'matches RUN
        If InStr(1, Program, Chr(10) & NewNumber & Chr(0)) Then NewNumber = NewNumber + 10 'if there is such a line, increment NewNumber
Next
Program = Replace(Program, Chr(0), " ") 'replace back Chr(0) with whitespace
End Sub
dnep
sumber
BTW, solusi QBasic akan jauh lebih lama, karena QBasic tidak memiliki fungsi penggantian string yang terpasang sejauh yang saya ingat.
DLosc
Saya pikir Anda benar ... lupa tentang itu
dnep
1

Pip -rn , 63 byte

Ygn:#{_<aFIy}*t+tgR`(RUN|GO (SUB|TO)) (\d+)$`{b.s.(nd)}R`^\d+`n

Cobalah online!

Penjelasan

Mempersiapkan

The -rBendera membaca semua stdin dan menyimpannya sebagai daftar baris dalam variabel lokal g. Variabel global tdiinisialisasi menjadi 10, dan variabel global sdiinisialisasi ke " ".

Yg

Tarik daftar baris gke dalam variabel global y, sehingga tersedia di dalam fungsi yang akan kita definisikan.

Fungsi terjemahan nomor baris

Kami membangun fungsi yang memetakan dari nomor baris apa pun dalam skema penomoran asli (termasuk yang tidak ada) ke nomor baris yang sesuai dalam skema penomoran yang baru.

Misalkan kita memiliki garis-garis ini:

1 INPUT A
4 PRINT A
9 IF A=1 THEN GO TO 3

Kami ingin memetakan 1 hingga 10, 2-4 hingga 20, dan 5-9 hingga 30. Jika kami memiliki daftar nomor baris asli ( [1; 4; 9]), kami dapat menggunakan operasi filter untuk mengetahui berapa banyak dari angka-angka ini yang kurang daripada nomor baris yang kami coba konversi. Lipat gandakan hasilnya dengan 10 dan tambahkan 10, dan kami memiliki jawaban yang diinginkan.

Misalnya, saat mengonversi 9, ada dua nomor baris (1 dan 4) kurang dari 9. 2 * 10 + 10 memberi 30. Saat mengonversi 3, ada satu nomor baris (1) kurang dari 3. 1 * 10 + 10 memberi 20.

Berikut kodenya (sedikit dimodifikasi agar lebih mudah dibaca):

n:{#(_<aFIy)*t+t}
  {             }  Lambda function with parameter a:
        FIy         Filter y (the list of program lines) for
     _<a             lines that are numerically less than a
                    (In a numeric context, only the first run of digits on the line is considered)
   #(      )        Number of items in the filtered list
            *t+t    Times 10, plus 10
n:                 Assign that function to global variable n

Pengganti Pertama: GO TO, GO SUB, danRUN

Sisa dari program ini adalah ekspresi tunggal yang mengambil gdan melakukan beberapa penggantian regex (yang membuat vektor, berlaku untuk setiap baris dalamg ).

Inilah penggantian pertama:

g R `(RUN|GO (SUB|TO)) (\d+)$` {b.s.(nd)}

Regex cocok dengan salah satu dari RUN, GO SUBdan GO TO, diikuti oleh angka, diikuti oleh akhir baris. Ini memastikan tidak cocok dengan string dalam, juga tidak cocok RUNtanpa nomor baris.

Urutan kelompok penangkap penting. Kelompok pertama menangkap perintah (salah RUN, GO SUBatau GO TO). Grup kedua, jika digunakan, menangkap salah satu SUBatau TO. Kami tidak perlu menangkap bagian ini, tetapi grup yang tidak menangkap akan membutuhkan byte tambahan. Kemudian kelompok ketiga menangkap nomor baris.

Kami menggunakan fungsi panggilan balik untuk penggantian. Dengan fungsi callback di Pip, seluruh pertandingan adalah argumen pertama a, dan kelompok-kelompok capture agar adalah argumen berikutnya b, c, d, dan e. Jadi kita memiliki perintah di grup pertama, yang masuk b, dan nomor baris di grup ketiga, yang masuk d. Satu-satunya perubahan yang kita butuhkan untuk membuat adalah untuk lulus nomor baris melalui fungsi konversi kami, yang disebut Lisp gaya: (nd). Kemudian kami menggabungkannya bersamab dan spasi dan mengembalikannya.

Penggantian kedua: nomor baris

Yang tersisa untuk dikonversi adalah nomor baris di awal baris.

(...) R `^\d+` n

Regex cocok dengan angka di awal garis. Sekali lagi kami menggunakan fungsi callback; kali ini, fungsi konversi nitu sendiri sudah cukup, karena seluruh kecocokan (argumen pertama, a) adalah angka yang ingin kita konversi.

Karena ini adalah ekspresi terakhir dalam program, Pip mencetak ulang hasilnya. The -nbendera memisahkan daftar hasil dengan baris baru.

DLosc
sumber