Forum: Mikrocontroller und Digitale Elektronik ZX-Spectrum Basic : error handling aber wie?


von Jan (Gast)


Lesenswert?

Ich spiele mit STECCY und habe folgendes Programm :
1
10 INPUT "Input a number:";q$
2
20 LET d= VAL q$
3
30 PRINT "peek(23610) "; PEEK (23610)
4
40 LET e= d*2
5
50 PRINT "The input a number "; d; " times two is  "; e

Ich möchte eine Zahl von der Tastatur einlesen und mit Ihr rechnen. 
(Zeile 10)
Nach dem einlesen konvertiere ich diesen String in eine Zahl (Zeile 20)

Jetzt kommt das Problem :
Habe ich keine gültige Zahl eingegeben (z.B. ein Buchstabe ist 
dazwischengerutscht)
so hält mein Programm an und ich bekomme folgende Fehlermeldung :

C Nonsense in BASIC, 20:1

Eigentlich alles wie in erwartet

Wie kann ich es machen das das Programm nicht anhält?
Mit der Zeile 30 kann ich (sollte ich) prüfen ob VAL erfolgreich war 
oder nicht und gegebenenfalls auf eine Fehleingabe reagieren.

https://zxbasic.readthedocs.io/en/docs/val/
1
VAL(<string value>)
2
3
Description:
4
Converts the given numeric string value into its numeric value. It's the opposite of STR. If the string can be converted into a number, 
5
PEEK 23610 (ROM ERR_NR variable) will return 255 (Ok).
6
7
On the other side, if expression cannot be parsed (i.e. it's not a valid number expression), 0 will be returned, and PEEK 23610 (ROM ERR_NR variable) will return 9 (Invalid Argument).

Im Falle die Zahl kann konvertiert werden :
"PEEK will return 255 (Ok)." Das kann ich beobachten

Im Falle die Zahl kann nicht konvertiert werden :
"and PEEK 23610 (ROM ERR_NR variable) will return 9 "
Ich komme nie dazu , da das Programm vor dieser Zeile angehalten wird.

Ich möchte bei einer Falscher Eingabe die Eingabe wiederholen ohne das 
das Programm anhält.
Ich habe lange nach so was gesucht, leider habe ich nichts gefunden.
Müsste es nicht irgendwie mit CONTINUE gehen?
Wozu ist eigentlich CONTINUE?

Vielleicht kann mir jemand helfen, ich vermute die Lösung ist trivial.

Danke im Voraus,
Jan

von PittyJ (Gast)


Lesenswert?

Früher auf dem ZX81 gab es sowas wie
INPUT X
damit konnte man Zahlen einlesen.
Geht das jetzt nicht mehr, dass man das so umständlich machen muss?


Früher war alles besser. Die neumodischen Rechner sind so kompliziert.

von Martin V. (oldmax)


Lesenswert?

Hi
Ja, der alte Basic Interpreter.
Klar, ein Fehler, und es geht nicht weiter. Kann ja auch nicht, denn ein 
Fehler muss erst behoben sein, damit Werte im Programm gültig sind und 
nicht mit irgendwelchem Blödsinn weiter gearbeitet wird. Ein 
Compiliertes Programm ist auch abgestürzt und mußte neu gestartet 
werden. Auch moderne Programme liefern Fehlermeldungen und bearbeiten 
entsprechende Programmtele nicht. Also, eine Maßnahme, um solche Fehler 
abzufangen, ist die Bewertung der Eingabe auf Zulässigkeit. Etwa so
If q >="0" AND q <="9" then
  .....
End
OK, so genau kenn ich den alten Syntax nicht mehr, aber du mußt hält 
sicher stellen, das der Inhalt der Variable q auch n eine Zahl wandelbar 
ist und bspw. keine Leerzeichen enthält.
Gruß oldmax

von Stefan F. (Gast)


Lesenswert?

Martin V. schrieb:
> Klar, ein Fehler, und es geht nicht weiter.

http://www.antonis.de/qbebooks/gwbasman/onerror.html

von Jan (Gast)


Lesenswert?

Danke für die Antworten.

Stafen schrieb :
>http://www.antonis.de/qbebooks/gwbasman/onerror.html

ON ERR is an error-handling function mostly used as ON ERR GO TO or ON 
ERR CONT.

Da drüber bin ich schon gestolpert,
https://en.wikipedia.org/wiki/Sinclair_BASIC

so wie ich es verstehe geht es das nur ab der version T/S 2000 BASIC
Das kannte der spectrum 48k bzw. 128k noch nicht.

Martin V schrieb :
>Etwa so If q >="0" AND q <="9" then

Damit werde ich heute abend ein bisschen spielen.

q ist ein String (q$)
Überprüft das automatisch alle Zeichen im String?
Oder muss man explizit alle Zeichen überprüfen?

von Jan (Gast)


Lesenswert?

Martin schrieb:

>Klar, ein Fehler, und es geht nicht weiter. Kann ja auch nicht, denn ein
>Fehler muss erst behoben sein, damit Werte im Programm gültig sind und
>nicht mit irgendwelchem Blödsinn weiter gearbeitet wird

Das ist mir schon klar. Noch einmal.
Die Funktion VAL soll in der Lage sein das abzufangen:

>https://zxbasic.readthedocs.io/en/docs/val/
>VAL(<string value>)
>Description:
>Converts the given numeric string value into its numeric value. It's the 
>opposite of STR. If the string can be converted into a number,
>PEEK 23610 (ROM ERR_NR variable) will return 255 (Ok).

>On the other side, if expression cannot be parsed (i.e. it's not a valid >number 
expression),
>0 will be returned, and PEEK 23610 (ROM ERR_NR variable) will return 9
>(Invalid Argument).

Wie benutzt man die PEEK 23610 Abfrage in diesem Fall.

Gruss,
Jan

von Olaf (Gast)


Lesenswert?

> Wie kann ich es machen das das Programm nicht anhält?

Garnicht. Wir haben 1985 noch keine Eingabefehler gemacht.
Das lag daran das wir schon als Kinder darin geschult wurden
mehrere DIN-A4 Seiten Hexcode aus einer HappyComputer einzutippen
damit das neueste Spiel lief. :-D

Da koennen heutige Anwender nicht mehr mithalten. :-p

Die Alternative waere halt das du dir irgendeine Form von Parser 
schreibst. Sowas wie ON error Goto ist ein denkbares Hilfsmittel dazu. 
Weitere sind denkbar. Zum Beispiel kucken wo dein String im Ram liegt 
und da persoenlich durch steppen und auf Fehler kontrollieren.
Ist halt nur die Frage ob man dies in einem Zeilennummern-Basic aus den 
80ern so will.

Olaf

p.s: Der Original ZX-Spektrum haette uebrigens niemals einen EMV Test 
bestanden weil er abgestuerzt ist wenn meine Mutter ihre Staubsauger 
oder die Neonroehre in ihrem Arbeitszimmer eingeschaltet hat. Deshalb 
hab ich den Hexcode von MacWash dreimal eingetippt und schon frueh 
gelernt wie wichtig Backups sind....

von Jan (Gast)


Lesenswert?

Hallo Olaf,

danke für die Antwort.
Ich bin damit trotzdem unzufrieden.

Wie ist das mit dem VAL und PEEK 23610 zu verstehen?
Kann mir das vielleicht jemand erklären?

Gruss,
Jan

von Olaf (Gast)


Lesenswert?

> Wie benutzt man die PEEK 23610 Abfrage in diesem Fall.

Das liegt an dir. Dein PRogramm koennte dann ja einen
Fehler ausgeben und zurueck zur Eingabezeile springen.

Allerdings muesstest du vorher den Interpreter dazu bringen
bei einem Fehler eben nicht anzuhalten sondern deine Fehlerroutine
anzuspringen. Halt das was ein ON error Goto auch so macht.
Ich hab ZX Basic auch nicht mehr so drauf, floet, aber schau halt
mal ob es da einen entsprechenden Befehl gibt. Die Befehle standen
ja auf den Tasten. :-D

Olaf

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Jan schrieb:
> 10 INPUT "Input a number:";q$

Schreibe einfach

10 INPUT "Input a number:";d

und lösche Zeile 20.

von Jan (Gast)


Lesenswert?

Olaf schrieb :
>Allerdings muesstest du vorher den Interpreter dazu bringen
>bei einem Fehler eben nicht anzuhalten sondern deine Fehlerroutine
>anzuspringen. Halt das was ein ON error Goto auch so macht.

Genau so möchte ich es machen und genau das war auch meine Anfangsfrage 
:
>Wie kann ich es machen das das Programm nicht anhält?

Olaf schrieb :
>Ich hab ZX Basic auch nicht mehr so drauf, floet, aber schau halt
>mal ob es da einen entsprechenden Befehl gibt. Die Befehle standen
>ja auf den Tasten. :-D

Ich schreibe mit VS-Code auf dem PC und teste es mit einem Emulator.
ON ERR ist ein exklusives Befehl und wird nur vom Timex BASIC 
unterstützt.
Gibt es nicht eine Möglichkeit das automatische Anhalten beim Fehler mit 
einem POKE Befehl abzuschalten?

Das müsste irgendwie so aussehen :
1
10 INPUT "Input a number:";q$
2
20 POKE x? // Automatisches Anhalten ausschalten
3
30 LET d= VAL q$
4
40 IF PEEK (23610) = 9 THEN GO TO 100
5
50 POKE y? // Automatisches Anhalten wieder einschalten
6
..
7
..
8
100 REM Fehler : Falsche Eingabe
9
110 GO TO 10

Gruss,
Jan

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Martin V. schrieb:
> Etwa so
> If q >="0" AND q <="9" then
> .....

Das löst das Problem nicht für den String "2Foo". Und "9999" ist auch 
größer als "9".

Man müsste wirklich jedes Zeichen von q$ einzeln durchgehen. Geht im 
Sinclair-Basic, indem man die Substrings einzeln testet, siehe

https://worldofspectrum.org/ZXBasicManual/zxmanchap8.html

Das würde ich als Subroutine implementieren. Aber wie oben geschrieben: 
Wenn man INPUT mit einer numerischen Variablen statt String-Variablen 
aufruft, erledigt sich das Problem von selbst.

von Martin V. (oldmax)


Lesenswert?

Hi
Jan schrieb:
> Wie ist das mit dem VAL und PEEK 23610 zu verstehen?
Peek ist ein Basic-Befehl, der den Inhalt einer adressierten 
Speicherzelle geholt hat. Also x = PEEK (23610) hat der Variablen X den 
Wert (Inhalt ) der Speicherzelle mit der Adresse 23610 zugewiesen. Dein 
Befehl
PRINT "peek(23610) "; PEEK (23610)
schreibt dir auf den Bildschirm: peek (23610)  Wert-x
also den Text peek (23610) und einen mir unbekannten Wert, der in der 
Speicherzelle steht.
Wenn ich den Text von dir richtig interpretiere, dann lieferte eine 
gültige Wandlung den Wert 255, den du mit Print angezeigt bekommst. 
Natürlich kannst du den auch auswerten, z. B. in einer If-Anweisung
If PEEK (23610)<>255 then Print "Eingabe Fehlerhaft"
Wie aber dein Programm mit diesen Fehlern umgeht, kann ich beim besten 
Willen nicht mehr sagen, ist ja schließlich über 30 Jahre her.
Übrigends, oft ist das Programm in seiner Funktionalität klein, der 
Aufwand aber, fehlerhafte Eingaben zu verhindern dagegen riesig.

Stefan ⛄ F. schrieb:
> http://www.antonis.de/qbebooks/gwbasman/onerror.html

Na ja, Stefan, GW Basic konnte das, aber Sinclairs Basic glaube ich 
nicht. Den Spectrum hatte ich zwar nicht, aber bein ZX 81 bin ich mir 
fast sicher.

von Jan (Gast)


Lesenswert?

Frank schrieb :

>Schreibe einfach
>10 INPUT "Input a number:";d
>und lösche Zeile 20.

Das hilf ein bisschen, aber nicht ganz.
Wenn ich z.B. das hier eingebe :

123fdssd

Kann ich mit Return nicht quittieren, ich werde gezwungen die Eingabe zu 
korrigieren.

Wenn ich das hier eingebe :

dssd

Hält das Programm an mit dem Fehler :
2 Variable not found

Gruss,
Jan

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Jan schrieb:
> Wenn ich das hier eingebe :
> dssd
> Hält das Programm an mit dem Fehler :
> 2 Variable not found

Stimmt, habs gerade mit STECCY getestet - sowohl im 48K als auch im 
128K-Modus. Ich hatte doch glatt in Erinnerung, dass hier INPUT 
Buchstabeneingaben mit einem "?" quittiert und man das prinzipiell 
korrigieren muss. Wie einen das Gedächtnis schon nach knapp 40 Jahren 
trügen kann... ;)

