Gerileme Cuma: ZX spektrumumun temel listesini yeniden numaralandır


15

Karşılaştığım ilk programlama dili Sinclair BASIC'ti . Birçok BASIC lehçesi gibi, tüm kaynak kodu satırlarının numaralandırılmasını gerektirir .

Sonuç olarak, GO TOkomutun kullanımı deyimseldi ve yürütmeyi verilen satır numarasına atlar (etiket yok).

Ayrıca GO SUBtemel bir işlev çağrısı olarak kullanılabilecek ilgili bir komut vardır. Yine, yürütme verilen satır numarasına atlar, ancak bir RETURNkomuta ulaşıldığında yürütme GO SUB.

Benzer şekilde RUNkomut, verilen satırda programın yürütülmesini yeniden başlatacaktır.

Satır numaralı bir BASIC yorumlayıcısında herhangi bir zaman geçiren herkes, içinde boşluklar bulunan bir numaralandırma düzeni kullanmayı öğrenmiş olacaktır. Böylece yeni kod satırları eklemek daha kolaydır. Ancak o zaman bile, kendinizi art arda numaralandırılmış satırlar arasına yeni satırlar eklemeye ihtiyaç duyabilirsiniz.


Giriş olarak satır numaralı bir BASIC listesi verildiğinde, aynı programı çıktılayın, ancak satır numaraları 10'da başlayacak ve 10'luk adımlarla artan olacak şekilde yeniden numaralandırın. Giriş listesinde GO TOveya GO SUBkomutları olabilir , bu nedenle bunlarla ilişkili sayılar da ayarlanmalıdır.

  • GO TOve GO SUBkomutlar ya kendi satırlarında ya da satırların sonundadır IF THEN. Söylemesi güvenli, ^(\d+) .*GO (TO|SUB) (\d+)$bu tür çizgileri eşleştirmek için yeterlidir. Tırnak içindeki bu komutlar göz ardı edilmelidir.

  • RUNkomutlar her zaman kendi satırlarında olacaktır. Bu durumda bir satır numarası isteğe bağlıdır. Eksikse, yorumlayıcı programın üstünden başlar.

  • Bir ederse GO TO, GO SUBya RUNkomut referanslar var olmayan bir çizgi, o zaman yerine gelecek tanımlanan hat atlayacaktır. Girişinizin bununla başa çıkması ve bu tür satır referanslarının doğru satırı gösterecek şekilde sabitlendiğinden emin olması gerekir. Bu komutlardan birinde program bittikten sonra bir satır numarası verilirse, davranış tanımsız olabilir.

  • Satır numaraları her zaman 1 ila 9999 arasında pozitif tamsayılar olacaktır (kılavuza göre). Bu, girdi programlarının hiçbir zaman 999'dan fazla satıra sahip olmayacağı anlamına gelir.

  • Giriş satırları her zaman sayısal olarak artan sırada numaralandırılır.

  • Bu zorluğun amaçları doğrultusunda, giriş listeleri yalnızca yazdırılabilir ASCII içerecektir. ZX karakter seti için endişelenmenize gerek yok. Senin girişi aslında ZX BASIC ile yazılmış veya / birleştirme makinesi kodunu z80 mülk (ve orada eğer söyledikten, emülatörlerine dışarı orada ) Giriş kodlanmasını için, o zaman tercih edebilir ZX karakter kümesi yerine.

  • Bu amaç için özel olarak uyarlanmış herhangi bir yeniden numaralandırılmış kitaplık veya yardımcı programı kullanamazsınız.

Örnek Giriş:

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"

Örnek Çıktı:

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"

Bir ZX BASIC kılavuzuna bağlantı vermek istedim. Bulabildiğim en iyi şey http://www.worldofspectrum.org/ZXBasicManual/index.html gibi görünüyor, ancak bu ölü bir bağlantı gibi görünüyor. Geri dönüş makinesinin bir kopyası var .


7
Ayrıca 5000. soruyu sorar!
FryAmTheEggman

1
Nostalji zamanı - ilk bilgisayarım bir Spectrum 48K ve ilk montaj programlardan biri bir yeniden numaralandı
edc65

