1 Ostatnio edytowany przez Mq (2019-11-03 17:03:59)

Mam taki kłopot w Turbo Basicu, ale nie wiem czy może dotyczyć też zwykłego Basica.
Mam w programie coś takiego w podprogramie po GOSUB:

DIM A$(1)
...

K=0
INPUT A$
IF A$="X" THEN K=1
? A$,K
RETURN

Kłopot polega na tym, że czasami warunek się sprawdza, a czasami nie chce zaskoczyć. Program w pętli działa, ciągle wyświetlając od nowa INPUT, wprowadzam sobie jakiś znak i w 90% przypadków znak jest wprowadzony, ale od czasu do czasu pomimo, że go wprowadzam, to ? wyświetla mi nic dla A$ a K=0, chociaż powinno być 1
Czy jest jakiś znany błąd związany z poleceniem INPUT, albo jakieś zastrzeżenia co do użycia tego polecenia np. w pętlach, albo w podprogramach GOSUB?

Edit: wygląda na to, że znalazłem pewną prawidłowość, ale i tak bym chciał to jakoś wyjaśnić.
Otóż w swoim programie mam szereg warunków:
IF A$="X" THEN K=1
IF A$="Y" THEN K=2
IF A$="Z" THEN K=3
Problem zaczął się jak chciałem jeszcze sprawdzać wciśnięcie samego Return. Dodałem warunek:
IF A$=" " THEN K=9
Próbowałem też IF A$="" THEN K=9
W obu przypadkach działa tak sprawdzanie pustego stringu - ale właśnie czasem działa a czasem nie, a oprócz tego dodanie takiego warunku powoduje że wszystkie pozostałe "normalne warunki" też zaczynają działac czasami, a czasami nie.
Ciekawe...

2

... a wrzuć przed INPUT A$ to:

POKE 764,255

Kontakt: pin@usdk.pl

3

Sprawdziłem, nie pomaga. Wiem co robi, przywraca 255 w buforze klawiatury po wciśnięciu jakiegoś klawisza, bo tam zostaje ostatnio wciśnięty klawisz. Nie pomyślałem o tym, ale tak jak mówię, teraz przetestowałem i nic to niestety nie daje w tym wypadku.

Testowałem teraz jeszcze wielokrotnie temat na różne sposoby i widzę, że problem pojawia się jak próbuję sprawdzić czy nie ma pustego stringa po wciśnięciu Return na INPUT. Może w takim wypadku jest coś dziwnego/losowego w A$ czasami, bo właśnie w wypadku jak testuję taki warunek, to również inne warunki potem się sypią.

4

10 DIM A$(1)
20 INPUT A$
30 K=0
40 IF A$="A" THEN K=1
50 IF A$="B" THEN K=2
60 IF A$="" THEN K=3
70 ? A$;K
80 GOTO 20

Działa stabilnie i przewidywalnie.

Czy DIM robisz w środku procedury przed INPUT? Za pomocą DIM nie można redeklarować zmiennej więc wyleci wtedy błąd - trzeba to zrobić tylko raz na początku programu. Jeśli go złapiesz TRAP-em, to nie zauważysz problemu.

hex, code and ror'n'rol
niewiedza buduje, wiedza rujnuje

5

Próbowałeś IF LEN(A$)=0 ?

https://www.youtube.com/watch?v=jofNR_WkoCE

6

@mono, strukturę programu mam dokładnie taką jak napisałeś w przykładzie. Z tym że ja ten program mam dłuuuugi na kilkaset linii i jest to trochę rozstrzelone, ale DIM jest na początku, wywoływane tylko raz, kolejność wszystkich działań jest taka jak u Ciebie.

@Fox, dzięki za przypominajkę, zapomniałem już że się tak sprawdzało w Basicu - przypominam sobie dawne czasy po wielu latach, a mam przyzwyczajenia ze współczesnych języków, głównie z C i podobnych.
Jednak przy tak postawionym warunku mam te same problemy, te same objawy.

Ciekawe jest to, że ten problem pojawia mi się dość rzadko, raz na kilkadziesiąt wprowadzonych liter, lub Returnów.

Testuję to pod Altirrą, może ona robi jakiś problem?
Dziwna sprawa, bo na takim krótkim programiku jak te powyższy od mono nie udaje mi się tego błędu odtworzyć, a dzieje się na długim programie. Mam w nim też bardzo dużo GOSUB-ów jednych w drugich i gdzieś tam głęboko w nich siedzi dopiero ten INPUT A$. Może są jakieś granice stosu i coś się przez to kaszani ze zmiennymi?