von Jan (Gast)


Lesenswert?

Frank schrieb :

>Das würde ich als Subroutine implementieren. Aber wie oben geschrieben:
>Wenn man INPUT mit einer numerischen Variablen statt String-Variablen
>aufruft, erledigt sich das Problem von selbst.

Ich habe das FUNMATH Program modifiziert, auf vier stellen erweitert, 
Beep sequenzen eingebaut etc.

Ich kann aber von einem 8 Jährigen Kind nicht erlangen das er keinen 
Buchstaben eingeben darf. Es muss vom Program abgefangen werden.
Er soll damit üben und nicht direkt ein Absturz erleben :- )

Deshalb bin ich auf der Suche nach dieser Möglichkeit das umbedingt 
abzufangen.

>Man müsste wirklich jedes Zeichen von q$ einzeln durchgehen. Geht im
>Sinclair-Basic, indem man die Substrings einzeln testet, siehe
>https://worldofspectrum.org/ZXBasicManual/zxmanchap8.html
Ich schaue es mir an.

Geht das hier nicht irgend wie? :
1
10 INPUT "Input a number:";q$
2
20 POKE x? // Automatisches Anhalten ausschalten
3
30 LET d= VAL q$
4
40 IF PEEK (23610) = 9 THEN GO TO 100
5
50 POKE y? // Automatisches Anhalten wieder einschalten
6
..
7
..
8
100 REM Fehler : Falsche Eingabe
9
110 GO TO 10

