RunCPM Speed-Vergleich auf verschiedenen Plattformen

  • Das ist doch eine schöne Vervielfachung im Taktverhältnis der Methusalem-CPUs.

    Mit dem virtuellen BBC Micro (https://bbcmic.ro ) dauert es für 10 Stellen 12,76 s, für 20 Stellen 41,94 s

    Der Inhalt kann nicht angezeigt werden, da du keine Berechtigung hast, diesen Inhalt zu sehen.


    Entfernt man insbesondere die REM-Kommandos aus den inneren Schleifen, wird es nochmal sehr geringfügig schneller.

    Am WE werde ich das mal auf einem echten Acorn Electron beim RCT#29 in Bad Nenndorf probieren.

    Gibt es einen Online-Commodore-Basic-Emulator, den man unter Windows mit Copy-And-Paste füttern kann ?

  • Ich habe jetzt das PI Program nochmal ein bisschen auf IoT BASIC angepasst. Das sieht dann so aus

    Man kann jetzt beliebig viele Stellen berechnen, die Variable @ im Zeile 205 wird verwendet um rauszufinden, wie viel Speicher noch frei ist.

    In Zeile 230 wird die Heap Funktion FIND benutzt, um zu sehen, ob das Array schon da ist und es nötigenfalls mit CLR A() zu löschen.

    360 und 390 nutzen den Modulo Operator % anstelle Division und INT.

    Zeile 620 und 670 zeigen wie man Strings und Zahlen mischt, ohne VAL zu brauchen.

    Kleines Quiz dazu: Warum braucht man in Zeile 620 und 670 die Klammern um den Ausdruck? Wer das weiß, versteht wie der Parser gebaut ist ;-).

    In der Form ist es nochmal ca. 16% schneller. Grund ist vor allem %.

    IoT BASIC hat eine Menge von C geerbt. Es gibt MALLOC um Speicher zu reservieren, EVAL für selbstmodifizierende Programme und auf Arduino. CLR kann Strings und Arrays wieder löschen, analog zu free() in C. Exponentiation geht mit POW(,) statt mit ^.

  • Jedes Leerzeichen, jede Rem-Zeile, jeder zusätzliche Doppelpunkt verändert bei Microsoft-Basic die Laufzeit.

    slenz Das scheint bei IotBASIC nicht anders zu sein und sogar ganz schoen "drastisch" ;)
    Ich habe per SET 12,0 den Startindex auf 0 gesetzt und den "alten" Code genommen - dabei aber im Code die REMs dringelassen.

    Die Ausfuehrungzeit hat sich von 10.x auf 12.x Sekunden erhoeht :(

    Der Inhalt kann nicht angezeigt werden, da du keine Berechtigung hast, diesen Inhalt zu sehen.


    CalcPi mit SET 12,0 und REMs:

    CalcPi mit SET 12,0 aber ohne REMs:

  • Jedes Leerzeichen, jede Rem-Zeile, jeder zusätzliche Doppelpunkt verändert bei Microsoft-Basic die Laufzeit.

    slenz Das scheint bei IotBASIC nicht anders zu sein und sogar ganz schoen "drastisch" ;)
    Ich habe per SET 12,0 den Startindex auf 0 gesetzt und den "alten" Code genommen - dabei aber im Code die REMs dringelassen.

    Die Ausfuehrungzeit hat sich von 10.x auf 12.x Sekunden erhoeht :(

    Klar! Das liegt an der Zeit um ein Token zu interpretieren. Bei IoT-BASIC auf den typischen 8 bit MCU Plattformen wir Arduino ist die Token-Zeit ungefähr 40 Microsekunden und zwar ziemlich konstant. Es wird also alle 40 Microsekunden ein Token aus dem Speicher geholt und verarbeitet.

    Eine REM Zeile bei IoT BASIC ist:

    LINENUMBER 10 (3 bytes)

    TOKEN-REM (1 byte)

    TOKEN STRING LENGTH PAYLOAD (3+payloadsize bytes)

    Es werden also 3 Token Operationen ausgelöst. Dabei ist relativ egal wie lange der String ist, weil der String stets "in place" bleibt, es wird nur ein Pointer kopiert.

    Bei den alten Computern war die Token-Zeit nicht sehr wichtig, weil die Arithmetik so langsam war, dass es weniger auffiel. Bei 32 bit Microcontrollern ist die Arithmetik schnell und die Token-Zeit wird zum Flaschenhals.

    Anders als bei den Microsoft BASICs sind Whitespaces kein Problem, weil die der Tokenisierer entfernt. Auch Zeilennummern im Vergleich zu : sind relativ harmlos, weil jeweils auch nur ein Token.

  • Klar! Das liegt an der Zeit um ein Token zu interpretieren. Bei IoT-BASIC auf den typischen 8 bit MCU Plattformen wir Arduino ist die Token-Zeit ungefähr 40 Microsekunden und zwar ziemlich konstant. Es wird also alle 40 Microsekunden ein Token aus dem Speicher geholt und verarbeitet.

    slenz Das finde ich spannend und auch erstaunlich, dass es bei "so wenigen" REMs auffaellt :)

    Aber wie heisst es "die Mene macht das Gift) - denn hier gibt es auch REMs in Schleifen, das addiert sich dann - ich haette nur nicht gedacht dass es dann bei einer schnellen CPU auf einem Win10-PC dann doch 2 Sekunden von 12 ausmacht.

    Also wenn REMs dann nicht innerhalb der Schleife ;)

  • Würde ich so pauschal nicht sagen, kann man auch für Laufzeit-Themen gebrauchen...

    Das war nur so gemeint, dass wenn man "Speed" will man besser in der Schleife die REMs raus laesst.

    Wenn man die Laufzeit in der Schleife etwas langsamer haben will (z.B. um ein Spiel spielbar zu machen) koennte man auch REMs in Betracht nehmen.

    BTW; Ein REM-Laufzeitvergleich mit dem VGA32 und dem IoTBASIC:

    Ohne REMs waren die 1000 Pi-Stellen bei 284-294 Sekunden.

    Mit REMs liegt die Laufzeit dann bei ca. 354 Sekunden.

  • Ich würde keinem empfehlen, bei größeren, komplexeren Programmen die (meist) sinnvollen Kommentare zu entfernen, es sei denn es ist nicht mehr geplant, das Programm zu erweitern bzw. zu pflegen. Bei solchen Mini-Programmen wie hier im Forum mag das kein Verlust sein, ich habe aber auch BASIC-Programme mit hunderten oder sogar über tausend Zeilen (nicht die Zeilennummer, sondern die Anzahl ist gemeint!), da sind Kommentare essentiell !

    Für den PC benutze ich zur temporären "Optimierung" (passt auch für QBASIC-Quellen) manchmal https://hwiegman.home.xs4all.nl/downloads/remline.bas , damit sind halt automatisch keine REM-Zeilen mehr drin. Aber halt nur für's Ausprobieren.

    "The biggest communication problem is we do not listen to understand. We listen to reply." - Stephen Covey

    Webseite und Blog ist immer noch - seit fast 20 Jahren - online.

  • Das war nur so gemeint, dass wenn man "Speed" will man besser in der Schleife die REMs raus laesst.

    Wenn man die Laufzeit in der Schleife etwas langsamer haben will (z.B. um ein Spiel spielbar zu machen) koennte man auch REMs in Betracht nehmen.

    Schnapp dir mal nen C64 und probiere folgenden Einzeiler aus:

    10 poke 53280,0::::::::::poke53281,1:::::::::goto 10

    Dann variiere mal die Anzahl der Doppelpunkte....

    1ST1

  • Wegen der compile-Fehlermeldungen von MinGW32 (GCC 12.2.0 version) habe ich mal dessen
    C:\mingw32\i686-w64-mingw32\includedirent.h

    "gepatcht" dass er d_type und DT_REG wieder kennt und konnte somit dann auch auf dem PC die Version vom BASIC damit compilieren.

    Das wurde um 81KB groesser (110KB zu 191KB).

    Wenn man nun noch die compile-Optimierung -O3 dazu nimmt als compile-Option beim gcc, dann kommt man sogar auf 238KB

    Dafuer halbbiert sich die Ausfuehrungzeit ;)

    BTW: gerade getestet CATALOG zeigt kein Directory an, aber LOAD/SAVE klappt...

  • Toll wie Du Dich dafür engagierst, aber das IoT-BASIC ist schon recht speziell, habe mal was probiert und als es eine Endlosschleife (mit PRINT Ausgaben) war, wollte ich Ctrl-C zum Stoppen benutzen. Da ist dann der ganze Interpreter sofort beendet worden...

    Wie kann man denn mit dem Windows-Binary laufende Programme stoppen, ohne den Interpreter dabei zu beenden?

    "The biggest communication problem is we do not listen to understand. We listen to reply." - Stephen Covey

    Webseite und Blog ist immer noch - seit fast 20 Jahren - online.

  • Toll wie Du Dich dafür engagierst, aber das IoT-BASIC ist schon recht speziell, habe mal was probiert und als es eine Endlosschleife (mit PRINT Ausgaben) war, wollte ich Ctrl-C zum Stoppen benutzen. Da ist dann der ganze Interpreter sofort beendet worden...

    Wie kann man denn mit dem Windows-Binary laufende Programme stoppen, ohne den Interpreter dabei zu beenden?

    habe ich auch schon gemerkt, dass man mit Ctrl-C gleich ganz raus ist...

    evtl. kann uns slenz was zu BREAKCHAR sagen, und wie man dies in BASIC definiert, da die Standardbelegung (Default BREAKCHAR is '#') bei mir leider nicht greift:

  • Wegen BREAKCHAR: das geht leider auf Windows bzw. POSIX nicht. Der Mechanismus setzt voraus, dass I/O non blocking ist, was getchar auf POSIX Platformen nicht tut. Bei Arduino kann ich Zeichen aus dem Serial Stream abfangen.

    Ich habe eben mal einen Signalhandler implementiert und auf Windows und Mac getestet. Windows mit MINGW64 (siehe unten). Wenn ihr die neue Version von basic.c und hardware-posix.h runterladet und compiliert, müsste jetzt Ctrl-C ein Program unterbrechen können. Das ist nur wenig getestet. Feedback ist willkommen.

    Man kann jetzt aber den Interpreter nicht mehr mit Ctrl-C verlassen. Das geht aber immer mit CALL 0.

    Wegen Compilerproblemen: ich habe dazu eben auch eine neue Version von basic.c und hardware-posix.c eingecheckt. Diese Version kann mit MINGW64 compiliert werden. Die bisherige Version war nur MINGW32 getestet. Das "alte" sprich originale MINGW von mingw.org hat Standard POSIX Filehandling. Die Header von MINGW64 sehen eher wir Windows/MSDOS aus. Setzt bitte die Flag MINGW64 in basic.c vor dem Compilieren.

    Einmal editiert, zuletzt von slenz (23. März 2023 um 23:20)

  • Habs noch nicht probiert, aber mal in die Anleitung geschaut bzw. diese gelesen. Sieht interessant aus und könnte auch auf anderen Plattformen evtl. interessant sein. Insbesondere natürlich, wenn es schnell ist.

    Hätte mal ein paar Anregungen, was mir so aufgefallen/eingefallen ist.

    Zunächst aber mal - das mit den REM Zeilen (was ja hier der Diskussionsauslöser war) geht so wahrscheinlich wirklich nicht. Es verhindert vor allem GANZ wirksam, daß Leute sowas benutzen, wenn sie einfach mal Sachen probeiren wollen, die sie im Netz gefunden haben und die REM Zeilen haben. Niemand fängt heute an per Hand REM Zeilen zu entfernen oder gar Anführungszeichen drumherum zu setzen. Kurz für wirklich Benutzer, die selbst Programme damit schreiben ist das so OK und zumutbar (zumal es ja dann woanders auch mit den Anführungszeichen läuft), aber es schränkt wahrscheinlich den Kreis potentieller "Probierer" ziemlich ein.

    Na ja, egal. Wichtiger sind evtl. diese Sachen hier:

    Es gibt anscheinend nur eine Schleifenform: FOR NEXT STEP. Ganz klassisch. Gehört sich auch so. Aus dem Handbuch ist nicht ersichtlich, ob man auch abwärts zählen kann.

    Es wäre evtl. gut noch eine paar andere Varianten zu haben. Also sowas wie WHILE. Mir haben ja immer die späteren Commodore Schleifen Konstrukte in BASIC >= 3.5 gefallen, diese sind DO ... LOOP mit den Zusätzen WHILE und UNTIL , https://www.c64-wiki.de/wiki/LOOP_(BASIC_3.5)

    Ansonsten ist eine Mehrfachauswahl schön. Gerade in BASIC wird sowas sonst ganz schnell zu einem IF Desaster. Also sowas wie SWITCH(variable) - CASE 1 ; CASE 2 ; CASE 3 etc. ; In BCC Basic ließt sich das schöner, da wird benutzt CASE variable OF - WHEN 1 ; WHEN 2 ; ... ENDCASE.

    Evtl. lassen sich da ja auch zwei Varianten zumindest intern anlegen, die für Strings und Zahlen und Ints/Bytes unterschiedlichen Code verwenden.

    Da du ja die Variablen alle letztlich als Byteblocks ablegst inkl. Strings, kann man da evtl. schön solche Byteweisen Zugriff erlauben, wie das BBC sie hat. Dort kann man mit Variable!4 auf das 4te Byte/Word der Variablen direkt zugreifen. Da das auch mit Strings und Arrays geht, wird das eine schöne Form von PEEK/POKE und es ist relativ flexibel nutzbar, weil man statt der !4 auch eine Variable nehmen kann.

    In den deutschen Handbücher nennen sie das so schön "Byte Indirektionsparameter" ... http://www.riscos.com/support/develo…essmemlocs.html

    Ist ein mächtiges Tool und würde hier auch schon zum Einsatzzweck passen.

    Außerdem sind so ein paar Sachen aus C sicherlich auch eine Überlegung wert. Insbesonder dieses Variable++ bzw. Variable-- ist was sehr Nettes. Man kann ja ein Space dazwischen lassen. Und für Variable += 4 hätten sicher auch einige Leute was übrig.


    So, ab hier wird "spinnig"

    Was mir immer schon gefallen hätte, wäre sowas wie ein impliziter Counter in Schleifen. Insbesondere aber sowas wie ein Zusatzcounter, der in einer Schleife einfach mit hochgezählt werden kann. Also ungefähr sowas in der Art hier

    FOR I = 0 TO 100 [ STEP 1 [ WITH C1, Z, X ] ] : ... : NEXT I

    wobei C1, Z, X jeweils genauso wie I mitverändert werden.

    Schöne wäre auch sowas wie

    FOR I = 0 TO 100 [ STEP 1 [ WITH COPY C1, Z, X ] ] : ... : NEXT I

    was das gleiche macht, aber C1, Z, X werden nach Ablauf der Schleife wieder auf ihren Ursprungswert zurückgesetzt.

    Könnte auch heißen

    FOR I = 0 TO 100 [ STEP 1 [ WITH C1, Z, X [ USECOPY ] ] ] : ... : NEXT I

    auch wenn das ein schwieriges Konstrukt ist, weil sehr BASIC untypisch.

    Die Grafikbefehle sind ein wenig ... wenig. Vielleicht kann man die prinzipiell auch komplett weglassen und das wie eine Bibliothek behandeln und einen Befehl einführen, der abgfragt, ob Grafikbefehle überhaupt "einkompiliert" sind. Die meisten Leute auf den Mikrocontrollern werden sie eh nicht verwenden (können/wollen).

    Wenn sie aber dabei sind, dürfen es wirklich ein paar mehr sein. Insbesondere aber sollte man sich evtl überlegen, wie man die Koordinaten benutzt. Es hat nämlich gerade bei heute möglichen Auflösungen durchaus seinen Charme, wenn man die z.B. auch generell als Bildschirm-relativ angeben kann. Also etwa als PLOT ( X R, Y R ) bzw. PLOTR( X, Y ), wobei in dem Fall 100% die Maximalauflösung ist. Möglicherweise macht es auch Sinn statt 100% eine interne 255 zu nehmen oder eine 65536 oder mehr und Kommawerte (oder gefakte Kommawerte) zuzulassen. Der Charme bei sowas ist, daß man z.B. Diagramme o.ä. überall dann ähnlich anzeigen kann. Für präzise Sachen und Games taugt es eher bedingt (bzw. nur bei hohen realen Auflösungen).

    Außerdem ist ein TRIANGLE Befehl was sehr hübsches. Zumindest wenn man heute Spielkinder auf die "Plattform" holen will.

    So und jetzt ist erstmal gut ... ;)

    -- 1982 gab es keinen Raspberry Pi , aber Pi und Raspberries

  • Ich habe eben mal einen Signalhandler implementiert und auf Windows und Mac getestet.
    Windows mit MINGW64 (siehe unten). Wenn ihr die neue Version von basic.c und hardware-posix.h runterladet und compiliert, müsste jetzt Ctrl-C ein Program unterbrechen können.
    Das ist nur wenig getestet. Feedback ist willkommen.

    Man kann jetzt aber den Interpreter nicht mehr mit Ctrl-C verlassen. Das geht aber immer mit CALL 0.

    Wegen Compilerproblemen: ich habe dazu eben auch eine neue Version von basic.c und hardware-posix.c eingecheckt. Diese Version kann mit MINGW64 compiliert werden. Die bisherige Version war nur MINGW32 getestet.
    Das "alte" sprich originale MINGW von mingw.org hat Standard POSIX Filehandling. Die Header von MINGW64 sehen eher wir Windows/MSDOS aus. Setzt bitte die Flag MINGW64 in basic.c vor dem Compilieren.

    slenz Ich habe es eben mal mit dem WinLibs MinGW32 und MinGW64 compiliert und getestet.

    (GCC 12.2.0 + LLVM/Clang/LLD/LLDB 15.0.7 + MinGW-w64 10.0.0 (MSVCRT) - release 4)

    Bei beiden Versionen klappte es mit dem Flag MINGW64 (bei MinGW32 mit originaler dirent.h).

    Ctrl-C klappt nun einwandfrei wie auch die Ausgabe von CATALOG ;)

    Das Ctrl-C hatte ich bei den 1000 Stellen von Pi getestet und die Ausfuehrung wurde sauber abgebrochen, aber man ist noch im Interpreter. CALL 0 brachte mich auch einwandfrei zureuck zum Prompt.

    Der Inhalt kann nicht angezeigt werden, da du keine Berechtigung hast, diesen Inhalt zu sehen.


    Ein Zeilenumbruch nach dem Ctrl-C waer schoen (hatte hier 2mal ENTER gedrueckt) und eine Meldung wie "BREAK in 150" noch erste Sahne :)

    Peter z80.eu Gegen einen Alias von SYSTEM zu CALL 0 haette ich auch nichts ;)

    Einen Geschwindigkeitsvorteil bringt die 64Bit Version nicht gegenueber der 32Bit Version,
    dafuer laeuft die 32Bit Version auch unter Windows 64Bit ;)

    Compiliert hatte ich je nach Bit mit folgendem Befehl:

    Code
    gcc -m32 basic.c -o basic-win-32bit.exe -O3 -mconsole -lm
    gcc -m64 basic.c -o basic-win-64bit.exe -O3 -mconsole -lm
  • [...]

    Ctrl-C klappt nun einwandfrei wie auch die Ausgabe von CATALOG ;)

    Das Ctrl-C hatte ich bei den 1000 Stellen von Pi getestet und die Ausfuehrung wurde sauber abgebrochen, aber man ist noch im Interpreter. CALL 0 brachte mich auch einwandfrei zureuck zum Prompt.

    Einen Geschwindigkeitsvorteil bringt die 64Bit Version nicht gegenueber der 32Bit Version,
    dafuer laeuft die 32Bit Version auch unter Windows 64Bit ;)

    Compiliert hatte ich je nach Bit mit folgendem Befehl:

    Code
    gcc -m32 basic.c -o basic-win-32bit.exe -O3 -mconsole -lm
    gcc -m64 basic.c -o basic-win-64bit.exe -O3 -mconsole -lm

    Jetzt nur noch wie vorgeschlagen SYSTEM als zusätzlichen Befehl implementieren, und die Welt ist fast in Ordnung.

    Das mit den Anführungsstrichen für die Zeichenketten nach dem REM Befehl finde ich zwar immer noch gewöhnungsbedürftig, aber wenn man es weiß kann man damit leben 8o

    "The biggest communication problem is we do not listen to understand. We listen to reply." - Stephen Covey

    Webseite und Blog ist immer noch - seit fast 20 Jahren - online.

  • Das mit dem SYSTEM ginge schnell zu machen. Warum ist es nicht drin? Weil Tokens knapp sind. Der Interpreter ist so gebaut, dass er strikt 1 byte Tokens verwendet im Bereich von -1 bis -127. Momentan sind nur noch 20 Tokens frei. Deswegen spare ich.

    Die alten BASIC hatten das gleich Problem und haben irgendwann 2 byte Tokens eingeführt. Man sieht das schön, wenn man sich das Amstrad BASIC anschaut, dass sehr viele Keywords hatte.

    Ich zögere gerade, 2byte Tokens einzuführen, weil ich will, dass das BASIC auf Arduino 8 bit noch läuft. Ich werde in den nächsten Tagen 1.4 final releasen, danach schaue ich mir den Lexer nochmal an. Stichwort, dynamischer Namespace, also echte Aliases.

  • Zunächst aber mal - das mit den REM Zeilen (was ja hier der Diskussionsauslöser war) geht so wahrscheinlich wirklich nicht. Es verhindert vor allem GANZ wirksam, daß Leute sowas benutzen, wenn sie einfach mal Sachen probeiren wollen, die sie im Netz gefunden haben und die REM Zeilen haben. Niemand fängt heute an per Hand REM Zeilen zu entfernen oder gar Anführungszeichen drumherum zu setzen. Kurz für wirklich Benutzer, die selbst Programme damit schreiben ist das so OK und zumutbar (zumal es ja dann woanders auch mit den Anführungszeichen läuft), aber es schränkt wahrscheinlich den Kreis potentieller "Probierer" ziemlich ein

    Das mit dem REM ist tatsächlich eigenartig. Es ist eine direkte Konsequenz der Tokenisierung. Wenn man vollständige(!) Tokenisierung macht, muss jedes Objekt im Programspeicher einen Typ haben. Man könnte theoretisch einen Typ LITERAL einführen und dann würde man folgenderweise tokenisieren

    10 REM Das ist ein Text

    20 PRINT

    als

    LINENUMBER 10

    Token REM

    LITERAL 16 Das ist ein Text

    LINENUMBER 20

    Dann kann man bei LIST wieder eindeutig detokenisieren. Das Problem ist ja, dass man LIST machen will, d.h. den Code wieder zurück in Text verwandeln will.

    Warum verwende ich Strings? Weil

    10 REM "Das ist ein Text"

    einfach so tokensiert wird

    LINENUMBER 10

    Token REM

    STRING 16 Das ist ein Text

    MS BASIC hat das Problem gelöst, indem es nur die Zeilennummern und die Kommandos tokenisiert und sonst alle Objekte als Zeichenketten speichert. Das heisst dann aber auch, dass in Schleifen immer wieder die gleiche Zahl geparst werden muss. Der Grund warum die das so machen ist aber genau das Problem, das man hier bei REM hat.

    Zitat

    Es gibt anscheinend nur eine Schleifenform: FOR NEXT STEP. Ganz klassisch. Gehört sich auch so. Aus dem Handbuch ist nicht ersichtlich, ob man auch abwärts zählen kann.

    Es wäre evtl. gut noch eine paar andere Varianten zu haben. Also sowas wie WHILE. Mir haben ja immer die späteren Commodore Schleifen Konstrukte in BASIC >= 3.5 gefallen, diese sind DO ... LOOP mit den Zusätzen WHILE und UNTIL , https://www.c64-wiki.de/wiki/LOOP_(BASIC_3.5)

    Ja und nein. Es gibt ein paar Tricks, folgendes ist legal

    FOR I

    ....

    IF some condition THEN BREAK

    NEXT

    FOR I

    IF some condition THEN BREAK

    ....

    NEXT

    Ersteres ist DO ... UNTIL

    Zweiteres ist WHILE .... WEND

    Außerdem geht noch

    FOR I

    ... block A ...

    IF some condition THEN CONT

    ... block B ...

    NEXT

    CONT zählt in der Schleife die Variable weiter und überspringt block B

    Ich wollte mir Tokens sparsam sein, deswegen ist FOR eine Schleife für alle Fälle.

    Zitat

    Ansonsten ist eine Mehrfachauswahl schön. Gerade in BASIC wird sowas sonst ganz schnell zu einem IF Desaster. Also sowas wie SWITCH(variable) - CASE 1 ; CASE 2 ; CASE 3 etc. ; In BCC Basic ließt sich das schöner, da wird benutzt CASE variable OF - WHEN 1 ; WHEN 2 ; ... ENDCASE.

    Das ist syntaktisch recht kniffelig, ich hatte darüber nachgedacht aber keine einfache Syntax gefunden. Es müsste in etwa so sein:

    10 SWITCH <expression>

    20 CASE <expression>

    .... block A ...

    30 CASE <expression>

    .... block B ....

    ....

    90 END SWITCH

    Das ganze hat nur einen wirklichen Nutzen, wenn man das als Block Struktur aufbaut. Man muss dann aber SWITCHES in CASES parsen, was ein relativer Aufwand ist. Und dann wie macht man Dinge mit : eindeutig.

    Ist

    10 SWITCH <expression> : CASE <expression>: .... block A ...: CASE <expression>.... block B ....: END SWITCH

    was man will?

    Zitat

    Die Grafikbefehle sind ein wenig ... wenig. Vielleicht kann man die prinzipiell auch komplett weglassen und das wie eine Bibliothek behandeln und einen Befehl einführen, der abgfragt, ob Grafikbefehle überhaupt "einkompiliert" sind. Die meisten Leute auf den Mikrocontrollern werden sie eh nicht verwenden (können/wollen).

    Das ist tatsächlich so. Auf den MCUs ist das hardware-arduino.h File sehr komplex. Im Grunde ist es ein Mini OS. Die Grafikbefehle werden nur einkompiliert wenn die MCU eine Graphikhardware hat und HASGRAPH gesetzt ist. Generell werden viele Kommandosets nur angezogen, wenn die Platform das kann. Beispiel ist File I/O. Eine Platform ohne Filesystem hat kein OPEN und CLOSE.

    Generell sind die Graphikbefehle nur eine Skizze. Ich muss mir noch genauer einfallen lassen, wie man das macht.

  • Also sowas mag ich z.B. gar nicht, wenn das Programm anfängt selbsttätig Spaces oder anderes dazuzusetzen oder zu entfernen. Was anderes ist, wenn man sowas selbst als Macro o.ä. eingestellt hat. Aber z.B. der Editor von QBasic oder QuickB ist diesbezüglich sehr häßlich. Der einzige Vorteil den sowas hat ist, daß Programme dann immer gleich ordentlich aussehen - aber das ist ja genau der Kritikpunkt. :)

    Das eigentliche Problem an den REM Zeilen entsteht m.E. dann, wenn man echten Code "kommentiert" also z.B. mit REM ausmarkiert. In dem Moment ändert sich das dann hier von Token zu String bzw geht ohne Anführungsstriche nicht. Und noch schlimmer wird dann die entgegengesetzte Operation. Da muß ja i.P. der String wieder in Token gewandelt werden. So gesehen ist das eigentlich rein prinzipiell schon erstmal eine gute Lösung mit dem String für reine Kommentare.

    Vielleicht wäre ja eine Option, daß man hinter REM einfach immer und per Definition einen String erwartet, der dann auch bis zum Zeilenende reicht und folglich gar nicht besonders markiert werden muß (also ohne Anführungszeichen). Damit man aber trotzdem noch Programmzeilen mit Code ausmarkieren kann, macht man einfach ein Zuatzkommando auf: sowas wie "RMK" (remark) oder "CRM" (code rem) oder ":RM".


    Ich wollte mir Tokens sparsam sein, deswegen ist FOR eine Schleife für alle Fälle.

    OK. Scheint ja eng im Speicher zu sein.

    Der C nahe Ansatz wäre dann aber gewesen, eine While Schleife zu benutzen. ;)


    Na ja, je nachdem, wie komplex man das zulassen will. Für die reine Benutzung und das, was man oft mit sowas macht, würde es wohl völlig gausreichen, wenn nach einem CASE gar kein Block kommt, sondern das CASE einfach nur bis Zeilenende wirkt. Wer dann unbedingt mehr braucht, muß halt erstmal Gosubs bemühen, also

    Code
    10 SWITCH <expr/var> 
    20 CASE <expr> anweisung1 [ : anweisung2 [ : anweisung3 [ ... ] ] ]
    30 CASE <expr> anweisung1 [ : anweisung2 [ : anweisung3 [ ... ] ] ]
    40 CASE <expr> anweisung1 [ : anweisung2 [ : anweisung3 [ ... ] ] ]
    50 END SWITCH


    Generell sind die Graphikbefehle nur eine Skizze. Ich muss mir noch genauer einfallen lassen, wie man das macht.

    Klingt gut.

    Meine Ideen, wo man dafür Anregungen holen kann, wären die Löve Bibliothek und die Allegrobibliothek und da v.a. der 2D Teil. Außerdem kannst Du hier mal nach tomtom suchen. Da gibt es auch was. Siehe Double LORES Bibliothek für AppleSoft

    -- 1982 gab es keinen Raspberry Pi , aber Pi und Raspberries

  • MS BASIC hat das Problem gelöst, indem es nur die Zeilennummern und die Kommandos tokenisiert und sonst alle Objekte als Zeichenketten speichert. Das heisst dann aber auch, dass in Schleifen immer wieder die gleiche Zahl geparst werden muss. Der Grund warum die das so machen ist aber genau das Problem, das man hier bei REM hat.

    Gerade noch aufgefallen ... DAS macht aber auch alles richtig wunderbar langsam. Will man wohl eher nicht.

    -- 1982 gab es keinen Raspberry Pi , aber Pi und Raspberries

  • Es paßt schon. Aber es ist eben wohl nicht das, was so ein üblicher Basic Interpreter macht. Der hat doch eigentlich die Kommentare etc. eben immer mit im Speicher - deshalb tritt ja diese Art Problem überhaupt erst auf. Einen Compiler stört sowas gar nicht, v.a. deshalb, weil er ja genau das, was Du da vorschlägst, als allererstes macht.

    Der macht auch aus Funktionsnamen oder Befehlen keine Tokens - zumindest keine in der Art, daß er sie auch in normalen Text rückübersetzen können soll.

    So gesehen: der Vorschlag ist gut und würde helfen, aber eben nicht, wenn die Kommentare beim Ausführen immer mit im Speicher stehen sollen.

    -- 1982 gab es keinen Raspberry Pi , aber Pi und Raspberries

  • Code
    10 SWITCH <expr/var> 
    20 CASE <expr> anweisung1 [ : anweisung2 [ : anweisung3 [ ... ] ] ]
    30 CASE <expr> anweisung1 [ : anweisung2 [ : anweisung3 [ ... ] ] ]
    40 CASE <expr> anweisung1 [ : anweisung2 [ : anweisung3 [ ... ] ] ]
    50 END SWITCH

    Das gibt es schon, uns zwar geht das so:

    Code
    10 INPUT A
    20 IF A=1 THEN PRINT "EINS"
    30 ELSE IF A=2 THEN PRINT "ZWEI"
    40 ELSE IF A=3 THEN PRINT "DREI"
    50 ELSE PRINT "Unbekannt"
    60 GOTO 10

    ELSE kann bei IoT BASIC auf der nächsten Zeile nach IF kommen. Damit kann man genau solche Kettenabfragen bauen. Deswegen habe ich das so implementiert. Das ist ein Trick. ELSE wird vom Parser als "terminal symbol" gesehen, also einfach ein Zeilenanfang oder ":" . IF sucht das ELSE bis zum Anfang der Folgezeile es checkt dann, ob das ELSE vielleicht nach der Zeilennummer kommt. Das kann man mit minimalen Aufwand einbauen und kriegt eine Menge Nutzen für ein paar Bytes mehr Programmcode.

  • Vielleicht wäre ja eine Option, daß man hinter REM einfach immer und per Definition einen String erwartet, der dann auch bis zum Zeilenende reicht und folglich gar nicht besonders markiert werden muß (also ohne Anführungszeichen).

    Wenn man es beim REM immer als String nehmen wuerde, muesste man nur schauen ob man evtl. vorne und hinten ein " einfuegt oder ob diese schon vorhanden sind.

    So koennte man beider Versionen nutzen.

    Oder man strippt diese wenn vorhanden und nimmt alles nach dem "REM " (also ohne das eine Leerzeichen) als String - somit koennten andere Source-Quellen einfach eingefuegt/pasted werden ;)

  • Zitat

    Vielleicht wäre ja eine Option, daß man hinter REM einfach immer und per Definition einen String erwartet, der dann auch bis zum Zeilenende reicht und folglich gar nicht besonders markiert werden muß (also ohne Anführungszeichen). Damit man aber trotzdem noch Programmzeilen mit Code ausmarkieren kann, macht man einfach ein Zuatzkommando auf: sowas wie "RMK" (remark) oder "CRM" (code rem) oder ":RM".

    Ich hab das mal so ähnlich versucht. Scheint zu gehen. Ist bisher nur kurz getestet. Danke für den Gedanken!