7

A musisz mieć warunek tekstowy? Pod Turbo Basikiem użyj GET KEY po prostu (zamiast KEY można dowolną zmienną podstawić, ale KEY się pamięta) - jest to kod wciśniętego klawisza. Potem wyzeruj klawisz i tyle. ha, instrukcja zwraca kos wciśniętego klawisza.
A w swoim programie dodaj po input testowo PAUSE %1 (lub "pętlę" w Basicu liczącą od zera do jednego, pustą). Po mojemu za szybkie wywołanie, ale mogę się mylić.

Sikor umarł...

8

Dzięki Sikor:-) GET załatwia mi temat super, uprościł mi program, ulepszył i w ogóle jest gites:-) A problem który miałem zniknął.
Niemniej jednak nie wiem co mogło być problemem, pętle opóźniające i PAUSE też przetestowałem, ale nie pomagało.
Skoro jednak GET się sprawdza w moim przypadku idealnie, to nie będę już drążył.

9

Fox napisał/a:

Próbowałeś IF LEN(A$)=0 ?

Czy jest jakaś sytuacja kiedy A$="" nie zadziała, ale zadziała LEN(A$)=0 ?

hex, code and ror'n'rol
niewiedza buduje, wiedza rujnuje

10

Polecam się ;) A sprawa godna zbadania ;)

Sikor umarł...

11

@mono: u mnie oba te IF-y działały tak samo. Jednak gdy zastosowałem którykolwiek z nich, to mój problem występował tak samo.

@Sikor: też myślę że jest to warte zbadania, zwykle jestem dociekliwy w takich kwestiach, ale przesiedziałem nad tym dzisiaj chyba ze trzy godziny i potrzebuję rozwiązania skutecznego, żeby działało, a GET mi to zapewnił - trochę już opadłem nad tym z sił.

12 Ostatnio edytowany przez Sikor (2019-11-03 20:41:07)

Ciekawe jak by zadziałało z ELSE...
====
Edyta

Edyta napisał/a:

1 DIM A$(1)
2 Z=0
10 GOSUB 100
12 GOTO 10
100 K=0
101 INPUT A$
102 IF A$="X" THEN K=1
103 Z=Z+1:? A$,K,Z
104 RETURN

Na 150 wywołań działa prawidłowo. Ciekawe, czy czegoś w kodzie nie masz... Ważne, że GET działa.

Sikor umarł...

13

Dobra, nowy wpis, aby nie umknął"

1 DIM A$(1)
2 Z=0
10 GOSUB 100
12 GOTO 10
100 K=0
101 INPUT A$
102 IF A$="X" THEN K=1
103 IF ASC(A$)=155 THEN K=9
104 Z=Z+1:? A$,K,ASC(A$),Z
105 RETURN

Odpal ten program. Jak dałeś A$=" " to oczywiście sprawdzasz spację, nie RETURN. Jak widać w załączonym kodzie - samo wciśnięcie RETURN powoduje przepisanie ostatnio wciśniętego klawisza (ASC(A$) nam to sprawdza), za to... Nie przypisuje zmiennej A$ żadnej wartości. Widać to w tym kawałku kodu. Niestety, poke 764,255 nie wymazuje ostatniego znaku (czyli chyba jest trzymany cały czas na stosie lub w buforze klawiatury, raczej w tym drugim). Nie pamiętam sposobu na jego wyczyszczenie.

Sikor umarł...

14

... na MIŁOŚĆ BOSKĄ nie używajcie GOSUB, jak macie:

PROC, ENDPROC, EXEC

:)

Kontakt: pin@usdk.pl

15 Ostatnio edytowany przez Mq (2019-11-04 00:05:56)

@Sikor, no to może jakiś taki zbieg właśnie u mnie zachodził. Ale u mnie kod żyje, a jak nad czymś siedzę, to po kilku godzinach mam już zupełnie coś innego niż miałem na początku, więc nawet nie mam już jak swojego błędu odtworzyć.

Natomiast odpaliłem Twój programik, zmodyfikowałem mu tylko linię, żeby po return wpisywał K=9.

1 DIM A$(1)
2 Z=0
10 GOSUB 100
12 GOTO 10
100 K=0
101 INPUT A$:IF A$="" THEN K=9
102 IF A$="X" THEN K=1
104 Z=Z+1:? A$,K,ASC(A$),Z
105 RETURN