von Martin V. (oldmax)


Lesenswert?

Hi
Ich weiß nicht, ob das damals bei dem Basic möglich war, direkt bei der 
Eingabe die Zeichen abzufangen. Heutzutage ist das durch die 
Ereignisbehandlung kein Problem, wenn ein Textfeld geändert wird, die 
Zeichen vorher abzufangen und entsprechend zu behandeln. Wenn du das 
beim alten Basic machen willst, Eingabe vor der Zuweisung zum 
Eingabestring abzufangen, mußt du dir die entsprechende Routine im 
Betriebssystem suchen und verändern. Es könnte sein, das es einen 
Tastaturinterrupt gibt, wo du ansetzen könntest, aber von hier aus und 
ohne Unterlagen kann ich dir da nicht weiter helfen. Vielleicht findest 
du etwas unter der Bezeichnung IVT oder Interrupt Vector Table, wo 
angegeben ist, welche Adresse für einen Tastaturinterrupt zuständig ist. 
Ich weiß, das man beim Z80 die Sprungadresse ändern konnte.
Dazu mußt du dir die eingetragene Adresse merken (mit Peek holen), die 
Adresse deines zwischengeschobenen Codes eintragen. In dem Code kannst 
du dann die Zeichen entweder verwerfen oder übernehmen, in dem du dann 
zur gemerkten Adresse weiterleitest und die alte Interrupt Service 
Routine aufrufst. Aber dazu wirst du mehr wie Basic können müssen.
Zu meinen zeiten mit dem ZX81 waren REM Zeilen angesagt, in die mit 
POKE-Befehlen handverlesene Hexcodes eingetragen wurden. Diese hatte ich 
aus einer Liste mit Assembleranweisungen und den zugehörigen Hex-Codes.
Viel Spaß noch
Gruß oldmax

von Frank M. (ukw) (Moderator) Benutzerseite


Angehängte Dateien:

Lesenswert?

Anbei eine Lösung mit INKEY$. Wahrscheinlich muss man die PAUSE noch 
etwas größer machen, damit die Tastatur nicht sofort "repetiert".

