Mafia: Fehler oder BASIC-Trick?

Es gibt 70 Antworten in diesem Thema, welches 7.999 mal aufgerufen wurde. Der letzte Beitrag (2. März 2023 um 16:31) ist von JeeK.

  • Ich entwickle einen BASIC Parser/Compiler, den ich mit einem möglichst umfangreichen Programm testen wollte. Da war Mafia ein idealer Kandidat.

    Nun ist mir bei der Syntaxanalyse etwas aufgefallen. Es handelt sich um Mafia 1.20 (HtW), soweit ich mich erinnere:

    Code
    14006 PRINT"{CLEAR}{DOWN}der verkaeufer zeigt dir eine auswahl"
    14007 PRINT"{DOWN}der modelle. zum kauf die entsprechende"
    14008 PRINT"{DOWN}nummerntaste (0=ende) druecken!":GOSUB1100:PRINT"{CLEAR}";
    14010 X=2:IFLN=2THENX=X+1
    14011 FORI=0TOX:Y=X-1
    14012 FORI=0TOX:PRINT:FORJ=1TO5:PRINT" {LIGHT GRAY}{REVERSE ON}{SPACE*8}{BLACK}":NEXTJ
    14013 POKEPO+I,20+I:POKEV+2*I,38:POKEV+1+2*I,60+48*I:POKEV+39+I,0
    14014 PRINTTAB(10)"{UP*5}"CHR$(49+I)" "TM$(I+1):PRINTTAB(11);3000+1000*I"${DOWN*3}"
    14015 NEXT:Y=2^(X+1)-1:POKEV+23,Y:POKEV+29,Y:POKEV+21,Y:NEXT
    14020 GETX$:IFX$=""GOTO14020

    Das ist ziemlich unübersichtlich, deshalb hier die formatierte Ausgabe (überflüssige Labels wegoptimiert):

    Die erste FOR-Schleife wird nie mit NEXT abgeschlossen. Mir ist das aufgefallen weil sich die Einrückung bis zum Ende durchzieht.

    Die zweite Schleife verwendet ebenfalls I als Zähler.

    Jetzt ist die Frage, ob dadurch irgendwann der Stack überläuft, oder ist das ein spezieller Commodore-Trick?

    Ich würde ja sagen, die erste FOR-Schleife gehört da nicht hin. Oder vor Zeile 14020 ein NEXT? ?(

  • Hier ist doch dein fehlendes NEXT:

    14015 NEXT:Y=2^(X+1)-1:POKEV+23,Y:POKEV+29,Y:POKEV+21,Y:NEXT

    Das hast du unten "unterschlagen".

    - WiC64 - The Commodore 64 Wireless Interface -> Bitte melde dich an, um diesen Link zu sehen. | Bitte melde dich an, um diesen Link zu sehen.
    - WiC64 - Radio -> Bitte melde dich an, um diesen Link zu sehen.
    - WiC64 - GameBox -> Bitte melde dich an, um diesen Link zu sehen. :thumbsup:
    - WiC64 - DemoBox -> Bitte melde dich an, um diesen Link zu sehen.

  • Hier ist doch dein fehlendes NEXT:

    14015 NEXT:Y=2^(X+1)-1:POKEV+23,Y:POKEV+29,Y:POKEV+21,Y:NEXT

    Das hast du unten "unterschlagen".

    Beide müssten sich aber auf die For-Schleife mit I beziehen.

    Wenn nicht von irgendwo anders noch eine For-Schleife offen ist, dann sollte es eigentlich ein "Next without For" geben.

  • Bügelt nicht das zweite FOR das erste weg? Sind ja beide mit I als Laufvariable.

    Das NEXT guckt ja nur auf dem Stack nach, ob da eine Schleife drauf liegt. Eine "Zugehörigkeit" zu einem FOR ergibt sich nur indirekt.

    Aber dadurch muss das zweite ja zwangsläufig auf NEXT WITHOUT FOR laufen:

    Eben ausprobiert:

    10FORI=0TO4:?I

    20FORI=5TO10:?I

    30NEXT:?"ENDE SCHLEIFE 2":NEXT

    RUN

    0

    5

    6

    7

    8

    9

    10

    ENDE SCHLEIFE 2

    ?NEXT WITHOUT FOR ERROR IN 30

    READY.

    C64Studio: Bitte melde dich an, um diesen Link zu sehen. - Bitte melde dich an, um diesen Link zu sehen. --- C64Studio WIP: Bitte melde dich an, um diesen Link zu sehen. - Bitte melde dich an, um diesen Link zu sehen. --- Bitte melde dich an, um diesen Link zu sehen.

  • Also bei mir sind die Schleifen alle zu.

    Bitte melde dich an, um diesen Anhang zu sehen.

    - WiC64 - The Commodore 64 Wireless Interface -> Bitte melde dich an, um diesen Link zu sehen. | Bitte melde dich an, um diesen Link zu sehen.
    - WiC64 - Radio -> Bitte melde dich an, um diesen Link zu sehen.
    - WiC64 - GameBox -> Bitte melde dich an, um diesen Link zu sehen. :thumbsup:
    - WiC64 - DemoBox -> Bitte melde dich an, um diesen Link zu sehen.

  • Bügelt nicht das zweite FOR das erste weg? Sind ja beide mit I als Laufvariable.

    ja, das erste NEXT (bzw. das zweite) in 14015 wird dadurch zum Problem:

    Bitte melde dich an, um diesen Anhang zu sehen.

    ...zumindest wenn man nur diesen Programmabschnitt laufen lässt.

    Im Spiel selbst wirft das keinen Fehler aus?

  • Bügelt nicht das zweite FOR das erste weg? Sind ja beide mit I als Laufvariable.

    This.

    Das "überflüssige" NEXT muss sich auf ein weiteres, vorher geöffnetes FOR beziehen.

    Yes, I'm the guy responsible for the Bitte melde dich an, um diesen Link zu sehen. cross assembler. And some Bitte melde dich an, um diesen Link zu sehen..

  • Eigentlich sind es 3 Schleifen: eine Schleife mit I fängt in 14011 an. In 14012 fängt eine neue Schleife mit I an, wobei die alte nicht richtig beeendet wird. Außerdem fängt in der gleichen Zeile noch eine Schleife mit J an, die sind dann korrekt ineinander geschachtelt (die beiden NEXT hierfür sind in 14015). Ich würde sagen, der Code ist buggy.

  • Hier ist doch dein fehlendes NEXT:

    14015 NEXT:Y=2^(X+1)-1:POKEV+23,Y:POKEV+29,Y:POKEV+21,Y:NEXT

    Das hast du unten "unterschlagen".

    Ups, sorry, das war die Version wo ich es zum Test schon angehängt hatte.

    Im Original fehlt es. Ich korrigier das im ersten Post. (Edit: kann ich leider nicht)

    Code
    14006 PRINT"{CLEAR}{DOWN}der verkaeufer zeigt dir eine auswahl"
    14007 PRINT"{DOWN}der modelle. zum kauf die entsprechende"
    14008 PRINT"{DOWN}nummerntaste (0=ende) druecken!":GOSUB1100:PRINT"{CLEAR}";
    14010 X=2:IFLN=2THENX=X+1
    14011 FORI=0TOX:Y=X-1
    14012 FORI=0TOX:PRINT:FORJ=1TO5:PRINT" {LIGHT GRAY}{REVERSE ON}{SPACE*8}{BLACK}":NEXTJ
    14013 POKEPO+I,20+I:POKEV+2*I,38:POKEV+1+2*I,60+48*I:POKEV+39+I,0
    14014 PRINTTAB(10)"{UP*5}"CHR$(49+I)" "TM$(I+1):PRINTTAB(11);3000+1000*I"${DOWN*3}"
    14015 NEXT:Y=2^(X+1)-1:POKEV+23,Y:POKEV+29,Y:POKEV+21,Y
    14020 GETX$:IFX$=""GOTO14020

    Dass beide Schleifen I verwenden ist wohl nicht so tragisch, denn I wird ja innerhalb der Schleife als lokale Variable betrachtet. Man kann auch I beschreiben, es ändert den Schleifendurchlauf nicht. Da I nur in der inneren Schleife abgefragt wird gilt eben das I dieser Schleife, nicht der äußeren.

  • Die erste For Schleife wird doch trotzdem durch die in der nächsten Zeile gekillt.

    Das denke ich auch, aber Deine Farben passen nicht: das grüne NEXT sollte rot sein, weil das zum J gehört. Das gelbe NEXT sollte dann grün sein.

  • Das denke ich auch, aber Deine Farben passen nicht: das grüne NEXT sollte rot sein, weil das zum J gehört. Das gelbe NEXT sollte dann grün sein

    Das gelbe NEXT existiert nicht im Original. Das hatte ich hinzugefügt um zu schauen ob weiter hinten im Code noch weitere Ungereimtheiten auftauchen. Aber bis auf diese Stelle scheint alles sauber.

  • Dass beide Schleifen I verwenden ist wohl nicht so tragisch, denn I wird ja innerhalb der Schleife als lokale Variable betrachtet.

    Ähhhhh.... nein. Es wurde doch in Posting Bitte melde dich an, um diesen Link zu sehen. und Bitte melde dich an, um diesen Link zu sehen. alles schon geklärt. Sogar mit Beispiel-Listing.

    Bitte melde dich an, um diesen Link zu sehen. - Ratespiel • Bitte melde dich an, um diesen Link zu sehen. - BASIC-Erweiterung • Bitte melde dich an, um diesen Link zu sehen. - Sprite-Editor • Bitte melde dich an, um diesen Link zu sehen. - Zeichensatz-Editor Bitte melde dich an, um diesen Link zu sehen. - 2048 Blöcke

  • Dass beide Schleifen I verwenden ist wohl nicht so tragisch, denn I wird ja innerhalb der Schleife als lokale Variable betrachtet.

    Ähhhhh.... nein. Es wurde doch in Posting Bitte melde dich an, um diesen Link zu sehen. und Bitte melde dich an, um diesen Link zu sehen. alles schon geklärt. Sogar mit Beispiel-Listing.

    Danke, jetzt hat es gefunkt.

    Das NEXT braucht es nicht, weil die zweite FOR i Schleife den Stack der vorherigen überschreibt.

    Also doch ein merkwürdiger Sonderfall wieder :rolleyes:

    Code
    14011 FORI=0TOX:Y=X-1
    wird zu
    14011 Y=X-1

    Ich würde sagen, dann hat sich da ein FOR in die falsche Zeile verirrt.

  • Nein, NEXT ist auch nicht implizit mit einem überschreibenden FOR. Die erste Schleife wird damit abgebrochen.

    C64Studio: Bitte melde dich an, um diesen Link zu sehen. - Bitte melde dich an, um diesen Link zu sehen. --- C64Studio WIP: Bitte melde dich an, um diesen Link zu sehen. - Bitte melde dich an, um diesen Link zu sehen. --- Bitte melde dich an, um diesen Link zu sehen.

  • Syntaktisch korrekt wäre also

    Nein, denn dann würde die erste Schleife ja tatsächlich mehrfach durchlaufen. In Basic 2 passiert das aber nicht: Bereits während des ersten Durchlaufs wird erneut eine Schleife mit i als Zählvariable geöffnet und damit existiert die äußere Schleife einfach nicht mehr.

    Yes, I'm the guy responsible for the Bitte melde dich an, um diesen Link zu sehen. cross assembler. And some Bitte melde dich an, um diesen Link zu sehen..

  • Generell würde ich sagen, wenn du einen Parser für BASIC V2 bauen willst: Verabschiede dich von dem gedanklichen Konstrukt einer FOR-NEXT-Schleife. Das gibt es nämlich eigentlich nicht. Es gibt einen FOR-Befehl und einen NEXT-Befehl sowie einen Stack auf dem beide (zusammen mit GOSUB/RETURN) herumhühnern und "aus versehen" bilden die auch mal eine Schleife. Die meisten Programme sind so gebaut, dass das tatsächlich so aussieht, aber das muss nicht so sein. Du kannst ohne Probleme 5 NEXTs und 1 FOR haben oder umgekehrt.

    Sowas ist z.B. valide:

    Code
    10 for i=1 to 3
    15 print i
    20 on i goto 120,220,300
    100 for i=1 to 2
    110 print "(100)";:goto 15
    120 next:end
    200 for i=1 to 2
    210 print "(200)";i:goto 120
    220 next:goto 200
    300 goto 100

    Bitte melde dich an, um diesen Link zu sehen.

    Bitte melde dich an, um diesen Link zu sehen.

    Bitte melde dich an, um diesen Link zu sehen.

  • Generell würde ich sagen, wenn du einen Parser für BASIC V2 bauen willst: Verabschiede dich von dem gedanklichen Konstrukt einer FOR-NEXT-Schleife. Das gibt es nämlich eigentlich nicht. Es gibt einen FOR-Befehl und einen NEXT-Befehl sowie einen Stack auf dem beide (zusammen mit GOSUB/RETURN) herumhühnern und "aus versehen" bilden die auch mal eine Schleife. Die meisten Programme sind so gebaut, dass das tatsächlich so aussieht, aber das muss nicht so sein. Du kannst ohne Probleme 5 NEXTs und 1 FOR haben oder umgekehrt.

    Das Problem ist, dass die Zählervariablen mit gleichem Namen offenbar denselben Platz beanspruchen, also nicht einfach auf dem Stack gestapelt werden. Sonst würde das Konstrukt aus Mafia früher oder später OUT OF MEMORY liefern.

    Code
    FOR i=0 TO 10
      FOR j=0 TO 10
        FOR i=0 TO 10
        NEXT i
      NEXT j

    Der innere FOR i "klaut" der äußeren das i. Dadurch wird der äußere FOR überflüssig. Ein NEXT i am Schluss wäre ein Fehler.

    Unschön. Aber gut zu wissen.

  • Der innere FOR i "klaut" der äußeren das i. Dadurch wird der äußere FOR überflüssig. Ein NEXT i am Schluss wäre ein Fehler.

    Unschön. Aber gut zu wissen.

    Im Prinzip genau so.

    Aber irgendein Wahnsinniger könnte eine Konstruktion mit einem IF vor dem inneren FOR schaffen, so dass es manchmal doch mehr NEXT brauchen würde. Es gibt bestimmt noch was verwirrenderes als Egons Beispiel.

  • Im Prinzip genau so.

    Aber irgendein Wahnsinniger könnte eine Konstruktion mit einem IF vor dem inneren FOR schaffen, so dass es manchmal doch mehr NEXT brauchen würde. Es gibt bestimmt noch was verwirrenderes als Egons Beispiel.

    Klar...:D

    Bitte melde dich an, um diesen Link zu sehen.

    Bitte melde dich an, um diesen Link zu sehen.

    Bitte melde dich an, um diesen Link zu sehen.