READY
RUN
?X
X         1         88        1
?A
A         0         65        2
?
          9         65        3
?

I faktycznie to będzie ten problem.
Za pierwszym razem wpisałem X i się K ustawiło na 1,
za drugim razem wpisałem A i się K ustawiło na 0,
za trzecim razem dałem tylko return - i zadziałał warunek sprawdzający A$="", ale ASC(A$) pokazał kod poprzedniego klawisza, czyli A.
No i tu jest pies pogrzebany, mamy z jakiegoś powodu sytuację, że A$ jest jednocześnie pusty i niepusty. Nie mam pod ręką żywego Atari, żeby sprawdzić, czy też się tak zachowa. Testy robiłem na Altirra 3.20 w zwykłym Basicu.

@Pin, PROC i EXEC jest fajny, przejrzystość kodu bez dwóch zdań itd. Jak robisz pojedynczy skok, to też PROC EXEC zajmie Ci mniej pamięci niż GOSUB RETURN, bo PROC/ENDPROC zajmuje mniej niż RETURN. Ale za to EXEC zajmuje więcej niż GOSUB, więc jak masz do wykonania dziesiątki skoków do tego samego podprogramu, to każdy EXEC zajmuje więcej pamięci niż GOSUB i zaczyna program puchnąć. Akurat to co grzebię jest na tyle duże, że zależy mi na pamięci i każdy bajt się liczy, więc robię GOSUB.

16

rozgrzeszony ;)

Kontakt: pin@usdk.pl

17

@Mq, po prostu zaciekawił mnie temat. Zamiast tego pewnie zadziała zbadanie długości A$ - i przy zerowej dać 9, bo tak to chyba działa w tym wypadku. Swoją drogą ciekawa sprawa.

Sikor umarł...

18

Tak, tylko, że nawet gdy to robiłem, to mi się działy jaja. Nie mam już tego problematycznego kodu, ale myślę, że kłopot polegał na tym, że sprawdzałem sobie w szeregu IF-ami po kolei te warunki, tylko że w różny sposób. Prawdopodobnie mój problem się powtarzał dlatego, że na początku sprawdzałem w pierwszej linii Return, więc obojętnie czy sprawdzałem LEN(A$)=0, czy też A$="", to ten warunek prawdopodobnie działał poprawnie i przypisywał odpowiednią wartość pod moją zmienną wynikową. Tylko że po sprawdzeniu tego warunku leciały jeszcze warunki dot. poszczególnych wprowadzonych liter i prawdopodobnie któryś z tych warunków również zwracał prawdę i nadpisywał mi zmienną wynikową inną wartością. Stąd miałem bałagan. Myślę, że temat jest wyjaśniony.

19

Tak. Przypomniało mi się jeszcze, że ważna często była kolejność działań w IF pod Basiciem - tak ku potomności.
ok, myślę, że ten wątek można zamknąć - jak myślisz Mq?

Sikor umarł...

20

Tak, temat jest wyjaśniony, wiemy skąd się brały moje błędy.
Robiłem IF sprawdzający czy jest pusty string, w sensie, że wciśnięto Return, a następnie kolejny IF sprawdzający co jest w A$.

Jednak zastanawiające jest to, że mamy LEN(A$)=0, a pomimo to jak wyświetlimy ASC(A$), to wyświetli nam się kod znaku wcześniej tam wprowadzonego. Ciekawe z czego wynika taki błąd, czy jest to błąd Basica? Tak czy owak samo zachowanie jest wyjaśnione, więc należy na to uważać podczas programowania.

21

To błąd BASIC-a - ASC nie sprawdza długości ciągu i bierze zawsze pierwszy znak ze zmiennej tekstowej (czyli starą wartość, albo nieustaloną jeśli zmienna nie była zainicjalizowana wcześniej w pamięci). Uzupełniłem Atariki: http://atariki.krap.pl/index.php/Atari_ … ri%20BASIC

hex, code and ror'n'rol
niewiedza buduje, wiedza rujnuje

22

Dzięki mono za uzupełnienie, dzięki Mq udało się coś dodać do atariki ku potomnym ;)

Sikor umarł...

23

mono napisał/a:

Czy jest jakaś sytuacja kiedy A$="" nie zadziała, ale zadziała LEN(A$)=0 ?

Wygląda, że jest jakiś problem z porównywaniem stringów. Zaproponowałem więc w ciemno workaround.

https://www.youtube.com/watch?v=jofNR_WkoCE