Die Backspace-Taste könnte man noch mit CHR$(9) abfangen, um das letzte 
Zeichen aus b$ wieder zu löschen . Das überlasse ich dem interessierten 
User ;-)

Aber prinzipiell funktioniert das so.

P.S.

Im ZX-128K-Basic gibts die praktische Renumber-Funktion. Einfach 
Linke-Shift-Taste und 1 drücken, dann kommt ein Menü mit mehreren 
Einträgen, zum Beispiel "Renumber".

P.P.S

Am Ende kann man natürlich VAL(b$) aufrufen, ohne einen Error zu 
riskieren. Denn dann stehen in b$ garantiert nur Ziffern drin.

P.P.P.S

Wenn man in Zeile 60 die Abfrage negiert, spart man noch ein GOTO ;-)

: Bearbeitet durch Moderator
von Martin V. (oldmax)


Lesenswert?

Frank M. schrieb:
> Anbei eine Lösung mit INKEY$.

Stimmt, das hatte ich gar nicht mehr auf dem Schirm. Ist ja auch 
verdammt lange her...
gruß oldmax

von Frank M. (ukw) (Moderator) Benutzerseite


Angehängte Dateien:

Lesenswert?

Hier die Lösung mit INPUT, also die Antwort auf die ursprüngliche Frage.

Die Subroutine ab 100 checkt, ob a$ numerisch ist. Wenn ja, wird n auf 
1, anderenfalls auf 0 gesetzt.

Viel Spaß!

P.S.
Ich hatte bei INPUT a$ echte Schwierigkeiten, das Programm mit BREAK = 
SymbolShift+SPACE = ESC noch abzubrechen. Ich empfehle Dir erst einen 
SAVE, bevor Du es ausführst ;-)

P.P.S.
Ein Fehler ist mir gerade aufgefallen: Es muss natürlich
1
130 IF b$ < "0" OR b$ > "9" ....
heißen. Also kleiner/größer statt kleiner-gleich/größer-gleich

: Bearbeitet durch Moderator
von Olaf (Gast)


Lesenswert?

> Im ZX-128K-Basic gibts die praktische Renumber-Funktion.

Gott! Die verwoehnte Jugend mal wieder. Unsereins musste seinen 16k 
Spektrum noch selbst auf 48k aufruesten und die Assemblerprogramm in 
eine Remzeile poken. :-D

Olaf

von Jan (Gast)


Lesenswert?

Hallo Frank,

danke für die Lösungen. Die Lösung mit den INKEY$ funktioniert 
prinzipiell, sie  hat aber einige Nachteile.
Nach jedem Drücken einer Ziffer schreibt er die Ziffer in die nächste 
Zeile.
Mann müsste in der Zeile 50 PRINT AT verwenden anstatt von PRINT.
und dann auch noch die Anzahl der Ziffer zählen für die Position von 
PRINT AT, und dann noch die Die Backspace-Taste abfangen…


>damit die Tastatur nicht sofort "repetiert"

unschön, das habe ich auch beobachtet.

Die zweite Lösung :
>Die Subroutine ab 100 checkt, ob a$ numerisch ist. Wenn ja, wird n auf
>1, anderenfalls auf 0 gesetzt.

Ich glaube das ist die saubere Lösung. Ich werde es später ausprobieren.

>Ich hatte bei INPUT a$ echte Schwierigkeiten, das Programm mit BREAK =
>SymbolShift+SPACE = ESC noch abzubrechen. Ich empfehle Dir erst einen
>SAVE, bevor Du es ausführst ;-)

Zum Code-schreiben/debuggen benutze ich VS-Code. Da gibt es ein sehr 
schönes plug-in, NextBASIC.
Es hat ein tolles feature, es generiert die TAP datei aus dem Basic 
code.

Vielen Dank für die Hilfe,

Grüße,
Jan

von c-hater (Gast)


Lesenswert?

Jan schrieb:

> Nach jedem Drücken einer Ziffer schreibt er die Ziffer in die nächste
> Zeile.

Vieleicht hilft dies:

https://zxbasic.readthedocs.io/en/docs/print/

von Schlaumaier (Gast)


Lesenswert?

10 ee$ = ""
20 i$ = inkey$
30 if i$ = chr$(13) then goto 100
35 if i$ = " " then goto 20
40 ee$ = ee$ + e$
50 goto 20

100 nr = val(ee$)

So machte man das damals

In der "Schleife" wird permanent die Tastatur abgefragt. Der Tastendruck 
als STRING in der Variable i$ gespeichert. RETURN = Chr$(13) beendet die 
"Schleife" und macht mit Zeilen-Nr. 100 weiter.

In zeile 100 wird NR als Zahl durch die Umwandlung des zusammen 
gesetzten String erzeugt.

Das ganze nannte man Spagetti-Code-Programmierung. Weil du wild durch 
das Programm springen konntest. Und dich irgendwann selbst verhaspelst.

Ach ja, du kannst übriges auch nur Reaktionen auf bestimmte Tasten 
erzeugen.

Ich habe damals auf den Spectrum eine perfekte Eingaberoutine mit INKEY$ 
geschreiben, inkl. Pharser.  Poke musst du nur anwenden wenn du gewissen 
Sondertasten blockieren willst.

von Schlaumaier (Gast)


Lesenswert?

Nachtrag :

45 print at 4,6, ee%

Zeigt den eingebenen Text in Zeile 4, ab Position 6 an.

ON ERROR brauchte damals kein Mensch. Da konnten die Programmierer noch 
programmieren so das keine Fehler auftraten. ;)))

von foobar (Gast)


Lesenswert?

> LET d= VAL q$