2
@ edc65 Yeniden numaralandırma montaj kodunuz hala var mı? Eğer öyleyse, cevap olarak göndermekten memnuniyet duyarız!
Dijital Travma

1
Test durumu, bir dizgi değişmezinde en az bir goto / gosub içermelidir.
Peter Taylor

1
: Bir söz bulundu ZX81 olarak hesaplanmış GOTOs ve GOSUBs sağlarGOTO 100 + A*10 ve ZX Spektrumu Manual Ek C listeleri GO TOsayısal bir ifade (sabitleri için herhangi bir kısıtlama) kabul olarak. İşte ZX80 ve ZX81'de hesaplanan değerlerin tartışmasıGOTO . BTW, alanın neden Spectrum versiyonuna eklendiğini bilmiyorum.
Toby Speight

Yanıtlar:


5

JavaScript (ES6) 177

Düzenle Bir sonraki geçerli satır numarası için (maliyetli) tarama eklendi

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`
`

ÖLÇEK

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>


1
İyi görünüyor. + 1'im duruyor :)
Dijital Travma

2

Perl 6, 147 145 144 142 bayt

{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}})}

Bu muhtemelen biraz daha golf edilebilir.

Expanded

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} } 
            )
}

yöntemi kullanmak için bir sebep yok .min. kullanmak {min %line-map.keys».Num.grep:*>=$1yerine
Ven

1

Uygulamalar için Visual Basic, 288 bayt

BASIC lehçesinde bir çözüm sunmaya dayanamadım. Muhtemelen Visual Basic 6 / .NET veya küçük değişikliklere sahip diğer modern varyantlarla çalışır.

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

Kısa ve öz olmak için bir harfli değişken kullandım. Ayrıca, tüm gereksiz beyaz boşlukları bastırdım (VBE bunları içe aktarma sırasında otomatik olarak genişletir). Bayt sayısı son .BAS dosyası içindir, CHR (10) yeni satır olarak alınır.

VBE anlık penceresinden çağrılabilen alt program, bir Sinclair BASIC programı açar (ilk parametre bir ASCII dosyasının yolu - CHR (10) yeni satır olarak - programı içeren), satırları yeniden numaralandırır ve sonuçları bir Varyant değişkenine yazar (ikinci parametre).

Fikir, tüm olası kaynak hattı numaraları yineleme etmektir küçükten büyüğe ve her biri için, tüm eşleşen satır numaraları kez yanısıra en değiştirin GO TO, GO SUBveRUN bir sonraki kullanılabilir hedef hat numarası ile referanslar. Bu yaklaşımı kullanarak herhangi bir çeviri tablosuna ihtiyacımız yok. Hedef satır numarası, kaynak satır numarasında bir eşleşme bulunduğunda artar, bu nedenle "yanlış" satır referansları otomatik olarak bir sonraki geçerli sayıya ayarlanır. Yeni satır karakterleri, satır başlangıcı ve satır sonu işaretleri olarak kullanılır ve aynı satırın birden çok kez yeniden numaralandırılmasını önlemek için programda hiçbir zaman yazdırılamadığı için kullanılmayan bir CHR (0) kullanılır.

Bazı açıklamalar:

  • Kısacası, atlama ifadeleriyle bir eşleşme için mümkün olan daha küçük dizeyi kullanırız. Arama dizelerimizde satır sonu kullanıldığında, alıntı yapılan tekrarlamaları veya kullanıcı işlevlerini (Sinclair'de her zaman parantez kullanan) dahil etme riskiyle karşılaşmıyoruz. yapı GO TOnedeniyle daha büyük bir dize gerektirir FOR ... TO(örneğin karşılaştır 50 FOR X=AGO TO 100ve 50 GO TO 100)

  • GO TO200ZX el kitabı çeşitli örneklerde geçerli bir kod olduğunu ima etmesine rağmen, kod formdaki ifadeleri (boşluk olmadan) desteklemez (Bununla başa çıkmak için bir düzine bayt daha maliyetli olacaktır).

  • Kod, programın başına yeni bir satır ve programın sonuna yeni bir satır ekler. Sonunda bunu temizleyebilirim (bir düzine bayt daha) ama ZX'in muhtemelen boş satırları görmezden geleceğini anladım.

Aşağıda, daha okunabilir bir sürüm:

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

QBasic, hatırladığım kadarıyla yerleşik bir dize değiştirme işlevine sahip olmadığından, QBasic çözümü BTW çok daha uzun olacaktır.
DLosc

Sanırım haklısın ... bunu unuttun
dnep

1

Pip -rn , 63 bayt

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

Çevrimiçi deneyin!

açıklama

Kurmak

-rBayrak yerel değişkende hatların listesi olarak stdin ve mağazaların bunu her okur g. Global değişken t10'a önceden başlatılır ve global değişkene sönceden başlatılır " ".

Yg

Satır listesini gglobal değişkene ayırır y, böylece tanımlamak üzere olduğumuz fonksiyonun içinde bulunur.

Satır numarası çeviri işlevi

Orijinal numaralandırma şemasındaki herhangi bir satır numarasından (var olmayan bir numara dahil) yeni numaralandırma şemasındaki karşılık gelen satır numarasına eşlenen bir işlev oluştururuz.

Diyelim ki şu satırlarımız var:

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

1'den 10'a, 2-4'den 20'ye ve 5-9'dan 30'a kadar eşlemek istiyoruz. Orijinal satır numaralarının ( [1; 4; 9]) bir listesine sahipsek, bu numaralardan kaç tanesinin daha az olduğunu bulmak için bir filtre işlemi kullanabiliriz dönüştürmeye çalıştığımız satır numarasından daha fazla. Bu sonucu 10 ile çarpın ve 10 ekleyin ve istediğiniz cevaba sahibiz.

Örneğin, 9'u dönüştürürken 9'dan daha az iki satır numarası (1 ve 4) vardır. 2 * 10 + 10 30 verir. 3'ü dönüştürürken 3'ten daha az bir satır numarası (1) vardır. 1 * 10 + 10 20 verir.

İşte kod (okunması daha kolay olacak şekilde biraz değiştirildi):

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

İlk yedek: GO TO, GO SUB, veRUN

Programın geri kalanı, gbirkaç regex değiştirmesini alan (her bir çizgiye uygulayan, vektörleyen, uygulayan g) tek bir ifadedir .

İşte ilk değiştirme:

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

Normal ifade herhangi eşleşir RUN, GO SUBve GO TO, takip eden bir numara, satır sonuna eklenmiştir. Bu, dizelerin içinde RUNve bir satır numarası olmadan eşleşmediğinden emin olur.

Yakalama gruplarının sırası önemlidir. Birinci grup komutu (birini yakalar RUN, GO SUBya da GO TO). İkinci grup, eğer, yakalar kullanılan hiçbir SUBya da TO. Bu kısmı yakalamamız gerekmiyor, ancak yakalamayan bir grup için fazladan bayt gerekir. Sonra üçüncü grup satır numarasını yakalar.

Değiştirme için geri arama işlevi kullanıyoruz. Pip geri arama fonksiyonları sayesinde, bütün maç ilk argümanı a, ve sırayla yakalama grupları sonraki argümanlar vardır b, c, d, ve e. Bu yüzden, ilk grupta bdevreye giren komuta ve üçüncü gruptaki içeri giren satır numarası var d. Yapmamız gereken tek değişiklik, satır numarasını Lisp stili: adlı dönüşüm fonksiyonumuzdan geçirmektir (nd). Sonra bunu bbir boşlukla bir araya getirip geri veriyoruz .

İkinci değiştirme: satır numaraları

Dönüştürmek için kalan tek şey, satırların başlangıcındaki satır numaralarıdır.

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

Normal ifade, satırın başlangıcındaki rakamlarla eşleşir. Yine bir geri çağırma işlevi kullanıyoruz; ntüm eşleşme (ilk argüman a) dönüştürülmesini istediğimiz sayı olduğu için bu kez dönüştürme işlevinin kendisi yeterlidir .

Bu programdaki son ifade olduğundan Pip sonucu otomatik olarak yazdırır. -nBayrak yenisatırlar ile sonuç listesi ayırır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.