Mal mit Klammern probiert?
1
  LET d=VAL(q$)

von Schlaumaier (Gast)


Lesenswert?

wow. den LET befehl habe ich tatsächlich vergessen. Ist auch verdammt 
lange her und nur Sinclair nutzte den soweit ich mich erinnere.

von Olaf (Gast)


Lesenswert?

> lange her und nur Sinclair nutzte den soweit ich mich erinnere.

Ich glaub woanders konnte man den weglassen wenn man wollte. Aber beim 
Spektrum musste man die Befehle nicht Buchstabe fuer Buchstabe 
eintippen, da konnte man sich wohl etwas mehr Text erlauben.

Olaf

von Jan (Gast)


Lesenswert?

Schlaumaier schrieb:
1
10 ee$ = ""
2
20 i$ = inkey$
3
30 if i$ = chr$(13) then goto 100
4
35 if i$ = " " then goto 20
5
40 ee$ = ee$ + e$
6
50 goto 20
7
8
100 nr = val(ee$)

>So machte man das damals

an Welcher Stelle werden Tasten ungleich  0..9 ausgeschlossen?
mit der Zeile 35 wird space ausgeschlossen. ?

in der Zeile 100 darf ee$ nur die Ziffern beinhalten, sonst kommt die 
Fehlermeldung und Stop

von Peter M. (r2d3)


Lesenswert?

Hallo Schlaumaier,

Schlaumaier schrieb:
> 10 ee$ = ""
> 20 i$ = inkey$
> 30 if i$ = chr$(13) then goto 100
> 35 if i$ = " " then goto 20
> 40 ee$ = ee$ + e$
> 50 goto 20
>
> 100 nr = val(ee$)
>
> So machte man das damals

das ist wahrer Programmkot! Noch nicht einmal sieben Zeilen kriegst Du 
zum laufen. Da kann man nur hoffen, dass Du nichts mit kritischen 
Strukturen zu tun hast.

Tip:
https://www.koeln-lotse.de/2018/09/23/dreimol-null-es-null-bliev-null-der-lehrer-welsch/

: Bearbeitet durch User
von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Hi Jan,

Jan schrieb:

> Nach jedem Drücken einer Ziffer schreibt er die Ziffer in die nächste
> Zeile.

Weil Du das Semikolon am Ende des PRINT-Statements vergessen hast, schau 
Dir nochmal mein Beispiel an ;-)

> Mann müsste in der Zeile 50 PRINT AT verwenden anstatt von PRINT.

Nein, nicht notwendig.
1
PRINT a$;
positioniert den Cursor hinter das letzte Zeichen.

> Ich glaube das ist die saubere Lösung.

Ja, die ist auf jeden Fall besser.

> Zum Code-schreiben/debuggen benutze ich VS-Code. Da gibt es ein sehr
> schönes plug-in, NextBASIC.
> Es hat ein tolles feature, es generiert die TAP datei aus dem Basic
> code.

Nett ;-)

von Peter M. (r2d3)


Lesenswert?

Hallo Jan,

Jan schrieb:
> an Welcher Stelle werden Tasten ungleich  0..9 ausgeschlossen?

Gar nicht.

> mit der Zeile 35 wird space ausgeschlossen. ?

Ja, aber das ist wegen eines Fehlers hier sowieso überflüssig.

> in der Zeile 100 darf ee$ nur die Ziffern beinhalten, sonst kommt die
> Fehlermeldung und Stop

Schau' Dir den Kot an. Der funktioniert nicht. Siehst Du, warum?
Wenn Du es gleich richtig machst, brauchst Du keine Abfrage von " ".
Schau' Dir an, was Dir Martin V. und Frank M. präsentiert haben.

Alternativ kannst Du die Zeichenkette mit ASC() in eine Zahl wandeln und 
gucken, dass der ASCII-Code im Intervall [48;57] liegt. Das ist quasi 
die numerische Variante des String-Vergleichs der anderen Foristen.
Einen besonderen Wert solltest Du auch noch zulassen, damit das Ende der 
Eingabe erkannt wird, z.b. die Return-Taste (Code:13 "CR").

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Olaf schrieb:
> Aber beim Spektrum musste man die Befehle nicht Buchstabe fuer Buchstabe
> eintippen, da konnte man sich wohl etwas mehr Text erlauben.

Das hat etwas mit dem Token-Parser vom ZX-Basic zu tun. Der erste 
Tastendruck zu Beginn eines Basic-Statements erzeugt grundsätzlich ein 
Token. Daher war auch bei der Zuweisung das Token "LET" (Taste "l") 
obligatorisch. Man hätte gar keinen Einzelbuchstaben am Anfang eines 
Basic-Statements eingeben können.

von Peter M. (r2d3)


Lesenswert?

Schlaumaier schrieb:
> Ich habe damals auf den Spectrum eine perfekte Eingaberoutine mit INKEY$
> geschreiben, inkl. Pharser.  Poke musst du nur anwenden wenn du gewissen
> Sondertasten blockieren willst.

Meine Eingaberoutine umfasste nicht nur einen Pharser, sondern auch 
einen Farter und einen Phaser. Heraus kam der perfekte Kot. :)

Du bist echt ne Konifere. War bestimmt eine Syphillis-Arbeit für Dich!

: Bearbeitet durch User
von Schlaumaier (Gast)


Lesenswert?

Jan schrieb:
> mit der Zeile 35 wird space ausgeschlossen. ?

RICHTIG.

10 ee$ = ""
20 i$ = inkey$
30 if i$ = chr$(13) then goto 100
35 if i$ = " " then goto 20

40 if i$ ="1" then goto 50
41 if i$ ="2" then goto 50
42 if i$ ="3" then goto 50

44 rem u.s.w.

49 goto 20  : rem springt zurück und verhindert erweiterung der Eingabe

50 ee$ = ee$ + e$

50 goto 20

100 let nr = val(ee$)

Ganze Blöcke kannst du mit der ASC-Funktion abfragen und blocken.

zb.
43  if code(i$) > 50 and code(i$) < 60 then goto 50 : Rem Code liefert 
den ASCII-Wert eines 1 Stelligen String

Peter M. schrieb:
> Du bist echt ne Konifere. War bestimmt eine Syphillis-Arbeit für Dich!

War es. Aber sie war eine Prüfungsaufgabe die ich selbstverständlich mit 
Bestnote abgeschlossen habe. Da meine ersten Professionellen Programme 
auch in Basic liefen, habe ich diese Routine in ca. 4 Programmsprachen 
verwendet.

Gewandelte habe ich sie erst, als die Zeilen-Nummern und Sprünge 
abgeschafft wurden. Der Parser und die Technik des obigen Code benutze 
ich heute noch in VB.

Da heisst es dann.

 Private Sub Text1_KeyPress(sender As Object, e As 
System.Windows.Forms.KeyPressEventArgs) Handles Text1.KeyPress


if e.keychar = 13 then
  call neuberechnen
end if

if instr(text1.text,".") then  ' verhindert 2 x komma in einen
   e.keychar = ""
end if

end sub

Ich habe auf einen ZX-81 gelernt als noch jeder sagte :"Computer sind 
Kinderspielzeug". Den Typ vom Arbeitsamt den ich sagte ich will was mit 
Computer machen, sagt : 'Sie wollen sich mit Kinderspielzeug 
beschäftigen"
12 Jahre später habe ich sein Rechner von ein guten Anzahl Viren befreit 
und die Bilder seiner Enkel gerettet. ;)  So viel dazu.

von Schlaumaier (Gast)


Lesenswert?

Peter M. schrieb:
> Alternativ kannst Du die Zeichenkette mit ASC() in eine Zahl wandeln und
> gucken, dass der ASCII-Code im Intervall [48;57] liegt. D

Du benutze in Text-Operationen mathematischen Funktionen. GENIAL..

@TO

Gib bei goggle folgendes ein.    befehl basic spectrum

Da ist dann ein Link zu einer Dataset..... . Da ist das Handbuch des 
Spectrum zu lesen.

von Jan (Gast)


Lesenswert?

Frank schrieb :
>Weil Du das Semikolon am Ende des PRINT-Statements vergessen hast, schau
>Dir nochmal mein Beispiel an ;-)

Stimmt, ich habe das Semikolon übersehen und ich kannte das nicht mit 
dem optionalen Semikolon beim print.

Nun habe die Lösung mit INPUT ausprobiert. basic2.png
Dort war noch ein kleiner Fehler. Hat man direkt return gedrückt ohne 
vorher einen Zeichen einzugeben gab es einen Fehler, da die Stringlänge 
Null betrug.
ich habe die Zeile 105 eingefügt :

105 IF l=0 THEN  PRINT "Falsche Eingabe": LET n=0: RETURN

Ich habe noch die Möglichkeit geschaffen negative Zahlen einzugeben.
Es sieht dan so aus :
1
10 INPUT a$
2
20 GO SUB 100
3
30 IF n=1 THEN PRINT 2* VAL (a$)
4
40 GO TO 10
5
100 IF a$ = "-" THEN  PRINT "Falsche Eingabe": LET n=0: RETURN
6
102 LET l = LEN (a$)
7
105 IF l=0 THEN  PRINT "Falsche Eingabe": LET n=0: RETURN
8
110 FOR i=1 TO l
9
120 LET b$=a$(i TO i)
10
125 IF i=1 AND b$ = "-" THEN GO TO 140
11
130 IF b$ < "0" OR b$ > "9" THEN PRINT "Falsche Eingabe": LET n=0: RETURN
12
140 NEXT i
13
150 LET n=1
14
160 RETURN

Diese Eingabefunktion ist bombensicher und genügt den Anforderungen wo 
sie später verwendet wird.

Vielen Dank allen für die Anregungen und Hilfe.

Gruss,
Jan

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Jan schrieb:
> Stimmt, ich habe das Semikolon übersehen und ich kannte das nicht mit
> dem optionalen Semikolon beim print.

Ein Semikolon lässt den Cursor hinter dem letzten Zeichen stehen, ein 
Komma tabuliert auf Spalte 16, also Zeilenmitte.

Beispiele:
1
LET a$ = "World"
2
PRINT "Hello "; a$
3
PRINT "Hello ", a$

Übrigens gilt dasselbe für INPUT bzgl. Semikolon und Komma, z.B.
1
INPUT "Hello "; a$
2
INPUT "Hello ", a$

> Nun habe die Lösung mit INPUT ausprobiert. basic2.png
> Dort war noch ein kleiner Fehler. Hat man direkt return gedrückt ohne
> vorher einen Zeichen einzugeben gab es einen Fehler, da die Stringlänge
> Null betrug.

Stimmt, ist mir nachher auch aufgefallen, aber ich dachte mir schon, 
dass Du das noch selbst herausfindest ;-)

> ich habe die Zeile 105 eingefügt :
> 105 IF l=0 THEN  PRINT "Falsche Eingabe": LET n=0: RETURN

Gut.

> Diese Eingabefunktion ist bombensicher und genügt den Anforderungen wo
> sie später verwendet wird.

Freut mich, ich bin schon gespannt auf die Endversion von FUNMATH. Ich 
habe oben auch schon was von vierstelligen Zahlen gelesen. Hast Du die 
Ziffern-Zeichnungen über Draw tatsächlich vierstellig aufgebohrt? Ich 
nehme an, dass Du dafür den ursprünglichen Code von FUNMATH ziemlich 
umkrempeln musstest.

> Vielen Dank allen für die Anregungen und Hilfe.

Viel Spaß weiterhin mit STECCY ;-)

von Jan (Gast)


Lesenswert?

Danke für die Infos,

>Freut mich, ich bin schon gespannt auf die Endversion von FUNMATH. Ich
>habe oben auch schon was von vierstelligen Zahlen gelesen. Hast Du die
>Ziffern-Zeichnungen über Draw tatsächlich vierstellig aufgebohrt? Ich
>nehme an, dass Du dafür den ursprünglichen Code von FUNMATH ziemlich
>umkrempeln musstest.

Die Zahlen können dreistellig sein, und ich habe auch die Division 
eingeführt.(Für zwei vierstellige Zahlen reicht der Platz dort nicht.
Kopfrechnen bis Tausend sollte aber ausreichen)
Für das Zeichnen der Zahlen brauche ich eine Modulo Division,
leider ist sie nicht im Sinclair Basic vorhanden.

https://zxbasic.readthedocs.io/en/docs/operators/
Note: mod operator returns the modulus (the reminder) of x / y.
E.g. 12 mod 5 = 2. It does not exist in Sinclair BASIC.
schade


Das Zeichnen der Zahlen sieht Folgendermassen aus :
Die Zahlen werden auch "mittig und ohne führende Nullen" positioniert, 
dafür wird die Anzahl der vorhandenen Stellen berücksichtigt.
1
 2010 LET n=INT (RND*999)
2
 2020 LET m=INT (RND*999)
3
 ..
4
 ..
5
 2028 REM nh - Hunderter, nz - Zehner, ne - Einser
6
 2029 LET nh=INT (n/100): LET nz=INT ((n-(nh*100))/10): LET ne=n-(nh*100)-(nz*10)
7
 2033 IF n < 10 THEN LET a=35: GO SUB ne+100
8
 2034 IF n < 100 THEN IF n > 9 THEN LET a=18: GO SUB nz+100: LET a=a+33: GO SUB ne+100
9
 2035 IF n > 99 THEN LET a=2: GO SUB nh+100: LET a=a+33: GO SUB nz+100: LET a=a+33: GO SUB ne+100

Ich bin jetzt auf ein anderes Problem gestossen.

Die mit RND generierten Zahlen sind nach jedem Programmstart immer 
gleich.
D.h. die gestellten aufgaben sind beim jeden Run gleich.
Mein Sohn wird sich die Antworten merken :- )

Der Pseudozuffalsgenerator wird anscheinend immer mit dem gleichem Wert 
initialisiert.

Ich muss anscheinend RANDOMIZE [init_number] beim start ausführen.
Wo nehme ich eine Zufallszahl für die Initialisierung  her?

Eigentlich ist es seltsam da wikipedia sagt:
https://en.wikipedia.org/wiki/Sinclair_BASIC

RANDOMIZE   [number]
Initializes the random number generator;
if used without a number (or with 0),
it does this based on the computer's internal clock,
else it uses the number supplied, which must be in the range 
[1,65535][53]

Was ist nun mit dem internen clock?

>Viel Spaß weiterhin mit STECCY ;-)

Das macht schon Spaß.

Grüße und gute Nacht

von Jan (Gast)


Lesenswert?

Jan schrieb :

RANDOMIZE   [number]
>Initializes the random number generator;
>if used without a number (or with 0),
>it does this based on the computer's internal clock,
>else it uses the number supplied, which must be in the range
>[1,65535][53]

Jetzt beim lesen denke ich es verstanden zu haben.
Wird Randomize gar nicht aufgerufen dann wird der Zufallsgenerator nicht 
explizit initialisiert.
Oder besser gesagt er wird mit dem gleichem default Wert initialisiert.
Ich muss es einfach mal einmal ohne Parameter aufrufen dann sollte es 
mit der internen Zeit initialisiert werden

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Jan schrieb:
> Für das Zeichnen der Zahlen brauche ich eine Modulo Division,
> leider ist sie nicht im Sinclair Basic vorhanden.

MOD gibts zwar nicht, geht aber trotzdem:

Modulo-Anteil der Division (Beispiel 17 mod 10):
1
LET a = 17
2
LET m = a - 10 * INT(a/10)

In m steht anschließend 7.

EDIT:
Man kann sich auch eine eigene Funktion m (Modulo) schreiben:
1
10 DEF FN m(a,b) = a - b * INT (a/b)
2
20 LET x = FN m(17,10)
3
30 PRINT x

Jan schrieb:
> Ich muss es einfach mal einmal ohne Parameter aufrufen dann sollte es
> mit der internen Zeit initialisiert werden

So ist es. Wenn Du RANDOMIZE ohne Startwert aufrufst, ist die 
Zahlenreihenfolge nicht reproduzierbar. Mit Startwert ist sie 
reproduzierbar.

: Bearbeitet durch Moderator
von Jan (Gast)


Angehängte Dateien:

Lesenswert?

Frank schrieb:
>MOD gibts zwar nicht, geht aber trotzdem:

So ähnlich habe ich es auch nachgebildet.
1
2029 LET nh=INT (n/100): LET nz=INT ((n-(nh*100))/10): LET ne=n-(nh*100)-(nz*10)

Das mit den FN kannte ich aber noch nicht.
Ich muss mich da noch einarbeiten.

Ich glaube  NextBASIC Plug-in  könnte sehr viele nützliche Funktionen 
bieten.
Ich habe bis jetzt nur das generieren der TAP-Datei benutzt.

Mir ist noch eine weitere Idee für die Eingabefunktion eingefallen.

Der user soll das Ergebnis der Rechenaufgabe eingeben, dafür hat er nur 
eine bestimmte Zeit.
Es wird ein „Beep-Takt“ generiert, der zu Ende immer schneller wird. Dem 
User wird damit signalisiert das die Eingabezeit bald abgelaufen ist.
Schaft er die Eingabe nicht in dieser Zeit, so endet die Eingabe und es 
wird als falsche Antwort bewertet.

Darauf folgt die nächste Aufgabe…

Wie könnte man solch eine Eingabe realisieren?
Mit INPUT wird das nicht gehen, da INPUT alles anhält.
Man müsste Regelmäßig in einer Schleife die Tastatur abfragen und zwar 
ohne zu Pollen.
Vielleicht mit PEEK?

Hat jemand eine Idee?
Das macht langsam immer mehr Spaß.

Gruss,
Jan

von Dergute W. (derguteweka)


Lesenswert?

Jan schrieb:
> Hat jemand eine Idee?

Mit INKEY$ iirc.
Aber das waren dann die Geschichten, wo mir schon vor fast 40 Jahren 
aufm ZX81 klar wurde, dass da mit BASIC Ende Gelaende ist und ich 
dringend Assembler lernen muss.

Gruss
WK

von Frank M. (ukw) (Moderator) Benutzerseite


Angehängte Dateien:

Lesenswert?

Jan schrieb:
> Wie könnte man solch eine Eingabe realisieren?
> Mit INPUT wird das nicht gehen, da INPUT alles anhält.

Das geht mit INKEY$ - wie ich oben schon mal beispielsweise anriss. Denn 
INKEY$ wartet nicht, wenn man keine Taste drückt, sondern gibt einen 
Leerstring zurück.

Damit der Input dabei nicht wie verrükt repetiert und man direkt die 
Eingabe 111111111111 erzeugt, obwohl man nur kurz die Taste gedrückt 
hat, kann man warten, bis der User die Taste wieder loslässt - halt eine 
softwaremäßige Entprellung.

Das geht dann so wie im Bild gezeigt. Die Prüfung auf Ziffern und evtl. 
die Behandlung der BACKSPACE-Taste (CHR$(8)) musst Du natürlich noch 
selbst einbauen ;-)

Zwischen den Zeilen 10 und 20 kannst Du den ZX-Spectrum-Timer per PEEK 
abfragen.

P.S.

Wie schnell/langsam sind die DRAW-Sequenzen für die großen Ziffern in 
FUNMATH? Ich habe jetzt in STECCY ein Feature eingebaut, mit welchem man 
den Spectrum in den TURBO-Mode per Basic-Befehl OUT umschalten kann.

Dann läuft der STECCY mit x-facher Geschwindigkeit. Ebenso kann man den 
Spectrum per OUT-Befehl wieder auf Normalgeschwindigkeit zurückschalten, 
wenn zum Beispiel alle Ziffern per DRAW fertig gemalt sind. 
Interessiert? Das Feature kommt im nächsten Release, vermutlich dieses 
Wochenende.

: Bearbeitet durch Moderator
von Frank M. (ukw) (Moderator) Benutzerseite


Angehängte Dateien:

Lesenswert?

Hier noch eine kürzere Variante, welche auf die Verwendung von b$ 
verzichtet wird und der Return-Wert von INKEY$ direkt geprüft wird.

P.S.

Bitte auf alle Semikolons bei PRINT achten ;-)

: Bearbeitet durch Moderator
von Klaus R. (klara)


Lesenswert?

Jan schrieb:
> Wie kann ich es machen das das Programm nicht anhält?

Du gehst am besten zum Lichtschalter und machst die Langfeldröhre an. 
Dann geht es weiter und Du tippst das Programm wieder neu ein.
mfg klaus

von Jan (Gast)


Angehängte Dateien:

Lesenswert?

Frank schrieb :

>Das geht mit INKEY$ - wie ich oben schon mal beispielsweise anriss. Denn
>INKEY$ wartet nicht, wenn man keine Taste drückt, sondern gibt einen
>Leerstring zurück.

Danke für die Infos.
Ich werde inkey und inkey2 ausprobieren.
(heute aber nicht mehr)

>Wie schnell/langsam sind die DRAW-Sequenzen für die großen Ziffern in FUNMATH?

Ich habe ein CountDown (115 to 0) Testprogramm mit dieser Ziffernausgabe 
geschrieben.Es dauert ca. 65sec, im Turbo mode (F3) ca. 45sec.

>Ich habe jetzt in STECCY ein Feature eingebaut, mit welchem man den Spectrum in 
>den TURBO-Mode per Basic-Befehl OUT umschalten kann.

Das könnte man nutzen um an manchen stellen zu beschleunigen. cool

Grüße und gute Nacht,
Jan

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Hi Jan,

STECCY 1.5.2 ist draußen. Hier kannst Du per Software (z.B. in Basic) 
nicht nur den Turbo-Modus einschalten, sondern auch spezielle ROM-Hooks, 
welche die PLOT- und DRAW-Befehle, die Du in FUNMATH verwendest, 
nochmals beschleunigen.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.